DASH Media Packaging SDK
 All Classes Namespaces Functions Variables Typedefs 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/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 edash_packager {
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 };
32 
33 class PidState {
34  public:
35  enum PidType {
36  kPidPat,
37  kPidPmt,
38  kPidAudioPes,
39  kPidVideoPes,
40  };
41 
42  PidState(int pid, PidType pid_type,
43  scoped_ptr<TsSection> section_parser);
44 
45  // Extract the content of the TS packet and parse it.
46  // Return true if successful.
47  bool PushTsPacket(const TsPacket& ts_packet);
48 
49  // Flush the PID state (possibly emitting some pending frames)
50  // and reset its state.
51  void Flush();
52 
53  // Enable/disable the PID.
54  // Disabling a PID will reset its state and ignore any further incoming TS
55  // packets.
56  void Enable();
57  void Disable();
58  bool IsEnabled() const;
59 
60  PidType pid_type() const { return pid_type_; }
61 
62  scoped_refptr<StreamInfo>& config() { return config_; }
63  void set_config(const scoped_refptr<StreamInfo>& config) { config_ = config; }
64 
65  SampleQueue& sample_queue() { return sample_queue_; }
66 
67  private:
68  void ResetState();
69 
70  int pid_;
71  PidType pid_type_;
72  scoped_ptr<TsSection> section_parser_;
73 
74  bool enable_;
75  int continuity_counter_;
76  scoped_refptr<StreamInfo> config_;
77  SampleQueue sample_queue_;
78 };
79 
80 PidState::PidState(int pid, PidType pid_type,
81  scoped_ptr<TsSection> section_parser)
82  : pid_(pid),
83  pid_type_(pid_type),
84  section_parser_(section_parser.Pass()),
85  enable_(false),
86  continuity_counter_(-1) {
87  DCHECK(section_parser_);
88 }
89 
90 bool PidState::PushTsPacket(const TsPacket& ts_packet) {
91  DCHECK_EQ(ts_packet.pid(), pid_);
92 
93  // The current PID is not part of the PID filter,
94  // just discard the incoming TS packet.
95  if (!enable_)
96  return true;
97 
98  int expected_continuity_counter = (continuity_counter_ + 1) % 16;
99  if (continuity_counter_ >= 0 &&
100  ts_packet.continuity_counter() != expected_continuity_counter) {
101  DVLOG(1) << "TS discontinuity detected for pid: " << pid_;
102  // TODO(tinskip): Handle discontinuity better.
103  return false;
104  }
105 
106  bool status = section_parser_->Parse(
107  ts_packet.payload_unit_start_indicator(),
108  ts_packet.payload(),
109  ts_packet.payload_size());
110 
111  // At the minimum, when parsing failed, auto reset the section parser.
112  // Components that use the Mp2tMediaParser can take further action if needed.
113  if (!status) {
114  DVLOG(1) << "Parsing failed for pid = " << pid_;
115  ResetState();
116  }
117 
118  return status;
119 }
120 
121 void PidState::Flush() {
122  section_parser_->Flush();
123  ResetState();
124 }
125 
126 void PidState::Enable() {
127  enable_ = true;
128 }
129 
130 void PidState::Disable() {
131  if (!enable_)
132  return;
133 
134  ResetState();
135  enable_ = false;
136 }
137 
138 bool PidState::IsEnabled() const {
139  return enable_;
140 }
141 
142 void PidState::ResetState() {
143  section_parser_->Reset();
144  continuity_counter_ = -1;
145 }
146 
147 Mp2tMediaParser::Mp2tMediaParser()
148  : sbr_in_mimetype_(false),
149  is_initialized_(false) {
150 }
151 
152 Mp2tMediaParser::~Mp2tMediaParser() {
153  STLDeleteValues(&pids_);
154 }
155 
157  const InitCB& init_cb,
158  const NewSampleCB& new_sample_cb,
159  KeySource* decryption_key_source) {
160  DCHECK(!is_initialized_);
161  DCHECK(init_cb_.is_null());
162  DCHECK(!init_cb.is_null());
163  DCHECK(!new_sample_cb.is_null());
164 
165  init_cb_ = init_cb;
166  new_sample_cb_ = new_sample_cb;
167 }
168 
170  DVLOG(1) << "Mp2tMediaParser::Flush";
171 
172  // Flush the buffers and reset the pids.
173  for (std::map<int, PidState*>::iterator it = pids_.begin();
174  it != pids_.end(); ++it) {
175  DVLOG(1) << "Flushing PID: " << it->first;
176  PidState* pid_state = it->second;
177  pid_state->Flush();
178  }
179  bool result = EmitRemainingSamples();
180  STLDeleteValues(&pids_);
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  scoped_ptr<TsPacket> ts_packet(TsPacket::Parse(ts_buffer, ts_buffer_size));
212  if (!ts_packet) {
213  DVLOG(1) << "Error: invalid TS packet";
214  ts_byte_queue_.Pop(1);
215  continue;
216  }
217  DVLOG(LOG_LEVEL_TS)
218  << "Processing PID=" << ts_packet->pid()
219  << " start_unit=" << ts_packet->payload_unit_start_indicator();
220 
221  // Parse the section.
222  std::map<int, PidState*>::iterator it = pids_.find(ts_packet->pid());
223  if (it == pids_.end() &&
224  ts_packet->pid() == TsSection::kPidPat) {
225  // Create the PAT state here if needed.
226  scoped_ptr<TsSection> pat_section_parser(
227  new TsSectionPat(
228  base::Bind(&Mp2tMediaParser::RegisterPmt,
229  base::Unretained(this))));
230  scoped_ptr<PidState> pat_pid_state(
231  new PidState(ts_packet->pid(), PidState::kPidPat,
232  pat_section_parser.Pass()));
233  pat_pid_state->Enable();
234  it = pids_.insert(
235  std::pair<int, PidState*>(ts_packet->pid(),
236  pat_pid_state.release())).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 (std::map<int, PidState*>::iterator it = pids_.begin();
262  it != pids_.end(); ++it) {
263  PidState* pid_state = it->second;
264  if (pid_state->pid_type() == PidState::kPidPmt) {
265  DVLOG_IF(1, pmt_pid != it->first) << "More than one program is defined";
266  return;
267  }
268  }
269 
270  // Create the PMT state here if needed.
271  DVLOG(1) << "Create a new PMT parser";
272  scoped_ptr<TsSection> pmt_section_parser(
273  new TsSectionPmt(
274  base::Bind(&Mp2tMediaParser::RegisterPes,
275  base::Unretained(this), pmt_pid)));
276  scoped_ptr<PidState> pmt_pid_state(
277  new PidState(pmt_pid, PidState::kPidPmt, pmt_section_parser.Pass()));
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  scoped_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 == kStreamTypeAAC) {
304  es_parser.reset(
305  new EsParserAdts(
306  pes_pid,
307  base::Bind(&Mp2tMediaParser::OnNewStreamInfo,
308  base::Unretained(this)),
309  base::Bind(&Mp2tMediaParser::OnEmitSample,
310  base::Unretained(this)),
311  sbr_in_mimetype_));
312  is_audio = true;
313  } else {
314  return;
315  }
316 
317  // Create the PES state here.
318  DVLOG(1) << "Create a new PES state";
319  scoped_ptr<TsSection> pes_section_parser(
320  new TsSectionPes(es_parser.Pass()));
321  PidState::PidType pid_type =
322  is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes;
323  scoped_ptr<PidState> pes_pid_state(
324  new PidState(pes_pid, pid_type, pes_section_parser.Pass()));
325  pes_pid_state->Enable();
326  pids_.insert(std::pair<int, PidState*>(pes_pid, pes_pid_state.release()));
327 }
328 
329 void Mp2tMediaParser::OnNewStreamInfo(
330  const scoped_refptr<StreamInfo>& new_stream_info) {
331  DCHECK(new_stream_info);
332  DVLOG(1) << "OnVideoConfigChanged for pid=" << new_stream_info->track_id();
333 
334  PidMap::iterator pid_state = pids_.find(new_stream_info->track_id());
335  if (pid_state == pids_.end()) {
336  LOG(ERROR) << "PID State for new stream not found (pid = "
337  << new_stream_info->track_id() << ").";
338  return;
339  }
340 
341  // Set the stream configuration information for the PID.
342  pid_state->second->set_config(new_stream_info);
343 
344  // Finish initialization if all streams have configs.
345  FinishInitializationIfNeeded();
346 }
347 
348 bool Mp2tMediaParser::FinishInitializationIfNeeded() {
349  // Nothing to be done if already initialized.
350  if (is_initialized_)
351  return true;
352 
353  // Wait for more data to come to finish initialization.
354  if (pids_.empty())
355  return true;
356 
357  std::vector<scoped_refptr<StreamInfo> > all_stream_info;
358  uint32_t num_es(0);
359  for (PidMap::const_iterator iter = pids_.begin(); iter != pids_.end();
360  ++iter) {
361  if (((iter->second->pid_type() == PidState::kPidAudioPes) ||
362  (iter->second->pid_type() == PidState::kPidVideoPes))) {
363  ++num_es;
364  if (iter->second->config())
365  all_stream_info.push_back(iter->second->config());
366  }
367  }
368  if (num_es && (all_stream_info.size() == num_es)) {
369  // All stream configurations have been received. Initialization can
370  // be completed.
371  init_cb_.Run(all_stream_info);
372  DVLOG(1) << "Mpeg2TS stream parser initialization done";
373  is_initialized_ = true;
374  }
375  return true;
376 }
377 
378 void Mp2tMediaParser::OnEmitSample(
379  uint32_t pes_pid,
380  const scoped_refptr<MediaSample>& new_sample) {
381  DCHECK(new_sample);
382  DVLOG(LOG_LEVEL_ES)
383  << "OnEmitSample: "
384  << " pid="
385  << pes_pid
386  << " size="
387  << new_sample->data_size()
388  << " dts="
389  << new_sample->dts()
390  << " pts="
391  << new_sample->pts();
392 
393  // Add the sample to the appropriate PID sample queue.
394  PidMap::iterator pid_state = pids_.find(pes_pid);
395  if (pid_state == pids_.end()) {
396  LOG(ERROR) << "PID State for new sample not found (pid = "
397  << pes_pid << ").";
398  return;
399  }
400  pid_state->second->sample_queue().push_back(new_sample);
401 }
402 
403 bool Mp2tMediaParser::EmitRemainingSamples() {
404  DVLOG(LOG_LEVEL_ES) << "Mp2tMediaParser::EmitRemainingBuffers";
405 
406  // No buffer should be sent until fully initialized.
407  if (!is_initialized_)
408  return true;
409 
410  // Buffer emission.
411  for (PidMap::const_iterator pid_iter = pids_.begin(); pid_iter != pids_.end();
412  ++pid_iter) {
413  SampleQueue& sample_queue = pid_iter->second->sample_queue();
414  for (SampleQueue::iterator sample_iter = sample_queue.begin();
415  sample_iter != sample_queue.end();
416  ++sample_iter) {
417  if (!new_sample_cb_.Run(pid_iter->first, *sample_iter)) {
418  // Error processing sample. Propagate error condition.
419  return false;
420  }
421  }
422  sample_queue.clear();
423  }
424 
425  return true;
426 }
427 
428 } // namespace mp2t
429 } // namespace media
430 } // namespace edash_packager
bool Flush() override WARN_UNUSED_RESULT
void Push(const uint8_t *data, int size)
Append new bytes to the end of the queue.
Definition: byte_queue.cc:29
KeySource is responsible for encryption key acquisition.
Definition: key_source.h:33
bool Parse(const uint8_t *buf, int size) override WARN_UNUSED_RESULT
void Reset()
Reset the queue to the empty state.
Definition: byte_queue.cc:24
void Init(const InitCB &init_cb, const NewSampleCB &new_sample_cb, KeySource *decryption_key_source) override
void Peek(const uint8_t **data, int *size) const
Definition: byte_queue.cc:63