7 #include <packager/media/codecs/nal_unit_to_byte_stream_converter.h>
11 #include <absl/log/check.h>
12 #include <absl/log/log.h>
14 #include <packager/macros/compiler.h>
15 #include <packager/media/base/bit_reader.h>
16 #include <packager/media/base/buffer_reader.h>
17 #include <packager/media/base/buffer_writer.h>
18 #include <packager/media/codecs/nalu_reader.h>
25 const bool kEscapeData =
true;
26 const uint8_t kNaluStartCode[] = {0x00, 0x00, 0x00, 0x01};
28 const uint8_t kEmulationPreventionByte = 0x03;
30 const uint8_t kAccessUnitDelimiterRbspAnyPrimaryPicType = 0xF0;
32 bool IsNaluEqual(
const Nalu& left,
const Nalu& right) {
33 if (left.type() != right.type())
35 const size_t left_size = left.header_size() + left.payload_size();
36 const size_t right_size = right.header_size() + right.payload_size();
37 if (left_size != right_size)
39 return memcmp(left.data(), right.data(), left_size) == 0;
42 void AppendNalu(
const Nalu& nalu,
45 BufferWriter* buffer_writer) {
47 EscapeNalByteSequence(nalu.data(), nalu.header_size() + nalu.payload_size(),
50 buffer_writer->AppendArray(nalu.data(),
51 nalu.header_size() + nalu.payload_size());
55 void AddAccessUnitDelimiter(BufferWriter* buffer_writer) {
56 buffer_writer->AppendInt(
static_cast<uint8_t
>(Nalu::H264_AUD));
58 buffer_writer->AppendInt(kAccessUnitDelimiterRbspAnyPrimaryPicType);
63 void EscapeNalByteSequence(
const uint8_t* input,
65 BufferWriter* output_writer) {
69 int consecutive_zero_count = 0;
70 for (
size_t i = 0; i < input_size; ++i) {
71 if (consecutive_zero_count <= 1) {
72 output_writer->AppendInt(input[i]);
73 }
else if (consecutive_zero_count == 2) {
74 if (input[i] == 0 || input[i] == 1 || input[i] == 2 || input[i] == 3) {
76 output_writer->AppendInt(kEmulationPreventionByte);
79 output_writer->AppendInt(input[i]);
85 consecutive_zero_count = 0;
88 consecutive_zero_count = input[i] == 0 ? consecutive_zero_count + 1 : 0;
93 if (consecutive_zero_count > 0) {
94 DCHECK_GT(input_size, 0u);
95 DCHECK_EQ(input[input_size - 1], 0u);
96 output_writer->AppendInt(kEmulationPreventionByte);
103 void AppendSubsamples(uint32_t clear_bytes,
104 uint32_t cipher_bytes,
105 std::vector<SubsampleEntry>* subsamples) {
106 while (clear_bytes > UINT16_MAX) {
107 subsamples->emplace_back(UINT16_MAX, 0);
108 clear_bytes -= UINT16_MAX;
110 subsamples->emplace_back(clear_bytes, cipher_bytes);
138 bool AlignSubsamplesWithNalu(
size_t nalu_size,
139 size_t start_subsample_id,
140 std::vector<SubsampleEntry>* subsamples,
141 size_t* next_subsample_id) {
142 DCHECK(subsamples && !subsamples->empty());
143 size_t subsample_id = start_subsample_id;
144 size_t nalu_size_remain = nalu_size;
145 size_t subsample_bytes = 0;
146 while (subsample_id < subsamples->size()) {
147 subsample_bytes = subsamples->at(subsample_id).clear_bytes +
148 subsamples->at(subsample_id).cipher_bytes;
149 if (nalu_size_remain <= subsample_bytes) {
152 nalu_size_remain -= subsample_bytes;
156 if (subsample_id == subsamples->size()) {
157 DCHECK_GT(nalu_size_remain, 0u);
159 <<
"Total size of NAL unit is larger than the size of subsamples.";
163 if (nalu_size_remain == subsample_bytes) {
164 *next_subsample_id = subsample_id + 1;
168 DCHECK_GT(subsample_bytes, nalu_size_remain);
169 size_t clear_bytes = subsamples->at(subsample_id).clear_bytes;
170 size_t new_clear_bytes = 0;
171 size_t new_cipher_bytes = 0;
172 if (nalu_size_remain < clear_bytes) {
173 new_clear_bytes = nalu_size_remain;
175 new_clear_bytes = clear_bytes;
176 new_cipher_bytes = nalu_size_remain - clear_bytes;
178 subsamples->insert(subsamples->begin() + subsample_id,
179 SubsampleEntry(
static_cast<uint16_t
>(new_clear_bytes),
180 static_cast<uint32_t
>(new_cipher_bytes)));
182 subsamples->at(subsample_id).clear_bytes -=
183 static_cast<uint16_t
>(new_clear_bytes);
184 subsamples->at(subsample_id).cipher_bytes -=
185 static_cast<uint32_t
>(new_cipher_bytes);
186 *next_subsample_id = subsample_id;
193 std::vector<SubsampleEntry> MergeSubsamples(
194 const std::vector<SubsampleEntry>& subsamples) {
195 std::vector<SubsampleEntry> new_subsamples;
196 uint32_t clear_bytes = 0;
197 for (
size_t i = 0; i < subsamples.size(); ++i) {
198 clear_bytes += subsamples[i].clear_bytes;
200 if (subsamples[i].cipher_bytes > 0 || i == subsamples.size() - 1) {
201 AppendSubsamples(clear_bytes, subsamples[i].cipher_bytes,
206 return new_subsamples;
209 NalUnitToByteStreamConverter::NalUnitToByteStreamConverter()
210 : nalu_length_size_(0) {}
211 NalUnitToByteStreamConverter::~NalUnitToByteStreamConverter() {}
213 bool NalUnitToByteStreamConverter::Initialize(
214 const uint8_t* decoder_configuration_data,
215 size_t decoder_configuration_data_size) {
216 if (!decoder_configuration_data || decoder_configuration_data_size == 0) {
217 LOG(ERROR) <<
"Decoder conguration is empty.";
221 if (!decoder_config_.Parse(std::vector<uint8_t>(
222 decoder_configuration_data,
223 decoder_configuration_data + decoder_configuration_data_size))) {
227 if (decoder_config_.nalu_count() < 2) {
228 LOG(ERROR) <<
"Cannot find SPS or PPS.";
232 nalu_length_size_ = decoder_config_.nalu_length_size();
234 BufferWriter buffer_writer(decoder_configuration_data_size);
235 bool found_sps =
false;
236 bool found_pps =
false;
237 for (uint32_t i = 0; i < decoder_config_.nalu_count(); ++i) {
238 const Nalu& nalu = decoder_config_.nalu(i);
239 if (nalu.
type() == Nalu::H264NaluType::H264_SPS) {
240 buffer_writer.AppendArray(kNaluStartCode, std::size(kNaluStartCode));
241 AppendNalu(nalu, nalu_length_size_, !kEscapeData, &buffer_writer);
243 }
else if (nalu.
type() == Nalu::H264NaluType::H264_PPS) {
244 buffer_writer.AppendArray(kNaluStartCode, std::size(kNaluStartCode));
245 AppendNalu(nalu, nalu_length_size_, !kEscapeData, &buffer_writer);
247 }
else if (nalu.
type() == Nalu::H264NaluType::H264_SPSExtension) {
248 buffer_writer.AppendArray(kNaluStartCode, std::size(kNaluStartCode));
249 AppendNalu(nalu, nalu_length_size_, !kEscapeData, &buffer_writer);
252 if (!found_sps || !found_pps) {
253 LOG(ERROR) <<
"Failed to find SPS or PPS.";
257 buffer_writer.SwapBuffer(&decoder_configuration_in_byte_stream_);
261 bool NalUnitToByteStreamConverter::ConvertUnitToByteStream(
262 const uint8_t* sample,
265 std::vector<uint8_t>* output) {
266 return ConvertUnitToByteStreamWithSubsamples(
267 sample, sample_size, is_key_frame,
false, output,
274 bool NalUnitToByteStreamConverter::ConvertUnitToByteStreamWithSubsamples(
275 const uint8_t* sample,
278 bool escape_encrypted_nalu,
279 std::vector<uint8_t>* output,
280 std::vector<SubsampleEntry>* subsamples) {
281 if (!sample || sample_size == 0) {
282 LOG(WARNING) <<
"Sample is empty.";
286 std::vector<SubsampleEntry> temp_subsamples;
289 buffer_writer.AppendArray(kNaluStartCode, std::size(kNaluStartCode));
290 AddAccessUnitDelimiter(&buffer_writer);
292 buffer_writer.AppendVector(decoder_configuration_in_byte_stream_);
294 if (subsamples && !subsamples->empty()) {
297 AppendSubsamples(
static_cast<uint32_t
>(buffer_writer.Size()), 0u,
301 NaluReader nalu_reader(Nalu::kH264, nalu_length_size_, sample, sample_size);
303 NaluReader::Result result = nalu_reader.
Advance(&nalu);
305 size_t start_subsample_id = 0;
306 size_t next_subsample_id = 0;
307 while (result == NaluReader::kOk) {
308 const size_t old_nalu_size =
310 if (subsamples && !subsamples->empty()) {
311 if (!AlignSubsamplesWithNalu(old_nalu_size, start_subsample_id,
312 subsamples, &next_subsample_id)) {
316 switch (nalu.
type()) {
320 FALLTHROUGH_INTENDED;
321 case Nalu::H264_SPSExtension:
322 FALLTHROUGH_INTENDED;
323 case Nalu::H264_PPS: {
333 bool new_decoder_config =
true;
334 for (
size_t i = 0; i < decoder_config_.nalu_count(); ++i) {
335 if (IsNaluEqual(decoder_config_.nalu(i), nalu)) {
336 new_decoder_config =
false;
340 if (!new_decoder_config)
342 FALLTHROUGH_INTENDED;
345 bool escape_data =
false;
346 if (subsamples && !subsamples->empty()) {
347 if (escape_encrypted_nalu) {
348 for (
size_t i = start_subsample_id; i < next_subsample_id; ++i) {
349 if (subsamples->at(i).cipher_bytes != 0) {
356 buffer_writer.AppendArray(kNaluStartCode, std::size(kNaluStartCode));
357 AppendNalu(nalu, nalu_length_size_, escape_data, &buffer_writer);
359 if (subsamples && !subsamples->empty()) {
360 temp_subsamples.emplace_back(
361 static_cast<uint16_t
>(std::size(kNaluStartCode)), 0u);
368 if (subsamples->at(start_subsample_id).clear_bytes <
370 LOG(ERROR) <<
"Clear bytes ("
371 << subsamples->at(start_subsample_id).clear_bytes
372 <<
") in start subsample of NAL unit is less than NAL "
375 <<
"). The NAL unit length size is (partially) "
376 "encrypted. In that case, it cannot be "
377 "converted to byte stream.";
380 subsamples->at(start_subsample_id).clear_bytes -= nalu_length_size_;
381 temp_subsamples.insert(temp_subsamples.end(),
382 subsamples->begin() + start_subsample_id,
383 subsamples->begin() + next_subsample_id);
388 start_subsample_id = next_subsample_id;
389 result = nalu_reader.
Advance(&nalu);
392 DCHECK_NE(result, NaluReader::kOk);
393 if (result != NaluReader::kEOStream) {
394 LOG(ERROR) <<
"Stopped reading before end of stream.";
398 buffer_writer.SwapBuffer(output);
399 if (subsamples && !subsamples->empty()) {
400 if (next_subsample_id < subsamples->size()) {
402 <<
"The total size of NAL unit is shorter than the subsample size.";
408 *subsamples = MergeSubsamples(temp_subsamples);
All the methods that are virtual are virtual for mocking.