1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157

media / filters / h26x_annex_b_bitstream_builder.h [blame]

// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This file contains an implementation of a H26xAnnexBBitstreamBuilder class
// for constructing raw bitstream buffers containing NAL units in H.264 Annex-B
// stream format.
// See H.264 spec Annex B and chapter 7 for more details.

#ifndef MEDIA_FILTERS_H26X_ANNEX_B_BITSTREAM_BUILDER_H_
#define MEDIA_FILTERS_H26X_ANNEX_B_BITSTREAM_BUILDER_H_

#include <stdint.h>

#include "base/containers/heap_array.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "media/base/media_export.h"
#include "media/parsers/h264_parser.h"
#include "media/parsers/h265_nalu_parser.h"

namespace media {

// Holds one or more NALUs as a raw bitstream buffer in H.264 Annex-B format.
// Note that this class currently does NOT insert emulation prevention
// three-byte sequences (spec 7.3.1) by default.
class MEDIA_EXPORT H26xAnnexBBitstreamBuilder {
 public:
  // This is used by VA-API encoder and D3D12 encoder.
  // - For VA-API encoder, set |insert_emulation_prevention_bytes| to |false| as
  //   VA-API takes SPS/PPS RBSP and outputs the AnnexB bitstream.
  // - For D3D12 encoder, set |insert_emulation_prevention_bytes| to |true| as
  //   it only outputs slice NALU. We add SPS/PPS with EPB in Chromium to create
  //   an AnnexB bitstream.
  explicit H26xAnnexBBitstreamBuilder(
      bool insert_emulation_prevention_bytes = false);
  ~H26xAnnexBBitstreamBuilder();
  H26xAnnexBBitstreamBuilder(const H26xAnnexBBitstreamBuilder&) = delete;
  H26xAnnexBBitstreamBuilder& operator=(const H26xAnnexBBitstreamBuilder&) =
      delete;

  // Discard all data and reset the buffer for reuse.
  void Reset();

  // Append |num_bits| bits to the stream from |val|.
  // |val| is interpreted in the host endianness.
  template <typename T>
  void AppendBits(size_t num_bits, T val) {
    AppendU64(num_bits, static_cast<uint64_t>(val));
  }

  void AppendBits(size_t num_bits, bool val) {
    DCHECK_EQ(num_bits, 1ul);
    AppendBool(val);
  }

  // Append a one-bit bool/flag value |val| to the stream.
  void AppendBool(bool val);

  // Append a signed value in |val| in Exp-Golomb code.
  void AppendSE(int val);

  // Append an unsigned value in |val| in Exp-Golomb code.
  void AppendUE(unsigned int val);

  // Start a new NALU of type |nalu_type| and with given |nal_ref_idc|
  // (see spec). Note, that until FinishNALU() is called, some of the bits
  // may not be flushed into the buffer and the data will not be correctly
  // aligned with trailing bits.
  void BeginNALU(H264NALU::Type nalu_type, int nal_ref_idc);

  // Start a H265 NALU.
  void BeginNALU(H265NALU::Type nalu_type);

  // Finish current NALU. This will flush any cached bits and correctly align
  // the buffer with RBSP trailing bits. This MUST be called for the stream
  // returned by data() to be correct.
  void FinishNALU();

  // Finishes current bit stream. This will flush any cached bits in the reg
  // without RBSP trailing bits alignment. e.g. for packed slice header, it is
  // not a complete NALU, the slice data and RBSP trailing will be filled by
  // user mode driver. This MUST be called for the stream returned by data() to
  // be correct.
  void Flush();

  // Return number of full bytes in the stream. Note that FinishNALU() has to
  // be called to flush cached bits, or the return value will not include them.
  size_t BytesInBuffer() const;

  // Returns number of bits in the stream. Note that FinishNALU() or Flush() has
  // to be called to flush cached bits, or the return value will not include
  // them.
  size_t BitsInBuffer() const;

  // Return a pointer to the stream. FinishNALU() must be called before
  // accessing the stream, otherwise some bits may still be cached and not in
  // the buffer.
  //
  // TODO(crbug.com/40284755): Return a span up to `pos_` which is the range of
  // initialized bytes in `data_`.
  const uint8_t* data() const;

 private:
  FRIEND_TEST_ALL_PREFIXES(H26xAnnexBBitstreamBuilderAppendBitsTest,
                           AppendAndVerifyBits);

  // Allocate additional memory (kGrowBytes bytes) for the buffer.
  void Grow();

  // Append |num_bits| bits from U64 value |val| (in host endianness).
  void AppendU64(size_t num_bits, uint64_t val);

  // Flush any cached bits in the reg with byte granularity, i.e. enough
  // bytes to flush all pending bits, but not more.
  void FlushReg();

  typedef uint64_t RegType;
  enum {
    // Sizes of reg_.
    kRegByteSize = sizeof(RegType),
    kRegBitSize = kRegByteSize * 8,
    // Amount of bytes to grow the buffer by when we run out of
    // previously-allocated memory for it.
    kGrowBytes = 4096,
  };

  static_assert(kGrowBytes >= kRegByteSize,
                "kGrowBytes must be larger than kRegByteSize");

  // Whether to insert emulation prevention bytes in RBSP.
  bool insert_emulation_prevention_bytes_;

  // Whether BeginNALU() has been called but not FinishNALU().
  bool in_nalu_;

  // Unused bits left in reg_.
  size_t bits_left_in_reg_;

  // Cache for appended bits. Bits are flushed to data_ with kRegByteSize
  // granularity, i.e. when reg_ becomes full, or when an explicit FlushReg()
  // is called.
  RegType reg_;

  // Current byte offset in data_ (points to the start of unwritten bits).
  size_t pos_;
  // Current last bit in data_ (points to the start of unwritten bit).
  size_t bits_in_buffer_;

  // Buffer for stream data. Only the bytes before `pos_` have been initialized.
  base::HeapArray<uint8_t> data_;
};

}  // namespace media

#endif  // MEDIA_FILTERS_H26X_ANNEX_B_BITSTREAM_BUILDER_H_