[M120 Migration][hbbtv] Audio tracks count notification
[platform/framework/web/chromium-efl.git] / media / filters / h265_to_annex_b_bitstream_converter.cc
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.
4
5 #include "media/filters/h265_to_annex_b_bitstream_converter.h"
6
7 #include <stddef.h>
8
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"
13
14 namespace media {
15 namespace {
16
17 static const uint8_t kStartCodePrefix[3] = {0, 0, 1};
18 static const uint32_t kParamSetStartCodeSize = 1 + sizeof(kStartCodePrefix);
19
20 // Helper function which determines whether NAL unit of given type marks
21 // access unit boundary.
22 static bool IsAccessUnitBoundaryNal(int nal_unit_type) {
23   // Spec 7.4.2.4.4
24   // Check if this packet marks access unit boundary by checking the
25   // packet type.
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)) {
35     return true;
36   }
37   return false;
38 }
39
40 }  // namespace
41
42 H265ToAnnexBBitstreamConverter::H265ToAnnexBBitstreamConverter() = default;
43
44 H265ToAnnexBBitstreamConverter::~H265ToAnnexBBitstreamConverter() = default;
45
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);
52   DCHECK(hevc_config);
53
54   if (!hevc_config->Parse(configuration_record, configuration_record_size))
55     return false;
56
57   configuration_processed_ = true;
58   return true;
59 }
60
61 uint32_t H265ToAnnexBBitstreamConverter::GetConfigSize(
62     const mp4::HEVCDecoderConfigurationRecord& hevc_config) const {
63   uint32_t config_size = 0;
64
65   for (auto& nalu_array : hevc_config.arrays) {
66     for (auto& nalu : nalu_array.units) {
67       config_size += kParamSetStartCodeSize + nalu.size();
68     }
69   }
70   return config_size;
71 }
72
73 uint32_t H265ToAnnexBBitstreamConverter::CalculateNeededOutputBufferSize(
74     const uint8_t* input,
75     uint32_t input_size,
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_;
80
81   if (input_size == 0)
82     return 0;  // Error: invalid input data
83
84   if (!configuration_processed_) {
85     return 0;  // Error: configuration not handled, we don't know nal unit width
86   }
87
88   if (hevc_config)
89     output_size += GetConfigSize(*hevc_config);
90
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);
94
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.
99     }
100
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;
108     }
109
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
114     }
115     data_left -= nal_unit_length;
116
117     // Six bits after forbidden_zero_bit of first NAL unit byte signify
118     // nal_unit_type.
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;
124     }
125     // Start code prefix
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
131   }
132   return output_size;
133 }
134
135 bool H265ToAnnexBBitstreamConverter::ConvertHEVCDecoderConfigToByteStream(
136     const mp4::HEVCDecoderConfigurationRecord& hevc_config,
137     uint8_t* output,
138     uint32_t* output_size) {
139   uint8_t* out = output;
140   uint32_t out_size = *output_size;
141   *output_size = 0;
142
143   for (auto& nalu_array : hevc_config.arrays) {
144     for (auto& nalu : nalu_array.units) {
145       if (!WriteParamSet(nalu, &out, &out_size)) {
146         return false;
147       }
148     }
149   }
150
151   configuration_processed_ = true;
152   *output_size = out - output;
153   return true;
154 }
155
156 bool H265ToAnnexBBitstreamConverter::ConvertNalUnitStreamToByteStream(
157     const uint8_t* input,
158     uint32_t input_size,
159     const mp4::HEVCDecoderConfigurationRecord* hevc_config,
160     uint8_t* output,
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;
165
166   if (input_size == 0 || *output_size == 0) {
167     *output_size = 0;
168     return false;  // Error: invalid input
169   }
170
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);
174
175   // Do the actual conversion for the actual input packet
176   int nal_unit_count = 0;
177   while (data_left > 0) {
178     uint8_t i;
179     uint32_t nal_unit_length;
180
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;
187     }
188
189     if (nal_unit_length == 0) {
190       break;  // Successful conversion, end of buffer
191     } else if (nal_unit_length > data_left) {
192       *output_size = 0;
193       return false;  // Error: not enough data for correct conversion
194     }
195
196     // Six bits after forbidden_zero_bit of first NAL unit byte signify
197     // nal_unit_type.
198     int nal_unit_type = (*inscan >> 1) & 0x3F;
199     nal_unit_count++;
200
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.
203     if (hevc_config &&
204         (nal_unit_type != H265NALU::AUD_NUT || nal_unit_count > 1)) {
205       uint32_t output_bytes_used = outscan - output;
206
207       DCHECK_GE(*output_size, output_bytes_used);
208
209       uint32_t config_size = *output_size - output_bytes_used;
210       if (!ConvertHEVCDecoderConfigToByteStream(*hevc_config, outscan,
211                                                 &config_size)) {
212         DVLOG(1) << "Failed to insert parameter sets.";
213         *output_size = 0;
214         return false;  // Failed to convert the buffer.
215       }
216       outscan += config_size;
217       hevc_config = nullptr;
218     }
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 +
224             nal_unit_length >
225         *output_size) {
226       *output_size = 0;
227       return false;  // Error: too small output buffer
228     }
229
230     // Check if this packet marks access unit boundary by checking the
231     // packet type.
232     if (IsAccessUnitBoundaryNal(nal_unit_type)) {
233       first_nal_unit_in_access_unit_ = true;
234     }
235
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_) {
239       *outscan = 0;
240       outscan++;
241       first_nal_unit_in_access_unit_ = false;
242     }
243
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.
254   }
255   // Successful conversion, output the freshly allocated bitstream buffer.
256   *output_size = static_cast<uint32_t>(outscan - output);
257   return true;
258 }
259
260 bool H265ToAnnexBBitstreamConverter::WriteParamSet(
261     const std::vector<uint8_t>& param_set,
262     uint8_t** out,
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)
267     size--;
268   if (!size)
269     return false;
270
271   // Verify space.
272   uint32_t bytes_left = *out_size;
273   if (bytes_left < kParamSetStartCodeSize ||
274       bytes_left - kParamSetStartCodeSize < size) {
275     return false;
276   }
277
278   uint8_t* start = *out;
279   uint8_t* buf = start;
280
281   // Write the 4 byte Annex B start code.
282   *buf++ = 0;  // zero byte
283   memcpy(buf, kStartCodePrefix, sizeof(kStartCodePrefix));
284   buf += sizeof(kStartCodePrefix);
285
286   // Copy the data.
287   memcpy(buf, &param_set[0], size);
288   buf += size;
289
290   *out = buf;
291   *out_size -= buf - start;
292   return true;
293 }
294
295 }  // namespace media