5 #include "packager/media/formats/mp2t/mp2t_media_parser.h"
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"
22 namespace edash_packager {
28 kStreamTypeMpeg1Audio = 0x3,
30 kStreamTypeAVC = 0x1b,
42 PidState(
int pid, PidType pid_type,
43 scoped_ptr<TsSection> section_parser);
47 bool PushTsPacket(
const TsPacket& ts_packet);
58 bool IsEnabled()
const;
60 PidType pid_type()
const {
return pid_type_; }
62 scoped_refptr<StreamInfo>& config() {
return config_; }
63 void set_config(scoped_refptr<StreamInfo>& config) { config_ = config; }
65 SampleQueue& sample_queue() {
return sample_queue_; }
72 scoped_ptr<TsSection> section_parser_;
75 int continuity_counter_;
76 scoped_refptr<StreamInfo> config_;
77 SampleQueue sample_queue_;
80 PidState::PidState(
int pid, PidType pid_type,
81 scoped_ptr<TsSection> section_parser)
84 section_parser_(section_parser.Pass()),
86 continuity_counter_(-1) {
87 DCHECK(section_parser_);
90 bool PidState::PushTsPacket(
const TsPacket& ts_packet) {
91 DCHECK_EQ(ts_packet.pid(), pid_);
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_;
106 bool status = section_parser_->Parse(
107 ts_packet.payload_unit_start_indicator(),
109 ts_packet.payload_size());
114 DVLOG(1) <<
"Parsing failed for pid = " << pid_;
121 void PidState::Flush() {
122 section_parser_->Flush();
126 void PidState::Enable() {
130 void PidState::Disable() {
138 bool PidState::IsEnabled()
const {
142 void PidState::ResetState() {
143 section_parser_->Reset();
144 continuity_counter_ = -1;
147 Mp2tMediaParser::Mp2tMediaParser()
148 : sbr_in_mimetype_(false),
149 is_initialized_(false) {
152 Mp2tMediaParser::~Mp2tMediaParser() {
153 STLDeleteValues(&pids_);
157 const InitCB& init_cb,
158 const NewSampleCB& new_sample_cb,
160 DCHECK(!is_initialized_);
161 DCHECK(init_cb_.is_null());
162 DCHECK(!init_cb.is_null());
163 DCHECK(!new_sample_cb.is_null());
166 new_sample_cb_ = new_sample_cb;
170 DVLOG(1) <<
"Mp2tMediaParser::Flush";
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;
179 EmitRemainingSamples();
180 STLDeleteValues(&pids_);
184 ts_byte_queue_.
Reset();
188 DVLOG(1) <<
"Mp2tMediaParser::Parse size=" << size;
191 ts_byte_queue_.
Push(buf, size);
194 const uint8_t* ts_buffer;
196 ts_byte_queue_.
Peek(&ts_buffer, &ts_buffer_size);
197 if (ts_buffer_size < TsPacket::kPacketSize)
201 int skipped_bytes = TsPacket::Sync(ts_buffer, ts_buffer_size);
202 if (skipped_bytes > 0) {
203 DVLOG(1) <<
"Packet not aligned on a TS syncword:"
204 <<
" skipped_bytes=" << skipped_bytes;
205 ts_byte_queue_.
Pop(skipped_bytes);
210 scoped_ptr<TsPacket> ts_packet(TsPacket::Parse(ts_buffer, ts_buffer_size));
212 DVLOG(1) <<
"Error: invalid TS packet";
213 ts_byte_queue_.
Pop(1);
217 <<
"Processing PID=" << ts_packet->pid()
218 <<
" start_unit=" << ts_packet->payload_unit_start_indicator();
221 std::map<int, PidState*>::iterator it = pids_.find(ts_packet->pid());
222 if (it == pids_.end() &&
223 ts_packet->pid() == TsSection::kPidPat) {
225 scoped_ptr<TsSection> pat_section_parser(
227 base::Bind(&Mp2tMediaParser::RegisterPmt,
228 base::Unretained(
this))));
229 scoped_ptr<PidState> pat_pid_state(
230 new PidState(ts_packet->pid(), PidState::kPidPat,
231 pat_section_parser.Pass()));
232 pat_pid_state->Enable();
234 std::pair<int, PidState*>(ts_packet->pid(),
235 pat_pid_state.release())).first;
238 if (it != pids_.end()) {
239 if (!it->second->PushTsPacket(*ts_packet))
242 DVLOG(LOG_LEVEL_TS) <<
"Ignoring TS packet for pid: " << ts_packet->pid();
246 ts_byte_queue_.
Pop(TsPacket::kPacketSize);
250 return EmitRemainingSamples();
253 void Mp2tMediaParser::RegisterPmt(
int program_number,
int pmt_pid) {
254 DVLOG(1) <<
"RegisterPmt:"
255 <<
" program_number=" << program_number
256 <<
" pmt_pid=" << pmt_pid;
260 for (std::map<int, PidState*>::iterator it = pids_.begin();
261 it != pids_.end(); ++it) {
262 PidState* pid_state = it->second;
263 if (pid_state->pid_type() == PidState::kPidPmt) {
264 DVLOG_IF(1, pmt_pid != it->first) <<
"More than one program is defined";
270 DVLOG(1) <<
"Create a new PMT parser";
271 scoped_ptr<TsSection> pmt_section_parser(
273 base::Bind(&Mp2tMediaParser::RegisterPes,
274 base::Unretained(
this), pmt_pid)));
275 scoped_ptr<PidState> pmt_pid_state(
276 new PidState(pmt_pid, PidState::kPidPmt, pmt_section_parser.Pass()));
277 pmt_pid_state->Enable();
278 pids_.insert(std::pair<int, PidState*>(pmt_pid, pmt_pid_state.release()));
281 void Mp2tMediaParser::RegisterPes(
int pmt_pid,
284 DVLOG(1) <<
"RegisterPes:"
285 <<
" pes_pid=" << pes_pid
286 <<
" stream_type=" << std::hex << stream_type << std::dec;
287 std::map<int, PidState*>::iterator it = pids_.find(pes_pid);
288 if (it != pids_.end())
292 bool is_audio =
false;
293 scoped_ptr<EsParser> es_parser;
294 if (stream_type == kStreamTypeAVC) {
298 base::Bind(&Mp2tMediaParser::OnNewStreamInfo,
299 base::Unretained(
this)),
300 base::Bind(&Mp2tMediaParser::OnEmitSample,
301 base::Unretained(
this))));
302 }
else if (stream_type == kStreamTypeAAC) {
306 base::Bind(&Mp2tMediaParser::OnNewStreamInfo,
307 base::Unretained(
this)),
308 base::Bind(&Mp2tMediaParser::OnEmitSample,
309 base::Unretained(
this)),
317 DVLOG(1) <<
"Create a new PES state";
318 scoped_ptr<TsSection> pes_section_parser(
319 new TsSectionPes(es_parser.Pass()));
320 PidState::PidType pid_type =
321 is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes;
322 scoped_ptr<PidState> pes_pid_state(
323 new PidState(pes_pid, pid_type, pes_section_parser.Pass()));
324 pes_pid_state->Enable();
325 pids_.insert(std::pair<int, PidState*>(pes_pid, pes_pid_state.release()));
328 void Mp2tMediaParser::OnNewStreamInfo(
329 scoped_refptr<StreamInfo>& new_stream_info) {
330 DCHECK(new_stream_info);
331 DVLOG(1) <<
"OnVideoConfigChanged for pid=" << new_stream_info->track_id();
333 PidMap::iterator pid_state = pids_.find(new_stream_info->track_id());
334 if (pid_state == pids_.end()) {
335 LOG(ERROR) <<
"PID State for new stream not found (pid = "
336 << new_stream_info->track_id() <<
").";
341 pid_state->second->set_config(new_stream_info);
344 FinishInitializationIfNeeded();
347 bool Mp2tMediaParser::FinishInitializationIfNeeded() {
356 std::vector<scoped_refptr<StreamInfo> > all_stream_info;
358 for (PidMap::const_iterator iter = pids_.begin(); iter != pids_.end();
360 if (((iter->second->pid_type() == PidState::kPidAudioPes) ||
361 (iter->second->pid_type() == PidState::kPidVideoPes))) {
363 if (iter->second->config())
364 all_stream_info.push_back(iter->second->config());
367 if (num_es && (all_stream_info.size() == num_es)) {
370 init_cb_.Run(all_stream_info);
371 DVLOG(1) <<
"Mpeg2TS stream parser initialization done";
372 is_initialized_ =
true;
377 void Mp2tMediaParser::OnEmitSample(uint32_t pes_pid,
378 scoped_refptr<MediaSample>& new_sample) {
385 << new_sample->data_size()
389 << new_sample->pts();
392 PidMap::iterator pid_state = pids_.find(pes_pid);
393 if (pid_state == pids_.end()) {
394 LOG(ERROR) <<
"PID State for new sample not found (pid = "
398 pid_state->second->sample_queue().push_back(new_sample);
401 bool Mp2tMediaParser::EmitRemainingSamples() {
402 DVLOG(LOG_LEVEL_ES) <<
"Mp2tMediaParser::EmitRemainingBuffers";
405 if (!is_initialized_)
409 for (PidMap::const_iterator pid_iter = pids_.begin(); pid_iter != pids_.end();
411 SampleQueue& sample_queue = pid_iter->second->sample_queue();
412 for (SampleQueue::iterator sample_iter = sample_queue.begin();
413 sample_iter != sample_queue.end();
415 if (!new_sample_cb_.Run(pid_iter->first, *sample_iter)) {
420 sample_queue.clear();