Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(194)

Side by Side Diff: media/base/seekable_audio_buffer.cc

Issue 17112016: Add new class AudioBufferQueue. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "media/base/seekable_audio_buffer.h"
6
7 #include <algorithm>
8
9 #include "base/logging.h"
10 #include "media/base/audio_bus.h"
11 #include "media/base/buffers.h"
12
13 namespace media {
14
15 SeekableAudioBuffer::SeekableAudioBuffer(int forward_capacity)
16 : current_buffer_offset_(0),
17 forward_capacity_(forward_capacity),
18 forward_frames_(0),
19 current_time_(kNoTimestamp()) {
20 current_buffer_ = buffers_.begin();
21 }
22
23 SeekableAudioBuffer::~SeekableAudioBuffer() {}
24
25 void SeekableAudioBuffer::Clear() {
scherkus (not reviewing) 2013/06/19 23:38:06 do we ever call this method in production? can we
jrummell 2013/06/20 21:47:01 Clear() is called by alsa_output.cc, pulse_input.c
26 buffers_.clear();
27 current_buffer_ = buffers_.begin();
28 current_buffer_offset_ = 0;
29 forward_frames_ = 0;
30 current_time_ = kNoTimestamp();
31 }
32
33 bool SeekableAudioBuffer::Append(const scoped_refptr<AudioBuffer>& buffer_in) {
34 // Since the forward capacity is only used to check the criteria for buffer
35 // full, we always append data to the buffer.
36 buffers_.push_back(buffer_in);
DaleCurtis 2013/06/20 00:49:49 Does this not invalidate the current_buffer_ itera
jrummell 2013/06/20 21:47:01 For list, no. But for deque it does, so fixed.
37
38 // After we have written the first buffer, update |current_buffer_| to point
39 // to it.
40 if (current_buffer_ == buffers_.end()) {
41 DCHECK_EQ(0, forward_frames_);
DaleCurtis 2013/06/20 00:49:49 no yoda conditions.
scherkus (not reviewing) 2013/06/20 00:57:42 I feel I should elaborate on this. The gtest EXPE
jrummell 2013/06/20 21:47:01 Done. However, test code updated to have lots of y
42 current_buffer_ = buffers_.begin();
43 current_buffer_offset_ = 0;
44 current_time_ = buffer_in->timestamp();
45 }
46
47 // Update the |forward_frames_| counter since we have added frames.
48 forward_frames_ += buffer_in->frame_count();
49
50 // Advise the user to stop append if the amount of forward frames exceeds the
51 // forward capacity. A false return value means the user should stop appending
52 // more data to this buffer.
53 return forward_frames_ < forward_capacity_;
54 }
55
56 int SeekableAudioBuffer::ReadFrames(int frames, AudioBus* dest) {
57 DCHECK(dest);
scherkus (not reviewing) 2013/06/19 23:38:06 don't need to DCHECK pointers we immediately deref
jrummell 2013/06/20 21:47:01 Done.
58 DCHECK_GE(dest->frames(), frames);
59 return InternalRead(frames, true, 0, dest);
60 }
61
62 int SeekableAudioBuffer::PeekFrames(int frames,
63 int forward_offset,
64 AudioBus* dest) {
65 DCHECK(dest);
66 DCHECK_GE(dest->frames(), frames);
67 return InternalRead(frames, false, forward_offset, dest);
68 }
69
70 bool SeekableAudioBuffer::SeekFrames(int frames) {
71 // Perform seeking forward only if we have enough bytes in the queue.
72 if (frames > forward_frames_)
scherkus (not reviewing) 2013/06/19 23:38:06 think this can be a CHECK()? I like APIs that fai
jrummell 2013/06/20 21:47:01 Done.
73 return false;
74
75 // Do a read of |frames| frames.
76 int taken = InternalRead(frames, true, 0, NULL);
77 DCHECK_EQ(taken, frames);
78 return true;
79 }
80
81 int SeekableAudioBuffer::InternalRead(int frames,
82 bool advance_position,
83 int forward_offset,
84 AudioBus* dest) {
85 // Counts how many frames are actually read from the buffer queue.
86 int taken = 0;
87 BufferQueue::iterator current_buffer = current_buffer_;
88 int current_buffer_offset = current_buffer_offset_;
89
90 int frames_to_skip = forward_offset;
91 while (taken < frames) {
92 // |current_buffer| is valid since the first time this buffer is appended
93 // with data. Make sure there is data to be processed.
94 if (current_buffer == buffers_.end())
95 break;
96
97 scoped_refptr<AudioBuffer> buffer = *current_buffer;
98
99 int remaining_frames_in_buffer =
100 buffer->frame_count() - current_buffer_offset;
101
102 if (frames_to_skip > 0) {
103 // If there are frames to skip, do it first. May need to skip into
104 // subsequent buffers.
105 int skipped = std::min(remaining_frames_in_buffer, frames_to_skip);
106 current_buffer_offset += skipped;
107 frames_to_skip -= skipped;
108 } else {
109 // Find the right amount to copy from the current buffer. We shall copy no
110 // more than |frames| frames in total and each single step copies no more
111 // than the current buffer size.
112 int copied = std::min(frames - taken, remaining_frames_in_buffer);
113
114 // if |dest| is NULL, there's no need to copy.
115 if (dest)
116 buffer->ReadFrames(copied, current_buffer_offset, taken, dest);
117
118 // Increase total number of frames copied, which regulates when to end
119 // this loop.
120 taken += copied;
121
122 // We have read |copied| frames from the current buffer. Advance the
123 // offset.
124 current_buffer_offset += copied;
125 }
126
127 // Has the buffer has been consumed?
128 if (current_buffer_offset == buffer->frame_count()) {
129 if (advance_position) {
130 // Next buffer may not have timestamp, so we need to update current
131 // timestamp before switching to the next buffer.
132 UpdateCurrentTime(current_buffer, current_buffer_offset);
133 }
134
135 BufferQueue::iterator next = current_buffer;
136 ++next;
137 // If we are at the last buffer, no more data to be copied, so stop.
138 if (next == buffers_.end())
139 break;
140
141 // Advances the iterator.
142 current_buffer = next;
143 current_buffer_offset = 0;
144 }
145 }
146
147 if (advance_position) {
148 // Update the appropriate values since |taken| frames have been copied out.
149 forward_frames_ -= taken;
150 DCHECK_GE(forward_frames_, 0);
151 DCHECK(current_buffer_ != buffers_.end() || forward_frames_ == 0);
152
153 current_buffer_ = current_buffer;
154 current_buffer_offset_ = current_buffer_offset;
155
156 UpdateCurrentTime(current_buffer_, current_buffer_offset_);
157
158 // Remove any buffers before the current pointer as there is no going
159 // backwards.
160 while (true) {
DaleCurtis 2013/06/20 00:49:49 buffers_.erase(buffers_.begin(), current_buffer_)?
jrummell 2013/06/20 21:47:01 Done.
161 BufferQueue::iterator i = buffers_.begin();
162 if (i == current_buffer_)
163 break;
164 buffers_.erase(i);
165 }
166 }
167
168 return taken;
169 }
170
171 void SeekableAudioBuffer::UpdateCurrentTime(BufferQueue::iterator buffer,
172 int offset) {
173 if (buffer != buffers_.end() && (*buffer)->timestamp() != kNoTimestamp()) {
174 int64 time_offset = ((*buffer)->duration().InMicroseconds() * offset) /
DaleCurtis 2013/06/20 00:49:49 Use InMicrosecondsF() and round up by adding 0.5?
jrummell 2013/06/20 21:47:01 There is no InMicrosecondsF(), since TimeDelta is
175 (*buffer)->frame_count();
176 current_time_ = (*buffer)->timestamp() +
177 base::TimeDelta::FromMicroseconds(time_offset);
178 }
179 }
180
181 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698