1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "ring_buffer.h"
18
19 #include "integral_types.h"
20
21 namespace video_editing {
22
Init(int size,int num_channels,int num_readers)23 void RingBuffer::Init(int size, int num_channels, int num_readers) {
24 size_ = size;
25 num_channels_ = num_channels;
26 num_readers_ = num_readers;
27 temp_read_buffer_size_ = 1024;
28 initialized_ = true;
29 Reset();
30 }
31
RingBuffer()32 RingBuffer::RingBuffer()
33 : initialized_(false), samples_(NULL),
34 num_readers_(0), temp_read_buffer_(NULL) {
35 }
36
~RingBuffer()37 RingBuffer::~RingBuffer() {
38 delete[] samples_;
39 delete[] temp_read_buffer_;
40 }
41
Reset()42 void RingBuffer::Reset() {
43 delete[] samples_;
44 samples_ = new float[size_ * num_channels_];
45 memset(samples_, 0,
46 size_ * num_channels_ * sizeof(samples_[0]));
47
48 temp_read_buffer_size_ = 1024;
49 delete[] temp_read_buffer_;
50 temp_read_buffer_ = new float[temp_read_buffer_size_ * num_channels_];
51 memset(temp_read_buffer_, 0,
52 temp_read_buffer_size_ * num_channels_ * sizeof(samples_[0]));
53 readers_.clear();
54 for (int i = 0; i < num_readers_; ++i) {
55 readers_.push_back(0LL);
56 }
57 head_logical_ = 0LL;
58 head_ = 0;
59 }
60
available(int reader) const61 int RingBuffer::available(int reader) const {
62 return head_logical_ - readers_[reader];
63 }
64
overhead() const65 int RingBuffer::overhead() const {
66 int64 tail = GetTail();
67 return tail + size_ - head_logical_;
68 }
69
GetTail() const70 int64 RingBuffer::GetTail() const {
71 return *min_element(readers_.begin(), readers_.end());
72 }
73
Tell(int reader) const74 int64 RingBuffer::Tell(int reader) const {
75 return readers_[reader];
76 }
77
Seek(int reader,int64 position)78 void RingBuffer::Seek(int reader, int64 position) {
79 readers_[reader] = position;
80 }
81
Write(const float * samples,int num_frames)82 void RingBuffer::Write(const float* samples, int num_frames) {
83 if (!num_frames) {
84 return;
85 }
86 if (head_ + num_frames <= size_) {
87 memcpy(samples_ + head_ * num_channels_, samples,
88 num_frames * num_channels_ * sizeof(samples[0]));
89 head_ += num_frames;
90 } else {
91 int overhead = size_ - head_;
92 memcpy(samples_ + head_ * num_channels_, samples,
93 num_channels_ * overhead * sizeof(samples[0]));
94 head_ = num_frames - overhead;
95 memcpy(samples_, samples + overhead * num_channels_,
96 num_channels_ * head_ * sizeof(samples[0]));
97 }
98 head_logical_ += num_frames;
99 }
100
Copy(int reader,float * destination,int num_frames) const101 void RingBuffer::Copy(int reader, float* destination, int num_frames) const {
102 int pos = Tell(reader) % size_;
103 if (pos + num_frames <= size_) {
104 memcpy(destination, samples_ + pos * num_channels_,
105 num_channels_ * num_frames * sizeof(destination[0]));
106 } else {
107 int wrapped = size_ - pos;
108 memcpy(destination, samples_ + pos * num_channels_,
109 num_channels_ * wrapped * sizeof(destination[0]));
110 int remaining = num_frames - wrapped;
111 memcpy(destination + wrapped * num_channels_, samples_,
112 num_channels_ * remaining * sizeof(destination[0]));
113 }
114 }
115
GetPointer(int reader,int num_frames)116 float* RingBuffer::GetPointer(int reader, int num_frames) {
117 int pos = Tell(reader) % size_;
118 if (pos + num_frames <= size_) {
119 return samples_ + pos * num_channels_;
120 } else {
121 if (num_frames > temp_read_buffer_size_) {
122 temp_read_buffer_size_ = num_frames;
123 delete[] temp_read_buffer_;
124 temp_read_buffer_ =
125 new float[temp_read_buffer_size_ * num_channels_]; // NOLINT
126 }
127 Copy(reader, temp_read_buffer_, num_frames);
128 return temp_read_buffer_;
129 }
130 }
131
MergeBack(int reader,const float * source,int num_frames)132 void RingBuffer::MergeBack(int reader, const float* source, int num_frames) {
133 // If the source pointer is not the temporary buffer,
134 // data updates were performed in place, so there is nothing to do.
135 // Otherwise, copy samples from the temp buffer back to the ring buffer.
136 if (source == temp_read_buffer_) {
137 int pos = Tell(reader) % size_;
138 if (pos + num_frames <= size_) {
139 memcpy(samples_ + (pos * num_channels_), source,
140 num_channels_ * num_frames * sizeof(source[0]));
141 } else {
142 int wrapped = size_ - pos;
143 memcpy(samples_ + (pos * num_channels_), source,
144 num_channels_ * wrapped * sizeof(source[0]));
145 int remaining = num_frames - wrapped;
146 memcpy(samples_, source + (wrapped * num_channels_),
147 num_channels_ * remaining * sizeof(source[0]));
148 }
149 }
150 }
151
152 } // namespace video_editing
153