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