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/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,
45  PidType pid_type,
46  std::unique_ptr<TsSection> section_parser);
47 
48  // Extract the content of the TS packet and parse it.
49  // Return true if successful.
50  bool PushTsPacket(const TsPacket& ts_packet);
51 
52  // Flush the PID state (possibly emitting some pending frames)
53  // and reset its state.
54  void Flush();
55 
56  // Enable/disable the PID.
57  // Disabling a PID will reset its state and ignore any further incoming TS
58  // packets.
59  void Enable();
60  void Disable();
61  bool IsEnabled() const;
62 
63  PidType pid_type() const { return pid_type_; }
64 
65  scoped_refptr<StreamInfo>& config() { return config_; }
66  void set_config(const scoped_refptr<StreamInfo>& config) { config_ = config; }
67 
68  SampleQueue& sample_queue() { return sample_queue_; }
69 
70  private:
71  void ResetState();
72 
73  int pid_;
74  PidType pid_type_;
75  std::unique_ptr<TsSection> section_parser_;
76 
77  bool enable_;
78  int continuity_counter_;
79  scoped_refptr<StreamInfo> config_;
80  SampleQueue sample_queue_;
81 };
82 
83 PidState::PidState(int pid,
84  PidType pid_type,
85  std::unique_ptr<TsSection> section_parser)
86  : pid_(pid),
87  pid_type_(pid_type),
88  section_parser_(std::move(section_parser)),
89  enable_(false),
90  continuity_counter_(-1) {
91  DCHECK(section_parser_);
92 }
93 
94 bool PidState::PushTsPacket(const TsPacket& ts_packet) {
95  DCHECK_EQ(ts_packet.pid(), pid_);
96 
97  // The current PID is not part of the PID filter,
98  // just discard the incoming TS packet.
99  if (!enable_)
100  return true;
101 
102  int expected_continuity_counter = (continuity_counter_ + 1) % 16;
103  if (continuity_counter_ >= 0 &&
104  ts_packet.continuity_counter() != expected_continuity_counter) {
105  DVLOG(1) << "TS discontinuity detected for pid: " << pid_;
106  // TODO(tinskip): Handle discontinuity better.
107  return false;
108  }
109 
110  bool status = section_parser_->Parse(
111  ts_packet.payload_unit_start_indicator(),
112  ts_packet.payload(),
113  ts_packet.payload_size());
114 
115  // At the minimum, when parsing failed, auto reset the section parser.
116  // Components that use the Mp2tMediaParser can take further action if needed.
117  if (!status) {
118  DVLOG(1) << "Parsing failed for pid = " << pid_;
119  ResetState();
120  }
121 
122  return status;
123 }
124 
125 void PidState::Flush() {
126  section_parser_->Flush();
127  ResetState();
128 }
129 
130 void PidState::Enable() {
131  enable_ = true;
132 }
133 
134 void PidState::Disable() {
135  if (!enable_)
136  return;
137 
138  ResetState();
139  enable_ = false;
140 }
141 
142 bool PidState::IsEnabled() const {
143  return enable_;
144 }
145 
146 void PidState::ResetState() {
147  section_parser_->Reset();
148  continuity_counter_ = -1;
149 }
150 
151 Mp2tMediaParser::Mp2tMediaParser()
152  : sbr_in_mimetype_(false),
153  is_initialized_(false) {
154 }
155 
156 Mp2tMediaParser::~Mp2tMediaParser() {
157  STLDeleteValues(&pids_);
158 }
159 
161  const InitCB& init_cb,
162  const NewSampleCB& new_sample_cb,
163  KeySource* decryption_key_source) {
164  DCHECK(!is_initialized_);
165  DCHECK(init_cb_.is_null());
166  DCHECK(!init_cb.is_null());
167  DCHECK(!new_sample_cb.is_null());
168 
169  init_cb_ = init_cb;
170  new_sample_cb_ = new_sample_cb;
171 }
172 
174  DVLOG(1) << "Mp2tMediaParser::Flush";
175 
176  // Flush the buffers and reset the pids.
177  for (std::map<int, PidState*>::iterator it = pids_.begin();
178  it != pids_.end(); ++it) {
179  DVLOG(1) << "Flushing PID: " << it->first;
180  PidState* pid_state = it->second;
181  pid_state->Flush();
182  }
183  bool result = EmitRemainingSamples();
184  STLDeleteValues(&pids_);
185 
186  // Remove any bytes left in the TS buffer.
187  // (i.e. any partial TS packet => less than 188 bytes).
188  ts_byte_queue_.Reset();
189  return result;
190 }
191 
192 bool Mp2tMediaParser::Parse(const uint8_t* buf, int size) {
193  DVLOG(1) << "Mp2tMediaParser::Parse size=" << size;
194 
195  // Add the data to the parser state.
196  ts_byte_queue_.Push(buf, size);
197 
198  while (true) {
199  const uint8_t* ts_buffer;
200  int ts_buffer_size;
201  ts_byte_queue_.Peek(&ts_buffer, &ts_buffer_size);
202  if (ts_buffer_size < TsPacket::kPacketSize)
203  break;
204 
205  // Synchronization.
206  int skipped_bytes = TsPacket::Sync(ts_buffer, ts_buffer_size);
207  if (skipped_bytes > 0) {
208  DVLOG(1) << "Packet not aligned on a TS syncword:"
209  << " skipped_bytes=" << skipped_bytes;
210  ts_byte_queue_.Pop(skipped_bytes);
211  continue;
212  }
213 
214  // Parse the TS header, skipping 1 byte if the header is invalid.
215  std::unique_ptr<TsPacket> ts_packet(
216  TsPacket::Parse(ts_buffer, ts_buffer_size));
217  if (!ts_packet) {
218  DVLOG(1) << "Error: invalid TS packet";
219  ts_byte_queue_.Pop(1);
220  continue;
221  }
222  DVLOG(LOG_LEVEL_TS)
223  << "Processing PID=" << ts_packet->pid()
224  << " start_unit=" << ts_packet->payload_unit_start_indicator();
225 
226  // Parse the section.
227  std::map<int, PidState*>::iterator it = pids_.find(ts_packet->pid());
228  if (it == pids_.end() &&
229  ts_packet->pid() == TsSection::kPidPat) {
230  // Create the PAT state here if needed.
231  std::unique_ptr<TsSection> pat_section_parser(new TsSectionPat(
232  base::Bind(&Mp2tMediaParser::RegisterPmt, base::Unretained(this))));
233  std::unique_ptr<PidState> pat_pid_state(new PidState(
234  ts_packet->pid(), PidState::kPidPat, std::move(pat_section_parser)));
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  std::unique_ptr<TsSection> pmt_section_parser(new TsSectionPmt(base::Bind(
275  &Mp2tMediaParser::RegisterPes, base::Unretained(this), pmt_pid)));
276  std::unique_ptr<PidState> pmt_pid_state(
277  new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser)));
278  pmt_pid_state->Enable();
279  pids_.insert(std::pair<int, PidState*>(pmt_pid, pmt_pid_state.release()));
280 }
281 
282 void Mp2tMediaParser::RegisterPes(int pmt_pid,
283  int pes_pid,
284  int stream_type) {
285  DVLOG(1) << "RegisterPes:"
286  << " pes_pid=" << pes_pid
287  << " stream_type=" << std::hex << stream_type << std::dec;
288  std::map<int, PidState*>::iterator it = pids_.find(pes_pid);
289  if (it != pids_.end())
290  return;
291 
292  // Create a stream parser corresponding to the stream type.
293  bool is_audio = false;
294  std::unique_ptr<EsParser> es_parser;
295  if (stream_type == kStreamTypeAVC) {
296  es_parser.reset(
297  new EsParserH264(
298  pes_pid,
299  base::Bind(&Mp2tMediaParser::OnNewStreamInfo,
300  base::Unretained(this)),
301  base::Bind(&Mp2tMediaParser::OnEmitSample,
302  base::Unretained(this))));
303  } else if (stream_type == kStreamTypeHEVC) {
304  es_parser.reset(
305  new EsParserH265(
306  pes_pid,
307  base::Bind(&Mp2tMediaParser::OnNewStreamInfo,
308  base::Unretained(this)),
309  base::Bind(&Mp2tMediaParser::OnEmitSample,
310  base::Unretained(this))));
311  } else if (stream_type == kStreamTypeAAC) {
312  es_parser.reset(
313  new EsParserAdts(
314  pes_pid,
315  base::Bind(&Mp2tMediaParser::OnNewStreamInfo,
316  base::Unretained(this)),
317  base::Bind(&Mp2tMediaParser::OnEmitSample,
318  base::Unretained(this)),
319  sbr_in_mimetype_));
320  is_audio = true;
321  } else {
322  return;
323  }
324 
325  // Create the PES state here.
326  DVLOG(1) << "Create a new PES state";
327  std::unique_ptr<TsSection> pes_section_parser(
328  new TsSectionPes(std::move(es_parser)));
329  PidState::PidType pid_type =
330  is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes;
331  std::unique_ptr<PidState> pes_pid_state(
332  new PidState(pes_pid, pid_type, std::move(pes_section_parser)));
333  pes_pid_state->Enable();
334  pids_.insert(std::pair<int, PidState*>(pes_pid, pes_pid_state.release()));
335 }
336 
337 void Mp2tMediaParser::OnNewStreamInfo(
338  const scoped_refptr<StreamInfo>& new_stream_info) {
339  DCHECK(new_stream_info);
340  DVLOG(1) << "OnVideoConfigChanged for pid=" << new_stream_info->track_id();
341 
342  PidMap::iterator pid_state = pids_.find(new_stream_info->track_id());
343  if (pid_state == pids_.end()) {
344  LOG(ERROR) << "PID State for new stream not found (pid = "
345  << new_stream_info->track_id() << ").";
346  return;
347  }
348 
349  // Set the stream configuration information for the PID.
350  pid_state->second->set_config(new_stream_info);
351 
352  // Finish initialization if all streams have configs.
353  FinishInitializationIfNeeded();
354 }
355 
356 bool Mp2tMediaParser::FinishInitializationIfNeeded() {
357  // Nothing to be done if already initialized.
358  if (is_initialized_)
359  return true;
360 
361  // Wait for more data to come to finish initialization.
362  if (pids_.empty())
363  return true;
364 
365  std::vector<scoped_refptr<StreamInfo> > all_stream_info;
366  uint32_t num_es(0);
367  for (PidMap::const_iterator iter = pids_.begin(); iter != pids_.end();
368  ++iter) {
369  if (((iter->second->pid_type() == PidState::kPidAudioPes) ||
370  (iter->second->pid_type() == PidState::kPidVideoPes))) {
371  ++num_es;
372  if (iter->second->config())
373  all_stream_info.push_back(iter->second->config());
374  }
375  }
376  if (num_es && (all_stream_info.size() == num_es)) {
377  // All stream configurations have been received. Initialization can
378  // be completed.
379  init_cb_.Run(all_stream_info);
380  DVLOG(1) << "Mpeg2TS stream parser initialization done";
381  is_initialized_ = true;
382  }
383  return true;
384 }
385 
386 void Mp2tMediaParser::OnEmitSample(
387  uint32_t pes_pid,
388  const scoped_refptr<MediaSample>& new_sample) {
389  DCHECK(new_sample);
390  DVLOG(LOG_LEVEL_ES)
391  << "OnEmitSample: "
392  << " pid="
393  << pes_pid
394  << " size="
395  << new_sample->data_size()
396  << " dts="
397  << new_sample->dts()
398  << " pts="
399  << new_sample->pts();
400 
401  // Add the sample to the appropriate PID sample queue.
402  PidMap::iterator pid_state = pids_.find(pes_pid);
403  if (pid_state == pids_.end()) {
404  LOG(ERROR) << "PID State for new sample not found (pid = "
405  << pes_pid << ").";
406  return;
407  }
408  pid_state->second->sample_queue().push_back(new_sample);
409 }
410 
411 bool Mp2tMediaParser::EmitRemainingSamples() {
412  DVLOG(LOG_LEVEL_ES) << "Mp2tMediaParser::EmitRemainingBuffers";
413 
414  // No buffer should be sent until fully initialized.
415  if (!is_initialized_)
416  return true;
417 
418  // Buffer emission.
419  for (PidMap::const_iterator pid_iter = pids_.begin(); pid_iter != pids_.end();
420  ++pid_iter) {
421  SampleQueue& sample_queue = pid_iter->second->sample_queue();
422  for (SampleQueue::iterator sample_iter = sample_queue.begin();
423  sample_iter != sample_queue.end();
424  ++sample_iter) {
425  if (!new_sample_cb_.Run(pid_iter->first, *sample_iter)) {
426  // Error processing sample. Propagate error condition.
427  return false;
428  }
429  }
430  sample_queue.clear();
431  }
432 
433  return true;
434 }
435 
436 } // namespace mp2t
437 } // namespace media
438 } // 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