Home | History | Annotate | Download | only in filters
      1 // Copyright 2014 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/filters/h264_bitstream_buffer.h"
      6 
      7 #include "base/sys_byteorder.h"
      8 
      9 namespace media {
     10 
     11 H264BitstreamBuffer::H264BitstreamBuffer() : data_(NULL) {
     12   Reset();
     13 }
     14 
     15 H264BitstreamBuffer::~H264BitstreamBuffer() {
     16   free(data_);
     17   data_ = NULL;
     18 }
     19 
     20 void H264BitstreamBuffer::Reset() {
     21   free(data_);
     22   data_ = NULL;
     23 
     24   capacity_ = 0;
     25   pos_ = 0;
     26   reg_ = 0;
     27 
     28   Grow();
     29 
     30   bits_left_in_reg_ = kRegBitSize;
     31 }
     32 
     33 void H264BitstreamBuffer::Grow() {
     34   data_ = static_cast<uint8*>(realloc(data_, capacity_ + kGrowBytes));
     35   CHECK(data_) << "Failed growing the buffer";
     36   capacity_ += kGrowBytes;
     37 }
     38 
     39 void H264BitstreamBuffer::FlushReg() {
     40   // Flush all bytes that have at least one bit cached, but not more
     41   // (on Flush(), reg_ may not be full).
     42   size_t bits_in_reg = kRegBitSize - bits_left_in_reg_;
     43   if (bits_in_reg == 0)
     44     return;
     45 
     46   size_t bytes_in_reg = (bits_in_reg + 7) / 8;
     47   reg_ <<= (kRegBitSize - bits_in_reg);
     48 
     49   // Convert to MSB and append as such to the stream.
     50   reg_ = base::HostToNet64(reg_);
     51 
     52   // Make sure we have enough space. Grow() will CHECK() on allocation failure.
     53   if (pos_ + bytes_in_reg < capacity_)
     54     Grow();
     55 
     56   memcpy(data_ + pos_, &reg_, bytes_in_reg);
     57   pos_ += bytes_in_reg;
     58 
     59   reg_ = 0;
     60   bits_left_in_reg_ = kRegBitSize;
     61 }
     62 
     63 void H264BitstreamBuffer::AppendU64(size_t num_bits, uint64 val) {
     64   CHECK_LE(num_bits, kRegBitSize);
     65 
     66   while (num_bits > 0) {
     67     if (bits_left_in_reg_ == 0)
     68       FlushReg();
     69 
     70     uint64 bits_to_write =
     71         num_bits > bits_left_in_reg_ ? bits_left_in_reg_ : num_bits;
     72     uint64 val_to_write = (val >> (num_bits - bits_to_write));
     73     if (bits_to_write < 64)
     74       val_to_write &= ((1ull << bits_to_write) - 1);
     75     reg_ <<= bits_to_write;
     76     reg_ |= val_to_write;
     77     num_bits -= bits_to_write;
     78     bits_left_in_reg_ -= bits_to_write;
     79   }
     80 }
     81 
     82 void H264BitstreamBuffer::AppendBool(bool val) {
     83   if (bits_left_in_reg_ == 0)
     84     FlushReg();
     85 
     86   reg_ <<= 1;
     87   reg_ |= (static_cast<uint64>(val) & 1);
     88   --bits_left_in_reg_;
     89 }
     90 
     91 void H264BitstreamBuffer::AppendSE(int val) {
     92   if (val > 0)
     93     AppendUE(val * 2 - 1);
     94   else
     95     AppendUE(-val * 2);
     96 }
     97 
     98 void H264BitstreamBuffer::AppendUE(unsigned int val) {
     99   size_t num_zeros = 0;
    100   unsigned int v = val + 1;
    101 
    102   while (v > 1) {
    103     v >>= 1;
    104     ++num_zeros;
    105   }
    106 
    107   AppendBits(num_zeros, 0);
    108   AppendBits(num_zeros + 1, val + 1);
    109 }
    110 
    111 #define DCHECK_FINISHED()                                                      \
    112   DCHECK_EQ(bits_left_in_reg_, kRegBitSize) << "Pending bits not yet written " \
    113                                                "to the buffer, call "          \
    114                                                "FinishNALU() first."
    115 
    116 void H264BitstreamBuffer::BeginNALU(H264NALU::Type nalu_type, int nal_ref_idc) {
    117   DCHECK_FINISHED();
    118 
    119   DCHECK_LE(nalu_type, H264NALU::kEOStream);
    120   DCHECK_GE(nal_ref_idc, 0);
    121   DCHECK_LE(nal_ref_idc, 3);
    122 
    123   AppendBits(32, 0x00000001);
    124   AppendBits(1, 0);  // forbidden_zero_bit
    125   AppendBits(2, nal_ref_idc);
    126   AppendBits(5, nalu_type);
    127 }
    128 
    129 void H264BitstreamBuffer::FinishNALU() {
    130   // RBSP stop one bit.
    131   AppendBits(1, 1);
    132 
    133   // Byte-alignment zero bits.
    134   AppendBits(bits_left_in_reg_ % 8, 0);
    135 
    136   if (bits_left_in_reg_ != kRegBitSize)
    137     FlushReg();
    138 }
    139 
    140 size_t H264BitstreamBuffer::BytesInBuffer() {
    141   DCHECK_FINISHED();
    142   return pos_;
    143 }
    144 
    145 uint8* H264BitstreamBuffer::data() {
    146   DCHECK(data_);
    147   DCHECK_FINISHED();
    148 
    149   return data_;
    150 }
    151 
    152 }  // namespace media
    153