Shaka Packager SDK
Loading...
Searching...
No Matches
nalu_reader.cc
1// Copyright 2016 Google LLC. All rights reserved.
2//
3// Use of this source code is governed by a BSD-style
4// license that can be found in the LICENSE file or at
5// https://developers.google.com/open-source/licenses/bsd
6
7#include <packager/media/codecs/nalu_reader.h>
8
9#include <iostream>
10
11#include <absl/log/check.h>
12#include <absl/log/log.h>
13
14#include <packager/macros/logging.h>
15#include <packager/media/base/buffer_reader.h>
16#include <packager/media/codecs/h264_parser.h>
17
18namespace shaka {
19namespace media {
20
21namespace {
22inline bool IsStartCode(const uint8_t* data) {
23 return data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01;
24}
25
26// Edits |subsamples| given the number of consumed bytes.
27void UpdateSubsamples(uint64_t consumed_bytes,
28 std::vector<SubsampleEntry>* subsamples) {
29 if (consumed_bytes == 0 || subsamples->empty()) {
30 return;
31 }
32 size_t num_entries_to_delete = 0;
33 for (SubsampleEntry& subsample : *subsamples) {
34 if (subsample.clear_bytes > consumed_bytes) {
35 subsample.clear_bytes -= consumed_bytes;
36 consumed_bytes = 0;
37 break;
38 }
39 consumed_bytes -= subsample.clear_bytes;
40 subsample.clear_bytes = 0;
41
42 if (subsample.cipher_bytes > consumed_bytes) {
43 subsample.cipher_bytes -= consumed_bytes;
44 consumed_bytes = 0;
45 break;
46 }
47 consumed_bytes -= subsample.cipher_bytes;
48 subsample.cipher_bytes = 0;
49 ++num_entries_to_delete;
50 }
51
52 subsamples->erase(subsamples->begin(),
53 subsamples->begin() + num_entries_to_delete);
54}
55
56bool IsNaluLengthEncrypted(
57 uint8_t nalu_length_size,
58 const std::vector<SubsampleEntry>& subsamples) {
59 if (subsamples.empty())
60 return false;
61
62 for (const SubsampleEntry& subsample : subsamples) {
63 if (subsample.clear_bytes >= nalu_length_size) {
64 return false;
65 }
66 nalu_length_size -= subsample.clear_bytes;
67 if (subsample.cipher_bytes > 0) {
68 return true;
69 }
70 }
71 // Ran out of subsamples. Assume the rest is in the clear.
72 return false;
73}
74} // namespace
75
76Nalu::Nalu() = default;
77
78bool Nalu::Initialize(CodecType type,
79 const uint8_t* data,
80 uint64_t size) {
81 if (type == Nalu::kH264) {
82 return InitializeFromH264(data, size);
83 } else {
84 DCHECK_EQ(Nalu::kH265, type);
85 return InitializeFromH265(data, size);
86 }
87}
88
89// ITU-T H.264 (02/2014) 7.4.1 NAL unit semantics
90bool Nalu::InitializeFromH264(const uint8_t* data, uint64_t size) {
91 DCHECK(data);
92 if (size == 0)
93 return false;
94 const uint8_t header = data[0];
95 if ((header & 0x80) != 0) {
96 LOG(WARNING) << "forbidden_zero_bit shall be equal to 0 (header 0x"
97 << std::hex << static_cast<int>(header) << ").";
98 return false;
99 }
100
101 data_ = data;
102 header_size_ = 1;
103 payload_size_ = size - header_size_;
104 ref_idc_ = (header >> 5) & 0x3;
105 type_ = header & 0x1F;
106
107 // Reserved NAL units are not treated as valid NAL units here.
108 if (type_ == Nalu::H264_Unspecified || type_ == Nalu::H264_Reserved17 ||
109 type_ == Nalu::H264_Reserved18 || type_ >= Nalu::H264_Reserved22) {
110 VLOG(1) << "Unspecified or reserved nal_unit_type " << type_
111 << " (header 0x" << std::hex << static_cast<int>(header) << ").";
112 // Allow reserved NAL units. Some encoders and extended codecs use the
113 // reserved NAL units to carry their private data.
114 } else if (type_ == Nalu::H264_IDRSlice || type_ == Nalu::H264_SPS ||
115 type_ == Nalu::H264_SPSExtension ||
116 type_ == Nalu::H264_SubsetSPS || type_ == Nalu::H264_PPS) {
117 if (ref_idc_ == 0) {
118 LOG(WARNING) << "nal_ref_idc shall not be equal to 0 for nalu type "
119 << type_ << " (header 0x" << std::hex
120 << static_cast<int>(header) << ").";
121 return false;
122 }
123 } else if (type_ == Nalu::H264_SEIMessage ||
124 (type_ >= Nalu::H264_AUD && type_ <= Nalu::H264_FillerData)) {
125 if (ref_idc_ != 0) {
126 LOG(WARNING) << "nal_ref_idc shall be equal to 0 for nalu type " << type_
127 << " (header 0x" << std::hex << static_cast<int>(header)
128 << ").";
129 return false;
130 }
131 }
132
133 is_aud_ = type_ == H264_AUD;
134 is_vcl_ = (type_ >= Nalu::H264_NonIDRSlice && type_ <= Nalu::H264_IDRSlice);
135 is_video_slice_ =
136 (type_ == Nalu::H264_NonIDRSlice || type_ == Nalu::H264_IDRSlice);
137 can_start_access_unit_ =
138 (is_vcl_ || type_ == Nalu::H264_AUD || type_ == Nalu::H264_SPS ||
139 type_ == Nalu::H264_PPS || type_ == Nalu::H264_SEIMessage ||
140 (type_ >= Nalu::H264_PrefixNALUnit && type_ <= Nalu::H264_Reserved18));
141 return true;
142}
143
144// ITU-T H.265 (04/2015) 7.4.2.2 NAL unit header semantics
145bool Nalu::InitializeFromH265(const uint8_t* data, uint64_t size) {
146 DCHECK(data);
147 if (size < 2)
148 return false;
149 const uint16_t header = (data[0] << 8) | data[1];
150 if ((header & 0x8000) != 0) {
151 LOG(WARNING) << "forbidden_zero_bit shall be equal to 0 (header 0x"
152 << std::hex << header << ").";
153 return false;
154 }
155
156 data_ = data;
157 header_size_ = 2;
158 payload_size_ = size - header_size_;
159
160 type_ = (header >> 9) & 0x3F;
161 nuh_layer_id_ = (header >> 3) & 0x3F;
162 const int nuh_temporal_id_plus1 = header & 0x7;
163 if (nuh_temporal_id_plus1 == 0) {
164 LOG(WARNING) << "nul_temporal_id_plus1 shall not be equal to 0 (header 0x"
165 << std::hex << header << ").";
166 return false;
167 }
168 nuh_temporal_id_ = nuh_temporal_id_plus1 - 1;
169
170 if (type_ == Nalu::H265_EOB && nuh_layer_id_ != 0) {
171 LOG(WARNING) << "nuh_layer_id shall be equal to 0 for nalu type " << type_
172 << " (header 0x" << std::hex << header << ").";
173 return false;
174 }
175
176 // Reserved NAL units are not treated as valid NAL units here.
177 if ((type_ >= Nalu::H265_RSV_VCL_N10 && type_ <= Nalu::H265_RSV_VCL_R15) ||
178 (type_ >= Nalu::H265_RSV_IRAP_VCL22 && type_ < Nalu::H265_RSV_VCL31) ||
179 (type_ >= Nalu::H265_RSV_NVCL41)) {
180 VLOG(1) << "Unspecified or reserved nal_unit_type " << type_
181 << " (header 0x" << std::hex << header << ").";
182 // Allow reserved NAL units. Some encoders and extended codecs use the
183 // reserved NAL units to carry their private data. For example, Dolby Vision
184 // uses NAL unit type 62.
185 } else if ((type_ >= Nalu::H265_BLA_W_LP &&
186 type_ <= Nalu::H265_RSV_IRAP_VCL23) ||
187 type_ == Nalu::H265_VPS || type_ == Nalu::H265_SPS ||
188 type_ == Nalu::H265_EOS || type_ == Nalu::H265_EOB) {
189 if (nuh_temporal_id_ != 0) {
190 LOG(WARNING) << "TemporalId shall be equal to 0 for nalu type " << type_
191 << " (header 0x" << std::hex << header << ").";
192 return false;
193 }
194 } else if (type_ == Nalu::H265_TSA_N || type_ == Nalu::H265_TSA_R ||
195 (nuh_layer_id_ == 0 &&
196 (type_ == Nalu::H265_STSA_N || type_ == Nalu::H265_STSA_R))) {
197 if (nuh_temporal_id_ == 0) {
198 LOG(WARNING) << "TemporalId shall not be equal to 0 for nalu type "
199 << type_ << " (header 0x" << std::hex << header << ").";
200 return false;
201 }
202 }
203
204 is_aud_ = type_ == H265_AUD;
205 is_vcl_ = type_ >= Nalu::H265_TRAIL_N && type_ <= Nalu::H265_RSV_VCL31;
206 is_video_slice_ = is_vcl_;
207 can_start_access_unit_ =
208 nuh_layer_id_ == 0 &&
209 (is_vcl_ || type_ == Nalu::H265_AUD || type_ == Nalu::H265_VPS ||
210 type_ == Nalu::H265_SPS || type_ == Nalu::H265_PPS ||
211 type_ == Nalu::H265_PREFIX_SEI ||
212 (type_ >= Nalu::H265_RSV_NVCL41 && type_ <= Nalu::H265_RSV_NVCL44) ||
213 (type_ >= Nalu::H265_UNSPEC48 && type_ <= Nalu::H265_UNSPEC55));
214 return true;
215}
216
217NaluReader::NaluReader(Nalu::CodecType type,
218 uint8_t nal_length_size,
219 const uint8_t* stream,
220 uint64_t stream_size)
221 : NaluReader(type,
222 nal_length_size,
223 stream,
224 stream_size,
225 std::vector<SubsampleEntry>()) {}
226
227NaluReader::NaluReader(Nalu::CodecType type,
228 uint8_t nal_length_size,
229 const uint8_t* stream,
230 uint64_t stream_size,
231 const std::vector<SubsampleEntry>& subsamples)
232 : stream_(stream),
233 stream_size_(stream_size),
234 nalu_type_(type),
235 nalu_length_size_(nal_length_size),
236 format_(nal_length_size == 0 ? kAnnexbByteStreamFormat
237 : kNalUnitStreamFormat),
238 subsamples_(subsamples) {
239 DCHECK(stream);
240}
241
242NaluReader::~NaluReader() {}
243
244NaluReader::Result NaluReader::Advance(Nalu* nalu) {
245 if (stream_size_ <= 0)
246 return NaluReader::kEOStream;
247
248 uint8_t nalu_length_size_or_start_code_size;
249 uint64_t nalu_length;
250 if (format_ == kAnnexbByteStreamFormat) {
251 // This will move |stream_| to the start code.
252 uint64_t nalu_length_with_header;
253 if (!LocateNaluByStartCode(&nalu_length_with_header,
254 &nalu_length_size_or_start_code_size)) {
255 LOG(ERROR) << "Could not find next NALU, bytes left in stream: "
256 << stream_size_;
257 // This is actually an error. Since we always move to past the end of
258 // each NALU, if there is no next start code, then this is the first call
259 // and there are no start codes in the stream.
260 return NaluReader::kInvalidStream;
261 }
262 nalu_length = nalu_length_with_header - nalu_length_size_or_start_code_size;
263 } else {
264 BufferReader reader(stream_, stream_size_);
265 if (IsNaluLengthEncrypted(nalu_length_size_, subsamples_)) {
266 LOG(ERROR) << "NALU length is encrypted.";
267 return NaluReader::kInvalidStream;
268 }
269 if (!reader.ReadNBytesInto8(&nalu_length, nalu_length_size_))
270 return NaluReader::kInvalidStream;
271 nalu_length_size_or_start_code_size = nalu_length_size_;
272
273 if (nalu_length + nalu_length_size_ > stream_size_) {
274 LOG(ERROR) << "NALU length exceeds stream size: "
275 << stream_size_ << " < " << nalu_length;
276 return NaluReader::kInvalidStream;
277 }
278 if (nalu_length == 0) {
279 LOG(ERROR) << "NALU size 0";
280 return NaluReader::kInvalidStream;
281 }
282 }
283
284 const uint8_t* nalu_data = stream_ + nalu_length_size_or_start_code_size;
285 if (!nalu->Initialize(nalu_type_, nalu_data, nalu_length))
286 return NaluReader::kInvalidStream;
287
288 // Move parser state to after this NALU, so next time Advance
289 // is called, we will effectively be skipping it.
290 stream_ += nalu_length_size_or_start_code_size + nalu_length;
291 stream_size_ -= nalu_length_size_or_start_code_size + nalu_length;
292 UpdateSubsamples(nalu_length_size_or_start_code_size + nalu_length,
293 &subsamples_);
294
295 DVLOG(4) << "NALU type: " << static_cast<int>(nalu->type())
296 << " at: " << reinterpret_cast<const void*>(nalu->data())
297 << " data size: " << nalu->payload_size();
298
299 return NaluReader::kOk;
300}
301
303 if (stream_size_ >= 3) {
304 if (IsStartCode(stream_))
305 return true;
306 }
307 if (stream_size_ >= 4) {
308 if (stream_[0] == 0x00 && IsStartCode(stream_ + 1))
309 return true;
310 }
311 return false;
312}
313
314// static
315bool NaluReader::FindStartCode(const uint8_t* data,
316 uint64_t data_size,
317 uint64_t* offset,
318 uint8_t* start_code_size) {
319 uint64_t bytes_left = data_size;
320
321 while (bytes_left >= 3) {
322 if (IsStartCode(data)) {
323 // Found three-byte start code, set pointer at its beginning.
324 *offset = data_size - bytes_left;
325 *start_code_size = 3;
326
327 // If there is a zero byte before this start code,
328 // then it's actually a four-byte start code, so backtrack one byte.
329 if (*offset > 0 && *(data - 1) == 0x00) {
330 --(*offset);
331 ++(*start_code_size);
332 }
333
334 return true;
335 }
336
337 ++data;
338 --bytes_left;
339 }
340
341 // End of data: offset is pointing to the first byte that was not considered
342 // as a possible start of a start code.
343 *offset = data_size - bytes_left;
344 *start_code_size = 0;
345 return false;
346}
347
348// static
350 const uint8_t* data,
351 uint64_t data_size,
352 uint64_t* offset,
353 uint8_t* start_code_size,
354 const std::vector<SubsampleEntry>& subsamples) {
355 if (subsamples.empty()) {
356 return FindStartCode(data, data_size, offset, start_code_size);
357 }
358
359 uint64_t current_offset = 0;
360 for (const SubsampleEntry& subsample : subsamples) {
361 uint16_t clear_bytes = subsample.clear_bytes;
362 if (current_offset + clear_bytes > data_size) {
363 LOG(WARNING) << "The sum of subsample sizes is greater than data_size.";
364 clear_bytes = data_size - current_offset;
365 }
366
367 // Note that calling FindStartCode() here should get the correct
368 // start_code_size, even tho data + current_offset may be in the middle of
369 // the buffer because data + current_offset - 1 is either it shouldn't be
370 // accessed because it's data - 1 or it is encrypted.
371 const bool found_start_code = FindStartCode(
372 data + current_offset, clear_bytes, offset, start_code_size);
373 if (found_start_code) {
374 *offset += current_offset;
375 return true;
376 }
377 const uint64_t subsample_size =
378 subsample.clear_bytes + subsample.cipher_bytes;
379 current_offset += subsample_size;
380 if (current_offset > data_size) {
381 // Assign data_size here so that the returned offset points to the end of
382 // the data.
383 current_offset = data_size;
384 LOG(WARNING) << "The sum of subsamples is greater than data_size.";
385 break;
386 }
387 }
388
389 // If there is more that's not specified by the subsample entries, assume it
390 // is in the clear.
391 if (current_offset < data_size) {
392 const bool found_start_code =
393 FindStartCode(data + current_offset, data_size - current_offset, offset,
394 start_code_size);
395 *offset += current_offset;
396 return found_start_code;
397 }
398
399 // End of data: offset is pointing to the first byte that was not considered
400 // as a possible start of a start code.
401 *offset = current_offset;
402 *start_code_size = 0;
403 return false;
404}
405
406bool NaluReader::LocateNaluByStartCode(uint64_t* nalu_size,
407 uint8_t* start_code_size) {
408 // Find the start code of next NALU.
409 uint64_t nalu_start_off = 0;
410 uint8_t annexb_start_code_size = 0;
412 stream_, stream_size_,
413 &nalu_start_off, &annexb_start_code_size, subsamples_)) {
414 DVLOG(4) << "Could not find start code, end of stream?";
415 return false;
416 }
417
418 // Move the stream to the beginning of the NALU (pointing at the start code).
419 stream_ += nalu_start_off;
420 stream_size_ -= nalu_start_off;
421 // Shift the subsamples so that next call to FindStartCode() takes the updated
422 // subsample info.
423 UpdateSubsamples(nalu_start_off, &subsamples_);
424
425 const uint8_t* nalu_data = stream_ + annexb_start_code_size;
426 // This is a temporary subsample entries for finding next nalu. subsamples_
427 // should not be updated below.
428 std::vector<SubsampleEntry> subsamples_for_finding_next_nalu;
429 if (!subsamples_.empty()) {
430 subsamples_for_finding_next_nalu = subsamples_;
431 UpdateSubsamples(annexb_start_code_size, &subsamples_for_finding_next_nalu);
432 }
433 uint64_t max_nalu_data_size = stream_size_ - annexb_start_code_size;
434 if (max_nalu_data_size <= 0) {
435 DVLOG(3) << "End of stream";
436 return false;
437 }
438
439 // Find the start code of next NALU;
440 // if successful, |nalu_size_without_start_code| is the number of bytes from
441 // after previous start code to before this one;
442 // if next start code is not found, it is still a valid NALU since there
443 // are some bytes left after the first start code: all the remaining bytes
444 // belong to the current NALU.
445 uint64_t nalu_size_without_start_code = 0;
446 uint8_t next_start_code_size = 0;
447 while (true) {
449 nalu_data, max_nalu_data_size,
450 &nalu_size_without_start_code, &next_start_code_size,
451 subsamples_for_finding_next_nalu)) {
452 nalu_data += max_nalu_data_size;
453 break;
454 }
455
456 nalu_data += nalu_size_without_start_code + next_start_code_size;
457 max_nalu_data_size -= nalu_size_without_start_code + next_start_code_size;
458 UpdateSubsamples(nalu_size_without_start_code + next_start_code_size,
459 &subsamples_for_finding_next_nalu);
460 // If it is not a valid NAL unit, we will continue searching. This is to
461 // handle the case where emulation prevention are not applied.
462 Nalu nalu;
463 if (nalu.Initialize(nalu_type_, nalu_data, max_nalu_data_size)) {
464 nalu_data -= next_start_code_size;
465 break;
466 }
467 LOG(WARNING) << "Seeing invalid NAL unit. Emulation prevention may not "
468 "have been applied properly. Assuming it is part of the "
469 "previous NAL unit.";
470 }
471 *nalu_size = nalu_data - stream_;
472 *start_code_size = annexb_start_code_size;
473 return true;
474}
475
476} // namespace media
477} // namespace shaka
bool ReadNBytesInto8(uint64_t *v, size_t num_bytes)
NaluReader(Nalu::CodecType type, uint8_t nal_length_size, const uint8_t *stream, uint64_t stream_size)
static bool FindStartCodeInClearRange(const uint8_t *data, uint64_t data_size, uint64_t *offset, uint8_t *start_code_size, const std::vector< SubsampleEntry > &subsamples)
Result Advance(Nalu *nalu)
const uint8_t * data() const
This is the pointer to the Nalu data, pointing to the header.
Definition nalu_reader.h:96
uint64_t payload_size() const
Size of this Nalu minus header_size().
All the methods that are virtual are virtual for mocking.