5 #include "packager/media/formats/mp2t/mp2t_media_parser.h" 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_audio.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 #include "packager/media/formats/mp2t/ts_stream_type.h" 38 std::unique_ptr<TsSection> section_parser);
42 bool PushTsPacket(
const TsPacket& ts_packet);
53 bool IsEnabled()
const;
55 PidType pid_type()
const {
return pid_type_; }
57 std::shared_ptr<StreamInfo>& config() {
return config_; }
58 void set_config(
const std::shared_ptr<StreamInfo>& config) {
62 SampleQueue& sample_queue() {
return sample_queue_; }
69 std::unique_ptr<TsSection> section_parser_;
72 int continuity_counter_;
73 std::shared_ptr<StreamInfo> config_;
74 SampleQueue sample_queue_;
77 PidState::PidState(
int pid,
79 std::unique_ptr<TsSection> section_parser)
82 section_parser_(
std::move(section_parser)),
84 continuity_counter_(-1) {
85 DCHECK(section_parser_);
88 bool PidState::PushTsPacket(
const TsPacket& ts_packet) {
89 DCHECK_EQ(ts_packet.pid(), pid_);
96 int expected_continuity_counter = (continuity_counter_ + 1) % 16;
97 if (continuity_counter_ >= 0 &&
98 ts_packet.continuity_counter() != expected_continuity_counter) {
99 DVLOG(1) <<
"TS discontinuity detected for pid: " << pid_;
104 bool status = section_parser_->Parse(
105 ts_packet.payload_unit_start_indicator(),
107 ts_packet.payload_size());
112 DVLOG(1) <<
"Parsing failed for pid = " << pid_;
119 void PidState::Flush() {
120 section_parser_->Flush();
124 void PidState::Enable() {
128 void PidState::Disable() {
136 bool PidState::IsEnabled()
const {
140 void PidState::ResetState() {
141 section_parser_->Reset();
142 continuity_counter_ = -1;
145 Mp2tMediaParser::Mp2tMediaParser()
146 : sbr_in_mimetype_(false),
147 is_initialized_(false) {
150 Mp2tMediaParser::~Mp2tMediaParser() {}
156 DCHECK(!is_initialized_);
157 DCHECK(init_cb_.is_null());
158 DCHECK(!init_cb.is_null());
159 DCHECK(!new_sample_cb.is_null());
162 new_sample_cb_ = new_sample_cb;
166 DVLOG(1) <<
"Mp2tMediaParser::Flush";
169 for (
const auto& pair : pids_) {
170 DVLOG(1) <<
"Flushing PID: " << pair.first;
171 PidState* pid_state = pair.second.get();
174 bool result = EmitRemainingSamples();
179 ts_byte_queue_.Reset();
184 DVLOG(1) <<
"Mp2tMediaParser::Parse size=" << size;
187 ts_byte_queue_.Push(buf, size);
190 const uint8_t* ts_buffer;
192 ts_byte_queue_.Peek(&ts_buffer, &ts_buffer_size);
193 if (ts_buffer_size < TsPacket::kPacketSize)
197 int skipped_bytes = TsPacket::Sync(ts_buffer, ts_buffer_size);
198 if (skipped_bytes > 0) {
199 DVLOG(1) <<
"Packet not aligned on a TS syncword:" 200 <<
" skipped_bytes=" << skipped_bytes;
201 ts_byte_queue_.Pop(skipped_bytes);
206 std::unique_ptr<TsPacket> ts_packet(
207 TsPacket::Parse(ts_buffer, ts_buffer_size));
209 DVLOG(1) <<
"Error: invalid TS packet";
210 ts_byte_queue_.Pop(1);
214 <<
"Processing PID=" << ts_packet->pid()
215 <<
" start_unit=" << ts_packet->payload_unit_start_indicator();
218 std::map<int, std::unique_ptr<PidState>>::iterator it =
219 pids_.find(ts_packet->pid());
220 if (it == pids_.end() &&
221 ts_packet->pid() == TsSection::kPidPat) {
223 std::unique_ptr<TsSection> pat_section_parser(
new TsSectionPat(
224 base::Bind(&Mp2tMediaParser::RegisterPmt, base::Unretained(
this))));
225 std::unique_ptr<PidState> pat_pid_state(
new PidState(
226 ts_packet->pid(), PidState::kPidPat, std::move(pat_section_parser)));
227 pat_pid_state->Enable();
229 .insert(std::pair<
int, std::unique_ptr<PidState>>(
230 ts_packet->pid(), std::move(pat_pid_state)))
234 if (it != pids_.end()) {
235 if (!it->second->PushTsPacket(*ts_packet))
238 DVLOG(LOG_LEVEL_TS) <<
"Ignoring TS packet for pid: " << ts_packet->pid();
242 ts_byte_queue_.Pop(TsPacket::kPacketSize);
246 return EmitRemainingSamples();
249 void Mp2tMediaParser::RegisterPmt(
int program_number,
int pmt_pid) {
250 DVLOG(1) <<
"RegisterPmt:" 251 <<
" program_number=" << program_number
252 <<
" pmt_pid=" << pmt_pid;
256 for (
const auto& pair : pids_) {
257 if (pair.second->pid_type() == PidState::kPidPmt) {
258 DVLOG_IF(1, pmt_pid != pair.first) <<
"More than one program is defined";
264 DVLOG(1) <<
"Create a new PMT parser";
265 std::unique_ptr<TsSection> pmt_section_parser(
new TsSectionPmt(base::Bind(
266 &Mp2tMediaParser::RegisterPes, base::Unretained(
this), pmt_pid)));
267 std::unique_ptr<PidState> pmt_pid_state(
268 new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser)));
269 pmt_pid_state->Enable();
270 pids_.insert(std::pair<
int, std::unique_ptr<PidState>>(
271 pmt_pid, std::move(pmt_pid_state)));
274 void Mp2tMediaParser::RegisterPes(
int pmt_pid,
277 DVLOG(1) <<
"RegisterPes:" 278 <<
" pes_pid=" << pes_pid
279 <<
" stream_type=" << std::hex << stream_type << std::dec;
280 std::map<int, std::unique_ptr<PidState>>::iterator it = pids_.find(pes_pid);
281 if (it != pids_.end())
285 bool is_audio =
false;
286 std::unique_ptr<EsParser> es_parser;
287 switch (static_cast<TsStreamType>(stream_type)) {
288 case TsStreamType::kAvc:
291 base::Bind(&Mp2tMediaParser::OnNewStreamInfo, base::Unretained(
this)),
292 base::Bind(&Mp2tMediaParser::OnEmitSample, base::Unretained(
this))));
294 case TsStreamType::kHevc:
297 base::Bind(&Mp2tMediaParser::OnNewStreamInfo, base::Unretained(
this)),
298 base::Bind(&Mp2tMediaParser::OnEmitSample, base::Unretained(
this))));
300 case TsStreamType::kAdtsAac:
301 case TsStreamType::kAc3:
303 pes_pid, static_cast<TsStreamType>(stream_type),
304 base::Bind(&Mp2tMediaParser::OnNewStreamInfo, base::Unretained(
this)),
305 base::Bind(&Mp2tMediaParser::OnEmitSample, base::Unretained(
this)),
310 LOG_IF(ERROR, !stream_type_logged_once_[stream_type])
311 <<
"Ignore unsupported MPEG2TS stream type 0x" << std::hex
312 << stream_type << std::dec;
313 stream_type_logged_once_[stream_type] =
true;
319 DVLOG(1) <<
"Create a new PES state";
320 std::unique_ptr<TsSection> pes_section_parser(
322 PidState::PidType pid_type =
323 is_audio ? PidState::kPidAudioPes : PidState::kPidVideoPes;
324 std::unique_ptr<PidState> pes_pid_state(
325 new PidState(pes_pid, pid_type, std::move(pes_section_parser)));
326 pes_pid_state->Enable();
327 pids_.insert(std::pair<
int, std::unique_ptr<PidState>>(
328 pes_pid, std::move(pes_pid_state)));
331 void Mp2tMediaParser::OnNewStreamInfo(
332 const std::shared_ptr<StreamInfo>& new_stream_info) {
333 DCHECK(new_stream_info);
334 DVLOG(1) <<
"OnVideoConfigChanged for pid=" << new_stream_info->track_id();
336 PidMap::iterator pid_state = pids_.find(new_stream_info->track_id());
337 if (pid_state == pids_.end()) {
338 LOG(ERROR) <<
"PID State for new stream not found (pid = " 339 << new_stream_info->track_id() <<
").";
344 pid_state->second->set_config(new_stream_info);
347 FinishInitializationIfNeeded();
350 bool Mp2tMediaParser::FinishInitializationIfNeeded() {
359 std::vector<std::shared_ptr<StreamInfo>> all_stream_info;
361 for (PidMap::const_iterator iter = pids_.begin(); iter != pids_.end();
363 if (((iter->second->pid_type() == PidState::kPidAudioPes) ||
364 (iter->second->pid_type() == PidState::kPidVideoPes))) {
366 if (iter->second->config())
367 all_stream_info.push_back(iter->second->config());
370 if (num_es && (all_stream_info.size() == num_es)) {
373 init_cb_.Run(all_stream_info);
374 DVLOG(1) <<
"Mpeg2TS stream parser initialization done";
375 is_initialized_ =
true;
380 void Mp2tMediaParser::OnEmitSample(
382 const std::shared_ptr<MediaSample>& new_sample) {
389 << new_sample->data_size()
393 << new_sample->pts();
396 PidMap::iterator pid_state = pids_.find(pes_pid);
397 if (pid_state == pids_.end()) {
398 LOG(ERROR) <<
"PID State for new sample not found (pid = " 402 pid_state->second->sample_queue().push_back(new_sample);
405 bool Mp2tMediaParser::EmitRemainingSamples() {
406 DVLOG(LOG_LEVEL_ES) <<
"Mp2tMediaParser::EmitRemainingBuffers";
409 if (!is_initialized_)
413 for (PidMap::const_iterator pid_iter = pids_.begin(); pid_iter != pids_.end();
415 SampleQueue& sample_queue = pid_iter->second->sample_queue();
416 for (SampleQueue::iterator sample_iter = sample_queue.begin();
417 sample_iter != sample_queue.end();
419 if (!new_sample_cb_.Run(pid_iter->first, *sample_iter)) {
424 sample_queue.clear();
All the methods that are virtual are virtual for mocking.