| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/base/seekable_buffer.h" | 5 #include "media/base/seekable_buffer.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 | 8 |
| 9 #include "base/logging.h" | 9 #include "base/logging.h" |
| 10 #include "media/base/data_buffer.h" | 10 #include "media/base/data_buffer.h" |
| 11 | 11 |
| 12 namespace media { | 12 namespace media { |
| 13 | 13 |
| 14 SeekableBuffer::SeekableBuffer(size_t backward_capacity, | 14 SeekableBuffer::SeekableBuffer(int backward_capacity, |
| 15 size_t forward_capacity) | 15 int forward_capacity) |
| 16 : current_buffer_offset_(0), | 16 : current_buffer_offset_(0), |
| 17 backward_capacity_(backward_capacity), | 17 backward_capacity_(backward_capacity), |
| 18 backward_bytes_(0), | 18 backward_bytes_(0), |
| 19 forward_capacity_(forward_capacity), | 19 forward_capacity_(forward_capacity), |
| 20 forward_bytes_(0), | 20 forward_bytes_(0), |
| 21 current_time_(kNoTimestamp()) { | 21 current_time_(kNoTimestamp()) { |
| 22 current_buffer_ = buffers_.begin(); | 22 current_buffer_ = buffers_.begin(); |
| 23 } | 23 } |
| 24 | 24 |
| 25 SeekableBuffer::~SeekableBuffer() { | 25 SeekableBuffer::~SeekableBuffer() { |
| 26 } | 26 } |
| 27 | 27 |
| 28 void SeekableBuffer::Clear() { | 28 void SeekableBuffer::Clear() { |
| 29 buffers_.clear(); | 29 buffers_.clear(); |
| 30 current_buffer_ = buffers_.begin(); | 30 current_buffer_ = buffers_.begin(); |
| 31 current_buffer_offset_ = 0; | 31 current_buffer_offset_ = 0; |
| 32 backward_bytes_ = 0; | 32 backward_bytes_ = 0; |
| 33 forward_bytes_ = 0; | 33 forward_bytes_ = 0; |
| 34 current_time_ = kNoTimestamp(); | 34 current_time_ = kNoTimestamp(); |
| 35 } | 35 } |
| 36 | 36 |
| 37 size_t SeekableBuffer::Read(uint8* data, size_t size) { | 37 int SeekableBuffer::Read(uint8* data, int size) { |
| 38 DCHECK(data); | 38 DCHECK(data); |
| 39 return InternalRead(data, size, true, 0); | 39 return InternalRead(data, size, true, 0); |
| 40 } | 40 } |
| 41 | 41 |
| 42 size_t SeekableBuffer::Peek(uint8* data, size_t size, size_t forward_offset) { | 42 int SeekableBuffer::Peek(uint8* data, int size, int forward_offset) { |
| 43 DCHECK(data); | 43 DCHECK(data); |
| 44 return InternalRead(data, size, false, forward_offset); | 44 return InternalRead(data, size, false, forward_offset); |
| 45 } | 45 } |
| 46 | 46 |
| 47 bool SeekableBuffer::GetCurrentChunk(const uint8** data, size_t* size) const { | 47 bool SeekableBuffer::GetCurrentChunk(const uint8** data, int* size) const { |
| 48 BufferQueue::iterator current_buffer = current_buffer_; | 48 BufferQueue::iterator current_buffer = current_buffer_; |
| 49 size_t current_buffer_offset = current_buffer_offset_; | 49 int current_buffer_offset = current_buffer_offset_; |
| 50 // Advance position if we are in the end of the current buffer. | 50 // Advance position if we are in the end of the current buffer. |
| 51 while (current_buffer != buffers_.end() && | 51 while (current_buffer != buffers_.end() && |
| 52 current_buffer_offset >= (*current_buffer)->GetDataSize()) { | 52 current_buffer_offset >= (*current_buffer)->GetDataSize()) { |
| 53 ++current_buffer; | 53 ++current_buffer; |
| 54 current_buffer_offset = 0; | 54 current_buffer_offset = 0; |
| 55 } | 55 } |
| 56 if (current_buffer == buffers_.end()) | 56 if (current_buffer == buffers_.end()) |
| 57 return false; | 57 return false; |
| 58 *data = (*current_buffer)->GetData() + current_buffer_offset; | 58 *data = (*current_buffer)->GetData() + current_buffer_offset; |
| 59 *size = (*current_buffer)->GetDataSize() - current_buffer_offset; | 59 *size = (*current_buffer)->GetDataSize() - current_buffer_offset; |
| 60 return true; | 60 return true; |
| 61 } | 61 } |
| 62 | 62 |
| 63 bool SeekableBuffer::Append(Buffer* buffer_in) { | 63 bool SeekableBuffer::Append(Buffer* buffer_in) { |
| 64 if (buffers_.empty() && buffer_in->GetTimestamp().InMicroseconds() > 0) { | 64 if (buffers_.empty() && buffer_in->GetTimestamp().InMicroseconds() > 0) { |
| 65 current_time_ = buffer_in->GetTimestamp(); | 65 current_time_ = buffer_in->GetTimestamp(); |
| 66 } | 66 } |
| 67 | 67 |
| 68 // Since the forward capacity is only used to check the criteria for buffer | 68 // Since the forward capacity is only used to check the criteria for buffer |
| 69 // full, we always append data to the buffer. | 69 // full, we always append data to the buffer. |
| 70 buffers_.push_back(scoped_refptr<Buffer>(buffer_in)); | 70 buffers_.push_back(scoped_refptr<Buffer>(buffer_in)); |
| 71 | 71 |
| 72 // After we have written the first buffer, update |current_buffer_| to point | 72 // After we have written the first buffer, update |current_buffer_| to point |
| 73 // to it. | 73 // to it. |
| 74 if (current_buffer_ == buffers_.end()) { | 74 if (current_buffer_ == buffers_.end()) { |
| 75 DCHECK_EQ(0u, forward_bytes_); | 75 DCHECK_EQ(0, forward_bytes_); |
| 76 current_buffer_ = buffers_.begin(); | 76 current_buffer_ = buffers_.begin(); |
| 77 } | 77 } |
| 78 | 78 |
| 79 // Update the |forward_bytes_| counter since we have more bytes. | 79 // Update the |forward_bytes_| counter since we have more bytes. |
| 80 forward_bytes_ += buffer_in->GetDataSize(); | 80 forward_bytes_ += buffer_in->GetDataSize(); |
| 81 | 81 |
| 82 // Advise the user to stop append if the amount of forward bytes exceeds | 82 // Advise the user to stop append if the amount of forward bytes exceeds |
| 83 // the forward capacity. A false return value means the user should stop | 83 // the forward capacity. A false return value means the user should stop |
| 84 // appending more data to this buffer. | 84 // appending more data to this buffer. |
| 85 if (forward_bytes_ >= forward_capacity_) | 85 if (forward_bytes_ >= forward_capacity_) |
| 86 return false; | 86 return false; |
| 87 return true; | 87 return true; |
| 88 } | 88 } |
| 89 | 89 |
| 90 bool SeekableBuffer::Append(const uint8* data, size_t size) { | 90 bool SeekableBuffer::Append(const uint8* data, int size) { |
| 91 if (size > 0) { | 91 if (size > 0) { |
| 92 DataBuffer* data_buffer = new DataBuffer(size); | 92 DataBuffer* data_buffer = new DataBuffer(size); |
| 93 memcpy(data_buffer->GetWritableData(), data, size); | 93 memcpy(data_buffer->GetWritableData(), data, size); |
| 94 data_buffer->SetDataSize(size); | 94 data_buffer->SetDataSize(size); |
| 95 return Append(data_buffer); | 95 return Append(data_buffer); |
| 96 } else { | 96 } else { |
| 97 // Return true if we have forward capacity. | 97 // Return true if we have forward capacity. |
| 98 return forward_bytes_ < forward_capacity_; | 98 return forward_bytes_ < forward_capacity_; |
| 99 } | 99 } |
| 100 } | 100 } |
| 101 | 101 |
| 102 bool SeekableBuffer::Seek(int32 offset) { | 102 bool SeekableBuffer::Seek(int32 offset) { |
| 103 if (offset > 0) | 103 if (offset > 0) |
| 104 return SeekForward(offset); | 104 return SeekForward(offset); |
| 105 else if (offset < 0) | 105 else if (offset < 0) |
| 106 return SeekBackward(-offset); | 106 return SeekBackward(-offset); |
| 107 return true; | 107 return true; |
| 108 } | 108 } |
| 109 | 109 |
| 110 bool SeekableBuffer::SeekForward(size_t size) { | 110 bool SeekableBuffer::SeekForward(int size) { |
| 111 // Perform seeking forward only if we have enough bytes in the queue. | 111 // Perform seeking forward only if we have enough bytes in the queue. |
| 112 if (size > forward_bytes_) | 112 if (size > forward_bytes_) |
| 113 return false; | 113 return false; |
| 114 | 114 |
| 115 // Do a read of |size| bytes. | 115 // Do a read of |size| bytes. |
| 116 size_t taken = InternalRead(NULL, size, true, 0); | 116 int taken = InternalRead(NULL, size, true, 0); |
| 117 DCHECK_EQ(taken, size); | 117 DCHECK_EQ(taken, size); |
| 118 return true; | 118 return true; |
| 119 } | 119 } |
| 120 | 120 |
| 121 bool SeekableBuffer::SeekBackward(size_t size) { | 121 bool SeekableBuffer::SeekBackward(int size) { |
| 122 if (size > backward_bytes_) | 122 if (size > backward_bytes_) |
| 123 return false; | 123 return false; |
| 124 // Record the number of bytes taken. | 124 // Record the number of bytes taken. |
| 125 size_t taken = 0; | 125 int taken = 0; |
| 126 // Loop until we taken enough bytes and rewind by the desired |size|. | 126 // Loop until we taken enough bytes and rewind by the desired |size|. |
| 127 while (taken < size) { | 127 while (taken < size) { |
| 128 // |current_buffer_| can never be invalid when we are in this loop. It can | 128 // |current_buffer_| can never be invalid when we are in this loop. It can |
| 129 // only be invalid before any data is appended. The invalid case should be | 129 // only be invalid before any data is appended. The invalid case should be |
| 130 // handled by checks before we enter this loop. | 130 // handled by checks before we enter this loop. |
| 131 DCHECK(current_buffer_ != buffers_.end()); | 131 DCHECK(current_buffer_ != buffers_.end()); |
| 132 | 132 |
| 133 // We try to consume at most |size| bytes in the backward direction. We also | 133 // We try to consume at most |size| bytes in the backward direction. We also |
| 134 // have to account for the offset we are in the current buffer, so take the | 134 // have to account for the offset we are in the current buffer, so take the |
| 135 // minimum between the two to determine the amount of bytes to take from the | 135 // minimum between the two to determine the amount of bytes to take from the |
| 136 // current buffer. | 136 // current buffer. |
| 137 size_t consumed = std::min(size - taken, current_buffer_offset_); | 137 int consumed = std::min(size - taken, current_buffer_offset_); |
| 138 | 138 |
| 139 // Decreases the offset in the current buffer since we are rewinding. | 139 // Decreases the offset in the current buffer since we are rewinding. |
| 140 current_buffer_offset_ -= consumed; | 140 current_buffer_offset_ -= consumed; |
| 141 | 141 |
| 142 // Increase the amount of bytes taken in the backward direction. This | 142 // Increase the amount of bytes taken in the backward direction. This |
| 143 // determines when to stop the loop. | 143 // determines when to stop the loop. |
| 144 taken += consumed; | 144 taken += consumed; |
| 145 | 145 |
| 146 // Forward bytes increases and backward bytes decreases by the amount | 146 // Forward bytes increases and backward bytes decreases by the amount |
| 147 // consumed in the current buffer. | 147 // consumed in the current buffer. |
| 148 forward_bytes_ += consumed; | 148 forward_bytes_ += consumed; |
| 149 backward_bytes_ -= consumed; | 149 backward_bytes_ -= consumed; |
| 150 DCHECK_GE(backward_bytes_, 0u); | 150 DCHECK_GE(backward_bytes_, 0); |
| 151 | 151 |
| 152 // The current buffer pointed by current iterator has been consumed. Move | 152 // The current buffer pointed by current iterator has been consumed. Move |
| 153 // the iterator backward so it points to the previous buffer. | 153 // the iterator backward so it points to the previous buffer. |
| 154 if (current_buffer_offset_ == 0) { | 154 if (current_buffer_offset_ == 0) { |
| 155 if (current_buffer_ == buffers_.begin()) | 155 if (current_buffer_ == buffers_.begin()) |
| 156 break; | 156 break; |
| 157 // Move the iterator backward. | 157 // Move the iterator backward. |
| 158 --current_buffer_; | 158 --current_buffer_; |
| 159 // Set the offset into the current buffer to be the buffer size as we | 159 // Set the offset into the current buffer to be the buffer size as we |
| 160 // are preparing for rewind for next iteration. | 160 // are preparing for rewind for next iteration. |
| 161 current_buffer_offset_ = (*current_buffer_)->GetDataSize(); | 161 current_buffer_offset_ = (*current_buffer_)->GetDataSize(); |
| 162 } | 162 } |
| 163 } | 163 } |
| 164 | 164 |
| 165 UpdateCurrentTime(current_buffer_, current_buffer_offset_); | 165 UpdateCurrentTime(current_buffer_, current_buffer_offset_); |
| 166 | 166 |
| 167 DCHECK_EQ(taken, size); | 167 DCHECK_EQ(taken, size); |
| 168 return true; | 168 return true; |
| 169 } | 169 } |
| 170 | 170 |
| 171 void SeekableBuffer::EvictBackwardBuffers() { | 171 void SeekableBuffer::EvictBackwardBuffers() { |
| 172 // Advances the iterator until we hit the current pointer. | 172 // Advances the iterator until we hit the current pointer. |
| 173 while (backward_bytes_ > backward_capacity_) { | 173 while (backward_bytes_ > backward_capacity_) { |
| 174 BufferQueue::iterator i = buffers_.begin(); | 174 BufferQueue::iterator i = buffers_.begin(); |
| 175 if (i == current_buffer_) | 175 if (i == current_buffer_) |
| 176 break; | 176 break; |
| 177 scoped_refptr<Buffer> buffer = *i; | 177 scoped_refptr<Buffer> buffer = *i; |
| 178 backward_bytes_ -= buffer->GetDataSize(); | 178 backward_bytes_ -= buffer->GetDataSize(); |
| 179 DCHECK_GE(backward_bytes_, 0u); | 179 DCHECK_GE(backward_bytes_, 0); |
| 180 | 180 |
| 181 buffers_.erase(i); | 181 buffers_.erase(i); |
| 182 } | 182 } |
| 183 } | 183 } |
| 184 | 184 |
| 185 size_t SeekableBuffer::InternalRead(uint8* data, size_t size, | 185 int SeekableBuffer::InternalRead(uint8* data, int size, |
| 186 bool advance_position, | 186 bool advance_position, |
| 187 size_t forward_offset) { | 187 int forward_offset) { |
| 188 // Counts how many bytes are actually read from the buffer queue. | 188 // Counts how many bytes are actually read from the buffer queue. |
| 189 size_t taken = 0; | 189 int taken = 0; |
| 190 | 190 |
| 191 BufferQueue::iterator current_buffer = current_buffer_; | 191 BufferQueue::iterator current_buffer = current_buffer_; |
| 192 size_t current_buffer_offset = current_buffer_offset_; | 192 int current_buffer_offset = current_buffer_offset_; |
| 193 | 193 |
| 194 size_t bytes_to_skip = forward_offset; | 194 int bytes_to_skip = forward_offset; |
| 195 while (taken < size) { | 195 while (taken < size) { |
| 196 // |current_buffer| is valid since the first time this buffer is appended | 196 // |current_buffer| is valid since the first time this buffer is appended |
| 197 // with data. | 197 // with data. |
| 198 if (current_buffer == buffers_.end()) | 198 if (current_buffer == buffers_.end()) |
| 199 break; | 199 break; |
| 200 | 200 |
| 201 scoped_refptr<Buffer> buffer = *current_buffer; | 201 scoped_refptr<Buffer> buffer = *current_buffer; |
| 202 | 202 |
| 203 size_t remaining_bytes_in_buffer = | 203 int remaining_bytes_in_buffer = |
| 204 buffer->GetDataSize() - current_buffer_offset; | 204 buffer->GetDataSize() - current_buffer_offset; |
| 205 | 205 |
| 206 if (bytes_to_skip == 0) { | 206 if (bytes_to_skip == 0) { |
| 207 // Find the right amount to copy from the current buffer referenced by | 207 // Find the right amount to copy from the current buffer referenced by |
| 208 // |buffer|. We shall copy no more than |size| bytes in total and each | 208 // |buffer|. We shall copy no more than |size| bytes in total and each |
| 209 // single step copied no more than the current buffer size. | 209 // single step copied no more than the current buffer size. |
| 210 size_t copied = std::min(size - taken, remaining_bytes_in_buffer); | 210 int copied = std::min(size - taken, remaining_bytes_in_buffer); |
| 211 | 211 |
| 212 // |data| is NULL if we are seeking forward, so there's no need to copy. | 212 // |data| is NULL if we are seeking forward, so there's no need to copy. |
| 213 if (data) | 213 if (data) |
| 214 memcpy(data + taken, buffer->GetData() + current_buffer_offset, copied); | 214 memcpy(data + taken, buffer->GetData() + current_buffer_offset, copied); |
| 215 | 215 |
| 216 // Increase total number of bytes copied, which regulates when to end this | 216 // Increase total number of bytes copied, which regulates when to end this |
| 217 // loop. | 217 // loop. |
| 218 taken += copied; | 218 taken += copied; |
| 219 | 219 |
| 220 // We have read |copied| bytes from the current buffer. Advances the | 220 // We have read |copied| bytes from the current buffer. Advances the |
| 221 // offset. | 221 // offset. |
| 222 current_buffer_offset += copied; | 222 current_buffer_offset += copied; |
| 223 } else { | 223 } else { |
| 224 size_t skipped = std::min(remaining_bytes_in_buffer, bytes_to_skip); | 224 int skipped = std::min(remaining_bytes_in_buffer, bytes_to_skip); |
| 225 current_buffer_offset += skipped; | 225 current_buffer_offset += skipped; |
| 226 bytes_to_skip -= skipped; | 226 bytes_to_skip -= skipped; |
| 227 } | 227 } |
| 228 | 228 |
| 229 // The buffer has been consumed. | 229 // The buffer has been consumed. |
| 230 if (current_buffer_offset == buffer->GetDataSize()) { | 230 if (current_buffer_offset == buffer->GetDataSize()) { |
| 231 if (advance_position) { | 231 if (advance_position) { |
| 232 // Next buffer may not have timestamp, so we need to update current | 232 // Next buffer may not have timestamp, so we need to update current |
| 233 // timestamp before switching to the next buffer. | 233 // timestamp before switching to the next buffer. |
| 234 UpdateCurrentTime(current_buffer, current_buffer_offset); | 234 UpdateCurrentTime(current_buffer, current_buffer_offset); |
| 235 } | 235 } |
| 236 | 236 |
| 237 BufferQueue::iterator next = current_buffer; | 237 BufferQueue::iterator next = current_buffer; |
| 238 ++next; | 238 ++next; |
| 239 // If we are at the last buffer, don't advance. | 239 // If we are at the last buffer, don't advance. |
| 240 if (next == buffers_.end()) | 240 if (next == buffers_.end()) |
| 241 break; | 241 break; |
| 242 | 242 |
| 243 // Advances the iterator. | 243 // Advances the iterator. |
| 244 current_buffer = next; | 244 current_buffer = next; |
| 245 current_buffer_offset = 0; | 245 current_buffer_offset = 0; |
| 246 } | 246 } |
| 247 } | 247 } |
| 248 | 248 |
| 249 if (advance_position) { | 249 if (advance_position) { |
| 250 // We have less forward bytes and more backward bytes. Updates these | 250 // We have less forward bytes and more backward bytes. Updates these |
| 251 // counters by |taken|. | 251 // counters by |taken|. |
| 252 forward_bytes_ -= taken; | 252 forward_bytes_ -= taken; |
| 253 backward_bytes_ += taken; | 253 backward_bytes_ += taken; |
| 254 DCHECK_GE(forward_bytes_, 0u); | 254 DCHECK_GE(forward_bytes_, 0); |
| 255 DCHECK(current_buffer_ != buffers_.end() || forward_bytes_ == 0u); | 255 DCHECK(current_buffer_ != buffers_.end() || forward_bytes_ == 0); |
| 256 | 256 |
| 257 current_buffer_ = current_buffer; | 257 current_buffer_ = current_buffer; |
| 258 current_buffer_offset_ = current_buffer_offset; | 258 current_buffer_offset_ = current_buffer_offset; |
| 259 | 259 |
| 260 UpdateCurrentTime(current_buffer_, current_buffer_offset_); | 260 UpdateCurrentTime(current_buffer_, current_buffer_offset_); |
| 261 EvictBackwardBuffers(); | 261 EvictBackwardBuffers(); |
| 262 } | 262 } |
| 263 | 263 |
| 264 return taken; | 264 return taken; |
| 265 } | 265 } |
| 266 | 266 |
| 267 void SeekableBuffer::UpdateCurrentTime(BufferQueue::iterator buffer, | 267 void SeekableBuffer::UpdateCurrentTime(BufferQueue::iterator buffer, |
| 268 size_t offset) { | 268 int offset) { |
| 269 // Garbage values are unavoidable, so this check will remain. | 269 // Garbage values are unavoidable, so this check will remain. |
| 270 if (buffer != buffers_.end() && | 270 if (buffer != buffers_.end() && |
| 271 (*buffer)->GetTimestamp().InMicroseconds() > 0) { | 271 (*buffer)->GetTimestamp().InMicroseconds() > 0) { |
| 272 int64 time_offset = ((*buffer)->GetDuration().InMicroseconds() * | 272 int64 time_offset = ((*buffer)->GetDuration().InMicroseconds() * |
| 273 offset) / (*buffer)->GetDataSize(); | 273 offset) / (*buffer)->GetDataSize(); |
| 274 | 274 |
| 275 current_time_ = (*buffer)->GetTimestamp() + | 275 current_time_ = (*buffer)->GetTimestamp() + |
| 276 base::TimeDelta::FromMicroseconds(time_offset); | 276 base::TimeDelta::FromMicroseconds(time_offset); |
| 277 } | 277 } |
| 278 } | 278 } |
| 279 | 279 |
| 280 } // namespace media | 280 } // namespace media |
| OLD | NEW |