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