1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/filters/h265_to_annex_b_bitstream_converter.h"
9 #include "base/logging.h"
10 #include "media/formats/mp4/box_definitions.h"
11 #include "media/formats/mp4/hevc.h"
12 #include "media/video/h265_nalu_parser.h"
17 static const uint8_t kStartCodePrefix[3] = {0, 0, 1};
18 static const uint32_t kParamSetStartCodeSize = 1 + sizeof(kStartCodePrefix);
20 // Helper function which determines whether NAL unit of given type marks
21 // access unit boundary.
22 static bool IsAccessUnitBoundaryNal(int nal_unit_type) {
24 // Check if this packet marks access unit boundary by checking the
26 if (nal_unit_type == media::H265NALU::VPS_NUT ||
27 nal_unit_type == media::H265NALU::SPS_NUT ||
28 nal_unit_type == media::H265NALU::PPS_NUT ||
29 nal_unit_type == media::H265NALU::AUD_NUT ||
30 nal_unit_type == media::H265NALU::PREFIX_SEI_NUT ||
31 (nal_unit_type >= media::H265NALU::RSV_NVCL41 &&
32 nal_unit_type <= media::H265NALU::RSV_NVCL44) ||
33 (nal_unit_type >= media::H265NALU::UNSPEC48 &&
34 nal_unit_type <= media::H265NALU::UNSPEC55)) {
42 H265ToAnnexBBitstreamConverter::H265ToAnnexBBitstreamConverter() = default;
44 H265ToAnnexBBitstreamConverter::~H265ToAnnexBBitstreamConverter() = default;
46 bool H265ToAnnexBBitstreamConverter::ParseConfiguration(
47 const uint8_t* configuration_record,
48 int configuration_record_size,
49 mp4::HEVCDecoderConfigurationRecord* hevc_config) {
50 DCHECK(configuration_record);
51 DCHECK_GT(configuration_record_size, 0);
54 if (!hevc_config->Parse(configuration_record, configuration_record_size))
57 configuration_processed_ = true;
61 uint32_t H265ToAnnexBBitstreamConverter::GetConfigSize(
62 const mp4::HEVCDecoderConfigurationRecord& hevc_config) const {
63 uint32_t config_size = 0;
65 for (auto& nalu_array : hevc_config.arrays) {
66 for (auto& nalu : nalu_array.units) {
67 config_size += kParamSetStartCodeSize + nalu.size();
73 uint32_t H265ToAnnexBBitstreamConverter::CalculateNeededOutputBufferSize(
76 const mp4::HEVCDecoderConfigurationRecord* hevc_config) const {
77 uint32_t output_size = 0;
78 uint32_t data_left = input_size;
79 bool first_nal_in_this_access_unit = first_nal_unit_in_access_unit_;
82 return 0; // Error: invalid input data
84 if (!configuration_processed_) {
85 return 0; // Error: configuration not handled, we don't know nal unit width
89 output_size += GetConfigSize(*hevc_config);
91 uint8_t nal_unit_length_field_width = hevc_config->lengthSizeMinusOne + 1;
92 CHECK(nal_unit_length_field_width == 1 || nal_unit_length_field_width == 2 ||
93 nal_unit_length_field_width == 4);
95 // Then add the needed size for the actual packet
96 while (data_left > 0) {
97 if (data_left < nal_unit_length_field_width) {
98 return 0; // Error: not enough data for correct conversion.
101 // Read the next NAL unit length from the input buffer
102 uint8_t size_of_len_field;
103 uint32_t nal_unit_length;
104 for (nal_unit_length = 0, size_of_len_field = nal_unit_length_field_width;
105 size_of_len_field > 0; input++, size_of_len_field--, data_left--) {
106 nal_unit_length <<= 8;
107 nal_unit_length |= *input;
110 if (nal_unit_length == 0) {
111 break; // Signifies that no more data left in the buffer
112 } else if (nal_unit_length > data_left) {
113 return 0; // Error: Not enough data for correct conversion
115 data_left -= nal_unit_length;
117 // Six bits after forbidden_zero_bit of first NAL unit byte signify
119 int nal_unit_type = (*input >> 1) & 0x3F;
120 if (first_nal_in_this_access_unit ||
121 IsAccessUnitBoundaryNal(nal_unit_type)) {
122 output_size += 1; // Extra zero_byte for these nal units
123 first_nal_in_this_access_unit = false;
126 output_size += sizeof(kStartCodePrefix);
127 // Actual NAL unit size
128 output_size += nal_unit_length;
129 input += nal_unit_length;
130 // No need for trailing zero bits
135 bool H265ToAnnexBBitstreamConverter::ConvertHEVCDecoderConfigToByteStream(
136 const mp4::HEVCDecoderConfigurationRecord& hevc_config,
138 uint32_t* output_size) {
139 uint8_t* out = output;
140 uint32_t out_size = *output_size;
143 for (auto& nalu_array : hevc_config.arrays) {
144 for (auto& nalu : nalu_array.units) {
145 if (!WriteParamSet(nalu, &out, &out_size)) {
151 configuration_processed_ = true;
152 *output_size = out - output;
156 bool H265ToAnnexBBitstreamConverter::ConvertNalUnitStreamToByteStream(
157 const uint8_t* input,
159 const mp4::HEVCDecoderConfigurationRecord* hevc_config,
161 uint32_t* output_size) {
162 const uint8_t* inscan = input; // We read the input from here progressively
163 uint8_t* outscan = output; // We write the output to here progressively
164 uint32_t data_left = input_size;
166 if (input_size == 0 || *output_size == 0) {
168 return false; // Error: invalid input
171 uint8_t nal_unit_length_field_width = hevc_config->lengthSizeMinusOne + 1;
172 CHECK(nal_unit_length_field_width == 1 || nal_unit_length_field_width == 2 ||
173 nal_unit_length_field_width == 4);
175 // Do the actual conversion for the actual input packet
176 int nal_unit_count = 0;
177 while (data_left > 0) {
179 uint32_t nal_unit_length;
181 // Read the next NAL unit length from the input buffer by scanning
182 // the input stream with the specific length field width
183 for (nal_unit_length = 0, i = nal_unit_length_field_width;
184 i > 0 && data_left > 0; inscan++, i--, data_left--) {
185 nal_unit_length <<= 8;
186 nal_unit_length |= *inscan;
189 if (nal_unit_length == 0) {
190 break; // Successful conversion, end of buffer
191 } else if (nal_unit_length > data_left) {
193 return false; // Error: not enough data for correct conversion
196 // Six bits after forbidden_zero_bit of first NAL unit byte signify
198 int nal_unit_type = (*inscan >> 1) & 0x3F;
201 // Insert the config after the AUD if an AUD is the first NAL unit or
202 // before all NAL units if the first one isn't an AUD.
204 (nal_unit_type != H265NALU::AUD_NUT || nal_unit_count > 1)) {
205 uint32_t output_bytes_used = outscan - output;
207 DCHECK_GE(*output_size, output_bytes_used);
209 uint32_t config_size = *output_size - output_bytes_used;
210 if (!ConvertHEVCDecoderConfigToByteStream(*hevc_config, outscan,
212 DVLOG(1) << "Failed to insert parameter sets.";
214 return false; // Failed to convert the buffer.
216 outscan += config_size;
217 hevc_config = nullptr;
219 uint32_t start_code_len;
220 first_nal_unit_in_access_unit_
221 ? start_code_len = sizeof(kStartCodePrefix) + 1
222 : start_code_len = sizeof(kStartCodePrefix);
223 if (static_cast<uint32_t>(outscan - output) + start_code_len +
227 return false; // Error: too small output buffer
230 // Check if this packet marks access unit boundary by checking the
232 if (IsAccessUnitBoundaryNal(nal_unit_type)) {
233 first_nal_unit_in_access_unit_ = true;
236 // Write extra zero-byte before start code prefix if this packet
237 // signals next access unit.
238 if (first_nal_unit_in_access_unit_) {
241 first_nal_unit_in_access_unit_ = false;
244 // No need to write leading zero bits.
245 // Write start-code prefix.
246 memcpy(outscan, kStartCodePrefix, sizeof(kStartCodePrefix));
247 outscan += sizeof(kStartCodePrefix);
248 // Then write the actual NAL unit from the input buffer.
249 memcpy(outscan, inscan, nal_unit_length);
250 inscan += nal_unit_length;
251 data_left -= nal_unit_length;
252 outscan += nal_unit_length;
253 // No need for trailing zero bits.
255 // Successful conversion, output the freshly allocated bitstream buffer.
256 *output_size = static_cast<uint32_t>(outscan - output);
260 bool H265ToAnnexBBitstreamConverter::WriteParamSet(
261 const std::vector<uint8_t>& param_set,
263 uint32_t* out_size) const {
264 // Strip trailing null bytes.
265 size_t size = param_set.size();
266 while (size && param_set[size - 1] == 0)
272 uint32_t bytes_left = *out_size;
273 if (bytes_left < kParamSetStartCodeSize ||
274 bytes_left - kParamSetStartCodeSize < size) {
278 uint8_t* start = *out;
279 uint8_t* buf = start;
281 // Write the 4 byte Annex B start code.
282 *buf++ = 0; // zero byte
283 memcpy(buf, kStartCodePrefix, sizeof(kStartCodePrefix));
284 buf += sizeof(kStartCodePrefix);
287 memcpy(buf, ¶m_set[0], size);
291 *out_size -= buf - start;