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