7#include <packager/media/codecs/nal_unit_to_byte_stream_converter.h>
15#include <absl/log/check.h>
16#include <absl/log/log.h>
18#include <packager/macros/compiler.h>
19#include <packager/media/base/buffer_writer.h>
20#include <packager/media/base/decrypt_config.h>
21#include <packager/media/codecs/nalu_reader.h>
28const bool kEscapeData =
true;
29const uint8_t kNaluStartCode[] = {0x00, 0x00, 0x00, 0x01};
31const uint8_t kEmulationPreventionByte = 0x03;
33const uint8_t kAccessUnitDelimiterRbspAnyPrimaryPicType = 0xF0;
35bool IsNaluEqual(
const Nalu& left,
const Nalu& right) {
36 if (left.type() != right.type())
38 const size_t left_size = left.header_size() + left.payload_size();
39 const size_t right_size = right.header_size() + right.payload_size();
40 if (left_size != right_size)
42 return memcmp(left.data(), right.data(), left_size) == 0;
45void AppendNalu(
const Nalu& nalu,
48 BufferWriter* buffer_writer) {
50 EscapeNalByteSequence(nalu.data(), nalu.header_size() + nalu.payload_size(),
53 buffer_writer->AppendArray(nalu.data(),
54 nalu.header_size() + nalu.payload_size());
58void AddAccessUnitDelimiter(BufferWriter* buffer_writer) {
59 buffer_writer->AppendInt(
static_cast<uint8_t
>(Nalu::H264_AUD));
61 buffer_writer->AppendInt(kAccessUnitDelimiterRbspAnyPrimaryPicType);
66void EscapeNalByteSequence(
const uint8_t* input,
68 BufferWriter* output_writer) {
72 int consecutive_zero_count = 0;
73 for (
size_t i = 0; i < input_size; ++i) {
74 if (consecutive_zero_count <= 1) {
75 output_writer->AppendInt(input[i]);
76 }
else if (consecutive_zero_count == 2) {
77 if (input[i] == 0 || input[i] == 1 || input[i] == 2 || input[i] == 3) {
79 output_writer->AppendInt(kEmulationPreventionByte);
82 output_writer->AppendInt(input[i]);
88 consecutive_zero_count = 0;
91 consecutive_zero_count = input[i] == 0 ? consecutive_zero_count + 1 : 0;
96 if (consecutive_zero_count > 0) {
97 DCHECK_GT(input_size, 0u);
98 DCHECK_EQ(input[input_size - 1], 0u);
99 output_writer->AppendInt(kEmulationPreventionByte);
106void AppendSubsamples(uint32_t clear_bytes,
107 uint32_t cipher_bytes,
108 std::vector<SubsampleEntry>* subsamples) {
109 while (clear_bytes > UINT16_MAX) {
110 subsamples->emplace_back(UINT16_MAX, 0);
111 clear_bytes -= UINT16_MAX;
113 subsamples->emplace_back(clear_bytes, cipher_bytes);
141bool AlignSubsamplesWithNalu(
size_t nalu_size,
142 size_t start_subsample_id,
143 std::vector<SubsampleEntry>* subsamples,
144 size_t* next_subsample_id) {
145 DCHECK(subsamples && !subsamples->empty());
146 size_t subsample_id = start_subsample_id;
147 size_t nalu_size_remain = nalu_size;
148 size_t subsample_bytes = 0;
149 while (subsample_id < subsamples->size()) {
150 subsample_bytes = subsamples->at(subsample_id).clear_bytes +
151 subsamples->at(subsample_id).cipher_bytes;
152 if (nalu_size_remain <= subsample_bytes) {
155 nalu_size_remain -= subsample_bytes;
159 if (subsample_id == subsamples->size()) {
160 DCHECK_GT(nalu_size_remain, 0u);
162 <<
"Total size of NAL unit is larger than the size of subsamples.";
166 if (nalu_size_remain == subsample_bytes) {
167 *next_subsample_id = subsample_id + 1;
171 DCHECK_GT(subsample_bytes, nalu_size_remain);
172 size_t clear_bytes = subsamples->at(subsample_id).clear_bytes;
173 size_t new_clear_bytes = 0;
174 size_t new_cipher_bytes = 0;
175 if (nalu_size_remain < clear_bytes) {
176 new_clear_bytes = nalu_size_remain;
178 new_clear_bytes = clear_bytes;
179 new_cipher_bytes = nalu_size_remain - clear_bytes;
181 subsamples->insert(subsamples->begin() + subsample_id,
182 SubsampleEntry(
static_cast<uint16_t
>(new_clear_bytes),
183 static_cast<uint32_t
>(new_cipher_bytes)));
185 subsamples->at(subsample_id).clear_bytes -=
186 static_cast<uint16_t
>(new_clear_bytes);
187 subsamples->at(subsample_id).cipher_bytes -=
188 static_cast<uint32_t
>(new_cipher_bytes);
189 *next_subsample_id = subsample_id;
196std::vector<SubsampleEntry> MergeSubsamples(
197 const std::vector<SubsampleEntry>& subsamples) {
198 std::vector<SubsampleEntry> new_subsamples;
199 uint32_t clear_bytes = 0;
200 for (
size_t i = 0; i < subsamples.size(); ++i) {
201 clear_bytes += subsamples[i].clear_bytes;
203 if (subsamples[i].cipher_bytes > 0 || i == subsamples.size() - 1) {
204 AppendSubsamples(clear_bytes, subsamples[i].cipher_bytes,
209 return new_subsamples;
212NalUnitToByteStreamConverter::NalUnitToByteStreamConverter()
213 : nalu_length_size_(0) {}
214NalUnitToByteStreamConverter::~NalUnitToByteStreamConverter() {}
216bool NalUnitToByteStreamConverter::Initialize(
217 const uint8_t* decoder_configuration_data,
218 size_t decoder_configuration_data_size) {
219 if (!decoder_configuration_data || decoder_configuration_data_size == 0) {
220 LOG(ERROR) <<
"Decoder conguration is empty.";
224 if (!decoder_config_.Parse(std::vector<uint8_t>(
225 decoder_configuration_data,
226 decoder_configuration_data + decoder_configuration_data_size))) {
230 if (decoder_config_.nalu_count() < 2) {
231 LOG(ERROR) <<
"Cannot find SPS or PPS.";
235 nalu_length_size_ = decoder_config_.nalu_length_size();
237 BufferWriter buffer_writer(decoder_configuration_data_size);
238 bool found_sps =
false;
239 bool found_pps =
false;
240 for (uint32_t i = 0; i < decoder_config_.nalu_count(); ++i) {
241 const Nalu& nalu = decoder_config_.nalu(i);
242 if (nalu.
type() == Nalu::H264NaluType::H264_SPS) {
243 buffer_writer.AppendArray(kNaluStartCode, std::size(kNaluStartCode));
244 AppendNalu(nalu, nalu_length_size_, !kEscapeData, &buffer_writer);
246 }
else if (nalu.
type() == Nalu::H264NaluType::H264_PPS) {
247 buffer_writer.AppendArray(kNaluStartCode, std::size(kNaluStartCode));
248 AppendNalu(nalu, nalu_length_size_, !kEscapeData, &buffer_writer);
250 }
else if (nalu.
type() == Nalu::H264NaluType::H264_SPSExtension) {
251 buffer_writer.AppendArray(kNaluStartCode, std::size(kNaluStartCode));
252 AppendNalu(nalu, nalu_length_size_, !kEscapeData, &buffer_writer);
255 if (!found_sps || !found_pps) {
256 LOG(ERROR) <<
"Failed to find SPS or PPS.";
260 buffer_writer.SwapBuffer(&decoder_configuration_in_byte_stream_);
264bool NalUnitToByteStreamConverter::ConvertUnitToByteStream(
265 const uint8_t* sample,
268 std::vector<uint8_t>* output) {
269 return ConvertUnitToByteStreamWithSubsamples(
270 sample, sample_size, is_key_frame,
false, output,
277bool NalUnitToByteStreamConverter::ConvertUnitToByteStreamWithSubsamples(
278 const uint8_t* sample,
281 bool escape_encrypted_nalu,
282 std::vector<uint8_t>* output,
283 std::vector<SubsampleEntry>* subsamples) {
284 if (!sample || sample_size == 0) {
285 LOG(WARNING) <<
"Sample is empty.";
289 std::vector<SubsampleEntry> temp_subsamples;
292 buffer_writer.AppendArray(kNaluStartCode, std::size(kNaluStartCode));
293 AddAccessUnitDelimiter(&buffer_writer);
295 buffer_writer.AppendVector(decoder_configuration_in_byte_stream_);
297 if (subsamples && !subsamples->empty()) {
300 AppendSubsamples(
static_cast<uint32_t
>(buffer_writer.Size()), 0u,
304 NaluReader nalu_reader(Nalu::kH264, nalu_length_size_, sample, sample_size);
306 NaluReader::Result result = nalu_reader.
Advance(&nalu);
308 size_t start_subsample_id = 0;
309 size_t next_subsample_id = 0;
310 while (result == NaluReader::kOk) {
311 const size_t old_nalu_size =
313 if (subsamples && !subsamples->empty()) {
314 if (!AlignSubsamplesWithNalu(old_nalu_size, start_subsample_id,
315 subsamples, &next_subsample_id)) {
319 switch (nalu.
type()) {
323 FALLTHROUGH_INTENDED;
324 case Nalu::H264_SPSExtension:
325 FALLTHROUGH_INTENDED;
326 case Nalu::H264_PPS: {
336 bool new_decoder_config =
true;
337 for (
size_t i = 0; i < decoder_config_.nalu_count(); ++i) {
338 if (IsNaluEqual(decoder_config_.nalu(i), nalu)) {
339 new_decoder_config =
false;
343 if (!new_decoder_config)
345 FALLTHROUGH_INTENDED;
348 bool escape_data =
false;
349 if (subsamples && !subsamples->empty()) {
350 if (escape_encrypted_nalu) {
351 for (
size_t i = start_subsample_id; i < next_subsample_id; ++i) {
352 if (subsamples->at(i).cipher_bytes != 0) {
359 buffer_writer.AppendArray(kNaluStartCode, std::size(kNaluStartCode));
360 AppendNalu(nalu, nalu_length_size_, escape_data, &buffer_writer);
362 if (subsamples && !subsamples->empty()) {
363 temp_subsamples.emplace_back(
364 static_cast<uint16_t
>(std::size(kNaluStartCode)), 0u);
371 if (subsamples->at(start_subsample_id).clear_bytes <
373 LOG(ERROR) <<
"Clear bytes ("
374 << subsamples->at(start_subsample_id).clear_bytes
375 <<
") in start subsample of NAL unit is less than NAL "
378 <<
"). The NAL unit length size is (partially) "
379 "encrypted. In that case, it cannot be "
380 "converted to byte stream.";
383 subsamples->at(start_subsample_id).clear_bytes -= nalu_length_size_;
384 temp_subsamples.insert(temp_subsamples.end(),
385 subsamples->begin() + start_subsample_id,
386 subsamples->begin() + next_subsample_id);
391 start_subsample_id = next_subsample_id;
392 result = nalu_reader.
Advance(&nalu);
395 DCHECK_NE(result, NaluReader::kOk);
396 if (result != NaluReader::kEOStream) {
397 LOG(ERROR) <<
"Stopped reading before end of stream.";
401 buffer_writer.SwapBuffer(output);
402 if (subsamples && !subsamples->empty()) {
403 if (next_subsample_id < subsamples->size()) {
405 <<
"The total size of NAL unit is shorter than the subsample size.";
411 *subsamples = MergeSubsamples(temp_subsamples);
All the methods that are virtual are virtual for mocking.