DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
mp2t_media_parser.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/mp2t_media_parser.h"
6 
7 #include "packager/base/bind.h"
8 #include "packager/base/memory/scoped_ptr.h"
9 #include "packager/base/stl_util.h"
10 #include "packager/media/base/media_sample.h"
11 #include "packager/media/base/stream_info.h"
12 #include "packager/media/formats/mp2t/es_parser.h"
13 #include "packager/media/formats/mp2t/es_parser_adts.h"
14 #include "packager/media/formats/mp2t/es_parser_h264.h"
15 #include "packager/media/formats/mp2t/es_parser_h265.h"
16 #include "packager/media/formats/mp2t/mp2t_common.h"
17 #include "packager/media/formats/mp2t/ts_packet.h"
18 #include "packager/media/formats/mp2t/ts_section.h"
19 #include "packager/media/formats/mp2t/ts_section_pat.h"
20 #include "packager/media/formats/mp2t/ts_section_pes.h"
21 #include "packager/media/formats/mp2t/ts_section_pmt.h"
22 
23 namespace shaka {
24 namespace media {
25 namespace mp2t {
26 
27 enum StreamType {
28  // ISO-13818.1 / ITU H.222 Table 2.34 "Stream type assignments"
29  kStreamTypeMpeg1Audio = 0x3,
30  kStreamTypeAAC = 0xf,
31  kStreamTypeAVC = 0x1b,
32  kStreamTypeHEVC = 0x24,
33 };
34 
35 class PidState {
36  public:
37  enum PidType {
38  kPidPat,
39  kPidPmt,
40  kPidAudioPes,
41  kPidVideoPes,
42  };
43 
44  PidState(int pid, PidType pid_type,
45  scoped_ptr<TsSection> section_parser);
46 
47  // Extract the content of the TS packet and parse it.
48  // Return true if successful.
49  bool PushTsPacket(const TsPacket& ts_packet);
50 
51  // Flush the PID state (possibly emitting some pending frames)
52  // and reset its state.
53  void Flush();
54 
55  // Enable/disable the PID.
56  // Disabling a PID will reset its state and ignore any further incoming TS
57  // packets.
58  void Enable();
59  void Disable();
60  bool IsEnabled() const;
61 
62  PidType pid_type() const { return pid_type_; }
63 
64  scoped_refptr<StreamInfo>& config() { return config_; }
65  void set_config(const scoped_refptr<StreamInfo>& config) { config_ = config; }
66 
67  SampleQueue& sample_queue() { return sample_queue_; }
68 
69  private:
70  void ResetState();
71 
72  int pid_;
73  PidType pid_type_;
74  scoped_ptr<TsSection> section_parser_;
75 
76  bool enable_;
77  int continuity_counter_;
78  scoped_refptr<StreamInfo> config_;
79  SampleQueue sample_queue_;
80 };
81 
82 PidState::PidState(int pid, PidType pid_type,
83  scoped_ptr<TsSection> section_parser)
84  : pid_(pid),
85  pid_type_(pid_type),
86  section_parser_(section_parser.Pass()),
87  enable_(false),
88  continuity_counter_(-1) {
89  DCHECK(section_parser_);
90 }
91 
92 bool PidState::PushTsPacket(const TsPacket& ts_packet) {
93  DCHECK_EQ(ts_packet.pid(), pid_);
94 
95  // The current PID is not part of the PID filter,
96  // just discard the incoming TS packet.
97  if (!enable_)
98  return true;
99 
100  int expected_continuity_counter = (continuity_counter_ + 1) % 16;
101  if (continuity_counter_ >= 0 &&
102  ts_packet.continuity_counter() != expected_continuity_counter) {
103  DVLOG(1) << "TS discontinuity detected for pid: " << pid_;
104  // TODO(tinskip): Handle discontinuity better.
105  return false;
106  }
107 
108  bool status = section_parser_->Parse(
109  ts_packet.payload_unit_start_indicator(),
110  ts_packet.payload(),
111  ts_packet.payload_size());
112 
113  // At the minimum, when parsing failed, auto reset the section parser.
114  // Components that use the Mp2tMediaParser can take further action if needed.
115  if (!status) {
116  DVLOG(1) << "Parsing failed for pid = " << pid_;
117  ResetState();
118  }
119 
120  return status;
121 }
122 
123 void PidState::Flush() {
124  section_parser_->Flush();
125  ResetState();
126 }
127 
128 void PidState::Enable() {
129  enable_ = true;
130 }
131 
132 void PidState::Disable() {
133  if (!enable_)
134  return;
135 
136  ResetState();
137  enable_ = false;
138 }
139 
140 bool PidState::IsEnabled() const {
141  return enable_;
142 }
143 
144 void PidState::ResetState() {
145  section_parser_->Reset();
146  continuity_counter_ = -1;
147 }
148 
149 Mp2tMediaParser::Mp2tMediaParser()
150  : sbr_in_mimetype_(false),
151  is_initialized_(false) {
152 }
153 
154 Mp2tMediaParser::~Mp2tMediaParser() {
155  STLDeleteValues(&pids_);
156 }
157 
159  const InitCB& init_cb,
160  const NewSampleCB& new_sample_cb,
161  KeySource* decryption_key_source) {
162  DCHECK(!is_initialized_);
163  DCHECK(init_cb_.is_null());
164  DCHECK(!init_cb.is_null());
165  DCHECK(!new_sample_cb.is_null());
166 
167  init_cb_ = init_cb;
168  new_sample_cb_ = new_sample_cb;
169 }
170 
172  DVLOG(1) << "Mp2tMediaParser::Flush";
173 
174  // Flush the buffers and reset the pids.
175  for (std::map<int, PidState*>::iterator it = pids_.begin();
176  it != pids_.end(); ++it) {
177  DVLOG(1) << "Flushing PID: " << it->first;
178  PidState* pid_state = it->second;
179  pid_state->Flush();
180  }
181  bool result = EmitRemainingSamples();
182  STLDeleteValues(&pids_);
183 
184  // Remove any bytes left in the TS buffer.
185  // (i.e. any partial TS packet => less than 188 bytes).
186  ts_byte_queue_.Reset();
187  return result;
188 }
189 
190 bool Mp2tMediaParser::Parse(const uint8_t* buf, int size) {
191  DVLOG(1) << "Mp2tMediaParser::Parse size=" << size;
192 
193  // Add the data to the parser state.
194  ts_byte_queue_.Push(buf, size);
195 
196  while (true) {
197  const uint8_t* ts_buffer;
198  int ts_buffer_size;
199  ts_byte_queue_.Peek(&ts_buffer, &ts_buffer_size);
200  if (ts_buffer_size < TsPacket::kPacketSize)
201  break;
202 
203  // Synchronization.
204  int skipped_bytes = TsPacket::Sync(ts_buffer, ts_buffer_size);
205  if (skipped_bytes > 0) {
206  DVLOG(1) << "Packet not aligned on a TS syncword:"
207  << " skipped_bytes=" << skipped_bytes;
208  ts_byte_queue_.Pop(skipped_bytes);
209  continue;
210  }
211 
212  // Parse the TS header, skipping 1 byte if the header is invalid.
213  scoped_ptr<TsPacket> ts_packet(TsPacket::Parse(ts_buffer, ts_buffer_size));
214  if (!ts_packet) {
215  DVLOG(1) << "Error: invalid TS packet";
216  ts_byte_queue_.Pop(1);
217  continue;
218  }
219  DVLOG(LOG_LEVEL_TS)
220  << "Processing PID=" << ts_packet->pid()
221  << " start_unit=" << ts_packet->payload_unit_start_indicator();
222 
223  // Parse the section.
224  std::map<int, PidState*>::iterator it = pids_.find(ts_packet->pid());
225  if (it == pids_.end() &&
226  ts_packet->pid() == TsSection::kPidPat) {
227  // Create the PAT state here if needed.
228  scoped_ptr<TsSection> pat_section_parser(
229  new TsSectionPat(
230  base::Bind(&Mp2tMediaParser::RegisterPmt,
231  base::Unretained(this))));
232  scoped_ptr<PidState> pat_pid_state(
233  new PidState(ts_packet->pid(), PidState::kPidPat,
234  pat_section_parser.Pass()));
235  pat_pid_state->Enable();
236  it = pids_.insert(
237  std::pair<int, PidState*>(ts_packet->pid(),
238  pat_pid_state.release())).first;
239  }
240 
241  if (it != pids_.end()) {
242  if (!it->second->PushTsPacket(*ts_packet))
243  return false;
244  } else {
245  DVLOG(LOG_LEVEL_TS) << "Ignoring TS packet for pid: " << ts_packet->pid();
246  }
247 
248  // Go to the next packet.
249  ts_byte_queue_.Pop(TsPacket::kPacketSize);
250  }
251 
252  // Emit the A/V buffers that kept accumulating during TS parsing.
253  return EmitRemainingSamples();
254 }
255 
256 void Mp2tMediaParser::RegisterPmt(int program_number, int pmt_pid) {
257  DVLOG(1) << "RegisterPmt:"
258  << " program_number=" << program_number
259  << " pmt_pid=" << pmt_pid;
260 
261  // Only one TS program is allowed. Ignore the incoming program map table,
262  // if there is already one registered.
263  for (std::map<int, PidState*>::iterator it = pids_.begin();
264  it != pids_.end(); ++it) {
265  PidState* pid_state = it->second;
266  if (pid_state->pid_type() == PidState::kPidPmt) {
267  DVLOG_IF(1, pmt_pid != it->first) << "More than one program is defined";
268  return;
269  }
270  }
271 
272  // Create the PMT state here if needed.
273  DVLOG(1) << "Create a new PMT parser";
274  scoped_ptr<TsSection> pmt_section_parser(
275  new TsSectionPmt(
276  base::Bind(&Mp2tMediaParser::RegisterPes,
277  base::Unretained(this), pmt_pid)));
278  scoped_ptr<PidState> pmt_pid_state(
279  new PidState(pmt_pid, PidState::kPidPmt, pmt_section_parser.Pass()));
280  pmt_pid_state->Enable();
281  pids_.insert(std::pair<int, PidState*>(pmt_pid, pmt_pid_state.release()));
282 }
283 
284 void Mp2tMediaParser::RegisterPes(int pmt_pid,
285  int pes_pid,
286  int stream_type) {
287  DVLOG(1) << "RegisterPes:"
288  << " pes_pid=" << pes_pid
289  << " stream_type=" << std::hex << stream_type << std::dec;
290  std::map<int, PidState*>::iterator it = pids_.find(pes_pid);
291  if (it != pids_.end())
292  return;
293 
294  // Create a stream parser corresponding to the stream type.
295  bool is_audio = false;
296  scoped_ptr<EsParser> es_parser;
297  if (stream_type == kStreamTypeAVC) {
298  es_parser.reset(
299  new EsParserH264(
300  pes_pid,
301  base::Bind(&Mp2tMediaParser::OnNewStreamInfo,
302  base::Unretained(this)),
303  base::Bind(&Mp2tMediaParser::OnEmitSample,
304  base::Unretained(this))));
305  } else if (stream_type == kStreamTypeHEVC) {
306  es_parser.reset(
307  new EsParserH265(
308  pes_pid,
309  base::Bind(&Mp2tMediaParser::OnNewStreamInfo,
310  base::Unretained(this)),
311  base::Bind(&Mp2tMediaParser::OnEmitSample,
312  base::Unretained(this))));
313  } else if (stream_type == kStreamTypeAAC) {
314  es_parser.reset(
315  new EsParserAdts(
316  pes_pid,
317  base::Bind(&Mp2tMediaParser::OnNewStreamInfo,
318  base::Unretained(this)),
319  base::Bind(&Mp2tMediaParser::OnEmitSample,
320  base::Unretained(this)),
321  sbr_in_mimetype_));
322  is_audio = true;
323  } else {
324  return;
325  }
326 
327  // Create the PES state here.
328  DVLOG(1) << "Create a new PES state";
329  scoped_ptr<TsSection> pes_section_parser(
330  new TsSectionPes(es_parser.Pass()));
331  PidState::PidType pid_type =
332  is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes;
333  scoped_ptr<PidState> pes_pid_state(
334  new PidState(pes_pid, pid_type, pes_section_parser.Pass()));
335  pes_pid_state->Enable();
336  pids_.insert(std::pair<int, PidState*>(pes_pid, pes_pid_state.release()));
337 }
338 
339 void Mp2tMediaParser::OnNewStreamInfo(
340  const scoped_refptr<StreamInfo>& new_stream_info) {
341  DCHECK(new_stream_info);
342  DVLOG(1) << "OnVideoConfigChanged for pid=" << new_stream_info->track_id();
343 
344  PidMap::iterator pid_state = pids_.find(new_stream_info->track_id());
345  if (pid_state == pids_.end()) {
346  LOG(ERROR) << "PID State for new stream not found (pid = "
347  << new_stream_info->track_id() << ").";
348  return;
349  }
350 
351  // Set the stream configuration information for the PID.
352  pid_state->second->set_config(new_stream_info);
353 
354  // Finish initialization if all streams have configs.
355  FinishInitializationIfNeeded();
356 }
357 
358 bool Mp2tMediaParser::FinishInitializationIfNeeded() {
359  // Nothing to be done if already initialized.
360  if (is_initialized_)
361  return true;
362 
363  // Wait for more data to come to finish initialization.
364  if (pids_.empty())
365  return true;
366 
367  std::vector<scoped_refptr<StreamInfo> > all_stream_info;
368  uint32_t num_es(0);
369  for (PidMap::const_iterator iter = pids_.begin(); iter != pids_.end();
370  ++iter) {
371  if (((iter->second->pid_type() == PidState::kPidAudioPes) ||
372  (iter->second->pid_type() == PidState::kPidVideoPes))) {
373  ++num_es;
374  if (iter->second->config())
375  all_stream_info.push_back(iter->second->config());
376  }
377  }
378  if (num_es && (all_stream_info.size() == num_es)) {
379  // All stream configurations have been received. Initialization can
380  // be completed.
381  init_cb_.Run(all_stream_info);
382  DVLOG(1) << "Mpeg2TS stream parser initialization done";
383  is_initialized_ = true;
384  }
385  return true;
386 }
387 
388 void Mp2tMediaParser::OnEmitSample(
389  uint32_t pes_pid,
390  const scoped_refptr<MediaSample>& new_sample) {
391  DCHECK(new_sample);
392  DVLOG(LOG_LEVEL_ES)
393  << "OnEmitSample: "
394  << " pid="
395  << pes_pid
396  << " size="
397  << new_sample->data_size()
398  << " dts="
399  << new_sample->dts()
400  << " pts="
401  << new_sample->pts();
402 
403  // Add the sample to the appropriate PID sample queue.
404  PidMap::iterator pid_state = pids_.find(pes_pid);
405  if (pid_state == pids_.end()) {
406  LOG(ERROR) << "PID State for new sample not found (pid = "
407  << pes_pid << ").";
408  return;
409  }
410  pid_state->second->sample_queue().push_back(new_sample);
411 }
412 
413 bool Mp2tMediaParser::EmitRemainingSamples() {
414  DVLOG(LOG_LEVEL_ES) << "Mp2tMediaParser::EmitRemainingBuffers";
415 
416  // No buffer should be sent until fully initialized.
417  if (!is_initialized_)
418  return true;
419 
420  // Buffer emission.
421  for (PidMap::const_iterator pid_iter = pids_.begin(); pid_iter != pids_.end();
422  ++pid_iter) {
423  SampleQueue& sample_queue = pid_iter->second->sample_queue();
424  for (SampleQueue::iterator sample_iter = sample_queue.begin();
425  sample_iter != sample_queue.end();
426  ++sample_iter) {
427  if (!new_sample_cb_.Run(pid_iter->first, *sample_iter)) {
428  // Error processing sample. Propagate error condition.
429  return false;
430  }
431  }
432  sample_queue.clear();
433  }
434 
435  return true;
436 }
437 
438 } // namespace mp2t
439 } // namespace media
440 } // namespace shaka
void Init(const InitCB &init_cb, const NewSampleCB &new_sample_cb, KeySource *decryption_key_source) override
void Push(const uint8_t *data, int size)
Append new bytes to the end of the queue.
Definition: byte_queue.cc:29
void Pop(int count)
Definition: byte_queue.cc:70
bool Flush() override WARN_UNUSED_RESULT
void Reset()
Reset the queue to the empty state.
Definition: byte_queue.cc:24
void Peek(const uint8_t **data, int *size) const
Definition: byte_queue.cc:63
KeySource is responsible for encryption key acquisition.
Definition: key_source.h:31
bool Parse(const uint8_t *buf, int size) override WARN_UNUSED_RESULT