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_ = |
| 153 (*buffer)->timestamp() + base::TimeDelta::FromMicroseconds( |
| 154 static_cast<int64>(time_offset + 0.5)); |
| 155 } |
| 156 } |
| 157 |
| 158 } // namespace media |
OLD | NEW |