/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ring_buffer.h" #include "integral_types.h" namespace video_editing { void RingBuffer::Init(int size, int num_channels, int num_readers) { size_ = size; num_channels_ = num_channels; num_readers_ = num_readers; temp_read_buffer_size_ = 1024; initialized_ = true; Reset(); } RingBuffer::RingBuffer() : initialized_(false), samples_(NULL), num_readers_(0), temp_read_buffer_(NULL) { } RingBuffer::~RingBuffer() { delete[] samples_; delete[] temp_read_buffer_; } void RingBuffer::Reset() { delete[] samples_; samples_ = new float[size_ * num_channels_]; memset(samples_, 0, size_ * num_channels_ * sizeof(samples_[0])); temp_read_buffer_size_ = 1024; delete[] temp_read_buffer_; temp_read_buffer_ = new float[temp_read_buffer_size_ * num_channels_]; memset(temp_read_buffer_, 0, temp_read_buffer_size_ * num_channels_ * sizeof(samples_[0])); readers_.clear(); for (int i = 0; i < num_readers_; ++i) { readers_.push_back(0LL); } head_logical_ = 0LL; head_ = 0; } int RingBuffer::available(int reader) const { return head_logical_ - readers_[reader]; } int RingBuffer::overhead() const { int64 tail = GetTail(); return tail + size_ - head_logical_; } int64 RingBuffer::GetTail() const { return *min_element(readers_.begin(), readers_.end()); } int64 RingBuffer::Tell(int reader) const { return readers_[reader]; } void RingBuffer::Seek(int reader, int64 position) { readers_[reader] = position; } void RingBuffer::Write(const float* samples, int num_frames) { if (!num_frames) { return; } if (head_ + num_frames <= size_) { memcpy(samples_ + head_ * num_channels_, samples, num_frames * num_channels_ * sizeof(samples[0])); head_ += num_frames; } else { int overhead = size_ - head_; memcpy(samples_ + head_ * num_channels_, samples, num_channels_ * overhead * sizeof(samples[0])); head_ = num_frames - overhead; memcpy(samples_, samples + overhead * num_channels_, num_channels_ * head_ * sizeof(samples[0])); } head_logical_ += num_frames; } void RingBuffer::Copy(int reader, float* destination, int num_frames) const { int pos = Tell(reader) % size_; if (pos + num_frames <= size_) { memcpy(destination, samples_ + pos * num_channels_, num_channels_ * num_frames * sizeof(destination[0])); } else { int wrapped = size_ - pos; memcpy(destination, samples_ + pos * num_channels_, num_channels_ * wrapped * sizeof(destination[0])); int remaining = num_frames - wrapped; memcpy(destination + wrapped * num_channels_, samples_, num_channels_ * remaining * sizeof(destination[0])); } } float* RingBuffer::GetPointer(int reader, int num_frames) { int pos = Tell(reader) % size_; if (pos + num_frames <= size_) { return samples_ + pos * num_channels_; } else { if (num_frames > temp_read_buffer_size_) { temp_read_buffer_size_ = num_frames; delete[] temp_read_buffer_; temp_read_buffer_ = new float[temp_read_buffer_size_ * num_channels_]; // NOLINT } Copy(reader, temp_read_buffer_, num_frames); return temp_read_buffer_; } } void RingBuffer::MergeBack(int reader, const float* source, int num_frames) { // If the source pointer is not the temporary buffer, // data updates were performed in place, so there is nothing to do. // Otherwise, copy samples from the temp buffer back to the ring buffer. if (source == temp_read_buffer_) { int pos = Tell(reader) % size_; if (pos + num_frames <= size_) { memcpy(samples_ + (pos * num_channels_), source, num_channels_ * num_frames * sizeof(source[0])); } else { int wrapped = size_ - pos; memcpy(samples_ + (pos * num_channels_), source, num_channels_ * wrapped * sizeof(source[0])); int remaining = num_frames - wrapped; memcpy(samples_, source + (wrapped * num_channels_), num_channels_ * remaining * sizeof(source[0])); } } } } // namespace video_editing