OLD | NEW |
---|---|
(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/audio_buffer_queue.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 AudioBufferQueue::AudioBufferQueue() { Clear(); } | |
16 AudioBufferQueue::~AudioBufferQueue() {} | |
17 | |
18 void AudioBufferQueue::Clear() { | |
19 buffers_.clear(); | |
20 current_buffer_ = buffers_.begin(); | |
21 current_buffer_offset_ = 0; | |
22 frames_ = 0; | |
23 current_time_ = kNoTimestamp(); | |
24 } | |
25 | |
26 void AudioBufferQueue::Append(const scoped_refptr<AudioBuffer>& buffer_in) { | |
27 // If we have just written the first buffer, update |current_time_| to be the | |
28 // start time. | |
29 if (buffers_.empty()) { | |
30 DCHECK_EQ(frames_, 0); | |
31 current_time_ = buffer_in->timestamp(); | |
32 } | |
33 | |
34 // Add the buffer to the queue. Inserting into deque invalidates all | |
35 // iterators, so point to the first buffer. | |
36 buffers_.push_back(buffer_in); | |
37 current_buffer_ = buffers_.begin(); | |
38 | |
39 // Update the |frames_| counter since we have added frames. | |
40 frames_ += buffer_in->frame_count(); | |
41 CHECK_GT(frames_, 0); // make sure it doesn't overflow. | |
42 } | |
43 | |
44 int AudioBufferQueue::ReadFrames(int frames, AudioBus* dest) { | |
45 DCHECK_GE(dest->frames(), frames); | |
46 return InternalRead(frames, true, 0, dest); | |
47 } | |
48 | |
49 int AudioBufferQueue::PeekFrames(int frames, | |
50 int forward_offset, | |
51 AudioBus* dest) { | |
52 DCHECK_GE(dest->frames(), frames); | |
53 return InternalRead(frames, false, forward_offset, dest); | |
54 } | |
55 | |
56 void AudioBufferQueue::SeekFrames(int frames) { | |
57 // Perform seek only if we have enough bytes in the queue. | |
58 CHECK_LE(frames, frames_); | |
59 int taken = InternalRead(frames, true, 0, NULL); | |
60 DCHECK_EQ(taken, frames); | |
61 } | |
62 | |
63 int AudioBufferQueue::InternalRead(int frames, | |
64 bool advance_position, | |
65 int forward_offset, | |
66 AudioBus* dest) { | |
67 // Counts how many frames are actually read from the buffer queue. | |
68 int taken = 0; | |
69 BufferQueue::iterator current_buffer = current_buffer_; | |
70 int current_buffer_offset = current_buffer_offset_; | |
71 | |
72 int frames_to_skip = forward_offset; | |
73 while (taken < frames) { | |
74 // |current_buffer| is valid since the first time this buffer is appended | |
75 // with data. Make sure there is data to be processed. | |
76 if (current_buffer == buffers_.end()) | |
77 break; | |
78 | |
79 scoped_refptr<AudioBuffer> buffer = *current_buffer; | |
80 | |
81 int remaining_frames_in_buffer = | |
82 buffer->frame_count() - current_buffer_offset; | |
83 | |
84 if (frames_to_skip > 0) { | |
85 // If there are frames to skip, do it first. May need to skip into | |
86 // subsequent buffers. | |
87 int skipped = std::min(remaining_frames_in_buffer, frames_to_skip); | |
88 current_buffer_offset += skipped; | |
89 frames_to_skip -= skipped; | |
90 } else { | |
91 // Find the right amount to copy from the current buffer. We shall copy no | |
92 // more than |frames| frames in total and each single step copies no more | |
93 // than the current buffer size. | |
94 int copied = std::min(frames - taken, remaining_frames_in_buffer); | |
95 | |
96 // if |dest| is NULL, there's no need to copy. | |
97 if (dest) | |
98 buffer->ReadFrames(copied, current_buffer_offset, taken, dest); | |
99 | |
100 // Increase total number of frames copied, which regulates when to end | |
101 // this loop. | |
102 taken += copied; | |
103 | |
104 // We have read |copied| frames from the current buffer. Advance the | |
105 // offset. | |
106 current_buffer_offset += copied; | |
107 } | |
108 | |
109 // Has the buffer has been consumed? | |
110 if (current_buffer_offset == buffer->frame_count()) { | |
111 if (advance_position) { | |
112 // Next buffer may not have timestamp, so we need to update current | |
113 // timestamp before switching to the next buffer. | |
114 UpdateCurrentTime(current_buffer, current_buffer_offset); | |
115 } | |
116 | |
117 // If we are at the last buffer, no more data to be copied, so stop. | |
118 BufferQueue::iterator next = current_buffer + 1; | |
119 if (next == buffers_.end()) | |
120 break; | |
121 | |
122 // Advances the iterator. | |
123 current_buffer = next; | |
124 current_buffer_offset = 0; | |
125 } | |
126 } | |
127 | |
128 if (advance_position) { | |
129 // Update the appropriate values since |taken| frames have been copied out. | |
130 frames_ -= taken; | |
131 DCHECK_GE(frames_, 0); | |
132 DCHECK(current_buffer_ != buffers_.end() || frames_ == 0); | |
133 | |
134 current_buffer_ = current_buffer; | |
135 current_buffer_offset_ = current_buffer_offset; | |
136 | |
137 UpdateCurrentTime(current_buffer_, current_buffer_offset_); | |
138 | |
139 // Remove any buffers before the current buffer as there is no going | |
140 // backwards. | |
141 buffers_.erase(buffers_.begin(), current_buffer_); | |
142 } | |
143 | |
144 return taken; | |
145 } | |
146 | |
147 void AudioBufferQueue::UpdateCurrentTime(BufferQueue::iterator buffer, | |
148 int offset) { | |
149 if (buffer != buffers_.end() && (*buffer)->timestamp() != kNoTimestamp()) { | |
150 double time_offset = ((*buffer)->duration().InMicroseconds() * offset) / | |
151 static_cast<double>((*buffer)->frame_count()); | |
152 current_time_ = | |
DaleCurtis
2013/06/21 00:44:22
Formatting looks really odd, but clang-format seem
jrummell
2013/06/21 01:17:22
I generally let clang-format do it's thing, so thi
| |
153 (*buffer)->timestamp() + base::TimeDelta::FromMicroseconds( | |
154 static_cast<int64>(time_offset + 0.5)); | |
155 } | |
156 } | |
157 | |
158 } // namespace media | |
OLD | NEW |