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