DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
es_parser_h26x.cc
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "packager/media/formats/mp2t/es_parser_h26x.h"
6 
7 #include <stdint.h>
8 
9 #include "packager/base/logging.h"
10 #include "packager/base/numerics/safe_conversions.h"
11 #include "packager/media/base/media_sample.h"
12 #include "packager/media/base/offset_byte_queue.h"
13 #include "packager/media/base/timestamp.h"
14 #include "packager/media/base/video_stream_info.h"
15 #include "packager/media/codecs/h26x_byte_to_unit_stream_converter.h"
16 #include "packager/media/formats/mp2t/mp2t_common.h"
17 
18 namespace shaka {
19 namespace media {
20 namespace mp2t {
21 
22 namespace {
23 
24 const int kStartCodeSize = 3;
25 const int kH264NaluHeaderSize = 1;
26 const int kH265NaluHeaderSize = 2;
27 
28 } // namespace
29 
30 EsParserH26x::EsParserH26x(
31  Nalu::CodecType type,
32  std::unique_ptr<H26xByteToUnitStreamConverter> stream_converter,
33  uint32_t pid,
34  const EmitSampleCB& emit_sample_cb)
35  : EsParser(pid),
36  emit_sample_cb_(emit_sample_cb),
37  type_(type),
38  es_queue_(new media::OffsetByteQueue()),
39  current_search_position_(0),
40  stream_converter_(std::move(stream_converter)),
41  pending_sample_duration_(0),
42  waiting_for_key_frame_(true) {}
43 
44 EsParserH26x::~EsParserH26x() {}
45 
46 bool EsParserH26x::Parse(const uint8_t* buf,
47  int size,
48  int64_t pts,
49  int64_t dts) {
50  // Note: Parse is invoked each time a PES packet has been reassembled.
51  // Unfortunately, a PES packet does not necessarily map
52  // to an h264/h265 access unit, although the HLS recommendation is to use one
53  // PES for each access unit (but this is just a recommendation and some
54  // streams do not comply with this recommendation).
55 
56  // HLS recommendation: "In AVC video, you should have both a DTS and a
57  // PTS in each PES header".
58  // However, some streams do not comply with this recommendation.
59  DVLOG_IF(1, pts == kNoTimestamp) << "Each video PES should have a PTS";
60  if (pts != kNoTimestamp) {
61  TimingDesc timing_desc;
62  timing_desc.pts = pts;
63  timing_desc.dts = (dts != kNoTimestamp) ? dts : pts;
64 
65  // Link the end of the byte queue with the incoming timing descriptor.
66  timing_desc_list_.push_back(
67  std::pair<int64_t, TimingDesc>(es_queue_->tail(), timing_desc));
68  }
69 
70  // Add the incoming bytes to the ES queue.
71  es_queue_->Push(buf, size);
72 
73  // We should always have entries in the vector and it should always start
74  // with |can_start_access_unit == true|. If not, we are just starting and
75  // should skip to the first access unit.
76  if (access_unit_nalus_.empty()) {
77  if (!SkipToFirstAccessUnit())
78  return true;
79  }
80  DCHECK(!access_unit_nalus_.empty());
81  DCHECK(access_unit_nalus_.front().nalu.can_start_access_unit());
82 
83  return ParseInternal();
84 }
85 
86 void EsParserH26x::Flush() {
87  DVLOG(1) << "EsParserH26x::Flush";
88 
89  // Simulate an additional AUD to force emitting the last access unit
90  // which is assumed to be complete at this point.
91  if (type_ == Nalu::kH264) {
92  const uint8_t aud[] = {0x00, 0x00, 0x01, 0x09};
93  es_queue_->Push(aud, sizeof(aud));
94  } else {
95  DCHECK_EQ(Nalu::kH265, type_);
96  const uint8_t aud[] = {0x00, 0x00, 0x01, 0x46, 0x01};
97  es_queue_->Push(aud, sizeof(aud));
98  }
99 
100  CHECK(ParseInternal());
101 
102  // Note that the end argument is exclusive. We do not want to include the
103  // fake AUD we just added, so the argument should point to the AUD.
104  if (access_unit_nalus_.size() > 1 &&
105  !ProcessAccessUnit(access_unit_nalus_.end() - 1)) {
106  LOG(WARNING) << "Error processing last access unit.";
107  }
108 
109  if (pending_sample_) {
110  // Flush pending sample.
111  DCHECK(pending_sample_duration_);
112  pending_sample_->set_duration(pending_sample_duration_);
113  emit_sample_cb_.Run(pid(), pending_sample_);
114  pending_sample_ = scoped_refptr<MediaSample>();
115  }
116 }
117 
118 void EsParserH26x::Reset() {
119  es_queue_.reset(new media::OffsetByteQueue());
120  current_search_position_ = 0;
121  access_unit_nalus_.clear();
122  timing_desc_list_.clear();
123  pending_sample_ = scoped_refptr<MediaSample>();
124  pending_sample_duration_ = 0;
125  waiting_for_key_frame_ = true;
126 }
127 
128 bool EsParserH26x::SkipToFirstAccessUnit() {
129  DCHECK(access_unit_nalus_.empty());
130  while (access_unit_nalus_.empty()) {
131  if (!SearchForNextNalu())
132  return false;
133 
134  // If we can't start an access unit, remove it and continue.
135  DCHECK_EQ(1u, access_unit_nalus_.size());
136  if (!access_unit_nalus_.back().nalu.can_start_access_unit())
137  access_unit_nalus_.clear();
138  }
139  return true;
140 }
141 
142 bool EsParserH26x::SearchForNextNalu() {
143  const uint8_t* es;
144  int es_size;
145  es_queue_->PeekAt(current_search_position_, &es, &es_size);
146 
147  // Find a start code.
148  uint64_t start_code_offset;
149  uint8_t start_code_size;
150  const bool start_code_found = NaluReader::FindStartCode(
151  es, es_size, &start_code_offset, &start_code_size);
152 
153  if (!start_code_found) {
154  // We didn't find a start code, so we don't have to search this data again.
155  if (es_size > kStartCodeSize)
156  current_search_position_ += es_size - kStartCodeSize;
157  return false;
158  }
159 
160  // Ensure the next NAL unit is a real NAL unit.
161  const uint8_t* nalu_ptr = es + start_code_offset + start_code_size;
162  // This size is likely inaccurate, this is just to get the header info.
163  const int64_t next_nalu_size = es_size - start_code_offset - start_code_size;
164  if (next_nalu_size <
165  (type_ == Nalu::kH264 ? kH264NaluHeaderSize : kH265NaluHeaderSize)) {
166  // There was not enough data, wait for more.
167  return false;
168  }
169 
170  Nalu next_nalu;
171  if (!next_nalu.Initialize(type_, nalu_ptr, next_nalu_size)) {
172  // The next NAL unit is invalid, skip it and search again.
173  current_search_position_ += start_code_offset + start_code_size;
174  return SearchForNextNalu();
175  }
176 
177  current_search_position_ += start_code_offset + start_code_size;
178 
179  NaluInfo info;
180  info.position = current_search_position_ - start_code_size;
181  info.start_code_size = start_code_size;
182  info.nalu = next_nalu;
183  access_unit_nalus_.push_back(info);
184 
185  return true;
186 }
187 
188 bool EsParserH26x::ProcessAccessUnit(std::deque<NaluInfo>::iterator end) {
189  DCHECK(end < access_unit_nalus_.end());
190  auto begin = access_unit_nalus_.begin();
191  const uint8_t* es;
192  int es_size;
193  es_queue_->PeekAt(begin->position, &es, &es_size);
194  DCHECK_GE(static_cast<uint64_t>(es_size), (end->position - begin->position));
195 
196  // Process the NAL units in the access unit.
197  bool is_key_frame = false;
198  int pps_id = -1;
199  for (auto it = begin; it != end; ++it) {
200  if (it->nalu.nuh_layer_id() == 0) {
201  // Update the NALU because the data pointer may have been invalidated.
202  CHECK(it->nalu.Initialize(
203  type_, es + (it->position - begin->position) + it->start_code_size,
204  ((it+1)->position - it->position) - it->start_code_size));
205  if (!ProcessNalu(it->nalu, &is_key_frame, &pps_id))
206  return false;
207  }
208  }
209 
210  if (is_key_frame)
211  waiting_for_key_frame_ = false;
212  if (!waiting_for_key_frame_) {
213  const uint64_t access_unit_size = end->position - begin->position;
214  RCHECK(EmitFrame(begin->position, access_unit_size, is_key_frame, pps_id));
215  }
216 
217  return true;
218 }
219 
220 bool EsParserH26x::ParseInternal() {
221  while (true) {
222  if (!SearchForNextNalu())
223  return true;
224 
225  // ITU H.264 sec. 7.4.1.2.3
226  // H264: The first of the NAL units with |can_start_access_unit() == true|
227  // after the last VCL NAL unit of a primary coded picture specifies the
228  // start of a new access unit. |nuh_layer_id()| is for H265 only; it is
229  // included below for ease of computation (the value is always 0).
230  // ITU H.265 sec. 7.4.2.4.4
231  // H265: The first of the NAL units with |can_start_access_unit() == true|
232  // after the last VCL NAL unit preceding firstBlPicNalUnit (the first
233  // VCL NAL unit of a coded picture with nuh_layer_id equal to 0), if
234  // any, specifies the start of a new access unit.
235  DCHECK(!access_unit_nalus_.empty());
236  if (!access_unit_nalus_.back().nalu.is_video_slice() ||
237  access_unit_nalus_.back().nalu.nuh_layer_id() != 0) {
238  continue;
239  }
240 
241  // First, find the end of the access unit. Search backward to find the
242  // first VCL NALU before the current one.
243  auto access_unit_end_rit = access_unit_nalus_.rbegin();
244  bool found_vcl = false;
245  for (auto rit = access_unit_nalus_.rbegin() + 1;
246  rit != access_unit_nalus_.rend(); ++rit) {
247  if (rit->nalu.is_video_slice()) {
248  found_vcl = true;
249  break;
250  } else if (rit->nalu.can_start_access_unit()) {
251  // The start of the next access unit is the first unit with
252  // |can_start_access_unit| after the previous VCL unit.
253  access_unit_end_rit = rit;
254  }
255  }
256  if (!found_vcl)
257  return true;
258 
259  // Get a forward iterator that corresponds to the same element pointed by
260  // |access_unit_end_rit|. Note: |end| refers to the exclusive end and
261  // will point to a valid object.
262  auto end = (access_unit_end_rit + 1).base();
263  if (!ProcessAccessUnit(end))
264  return false;
265 
266  // Delete the data we have already processed.
267  es_queue_->Trim(end->position);
268  access_unit_nalus_.erase(access_unit_nalus_.begin(), end);
269  }
270 }
271 
272 bool EsParserH26x::EmitFrame(int64_t access_unit_pos,
273  int access_unit_size,
274  bool is_key_frame,
275  int pps_id) {
276  // Get the access unit timing info.
277  TimingDesc current_timing_desc = {kNoTimestamp, kNoTimestamp};
278  while (!timing_desc_list_.empty() &&
279  timing_desc_list_.front().first <= access_unit_pos) {
280  current_timing_desc = timing_desc_list_.front().second;
281  timing_desc_list_.pop_front();
282  }
283  if (current_timing_desc.pts == kNoTimestamp)
284  return false;
285 
286  // Emit a frame.
287  DVLOG(LOG_LEVEL_ES) << "Emit frame: stream_pos=" << access_unit_pos
288  << " size=" << access_unit_size;
289  int es_size;
290  const uint8_t* es;
291  es_queue_->PeekAt(access_unit_pos, &es, &es_size);
292 
293  // Convert frame to unit stream format.
294  std::vector<uint8_t> converted_frame;
295  if (!stream_converter_->ConvertByteStreamToNalUnitStream(
296  es, access_unit_size, &converted_frame)) {
297  DLOG(ERROR) << "Failure to convert video frame to unit stream format.";
298  return false;
299  }
300 
301  // Update the video decoder configuration if needed.
302  RCHECK(UpdateVideoDecoderConfig(pps_id));
303 
304  // Create the media sample, emitting always the previous sample after
305  // calculating its duration.
306  scoped_refptr<MediaSample> media_sample = MediaSample::CopyFrom(
307  converted_frame.data(), converted_frame.size(), is_key_frame);
308  media_sample->set_dts(current_timing_desc.dts);
309  media_sample->set_pts(current_timing_desc.pts);
310  if (pending_sample_) {
311  DCHECK_GT(media_sample->dts(), pending_sample_->dts());
312  pending_sample_duration_ = media_sample->dts() - pending_sample_->dts();
313  pending_sample_->set_duration(pending_sample_duration_);
314  emit_sample_cb_.Run(pid(), pending_sample_);
315  }
316  pending_sample_ = media_sample;
317 
318  return true;
319 }
320 
321 } // namespace mp2t
322 } // namespace media
323 } // namespace shaka
static scoped_refptr< MediaSample > CopyFrom(const uint8_t *data, size_t size, bool is_key_frame)
Definition: media_sample.cc:45