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