Chromium Code Reviews| Index: media/filters/h264_bitstream_buffer.cc |
| diff --git a/media/filters/h264_bitstream_buffer.cc b/media/filters/h264_bitstream_buffer.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..50373b7e7285b7ebd5f9e5e9e5c063614b51bfb6 |
| --- /dev/null |
| +++ b/media/filters/h264_bitstream_buffer.cc |
| @@ -0,0 +1,153 @@ |
| +// Copyright (c) 2014 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/filters/h264_bitstream_buffer.h" |
| + |
| +#include "base/sys_byteorder.h" |
| +#include "cc/base/util.h" |
| + |
| +namespace media { |
| + |
| +H264BitstreamBuffer::H264BitstreamBuffer() : data_(NULL) { |
| + Reset(); |
| +} |
| + |
| +H264BitstreamBuffer::~H264BitstreamBuffer() { |
| + free(data_); |
| + data_ = NULL; |
| +} |
| + |
| +void H264BitstreamBuffer::Reset() { |
| + free(data_); |
| + data_ = NULL; |
| + |
| + capacity_ = 0; |
| + pos_ = 0; |
| + reg_ = 0; |
| + |
| + Grow(); |
| + |
| + bits_left_in_reg_ = kRegBitSize; |
| +} |
| + |
| +void H264BitstreamBuffer::Grow() { |
| + data_ = static_cast<uint8*>(realloc(data_, capacity_ + kGrowBytes)); |
| + CHECK(data_) << "Failed growing the buffer"; |
|
wuchengli
2014/06/18 15:57:44
This is not a programming error and shouldn't use
Pawel Osciak
2014/06/19 01:31:11
It actually would be. Allocations in Chrome cannot
wuchengli
2014/06/19 04:28:34
Interesting. You mean we should CHECK the result o
Pawel Osciak
2014/06/19 04:57:42
No, I'm just overly fastidious.
Check out https://
|
| + capacity_ += kGrowBytes; |
| +} |
| + |
| +void H264BitstreamBuffer::FlushReg() { |
| + // Flush all bytes that have at least one bit cached, but not more |
| + // (on Flush(), reg_ may not be full). |
| + size_t bits_in_reg = kRegBitSize - bits_left_in_reg_; |
| + if (bits_in_reg == 0) |
| + return; |
| + |
| + size_t bytes_in_reg = (bits_in_reg + 7) / 8; |
| + reg_ <<= (kRegBitSize - bits_in_reg); |
| + |
| + // Convert to MSB and append as such to the stream. |
| + reg_ = base::HostToNet64(reg_); |
| + |
| + // Make sure we have enough space. Grow() will CHECK() on allocation failure. |
| + if (pos_ + bytes_in_reg < capacity_) |
| + Grow(); |
| + |
| + memcpy(data_ + pos_, ®_, bytes_in_reg); |
| + pos_ += bytes_in_reg; |
| + |
| + reg_ = 0; |
| + bits_left_in_reg_ = kRegBitSize; |
| +} |
| + |
| +void H264BitstreamBuffer::AppendU64(size_t num_bits, uint64 val) { |
| + CHECK_LE(num_bits, kRegBitSize); |
| + |
| + while (num_bits > 0) { |
| + if (bits_left_in_reg_ == 0) |
| + FlushReg(); |
| + |
| + uint64 bits_to_write = |
| + num_bits > bits_left_in_reg_ ? bits_left_in_reg_ : num_bits; |
| + uint64 val_to_write = (val >> (num_bits - bits_to_write)); |
| + if (bits_to_write < 64) |
| + val_to_write &= ((1ull << bits_to_write) - 1); |
| + reg_ <<= bits_to_write; |
| + reg_ |= val_to_write; |
| + num_bits -= bits_to_write; |
| + bits_left_in_reg_ -= bits_to_write; |
| + } |
| +} |
| + |
| +void H264BitstreamBuffer::AppendBool(bool val) { |
| + if (bits_left_in_reg_ == 0) |
| + FlushReg(); |
| + |
| + reg_ <<= 1; |
| + reg_ |= (static_cast<uint64>(val) & 1); |
| + --bits_left_in_reg_; |
| +} |
| + |
| +void H264BitstreamBuffer::AppendSE(int val) { |
| + if (val > 0) |
| + AppendUE(val * 2 - 1); |
| + else |
| + AppendUE(-val * 2); |
| +} |
| + |
| +void H264BitstreamBuffer::AppendUE(unsigned int val) { |
| + size_t num_zeros = 0; |
| + unsigned int v = val + 1; |
| + |
| + while (v > 1) { |
| + v >>= 1; |
| + ++num_zeros; |
| + } |
| + |
| + AppendBits(num_zeros, 0); |
| + AppendBits(num_zeros + 1, val + 1); |
| +} |
| + |
| +#define DCHECK_FINISHED() \ |
| + DCHECK_EQ(bits_left_in_reg_, kRegBitSize) << "Pending bits not yet written " \ |
| + "to the buffer, call " \ |
| + "FinishNALU() first." |
| + |
| +void H264BitstreamBuffer::BeginNALU(H264NALU::Type nalu_type, int nal_ref_idc) { |
| + DCHECK_FINISHED(); |
| + |
| + DCHECK_LE(nalu_type, H264NALU::kEOStream); |
| + DCHECK_GE(nal_ref_idc, 0); |
| + DCHECK_LE(nal_ref_idc, 3); |
| + |
| + AppendBits(32, 0x00000001); |
| + AppendBits(1, 0); // forbidden_zero_bit |
| + AppendBits(2, nal_ref_idc); |
| + AppendBits(5, nalu_type); |
| +} |
| + |
| +void H264BitstreamBuffer::FinishNALU() { |
| + // RBSP stop one bit. |
| + AppendBits(1, 1); |
| + |
| + // Byte-alignment zero bits. |
| + AppendBits(bits_left_in_reg_ % 8, 0); |
| + |
| + if (bits_left_in_reg_ != kRegBitSize) |
| + FlushReg(); |
| +} |
| + |
| +size_t H264BitstreamBuffer::BytesInBuffer() { |
| + DCHECK_FINISHED(); |
| + return pos_; |
| +} |
| + |
| +uint8* H264BitstreamBuffer::data() { |
| + DCHECK(data_); |
| + DCHECK_FINISHED(); |
| + |
| + return data_; |
| +} |
| + |
| +} // namespace media |