DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
nalu_reader.cc
1 // Copyright 2016 Google Inc. 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/filters/nalu_reader.h"
8 
9 #include <iostream>
10 
11 #include "packager/base/logging.h"
12 #include "packager/media/base/buffer_reader.h"
13 #include "packager/media/filters/h264_parser.h"
14 
15 namespace shaka {
16 namespace media {
17 
18 namespace {
19 inline bool IsStartCode(const uint8_t* data) {
20  return data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01;
21 }
22 } // namespace
23 
24 Nalu::Nalu()
25  : data_(nullptr),
26  header_size_(0),
27  payload_size_(0),
28  ref_idc_(0),
29  nuh_layer_id_(0),
30  nuh_temporal_id_(0),
31  type_(0),
32  is_video_slice_(false) {}
33 
34 bool Nalu::Initialize(CodecType type,
35  const uint8_t* data,
36  uint64_t size) {
37  if (type == Nalu::kH264) {
38  return InitializeFromH264(data, size);
39  } else {
40  DCHECK_EQ(Nalu::kH265, type);
41  return InitializeFromH265(data, size);
42  }
43 }
44 
45 // ITU-T H.264 (02/2014) 7.4.1 NAL unit semantics
46 bool Nalu::InitializeFromH264(const uint8_t* data, uint64_t size) {
47  DCHECK(data);
48  if (size == 0)
49  return false;
50  const uint8_t header = data[0];
51  if ((header & 0x80) != 0) {
52  LOG(WARNING) << "forbidden_zero_bit shall be equal to 0 (header 0x"
53  << std::hex << static_cast<int>(header) << ").";
54  return false;
55  }
56 
57  data_ = data;
58  header_size_ = 1;
59  payload_size_ = size - header_size_;
60  ref_idc_ = (header >> 5) & 0x3;
61  type_ = header & 0x1F;
62 
63  // Reserved NAL units are not treated as valid NAL units here.
64  if (type_ == Nalu::H264_Unspecified || type_ == Nalu::H264_Reserved17 ||
65  type_ == Nalu::H264_Reserved18 || type_ >= Nalu::H264_Reserved22) {
66  LOG(WARNING) << "Unspecified or reserved nal_unit_type " << type_
67  << " (header 0x" << std::hex << static_cast<int>(header)
68  << ").";
69  return false;
70  } else if (type_ == Nalu::H264_IDRSlice || type_ == Nalu::H264_SPS ||
71  type_ == Nalu::H264_SPSExtension || type_ == Nalu::H264_SubsetSPS ||
72  type_ == Nalu::H264_PPS) {
73  if (ref_idc_ == 0) {
74  LOG(WARNING) << "nal_ref_idc shall not be equal to 0 for nalu type "
75  << type_ << " (header 0x" << std::hex
76  << static_cast<int>(header) << ").";
77  return false;
78  }
79  } else if (type_ == Nalu::H264_SEIMessage ||
80  (type_ >= Nalu::H264_AUD && type_ <= Nalu::H264_FillerData)) {
81  if (ref_idc_ != 0) {
82  LOG(WARNING) << "nal_ref_idc shall be equal to 0 for nalu type " << type_
83  << " (header 0x" << std::hex << static_cast<int>(header)
84  << ").";
85  return false;
86  }
87  }
88 
89  is_video_slice_ = (type_ >= Nalu::H264_NonIDRSlice &&
90  type_ <= Nalu::H264_IDRSlice);
91  can_start_access_unit_ =
92  (is_video_slice_ || type_ == Nalu::H264_AUD || type_ == Nalu::H264_SPS ||
93  type_ == Nalu::H264_PPS || type_ == Nalu::H264_SEIMessage ||
94  (type_ >= Nalu::H264_PrefixNALUnit && type_ <= Nalu::H264_Reserved18));
95  return true;
96 }
97 
98 // ITU-T H.265 (04/2015) 7.4.2.2 NAL unit header semantics
99 bool Nalu::InitializeFromH265(const uint8_t* data, uint64_t size) {
100  DCHECK(data);
101  if (size < 2)
102  return false;
103  const uint16_t header = (data[0] << 8) | data[1];
104  if ((header & 0x8000) != 0) {
105  LOG(WARNING) << "forbidden_zero_bit shall be equal to 0 (header 0x"
106  << std::hex << header << ").";
107  return false;
108  }
109 
110  data_ = data;
111  header_size_ = 2;
112  payload_size_ = size - header_size_;
113 
114  type_ = (header >> 9) & 0x3F;
115  nuh_layer_id_ = (header >> 3) & 0x3F;
116  const int nuh_temporal_id_plus1 = header & 0x7;
117  if (nuh_temporal_id_plus1 == 0) {
118  LOG(WARNING) << "nul_temporal_id_plus1 shall not be equal to 0 (header 0x"
119  << std::hex << header << ").";
120  return false;
121  }
122  nuh_temporal_id_ = nuh_temporal_id_plus1 - 1;
123 
124  if (type_ == Nalu::H265_EOB && nuh_layer_id_ != 0) {
125  LOG(WARNING) << "nuh_layer_id shall be equal to 0 for nalu type " << type_
126  << " (header 0x" << std::hex << header << ").";
127  return false;
128  }
129 
130  // Reserved NAL units are not treated as valid NAL units here.
131  if ((type_ >= Nalu::H265_RSV_VCL_N10 && type_ <= Nalu::H265_RSV_VCL_R15) ||
132  (type_ >= Nalu::H265_RSV_IRAP_VCL22 && type_ < Nalu::H265_RSV_VCL31) ||
133  (type_ >= Nalu::H265_RSV_NVCL41)) {
134  LOG(WARNING) << "Unspecified or reserved nal_unit_type " << type_
135  << " (header 0x" << std::hex << header << ").";
136  return false;
137  } else if ((type_ >= Nalu::H265_BLA_W_LP &&
138  type_ <= Nalu::H265_RSV_IRAP_VCL23) ||
139  type_ == Nalu::H265_VPS || type_ == Nalu::H265_SPS ||
140  type_ == Nalu::H265_EOS || type_ == Nalu::H265_EOB) {
141  if (nuh_temporal_id_ != 0) {
142  LOG(WARNING) << "TemporalId shall be equal to 0 for nalu type " << type_
143  << " (header 0x" << std::hex << header << ").";
144  return false;
145  }
146  } else if (type_ == Nalu::H265_TSA_N || type_ == Nalu::H265_TSA_R ||
147  (nuh_layer_id_ == 0 &&
148  (type_ == Nalu::H265_STSA_N || type_ == Nalu::H265_STSA_R))) {
149  if (nuh_temporal_id_ == 0) {
150  LOG(WARNING) << "TemporalId shall not be equal to 0 for nalu type "
151  << type_ << " (header 0x" << std::hex << header << ").";
152  return false;
153  }
154  }
155 
156  is_video_slice_ = type_ >= Nalu::H265_TRAIL_N && type_ <= Nalu::H265_CRA_NUT;
157  can_start_access_unit_ =
158  nuh_layer_id_ == 0 &&
159  (is_video_slice_ || type_ == Nalu::H265_AUD || type_ == Nalu::H265_VPS ||
160  type_ == Nalu::H265_SPS || type_ == Nalu::H265_PPS ||
161  type_ == Nalu::H265_PREFIX_SEI ||
162  (type_ >= Nalu::H265_RSV_NVCL41 && type_ <= Nalu::H265_RSV_NVCL44) ||
163  (type_ >= Nalu::H265_UNSPEC48 && type_ <= Nalu::H265_UNSPEC55));
164  return true;
165 }
166 
167 NaluReader::NaluReader(Nalu::CodecType type,
168  uint8_t nal_length_size,
169  const uint8_t* stream,
170  uint64_t stream_size)
171  : stream_(stream),
172  stream_size_(stream_size),
173  nalu_type_(type),
174  nalu_length_size_(nal_length_size),
175  format_(nal_length_size == 0 ? kAnnexbByteStreamFormat
176  : kNalUnitStreamFormat) {
177  DCHECK(stream);
178 }
179 NaluReader::~NaluReader() {}
180 
181 NaluReader::Result NaluReader::Advance(Nalu* nalu) {
182  if (stream_size_ <= 0)
183  return NaluReader::kEOStream;
184 
185  uint8_t nalu_length_size_or_start_code_size;
186  uint64_t nalu_length;
187  if (format_ == kAnnexbByteStreamFormat) {
188  // This will move |stream_| to the start code.
189  uint64_t nalu_length_with_header;
190  if (!LocateNaluByStartCode(&nalu_length_with_header,
191  &nalu_length_size_or_start_code_size)) {
192  LOG(ERROR) << "Could not find next NALU, bytes left in stream: "
193  << stream_size_;
194  // This is actually an error. Since we always move to past the end of
195  // each NALU, if there is no next start code, then this is the first call
196  // and there are no start codes in the stream.
197  return NaluReader::kInvalidStream;
198  }
199  nalu_length = nalu_length_with_header - nalu_length_size_or_start_code_size;
200  } else {
201  BufferReader reader(stream_, stream_size_);
202  if (!reader.ReadNBytesInto8(&nalu_length, nalu_length_size_))
203  return NaluReader::kInvalidStream;
204  nalu_length_size_or_start_code_size = nalu_length_size_;
205 
206  if (nalu_length + nalu_length_size_ > stream_size_) {
207  LOG(ERROR) << "NALU length exceeds stream size: "
208  << stream_size_ << " < " << nalu_length;
209  return NaluReader::kInvalidStream;
210  }
211  if (nalu_length == 0) {
212  LOG(ERROR) << "NALU size 0";
213  return NaluReader::kInvalidStream;
214  }
215  }
216 
217  const uint8_t* nalu_data = stream_ + nalu_length_size_or_start_code_size;
218  if (!nalu->Initialize(nalu_type_, nalu_data, nalu_length))
219  return NaluReader::kInvalidStream;
220 
221  // Move parser state to after this NALU, so next time Advance
222  // is called, we will effectively be skipping it.
223  stream_ += nalu_length_size_or_start_code_size + nalu_length;
224  stream_size_ -= nalu_length_size_or_start_code_size + nalu_length;
225 
226  DVLOG(4) << "NALU type: " << static_cast<int>(nalu->type())
227  << " at: " << reinterpret_cast<const void*>(nalu->data())
228  << " data size: " << nalu->payload_size();
229 
230  return NaluReader::kOk;
231 }
232 
234  if (stream_size_ >= 3) {
235  if (IsStartCode(stream_))
236  return true;
237  }
238  if (stream_size_ >= 4) {
239  if (stream_[0] == 0x00 && IsStartCode(stream_ + 1))
240  return true;
241  }
242  return false;
243 }
244 
245 // static
246 bool NaluReader::FindStartCode(const uint8_t* data,
247  uint64_t data_size,
248  uint64_t* offset,
249  uint8_t* start_code_size) {
250  uint64_t bytes_left = data_size;
251 
252  while (bytes_left >= 3) {
253  if (IsStartCode(data)) {
254  // Found three-byte start code, set pointer at its beginning.
255  *offset = data_size - bytes_left;
256  *start_code_size = 3;
257 
258  // If there is a zero byte before this start code,
259  // then it's actually a four-byte start code, so backtrack one byte.
260  if (*offset > 0 && *(data - 1) == 0x00) {
261  --(*offset);
262  ++(*start_code_size);
263  }
264 
265  return true;
266  }
267 
268  ++data;
269  --bytes_left;
270  }
271 
272  // End of data: offset is pointing to the first byte that was not considered
273  // as a possible start of a start code.
274  *offset = data_size - bytes_left;
275  *start_code_size = 0;
276  return false;
277 }
278 
279 bool NaluReader::LocateNaluByStartCode(uint64_t* nalu_size,
280  uint8_t* start_code_size) {
281  // Find the start code of next NALU.
282  uint64_t nalu_start_off = 0;
283  uint8_t annexb_start_code_size = 0;
284  if (!FindStartCode(stream_, stream_size_,
285  &nalu_start_off, &annexb_start_code_size)) {
286  DVLOG(4) << "Could not find start code, end of stream?";
287  return false;
288  }
289 
290  // Move the stream to the beginning of the NALU (pointing at the start code).
291  stream_ += nalu_start_off;
292  stream_size_ -= nalu_start_off;
293 
294  const uint8_t* nalu_data = stream_ + annexb_start_code_size;
295  uint64_t max_nalu_data_size = stream_size_ - annexb_start_code_size;
296  if (max_nalu_data_size <= 0) {
297  DVLOG(3) << "End of stream";
298  return false;
299  }
300 
301  // Find the start code of next NALU;
302  // if successful, |nalu_size_without_start_code| is the number of bytes from
303  // after previous start code to before this one;
304  // if next start code is not found, it is still a valid NALU since there
305  // are some bytes left after the first start code: all the remaining bytes
306  // belong to the current NALU.
307  uint64_t nalu_size_without_start_code = 0;
308  uint8_t next_start_code_size = 0;
309  while (true) {
310  if (!FindStartCode(nalu_data, max_nalu_data_size,
311  &nalu_size_without_start_code, &next_start_code_size)) {
312  nalu_data += max_nalu_data_size;
313  break;
314  }
315 
316  nalu_data += nalu_size_without_start_code + next_start_code_size;
317  max_nalu_data_size -= nalu_size_without_start_code + next_start_code_size;
318  // If it is not a valid NAL unit, we will continue searching. This is to
319  // handle the case where emulation prevention are not applied.
320  Nalu nalu;
321  if (nalu.Initialize(nalu_type_, nalu_data, max_nalu_data_size)) {
322  nalu_data -= next_start_code_size;
323  break;
324  }
325  LOG(WARNING) << "Seeing invalid NAL unit. Emulation prevention may not "
326  "have been applied properly. Assuming it is part of the "
327  "previous NAL unit.";
328  }
329  *nalu_size = nalu_data - stream_;
330  *start_code_size = annexb_start_code_size;
331  return true;
332 }
333 
334 } // namespace media
335 } // namespace shaka
uint64_t payload_size() const
Size of this Nalu minus header_size().
Definition: nalu_reader.h:101
int type() const
Definition: nalu_reader.h:112
bool ReadNBytesInto8(uint64_t *v, size_t num_bytes) WARN_UNUSED_RESULT
Result Advance(Nalu *nalu)
Definition: nalu_reader.cc:181
NaluReader(Nalu::CodecType type, uint8_t nal_length_size, const uint8_t *stream, uint64_t stream_size)
Definition: nalu_reader.cc:167
const uint8_t * data() const
This is the pointer to the Nalu data, pointing to the header.
Definition: nalu_reader.h:96