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(uint8_t nalu_length_size,
57 const std::vector<SubsampleEntry>& subsamples) {
58 if (subsamples.empty())
59 return false;
60
61 for (const SubsampleEntry& subsample : subsamples) {
62 if (subsample.clear_bytes >= nalu_length_size) {
63 return false;
64 }
65 nalu_length_size -= subsample.clear_bytes;
66 if (subsample.cipher_bytes > 0) {
67 return true;
68 }
69 }
70 // Ran out of subsamples. Assume the rest is in the clear.
71 return false;
72}
73} // namespace
74
75Nalu::Nalu() = default;
76
77bool Nalu::Initialize(CodecType type, const uint8_t* data, uint64_t size) {
78 if (type == Nalu::kH264) {
79 return InitializeFromH264(data, size);
80 } else {
81 DCHECK_EQ(Nalu::kH265, type);
82 return InitializeFromH265(data, size);
83 }
84}
85
86// ITU-T H.264 (02/2014) 7.4.1 NAL unit semantics
87bool Nalu::InitializeFromH264(const uint8_t* data, uint64_t size) {
88 DCHECK(data);
89 if (size == 0)
90 return false;
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) << ").";
95 return false;
96 }
97
98 data_ = data;
99 header_size_ = 1;
100 payload_size_ = size - header_size_;
101 ref_idc_ = (header >> 5) & 0x3;
102 type_ = header & 0x1F;
103
104 // Reserved NAL units are not treated as valid NAL units here.
105 if (type_ == Nalu::H264_Unspecified || type_ == Nalu::H264_Reserved17 ||
106 type_ == Nalu::H264_Reserved18 || type_ >= Nalu::H264_Reserved22) {
107 VLOG(1) << "Unspecified or reserved nal_unit_type " << type_
108 << " (header 0x" << std::hex << static_cast<int>(header) << ").";
109 // Allow reserved NAL units. Some encoders and extended codecs use the
110 // reserved NAL units to carry their private data.
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) {
114 if (ref_idc_ == 0) {
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) << ").";
118 return false;
119 }
120 } else if (type_ == Nalu::H264_SEIMessage ||
121 (type_ >= Nalu::H264_AUD && type_ <= Nalu::H264_FillerData)) {
122 if (ref_idc_ != 0) {
123 LOG(WARNING) << "nal_ref_idc shall be equal to 0 for nalu type " << type_
124 << " (header 0x" << std::hex << static_cast<int>(header)
125 << ").";
126 return false;
127 }
128 }
129
130 is_aud_ = type_ == H264_AUD;
131 is_vcl_ = (type_ >= Nalu::H264_NonIDRSlice && type_ <= Nalu::H264_IDRSlice);
132 is_video_slice_ =
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));
138 return true;
139}
140
141// ITU-T H.265 (04/2015) 7.4.2.2 NAL unit header semantics
142bool Nalu::InitializeFromH265(const uint8_t* data, uint64_t size) {
143 DCHECK(data);
144 if (size < 2)
145 return false;
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 << ").";
150 return false;
151 }
152
153 data_ = data;
154 header_size_ = 2;
155 payload_size_ = size - header_size_;
156
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 << ").";
163 return false;
164 }
165 nuh_temporal_id_ = nuh_temporal_id_plus1 - 1;
166
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 << ").";
170 return false;
171 }
172
173 // Reserved NAL units are not treated as valid NAL units here.
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 VLOG(1) << "Unspecified or reserved nal_unit_type " << type_
178 << " (header 0x" << std::hex << header << ").";
179 // Allow reserved NAL units. Some encoders and extended codecs use the
180 // reserved NAL units to carry their private data. For example, Dolby Vision
181 // uses NAL unit type 62.
182 } else if ((type_ >= Nalu::H265_BLA_W_LP &&
183 type_ <= Nalu::H265_RSV_IRAP_VCL23) ||
184 type_ == Nalu::H265_VPS || type_ == Nalu::H265_SPS ||
185 type_ == Nalu::H265_EOS || type_ == Nalu::H265_EOB) {
186 if (nuh_temporal_id_ != 0) {
187 LOG(WARNING) << "TemporalId shall be equal to 0 for nalu type " << type_
188 << " (header 0x" << std::hex << header << ").";
189 return false;
190 }
191 } else if (type_ == Nalu::H265_TSA_N || type_ == Nalu::H265_TSA_R ||
192 (nuh_layer_id_ == 0 &&
193 (type_ == Nalu::H265_STSA_N || type_ == Nalu::H265_STSA_R))) {
194 if (nuh_temporal_id_ == 0) {
195 LOG(WARNING) << "TemporalId shall not be equal to 0 for nalu type "
196 << type_ << " (header 0x" << std::hex << header << ").";
197 return false;
198 }
199 }
200
201 is_aud_ = type_ == H265_AUD;
202 is_vcl_ = type_ >= Nalu::H265_TRAIL_N && type_ <= Nalu::H265_RSV_VCL31;
203 is_video_slice_ = is_vcl_;
204 can_start_access_unit_ =
205 nuh_layer_id_ == 0 &&
206 (is_vcl_ || type_ == Nalu::H265_AUD || type_ == Nalu::H265_VPS ||
207 type_ == Nalu::H265_SPS || type_ == Nalu::H265_PPS ||
208 type_ == Nalu::H265_PREFIX_SEI ||
209 (type_ >= Nalu::H265_RSV_NVCL41 && type_ <= Nalu::H265_RSV_NVCL44) ||
210 (type_ >= Nalu::H265_UNSPEC48 && type_ <= Nalu::H265_UNSPEC55));
211 return true;
212}
213
214NaluReader::NaluReader(Nalu::CodecType type,
215 uint8_t nal_length_size,
216 const uint8_t* stream,
217 uint64_t stream_size)
218 : NaluReader(type,
219 nal_length_size,
220 stream,
221 stream_size,
222 std::vector<SubsampleEntry>()) {}
223
224NaluReader::NaluReader(Nalu::CodecType type,
225 uint8_t nal_length_size,
226 const uint8_t* stream,
227 uint64_t stream_size,
228 const std::vector<SubsampleEntry>& subsamples)
229 : stream_(stream),
230 stream_size_(stream_size),
231 nalu_type_(type),
232 nalu_length_size_(nal_length_size),
233 format_(nal_length_size == 0 ? kAnnexbByteStreamFormat
234 : kNalUnitStreamFormat),
235 subsamples_(subsamples) {
236 DCHECK(stream);
237}
238
239NaluReader::~NaluReader() {}
240
241NaluReader::Result NaluReader::Advance(Nalu* nalu) {
242 if (stream_size_ <= 0)
243 return NaluReader::kEOStream;
244
245 uint8_t nalu_length_size_or_start_code_size;
246 uint64_t nalu_length;
247 if (format_ == kAnnexbByteStreamFormat) {
248 // This will move |stream_| to the start code.
249 uint64_t nalu_length_with_header;
250 if (!LocateNaluByStartCode(&nalu_length_with_header,
251 &nalu_length_size_or_start_code_size)) {
252 LOG(ERROR) << "Could not find next NALU, bytes left in stream: "
253 << stream_size_;
254 // This is actually an error. Since we always move to past the end of
255 // each NALU, if there is no next start code, then this is the first call
256 // and there are no start codes in the stream.
257 return NaluReader::kInvalidStream;
258 }
259 nalu_length = nalu_length_with_header - nalu_length_size_or_start_code_size;
260 } else {
261 BufferReader reader(stream_, stream_size_);
262 if (IsNaluLengthEncrypted(nalu_length_size_, subsamples_)) {
263 LOG(ERROR) << "NALU length is encrypted.";
264 return NaluReader::kInvalidStream;
265 }
266 if (!reader.ReadNBytesInto8(&nalu_length, nalu_length_size_))
267 return NaluReader::kInvalidStream;
268 nalu_length_size_or_start_code_size = nalu_length_size_;
269
270 if (nalu_length + nalu_length_size_ > stream_size_) {
271 LOG(ERROR) << "NALU length exceeds stream size: " << stream_size_ << " < "
272 << nalu_length;
273 return NaluReader::kInvalidStream;
274 }
275 if (nalu_length == 0) {
276 LOG(ERROR) << "NALU size 0";
277 return NaluReader::kInvalidStream;
278 }
279 }
280
281 const uint8_t* nalu_data = stream_ + nalu_length_size_or_start_code_size;
282 if (!nalu->Initialize(nalu_type_, nalu_data, nalu_length))
283 return NaluReader::kInvalidStream;
284
285 // Move parser state to after this NALU, so next time Advance
286 // is called, we will effectively be skipping it.
287 stream_ += nalu_length_size_or_start_code_size + nalu_length;
288 stream_size_ -= nalu_length_size_or_start_code_size + nalu_length;
289 UpdateSubsamples(nalu_length_size_or_start_code_size + nalu_length,
290 &subsamples_);
291
292 DVLOG(4) << "NALU type: " << static_cast<int>(nalu->type())
293 << " at: " << reinterpret_cast<const void*>(nalu->data())
294 << " data size: " << nalu->payload_size();
295
296 return NaluReader::kOk;
297}
298
300 if (stream_size_ >= 3) {
301 if (IsStartCode(stream_))
302 return true;
303 }
304 if (stream_size_ >= 4) {
305 if (stream_[0] == 0x00 && IsStartCode(stream_ + 1))
306 return true;
307 }
308 return false;
309}
310
311// static
312bool NaluReader::FindStartCode(const uint8_t* data,
313 uint64_t data_size,
314 uint64_t* offset,
315 uint8_t* start_code_size) {
316 uint64_t bytes_left = data_size;
317
318 while (bytes_left >= 3) {
319 if (IsStartCode(data)) {
320 // Found three-byte start code, set pointer at its beginning.
321 *offset = data_size - bytes_left;
322 *start_code_size = 3;
323
324 // If there is a zero byte before this start code,
325 // then it's actually a four-byte start code, so backtrack one byte.
326 if (*offset > 0 && *(data - 1) == 0x00) {
327 --(*offset);
328 ++(*start_code_size);
329 }
330
331 return true;
332 }
333
334 ++data;
335 --bytes_left;
336 }
337
338 // End of data: offset is pointing to the first byte that was not considered
339 // as a possible start of a start code.
340 *offset = data_size - bytes_left;
341 *start_code_size = 0;
342 return false;
343}
344
345// static
347 const uint8_t* data,
348 uint64_t data_size,
349 uint64_t* offset,
350 uint8_t* start_code_size,
351 const std::vector<SubsampleEntry>& subsamples) {
352 if (subsamples.empty()) {
353 return FindStartCode(data, data_size, offset, start_code_size);
354 }
355
356 uint64_t current_offset = 0;
357 for (const SubsampleEntry& subsample : subsamples) {
358 uint16_t clear_bytes = subsample.clear_bytes;
359 if (current_offset + clear_bytes > data_size) {
360 LOG(WARNING) << "The sum of subsample sizes is greater than data_size.";
361 clear_bytes = data_size - current_offset;
362 }
363
364 // Note that calling FindStartCode() here should get the correct
365 // start_code_size, even tho data + current_offset may be in the middle of
366 // the buffer because data + current_offset - 1 is either it shouldn't be
367 // accessed because it's data - 1 or it is encrypted.
368 const bool found_start_code = FindStartCode(
369 data + current_offset, clear_bytes, offset, start_code_size);
370 if (found_start_code) {
371 *offset += current_offset;
372 return true;
373 }
374 const uint64_t subsample_size =
375 subsample.clear_bytes + subsample.cipher_bytes;
376 current_offset += subsample_size;
377 if (current_offset > data_size) {
378 // Assign data_size here so that the returned offset points to the end of
379 // the data.
380 current_offset = data_size;
381 LOG(WARNING) << "The sum of subsamples is greater than data_size.";
382 break;
383 }
384 }
385
386 // If there is more that's not specified by the subsample entries, assume it
387 // is in the clear.
388 if (current_offset < data_size) {
389 const bool found_start_code =
390 FindStartCode(data + current_offset, data_size - current_offset, offset,
391 start_code_size);
392 *offset += current_offset;
393 return found_start_code;
394 }
395
396 // End of data: offset is pointing to the first byte that was not considered
397 // as a possible start of a start code.
398 *offset = current_offset;
399 *start_code_size = 0;
400 return false;
401}
402
403bool NaluReader::LocateNaluByStartCode(uint64_t* nalu_size,
404 uint8_t* start_code_size) {
405 // Find the start code of next NALU.
406 uint64_t nalu_start_off = 0;
407 uint8_t annexb_start_code_size = 0;
408 if (!FindStartCodeInClearRange(stream_, stream_size_, &nalu_start_off,
409 &annexb_start_code_size, subsamples_)) {
410 DVLOG(4) << "Could not find start code, end of stream?";
411 return false;
412 }
413
414 // Move the stream to the beginning of the NALU (pointing at the start code).
415 stream_ += nalu_start_off;
416 stream_size_ -= nalu_start_off;
417 // Shift the subsamples so that next call to FindStartCode() takes the updated
418 // subsample info.
419 UpdateSubsamples(nalu_start_off, &subsamples_);
420
421 const uint8_t* nalu_data = stream_ + annexb_start_code_size;
422 // This is a temporary subsample entries for finding next nalu. subsamples_
423 // should not be updated below.
424 std::vector<SubsampleEntry> subsamples_for_finding_next_nalu;
425 if (!subsamples_.empty()) {
426 subsamples_for_finding_next_nalu = subsamples_;
427 UpdateSubsamples(annexb_start_code_size, &subsamples_for_finding_next_nalu);
428 }
429 uint64_t max_nalu_data_size = stream_size_ - annexb_start_code_size;
430 if (max_nalu_data_size <= 0) {
431 DVLOG(3) << "End of stream";
432 return false;
433 }
434
435 // Find the start code of next NALU;
436 // if successful, |nalu_size_without_start_code| is the number of bytes from
437 // after previous start code to before this one;
438 // if next start code is not found, it is still a valid NALU since there
439 // are some bytes left after the first start code: all the remaining bytes
440 // belong to the current NALU.
441 uint64_t nalu_size_without_start_code = 0;
442 uint8_t next_start_code_size = 0;
443 while (true) {
445 nalu_data, max_nalu_data_size, &nalu_size_without_start_code,
446 &next_start_code_size, subsamples_for_finding_next_nalu)) {
447 nalu_data += max_nalu_data_size;
448 break;
449 }
450
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);
455 // If it is not a valid NAL unit, we will continue searching. This is to
456 // handle the case where emulation prevention are not applied.
457 Nalu nalu;
458 if (nalu.Initialize(nalu_type_, nalu_data, max_nalu_data_size)) {
459 nalu_data -= next_start_code_size;
460 break;
461 }
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.";
465 }
466 *nalu_size = nalu_data - stream_;
467 *start_code_size = annexb_start_code_size;
468 return true;
469}
470
471} // namespace media
472} // 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.