// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "media/base/byte_queue.h" #include #include #include "base/check_op.h" #include "base/numerics/checked_math.h" namespace media { ByteQueue::ByteQueue() : buffer_(new uint8_t[size_]) {} ByteQueue::~ByteQueue() = default; void ByteQueue::Reset() { offset_ = 0; used_ = 0; } void ByteQueue::Push(const uint8_t* data, int size) { DCHECK(data); DCHECK_GT(size, 0); // This can never overflow since used and size are both ints. const size_t size_needed = static_cast(used_) + size; // Check to see if we need a bigger buffer. if (size_needed > size_) { // Growth is based on base::circular_deque which grows at 25%. const size_t safe_size = (base::CheckedNumeric(size_) + size_ / 4).ValueOrDie(); const size_t new_size = std::max(size_needed, safe_size); // Copy the data from the old buffer to the start of the new one. if (used_ > 0) { // Note: We could use realloc() here, but would need an additional move to // pack data at offset_ = 0 after a potential internal new allocation + // copy by realloc(). // // In local tests on a few top video sites that ends up being the common // case, so just prefer to copy and pack ourselves. std::unique_ptr new_buffer(new uint8_t[new_size]); memcpy(new_buffer.get(), Front(), used_); buffer_ = std::move(new_buffer); } else { // Free the existing |data| first so that the memory can be reused, if // possible. Note that the new array is purposely not initialized. buffer_.reset(); buffer_.reset(new uint8_t[new_size]); } size_ = new_size; offset_ = 0; } else if ((offset_ + used_ + size) > size_) { // The buffer is big enough, but we need to move the data in the queue. memmove(buffer_.get(), Front(), used_); offset_ = 0; } memcpy(Front() + used_, data, size); used_ += size; } void ByteQueue::Peek(const uint8_t** data, int* size) const { DCHECK(data); DCHECK(size); *data = Front(); *size = used_; } void ByteQueue::Pop(int count) { DCHECK_LE(count, used_); offset_ += count; used_ -= count; // Move the offset back to 0 if we have reached the end of the buffer. if (offset_ == size_) { DCHECK_EQ(used_, 0); offset_ = 0; } } uint8_t* ByteQueue::Front() const { return buffer_.get() + offset_; } } // namespace media