7 #include "packager/media/codecs/nalu_reader.h" 11 #include "packager/base/logging.h" 12 #include "packager/media/base/buffer_reader.h" 13 #include "packager/media/codecs/h264_parser.h" 19 inline bool IsStartCode(
const uint8_t* data) {
20 return data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01;
24 void UpdateSubsamples(uint64_t consumed_bytes,
25 std::vector<SubsampleEntry>* subsamples) {
26 if (consumed_bytes == 0 || subsamples->empty()) {
29 size_t num_entries_to_delete = 0;
30 for (SubsampleEntry& subsample : *subsamples) {
31 if (subsample.clear_bytes > consumed_bytes) {
32 subsample.clear_bytes -= consumed_bytes;
36 consumed_bytes -= subsample.clear_bytes;
37 subsample.clear_bytes = 0;
39 if (subsample.cipher_bytes > consumed_bytes) {
40 subsample.cipher_bytes -= consumed_bytes;
44 consumed_bytes -= subsample.cipher_bytes;
45 subsample.cipher_bytes = 0;
46 ++num_entries_to_delete;
49 subsamples->erase(subsamples->begin(),
50 subsamples->begin() + num_entries_to_delete);
53 bool IsNaluLengthEncrypted(
54 uint8_t nalu_length_size,
55 const std::vector<SubsampleEntry>& subsamples) {
56 if (subsamples.empty())
59 for (
const SubsampleEntry& subsample : subsamples) {
60 if (subsample.clear_bytes >= nalu_length_size) {
63 nalu_length_size -= subsample.clear_bytes;
64 if (subsample.cipher_bytes > 0) {
73 Nalu::Nalu() =
default;
75 bool Nalu::Initialize(CodecType type,
78 if (type == Nalu::kH264) {
79 return InitializeFromH264(data, size);
81 DCHECK_EQ(Nalu::kH265, type);
82 return InitializeFromH265(data, size);
87 bool Nalu::InitializeFromH264(
const uint8_t* data, uint64_t size) {
91 const uint8_t header = data[0];
92 if ((header & 0x80) != 0) {
93 LOG(WARNING) <<
"forbidden_zero_bit shall be equal to 0 (header 0x" 94 << std::hex << static_cast<int>(header) <<
").";
100 payload_size_ = size - header_size_;
101 ref_idc_ = (header >> 5) & 0x3;
102 type_ = header & 0x1F;
105 if (type_ == Nalu::H264_Unspecified || type_ == Nalu::H264_Reserved17 ||
106 type_ == Nalu::H264_Reserved18 || type_ >= Nalu::H264_Reserved22) {
107 LOG(WARNING) <<
"Unspecified or reserved nal_unit_type " << type_
108 <<
" (header 0x" << std::hex << static_cast<int>(header)
111 }
else if (type_ == Nalu::H264_IDRSlice || type_ == Nalu::H264_SPS ||
112 type_ == Nalu::H264_SPSExtension ||
113 type_ == Nalu::H264_SubsetSPS || type_ == Nalu::H264_PPS) {
115 LOG(WARNING) <<
"nal_ref_idc shall not be equal to 0 for nalu type " 116 << type_ <<
" (header 0x" << std::hex
117 <<
static_cast<int>(header) <<
").";
120 }
else if (type_ == Nalu::H264_SEIMessage ||
121 (type_ >= Nalu::H264_AUD && type_ <= Nalu::H264_FillerData)) {
123 LOG(WARNING) <<
"nal_ref_idc shall be equal to 0 for nalu type " << type_
124 <<
" (header 0x" << std::hex << static_cast<int>(header)
130 is_aud_ = type_ == H264_AUD;
131 is_vcl_ = (type_ >= Nalu::H264_NonIDRSlice && type_ <= Nalu::H264_IDRSlice);
133 (type_ == Nalu::H264_NonIDRSlice || type_ == Nalu::H264_IDRSlice);
134 can_start_access_unit_ =
135 (is_vcl_ || type_ == Nalu::H264_AUD || type_ == Nalu::H264_SPS ||
136 type_ == Nalu::H264_PPS || type_ == Nalu::H264_SEIMessage ||
137 (type_ >= Nalu::H264_PrefixNALUnit && type_ <= Nalu::H264_Reserved18));
142 bool Nalu::InitializeFromH265(
const uint8_t* data, uint64_t size) {
146 const uint16_t header = (data[0] << 8) | data[1];
147 if ((header & 0x8000) != 0) {
148 LOG(WARNING) <<
"forbidden_zero_bit shall be equal to 0 (header 0x" 149 << std::hex << header <<
").";
155 payload_size_ = size - header_size_;
157 type_ = (header >> 9) & 0x3F;
158 nuh_layer_id_ = (header >> 3) & 0x3F;
159 const int nuh_temporal_id_plus1 = header & 0x7;
160 if (nuh_temporal_id_plus1 == 0) {
161 LOG(WARNING) <<
"nul_temporal_id_plus1 shall not be equal to 0 (header 0x" 162 << std::hex << header <<
").";
165 nuh_temporal_id_ = nuh_temporal_id_plus1 - 1;
167 if (type_ == Nalu::H265_EOB && nuh_layer_id_ != 0) {
168 LOG(WARNING) <<
"nuh_layer_id shall be equal to 0 for nalu type " << type_
169 <<
" (header 0x" << std::hex << header <<
").";
174 if ((type_ >= Nalu::H265_RSV_VCL_N10 && type_ <= Nalu::H265_RSV_VCL_R15) ||
175 (type_ >= Nalu::H265_RSV_IRAP_VCL22 && type_ < Nalu::H265_RSV_VCL31) ||
176 (type_ >= Nalu::H265_RSV_NVCL41)) {
177 LOG(WARNING) <<
"Unspecified or reserved nal_unit_type " << type_
178 <<
" (header 0x" << std::hex << header <<
").";
180 }
else if ((type_ >= Nalu::H265_BLA_W_LP &&
181 type_ <= Nalu::H265_RSV_IRAP_VCL23) ||
182 type_ == Nalu::H265_VPS || type_ == Nalu::H265_SPS ||
183 type_ == Nalu::H265_EOS || type_ == Nalu::H265_EOB) {
184 if (nuh_temporal_id_ != 0) {
185 LOG(WARNING) <<
"TemporalId shall be equal to 0 for nalu type " << type_
186 <<
" (header 0x" << std::hex << header <<
").";
189 }
else if (type_ == Nalu::H265_TSA_N || type_ == Nalu::H265_TSA_R ||
190 (nuh_layer_id_ == 0 &&
191 (type_ == Nalu::H265_STSA_N || type_ == Nalu::H265_STSA_R))) {
192 if (nuh_temporal_id_ == 0) {
193 LOG(WARNING) <<
"TemporalId shall not be equal to 0 for nalu type " 194 << type_ <<
" (header 0x" << std::hex << header <<
").";
199 is_aud_ = type_ == H265_AUD;
200 is_vcl_ = type_ >= Nalu::H265_TRAIL_N && type_ <= Nalu::H265_CRA_NUT;
201 is_video_slice_ = is_vcl_;
202 can_start_access_unit_ =
203 nuh_layer_id_ == 0 &&
204 (is_vcl_ || type_ == Nalu::H265_AUD || type_ == Nalu::H265_VPS ||
205 type_ == Nalu::H265_SPS || type_ == Nalu::H265_PPS ||
206 type_ == Nalu::H265_PREFIX_SEI ||
207 (type_ >= Nalu::H265_RSV_NVCL41 && type_ <= Nalu::H265_RSV_NVCL44) ||
208 (type_ >= Nalu::H265_UNSPEC48 && type_ <= Nalu::H265_UNSPEC55));
213 uint8_t nal_length_size,
214 const uint8_t* stream,
215 uint64_t stream_size)
223 uint8_t nal_length_size,
224 const uint8_t* stream,
225 uint64_t stream_size,
226 const std::vector<SubsampleEntry>& subsamples)
228 stream_size_(stream_size),
230 nalu_length_size_(nal_length_size),
231 format_(nal_length_size == 0 ? kAnnexbByteStreamFormat
232 : kNalUnitStreamFormat),
233 subsamples_(subsamples) {
237 NaluReader::~NaluReader() {}
240 if (stream_size_ <= 0)
241 return NaluReader::kEOStream;
243 uint8_t nalu_length_size_or_start_code_size;
244 uint64_t nalu_length;
245 if (format_ == kAnnexbByteStreamFormat) {
247 uint64_t nalu_length_with_header;
248 if (!LocateNaluByStartCode(&nalu_length_with_header,
249 &nalu_length_size_or_start_code_size)) {
250 LOG(ERROR) <<
"Could not find next NALU, bytes left in stream: " 255 return NaluReader::kInvalidStream;
257 nalu_length = nalu_length_with_header - nalu_length_size_or_start_code_size;
260 if (IsNaluLengthEncrypted(nalu_length_size_, subsamples_)) {
261 LOG(ERROR) <<
"NALU length is encrypted.";
262 return NaluReader::kInvalidStream;
265 return NaluReader::kInvalidStream;
266 nalu_length_size_or_start_code_size = nalu_length_size_;
268 if (nalu_length + nalu_length_size_ > stream_size_) {
269 LOG(ERROR) <<
"NALU length exceeds stream size: " 270 << stream_size_ <<
" < " << nalu_length;
271 return NaluReader::kInvalidStream;
273 if (nalu_length == 0) {
274 LOG(ERROR) <<
"NALU size 0";
275 return NaluReader::kInvalidStream;
279 const uint8_t* nalu_data = stream_ + nalu_length_size_or_start_code_size;
280 if (!nalu->Initialize(nalu_type_, nalu_data, nalu_length))
281 return NaluReader::kInvalidStream;
285 stream_ += nalu_length_size_or_start_code_size + nalu_length;
286 stream_size_ -= nalu_length_size_or_start_code_size + nalu_length;
287 UpdateSubsamples(nalu_length_size_or_start_code_size + nalu_length,
290 DVLOG(4) <<
"NALU type: " <<
static_cast<int>(nalu->
type())
291 <<
" at: " << reinterpret_cast<const void*>(nalu->
data())
294 return NaluReader::kOk;
298 if (stream_size_ >= 3) {
299 if (IsStartCode(stream_))
302 if (stream_size_ >= 4) {
303 if (stream_[0] == 0x00 && IsStartCode(stream_ + 1))
310 bool NaluReader::FindStartCode(
const uint8_t* data,
313 uint8_t* start_code_size) {
314 uint64_t bytes_left = data_size;
316 while (bytes_left >= 3) {
317 if (IsStartCode(data)) {
319 *offset = data_size - bytes_left;
320 *start_code_size = 3;
324 if (*offset > 0 && *(data - 1) == 0x00) {
326 ++(*start_code_size);
338 *offset = data_size - bytes_left;
339 *start_code_size = 0;
348 uint8_t* start_code_size,
349 const std::vector<SubsampleEntry>& subsamples) {
350 if (subsamples.empty()) {
351 return FindStartCode(data, data_size, offset, start_code_size);
354 uint64_t current_offset = 0;
356 uint16_t clear_bytes = subsample.clear_bytes;
357 if (current_offset + clear_bytes > data_size) {
358 LOG(WARNING) <<
"The sum of subsample sizes is greater than data_size.";
359 clear_bytes = data_size - current_offset;
366 const bool found_start_code = FindStartCode(
367 data + current_offset, clear_bytes, offset, start_code_size);
368 if (found_start_code) {
369 *offset += current_offset;
372 const uint64_t subsample_size =
373 subsample.clear_bytes + subsample.cipher_bytes;
374 current_offset += subsample_size;
375 if (current_offset > data_size) {
378 current_offset = data_size;
379 LOG(WARNING) <<
"The sum of subsamples is greater than data_size.";
386 if (current_offset < data_size) {
387 const bool found_start_code =
388 FindStartCode(data + current_offset, data_size - current_offset, offset,
390 *offset += current_offset;
391 return found_start_code;
396 *offset = current_offset;
397 *start_code_size = 0;
401 bool NaluReader::LocateNaluByStartCode(uint64_t* nalu_size,
402 uint8_t* start_code_size) {
404 uint64_t nalu_start_off = 0;
405 uint8_t annexb_start_code_size = 0;
407 stream_, stream_size_,
408 &nalu_start_off, &annexb_start_code_size, subsamples_)) {
409 DVLOG(4) <<
"Could not find start code, end of stream?";
414 stream_ += nalu_start_off;
415 stream_size_ -= nalu_start_off;
418 UpdateSubsamples(nalu_start_off, &subsamples_);
420 const uint8_t* nalu_data = stream_ + annexb_start_code_size;
423 std::vector<SubsampleEntry> subsamples_for_finding_next_nalu;
424 if (!subsamples_.empty()) {
425 subsamples_for_finding_next_nalu = subsamples_;
426 UpdateSubsamples(annexb_start_code_size, &subsamples_for_finding_next_nalu);
428 uint64_t max_nalu_data_size = stream_size_ - annexb_start_code_size;
429 if (max_nalu_data_size <= 0) {
430 DVLOG(3) <<
"End of stream";
440 uint64_t nalu_size_without_start_code = 0;
441 uint8_t next_start_code_size = 0;
444 nalu_data, max_nalu_data_size,
445 &nalu_size_without_start_code, &next_start_code_size,
446 subsamples_for_finding_next_nalu)) {
447 nalu_data += max_nalu_data_size;
451 nalu_data += nalu_size_without_start_code + next_start_code_size;
452 max_nalu_data_size -= nalu_size_without_start_code + next_start_code_size;
453 UpdateSubsamples(nalu_size_without_start_code + next_start_code_size,
454 &subsamples_for_finding_next_nalu);
458 if (nalu.Initialize(nalu_type_, nalu_data, max_nalu_data_size)) {
459 nalu_data -= next_start_code_size;
462 LOG(WARNING) <<
"Seeing invalid NAL unit. Emulation prevention may not " 463 "have been applied properly. Assuming it is part of the " 464 "previous NAL unit.";
466 *nalu_size = nalu_data - stream_;
467 *start_code_size = annexb_start_code_size;
All the methods that are virtual are virtual for mocking.