DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs 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/filters/h264_byte_to_unit_stream_converter.h"
16 #include "packager/media/filters/h265_byte_to_unit_stream_converter.h"
17 #include "packager/media/formats/mp2t/mp2t_common.h"
18 
19 namespace edash_packager {
20 namespace media {
21 namespace mp2t {
22 
23 namespace {
24 
25 H26xByteToUnitStreamConverter* CreateStreamConverter(Nalu::CodecType type) {
26  if (type == Nalu::kH264) {
27  return new H264ByteToUnitStreamConverter();
28  } else {
29  DCHECK_EQ(Nalu::kH265, type);
30  return new H265ByteToUnitStreamConverter();
31  }
32 }
33 
34 } // anonymous namespace
35 
36 EsParserH26x::EsParserH26x(Nalu::CodecType type,
37  uint32_t pid,
38  const EmitSampleCB& emit_sample_cb)
39  : EsParser(pid),
40  emit_sample_cb_(emit_sample_cb),
41  type_(type),
42  es_queue_(new media::OffsetByteQueue()),
43  current_access_unit_pos_(0),
44  found_access_unit_(false),
45  stream_converter_(CreateStreamConverter(type)),
46  pending_sample_duration_(0),
47  waiting_for_key_frame_(true) {
48 }
49 
50 EsParserH26x::~EsParserH26x() {}
51 
52 bool EsParserH26x::Parse(const uint8_t* buf,
53  int size,
54  int64_t pts,
55  int64_t dts) {
56  // Note: Parse is invoked each time a PES packet has been reassembled.
57  // Unfortunately, a PES packet does not necessarily map
58  // to an h264/h265 access unit, although the HLS recommendation is to use one
59  // PES for each access unit (but this is just a recommendation and some
60  // streams do not comply with this recommendation).
61 
62  // HLS recommendation: "In AVC video, you should have both a DTS and a
63  // PTS in each PES header".
64  // However, some streams do not comply with this recommendation.
65  DVLOG_IF(1, pts == kNoTimestamp) << "Each video PES should have a PTS";
66  if (pts != kNoTimestamp) {
67  TimingDesc timing_desc;
68  timing_desc.pts = pts;
69  timing_desc.dts = (dts != kNoTimestamp) ? dts : pts;
70 
71  // Link the end of the byte queue with the incoming timing descriptor.
72  timing_desc_list_.push_back(
73  std::pair<int64_t, TimingDesc>(es_queue_->tail(), timing_desc));
74  }
75 
76  // Add the incoming bytes to the ES queue.
77  es_queue_->Push(buf, size);
78 
79  // Skip to the first access unit.
80  if (!found_access_unit_) {
81  if (!FindNextAccessUnit(current_access_unit_pos_,
82  &current_access_unit_pos_)) {
83  return true;
84  }
85  es_queue_->Trim(current_access_unit_pos_);
86  found_access_unit_ = true;
87  }
88 
89  return ParseInternal();
90 }
91 
92 void EsParserH26x::Flush() {
93  DVLOG(1) << "EsParserH26x::Flush";
94 
95  // Simulate an additional AUD to force emitting the last access unit
96  // which is assumed to be complete at this point.
97  if (type_ == Nalu::kH264) {
98  uint8_t aud[] = {0x00, 0x00, 0x01, 0x09};
99  es_queue_->Push(aud, sizeof(aud));
100  } else {
101  DCHECK_EQ(Nalu::kH265, type_);
102  uint8_t aud[] = {0x00, 0x00, 0x01, 0x46, 0x01};
103  es_queue_->Push(aud, sizeof(aud));
104  }
105  ParseInternal();
106 
107  if (pending_sample_) {
108  // Flush pending sample.
109  DCHECK(pending_sample_duration_);
110  pending_sample_->set_duration(pending_sample_duration_);
111  emit_sample_cb_.Run(pid(), pending_sample_);
112  pending_sample_ = scoped_refptr<MediaSample>();
113  }
114 }
115 
116 void EsParserH26x::Reset() {
117  es_queue_.reset(new media::OffsetByteQueue());
118  current_access_unit_pos_ = 0;
119  found_access_unit_ = false;
120  timing_desc_list_.clear();
121  pending_sample_ = scoped_refptr<MediaSample>();
122  pending_sample_duration_ = 0;
123  waiting_for_key_frame_ = true;
124 }
125 
126 bool EsParserH26x::FindNextAccessUnit(int64_t stream_pos,
127  int64_t* next_unit_pos) {
128  // TODO(modmaker): Avoid re-parsing by saving old position.
129  // Every access unit must have a VCL entry and defines the end of the access
130  // unit. Track it to return on the element after it so we get the whole
131  // access unit.
132  bool seen_vcl_nalu = false;
133  while (true) {
134  const uint8_t* es;
135  int size;
136  es_queue_->PeekAt(stream_pos, &es, &size);
137 
138  // Find a start code.
139  uint64_t start_code_offset;
140  uint8_t start_code_size;
141  bool start_code_found = NaluReader::FindStartCode(
142  es, size, &start_code_offset, &start_code_size);
143  stream_pos += start_code_offset;
144 
145  // No start code found or NALU type not available yet.
146  if (!start_code_found ||
147  start_code_offset + start_code_size >= static_cast<uint64_t>(size)) {
148  return false;
149  }
150 
151  Nalu nalu;
152  const uint8_t* nalu_ptr = es + start_code_offset + start_code_size;
153  size_t nalu_size = size - (start_code_offset + start_code_size);
154  if (nalu.Initialize(type_, nalu_ptr, nalu_size)) {
155  // ITU H.264 sec. 7.4.1.2.3
156  // H264: The first of the NAL units with |can_start_access_unit() == true|
157  // after the last VCL NAL unit of a primary coded picture specifies the
158  // start of a new access unit. |nuh_layer_id()| is for H265 only; it is
159  // included below for ease of computation (the value is always 0).
160  // ITU H.265 sec. 7.4.2.4.4
161  // H265: The first of the NAL units with |can_start_access_unit() == true|
162  // after the last VCL NAL unit preceding firstBlPicNalUnit (the first
163  // VCL NAL unit of a coded picture with nuh_layer_id equal to 0), if
164  // any, specifies the start of a new access unit.
165  // TODO(modmaker): This does not handle nuh_layer_id != 0 correctly.
166  // AUD VCL SEI VCL* VPS VCL
167  // | Current method splits here.
168  // | Should split here.
169  // If we are searching for the first access unit, then stop at the first
170  // NAL unit that can start an access unit.
171  if ((seen_vcl_nalu || !found_access_unit_) &&
172  nalu.can_start_access_unit()) {
173  break;
174  }
175  bool is_vcl_nalu = nalu.is_video_slice() && nalu.nuh_layer_id() == 0;
176  seen_vcl_nalu |= is_vcl_nalu;
177  }
178 
179  // The current NALU is not an AUD, skip the start code
180  // and continue parsing the stream.
181  stream_pos += start_code_size;
182  }
183 
184  *next_unit_pos = stream_pos;
185  return true;
186 }
187 
188 bool EsParserH26x::ParseInternal() {
189  DCHECK_LE(es_queue_->head(), current_access_unit_pos_);
190  DCHECK_LE(current_access_unit_pos_, es_queue_->tail());
191 
192  // Resume parsing later if no AUD was found.
193  int64_t access_unit_end;
194  if (!FindNextAccessUnit(current_access_unit_pos_, &access_unit_end))
195  return true;
196 
197  // At this point, we know we have a full access unit.
198  bool is_key_frame = false;
199  int pps_id_for_access_unit = -1;
200 
201  const uint8_t* es;
202  int size;
203  es_queue_->PeekAt(current_access_unit_pos_, &es, &size);
204  int access_unit_size = base::checked_cast<int, int64_t>(
205  access_unit_end - current_access_unit_pos_);
206  DCHECK_LE(access_unit_size, size);
207  NaluReader reader(type_, kIsAnnexbByteStream, es, access_unit_size);
208 
209  // TODO(modmaker): Consider combining with FindNextAccessUnit to avoid
210  // scanning the data twice.
211  while (true) {
212  Nalu nalu;
213  bool is_eos = false;
214  switch (reader.Advance(&nalu)) {
215  case NaluReader::kOk:
216  break;
217  case NaluReader::kEOStream:
218  is_eos = true;
219  break;
220  default:
221  return false;
222  }
223  if (is_eos)
224  break;
225 
226  if (!ProcessNalu(nalu, &is_key_frame, &pps_id_for_access_unit))
227  return false;
228  }
229 
230  if (waiting_for_key_frame_) {
231  waiting_for_key_frame_ = !is_key_frame;
232  }
233  if (!waiting_for_key_frame_) {
234  // Emit a frame and move the stream to the next AUD position.
235  RCHECK(EmitFrame(current_access_unit_pos_, access_unit_size,
236  is_key_frame, pps_id_for_access_unit));
237  }
238  current_access_unit_pos_ = access_unit_end;
239  es_queue_->Trim(current_access_unit_pos_);
240 
241  return true;
242 }
243 
244 bool EsParserH26x::EmitFrame(int64_t access_unit_pos,
245  int access_unit_size,
246  bool is_key_frame,
247  int pps_id) {
248  // Get the access unit timing info.
249  TimingDesc current_timing_desc = {kNoTimestamp, kNoTimestamp};
250  while (!timing_desc_list_.empty() &&
251  timing_desc_list_.front().first <= access_unit_pos) {
252  current_timing_desc = timing_desc_list_.front().second;
253  timing_desc_list_.pop_front();
254  }
255  if (current_timing_desc.pts == kNoTimestamp)
256  return false;
257 
258  // Emit a frame.
259  DVLOG(LOG_LEVEL_ES) << "Emit frame: stream_pos=" << current_access_unit_pos_
260  << " size=" << access_unit_size;
261  int es_size;
262  const uint8_t* es;
263  es_queue_->PeekAt(current_access_unit_pos_, &es, &es_size);
264  CHECK_GE(es_size, access_unit_size);
265 
266  // Convert frame to unit stream format.
267  std::vector<uint8_t> converted_frame;
268  if (!stream_converter_->ConvertByteStreamToNalUnitStream(
269  es, access_unit_size, &converted_frame)) {
270  DLOG(ERROR) << "Failure to convert video frame to unit stream format.";
271  return false;
272  }
273 
274  // Update the video decoder configuration if needed.
275  RCHECK(UpdateVideoDecoderConfig(pps_id));
276 
277  // Create the media sample, emitting always the previous sample after
278  // calculating its duration.
279  scoped_refptr<MediaSample> media_sample = MediaSample::CopyFrom(
280  converted_frame.data(), converted_frame.size(), is_key_frame);
281  media_sample->set_dts(current_timing_desc.dts);
282  media_sample->set_pts(current_timing_desc.pts);
283  if (pending_sample_) {
284  DCHECK_GT(media_sample->dts(), pending_sample_->dts());
285  pending_sample_duration_ = media_sample->dts() - pending_sample_->dts();
286  pending_sample_->set_duration(pending_sample_duration_);
287  emit_sample_cb_.Run(pid(), pending_sample_);
288  }
289  pending_sample_ = media_sample;
290 
291  return true;
292 }
293 
294 } // namespace mp2t
295 } // namespace media
296 } // namespace edash_packager
static scoped_refptr< MediaSample > CopyFrom(const uint8_t *data, size_t size, bool is_key_frame)
Definition: media_sample.cc:45