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