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 "packager/base/logging.h"
10 #include "packager/media/base/buffer_reader.h"
11 #include "packager/media/filters/h264_parser.h"
12 
13 namespace edash_packager {
14 namespace media {
15 
16 namespace {
17 inline bool IsStartCode(const uint8_t* data) {
18  return data[0] == 0x00 && data[1] == 0x00 && data[2] == 0x01;
19 }
20 } // namespace
21 
22 Nalu::Nalu()
23  : data_(nullptr),
24  data_size_(0),
25  header_size_(0),
26  ref_idc_(0),
27  type_(0),
28  is_video_slice_(false) {}
29 
30 bool Nalu::InitializeFromH264(const uint8_t* data, uint64_t size) {
31  DCHECK(data);
32  DCHECK_GT(size, 0u);
33  uint8_t header = data[0];
34  if ((header & 0x80) != 0)
35  return false;
36 
37  data_ = data;
38  header_size_ = 1;
39  data_size_ = size - 1;
40  ref_idc_ = (header >> 5) & 0x3;
41  type_ = header & 0x1F;
42  is_video_slice_ = (type_ >= Nalu::H264_NonIDRSlice &&
43  type_ <= Nalu::H264_IDRSlice);
44  return true;
45 }
46 
47 NaluReader::NaluReader(uint8_t nal_length_size,
48  const uint8_t* stream,
49  uint64_t stream_size)
50  : stream_(stream),
51  stream_size_(stream_size),
52  nalu_length_size_(nal_length_size),
53  format_(nal_length_size == 0 ? kAnnexbByteStreamFormat
54  : kNalUnitStreamFormat) {
55  DCHECK(stream);
56 }
57 NaluReader::~NaluReader() {}
58 
59 NaluReader::Result NaluReader::Advance(Nalu* nalu) {
60  if (stream_size_ <= 0)
61  return NaluReader::kEOStream;
62 
63  uint8_t nalu_length_size_or_start_code_size;
64  uint64_t nalu_length;
65  if (format_ == kAnnexbByteStreamFormat) {
66  // This will move |stream_| to the start code.
67  uint64_t nalu_length_with_header;
68  if (!LocateNaluByStartCode(&nalu_length_with_header,
69  &nalu_length_size_or_start_code_size)) {
70  LOG(ERROR) << "Could not find next NALU, bytes left in stream: "
71  << stream_size_;
72  // This is actually an error. Since we always move to past the end of
73  // each NALU, if there is no next start code, then this is the first call
74  // and there are no start codes in the stream.
75  return NaluReader::kInvalidStream;
76  }
77  nalu_length = nalu_length_with_header - nalu_length_size_or_start_code_size;
78  } else {
79  BufferReader reader(stream_, stream_size_);
80  if (!reader.ReadNBytesInto8(&nalu_length, nalu_length_size_))
81  return NaluReader::kInvalidStream;
82  nalu_length_size_or_start_code_size = nalu_length_size_;
83 
84  if (nalu_length + nalu_length_size_ > stream_size_) {
85  LOG(ERROR) << "NALU length exceeds stream size: "
86  << stream_size_ << " < " << nalu_length;
87  return NaluReader::kInvalidStream;
88  }
89  if (nalu_length == 0) {
90  LOG(ERROR) << "NALU size 0";
91  return NaluReader::kInvalidStream;
92  }
93  }
94 
95  const uint8_t* nalu_data = stream_ + nalu_length_size_or_start_code_size;
96  if (!nalu->InitializeFromH264(nalu_data, nalu_length))
97  return NaluReader::kInvalidStream;
98 
99  // Move parser state to after this NALU, so next time Advance
100  // is called, we will effectively be skipping it.
101  stream_ += nalu_length_size_or_start_code_size + nalu_length;
102  stream_size_ -= nalu_length_size_or_start_code_size + nalu_length;
103 
104  DVLOG(4) << "NALU type: " << static_cast<int>(nalu->type())
105  << " at: " << reinterpret_cast<const void*>(nalu->data())
106  << " data size: " << nalu->data_size()
107  << " ref: " << static_cast<int>(nalu->ref_idc());
108 
109  return NaluReader::kOk;
110 }
111 
113  if (stream_size_ >= 3) {
114  if (IsStartCode(stream_))
115  return true;
116  }
117  if (stream_size_ >= 4) {
118  if (stream_[0] == 0x00 && IsStartCode(stream_ + 1))
119  return true;
120  }
121  return false;
122 }
123 
124 // static
125 bool NaluReader::FindStartCode(const uint8_t* data,
126  uint64_t data_size,
127  uint64_t* offset,
128  uint8_t* start_code_size) {
129  uint64_t bytes_left = data_size;
130 
131  while (bytes_left >= 3) {
132  if (IsStartCode(data)) {
133  // Found three-byte start code, set pointer at its beginning.
134  *offset = data_size - bytes_left;
135  *start_code_size = 3;
136 
137  // If there is a zero byte before this start code,
138  // then it's actually a four-byte start code, so backtrack one byte.
139  if (*offset > 0 && *(data - 1) == 0x00) {
140  --(*offset);
141  ++(*start_code_size);
142  }
143 
144  return true;
145  }
146 
147  ++data;
148  --bytes_left;
149  }
150 
151  // End of data: offset is pointing to the first byte that was not considered
152  // as a possible start of a start code.
153  *offset = data_size - bytes_left;
154  *start_code_size = 0;
155  return false;
156 }
157 
158 bool NaluReader::LocateNaluByStartCode(uint64_t* nalu_size,
159  uint8_t* start_code_size) {
160  // Find the start code of next NALU.
161  uint64_t nalu_start_off = 0;
162  uint8_t annexb_start_code_size = 0;
163  if (!FindStartCode(stream_, stream_size_,
164  &nalu_start_off, &annexb_start_code_size)) {
165  DVLOG(4) << "Could not find start code, end of stream?";
166  return false;
167  }
168 
169  // Move the stream to the beginning of the NALU (pointing at the start code).
170  stream_ += nalu_start_off;
171  stream_size_ -= nalu_start_off;
172 
173  const uint8_t* nalu_data = stream_ + annexb_start_code_size;
174  uint64_t max_nalu_data_size = stream_size_ - annexb_start_code_size;
175  if (max_nalu_data_size <= 0) {
176  DVLOG(3) << "End of stream";
177  return false;
178  }
179 
180  // Find the start code of next NALU;
181  // if successful, |nalu_size_without_start_code| is the number of bytes from
182  // after previous start code to before this one;
183  // if next start code is not found, it is still a valid NALU since there
184  // are some bytes left after the first start code: all the remaining bytes
185  // belong to the current NALU.
186  uint64_t nalu_size_without_start_code = 0;
187  uint8_t next_start_code_size = 0;
188  if (!FindStartCode(nalu_data, max_nalu_data_size,
189  &nalu_size_without_start_code, &next_start_code_size)) {
190  nalu_size_without_start_code = max_nalu_data_size;
191  }
192  *nalu_size = nalu_size_without_start_code + annexb_start_code_size;
193  *start_code_size = annexb_start_code_size;
194  return true;
195 }
196 
197 } // namespace media
198 } // namespace edash_packager
NaluReader(uint8_t nal_length_size, const uint8_t *stream, uint64_t stream_size)
Definition: nalu_reader.cc:47
bool ReadNBytesInto8(uint64_t *v, size_t num_bytes) WARN_UNUSED_RESULT