5#include <packager/media/formats/mp2t/mp2t_media_parser.h>
17#include <absl/log/check.h>
18#include <absl/log/log.h>
20#include <packager/media/base/audio_stream_info.h>
21#include <packager/media/base/media_parser.h>
22#include <packager/media/base/media_sample.h>
23#include <packager/media/base/stream_info.h>
24#include <packager/media/base/text_sample.h>
25#include <packager/media/formats/mp2t/es_parser.h>
26#include <packager/media/formats/mp2t/es_parser_audio.h>
27#include <packager/media/formats/mp2t/es_parser_dvb.h>
28#include <packager/media/formats/mp2t/es_parser_h264.h>
29#include <packager/media/formats/mp2t/es_parser_h265.h>
30#include <packager/media/formats/mp2t/es_parser_teletext.h>
31#include <packager/media/formats/mp2t/mp2t_common.h>
32#include <packager/media/formats/mp2t/ts_audio_type.h>
33#include <packager/media/formats/mp2t/ts_packet.h>
34#include <packager/media/formats/mp2t/ts_section.h>
35#include <packager/media/formats/mp2t/ts_section_pat.h>
36#include <packager/media/formats/mp2t/ts_section_pes.h>
37#include <packager/media/formats/mp2t/ts_section_pmt.h>
38#include <packager/media/formats/mp2t/ts_stream_type.h>
56 std::unique_ptr<TsSection> section_parser);
60 bool PushTsPacket(
const TsPacket& ts_packet);
71 bool IsEnabled()
const;
73 PidType pid_type()
const {
return pid_type_; }
75 std::shared_ptr<StreamInfo>& config() {
return config_; }
76 void set_config(
const std::shared_ptr<StreamInfo>& config) {
81 friend Mp2tMediaParser;
86 std::unique_ptr<TsSection> section_parser_;
88 std::deque<std::shared_ptr<MediaSample>> media_sample_queue_;
89 std::deque<std::shared_ptr<TextSample>> text_sample_queue_;
92 int continuity_counter_;
93 std::shared_ptr<StreamInfo> config_;
96PidState::PidState(
int pid,
98 std::unique_ptr<TsSection> section_parser)
101 section_parser_(std::move(section_parser)),
103 continuity_counter_(-1) {
104 DCHECK(section_parser_);
107bool PidState::PushTsPacket(
const TsPacket& ts_packet) {
108 DCHECK_EQ(ts_packet.pid(), pid_);
115 int expected_continuity_counter = (continuity_counter_ + 1) % 16;
116 if (continuity_counter_ >= 0 &&
117 ts_packet.continuity_counter() != expected_continuity_counter) {
118 LOG(ERROR) <<
"TS discontinuity detected for pid: " << pid_;
124 section_parser_->Parse(ts_packet.payload_unit_start_indicator(),
125 ts_packet.payload(), ts_packet.payload_size());
130 LOG(ERROR) <<
"Parsing failed for pid = " << pid_ <<
", type=" << pid_type_;
137bool PidState::Flush() {
138 RCHECK(section_parser_->Flush());
143void PidState::Enable() {
147void PidState::Disable() {
155bool PidState::IsEnabled()
const {
159void PidState::ResetState() {
160 section_parser_->Reset();
161 continuity_counter_ = -1;
164Mp2tMediaParser::Mp2tMediaParser()
165 : sbr_in_mimetype_(false), is_initialized_(false) {}
167Mp2tMediaParser::~Mp2tMediaParser() {}
169void Mp2tMediaParser::Init(
const InitCB& init_cb,
173 DCHECK(!is_initialized_);
174 DCHECK(init_cb_ ==
nullptr);
175 DCHECK(init_cb !=
nullptr);
176 DCHECK(new_media_sample_cb !=
nullptr);
177 DCHECK(new_text_sample_cb !=
nullptr);
180 new_media_sample_cb_ = new_media_sample_cb;
181 new_text_sample_cb_ = new_text_sample_cb;
184bool Mp2tMediaParser::Flush() {
185 DVLOG(1) <<
"Mp2tMediaParser::Flush";
188 for (
const auto& pair : pids_) {
189 DVLOG(1) <<
"Flushing PID: " << pair.first;
190 PidState* pid_state = pair.second.get();
191 RCHECK(pid_state->Flush());
193 bool result = EmitRemainingSamples();
198 ts_byte_queue_.Reset();
202bool Mp2tMediaParser::Parse(
const uint8_t* buf,
int size) {
203 DVLOG(2) <<
"Mp2tMediaParser::Parse size=" << size;
206 ts_byte_queue_.Push(buf, size);
209 const uint8_t* ts_buffer;
211 ts_byte_queue_.Peek(&ts_buffer, &ts_buffer_size);
212 if (ts_buffer_size < TsPacket::kPacketSize)
216 int skipped_bytes = TsPacket::Sync(ts_buffer, ts_buffer_size);
217 if (skipped_bytes > 0) {
218 DVLOG(1) <<
"Packet not aligned on a TS syncword:"
219 <<
" skipped_bytes=" << skipped_bytes;
220 ts_byte_queue_.Pop(skipped_bytes);
225 std::unique_ptr<TsPacket> ts_packet(
226 TsPacket::Parse(ts_buffer, ts_buffer_size));
228 DVLOG(1) <<
"Error: invalid TS packet";
229 ts_byte_queue_.Pop(1);
232 DVLOG(LOG_LEVEL_TS) <<
"Processing PID=" << ts_packet->pid()
234 << ts_packet->payload_unit_start_indicator()
235 <<
" continuity_counter="
236 << ts_packet->continuity_counter();
238 auto it = pids_.find(ts_packet->pid());
239 if (it == pids_.end() && ts_packet->pid() == TsSection::kPidPat) {
241 std::unique_ptr<TsSection> pat_section_parser(
new TsSectionPat(
242 std::bind(&Mp2tMediaParser::RegisterPmt,
this, std::placeholders::_1,
243 std::placeholders::_2)));
244 std::unique_ptr<PidState> pat_pid_state(
new PidState(
245 ts_packet->pid(), PidState::kPidPat, std::move(pat_section_parser)));
246 pat_pid_state->Enable();
247 it = pids_.emplace(ts_packet->pid(), std::move(pat_pid_state)).first;
250 if (it != pids_.end()) {
251 RCHECK(it->second->PushTsPacket(*ts_packet));
253 DVLOG(LOG_LEVEL_TS) <<
"Ignoring TS packet for pid: " << ts_packet->pid();
257 ts_byte_queue_.Pop(TsPacket::kPacketSize);
261 return EmitRemainingSamples();
264void Mp2tMediaParser::RegisterPmt(
int program_number,
int pmt_pid) {
265 DVLOG(1) <<
"RegisterPmt:"
266 <<
" program_number=" << program_number <<
" pmt_pid=" << pmt_pid;
270 for (
const auto& pair : pids_) {
271 if (pair.second->pid_type() == PidState::kPidPmt) {
272 if (pmt_pid != pair.first) {
273 DVLOG(1) <<
"More than one program is defined";
280 DVLOG(1) <<
"Create a new PMT parser";
281 std::unique_ptr<TsSection> pmt_section_parser(
new TsSectionPmt(std::bind(
282 &Mp2tMediaParser::RegisterPes,
this, pmt_pid, std::placeholders::_1,
283 std::placeholders::_2, std::placeholders::_3, std::placeholders::_4,
284 std::placeholders::_5, std::placeholders::_6, std::placeholders::_7)));
285 std::unique_ptr<PidState> pmt_pid_state(
286 new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser)));
287 pmt_pid_state->Enable();
288 pids_.emplace(pmt_pid, std::move(pmt_pid_state));
291void Mp2tMediaParser::RegisterPes(
int pmt_pid,
293 TsStreamType stream_type,
294 uint32_t max_bitrate,
295 const std::string& lang,
296 TsAudioType audio_type,
297 const uint8_t* descriptor,
298 size_t descriptor_length) {
299 if (pids_.count(pes_pid) != 0)
301 DVLOG(1) <<
"RegisterPes:"
302 <<
" pes_pid=" << pes_pid <<
" stream_type=" << std::hex
303 <<
static_cast<int>(stream_type) << std::dec
304 <<
"max_bitrate=" << max_bitrate <<
" lang=" << lang
305 <<
"audio_type=" << std::hex <<
static_cast<int>(audio_type)
309 PidState::PidType pid_type = PidState::kPidVideoPes;
310 std::unique_ptr<EsParser> es_parser;
311 auto on_new_stream = std::bind(&Mp2tMediaParser::OnNewStreamInfo,
this,
312 pes_pid, std::placeholders::_1);
313 auto on_emit_media = std::bind(&Mp2tMediaParser::OnEmitMediaSample,
this,
314 pes_pid, std::placeholders::_1);
315 auto on_emit_text = std::bind(&Mp2tMediaParser::OnEmitTextSample,
this,
316 pes_pid, std::placeholders::_1);
317 switch (stream_type) {
318 case TsStreamType::kAvc:
319 es_parser.reset(
new EsParserH264(pes_pid, on_new_stream, on_emit_media));
321 case TsStreamType::kHevc:
322 es_parser.reset(
new EsParserH265(pes_pid, on_new_stream, on_emit_media));
324 case TsStreamType::kAdtsAac:
325 case TsStreamType::kMpeg1Audio:
326 case TsStreamType::kAc3:
328 new EsParserAudio(pes_pid,
static_cast<TsStreamType
>(stream_type),
329 on_new_stream, on_emit_media, sbr_in_mimetype_));
330 pid_type = PidState::kPidAudioPes;
332 case TsStreamType::kDvbSubtitles:
333 es_parser.reset(
new EsParserDvb(pes_pid, on_new_stream, on_emit_text,
334 descriptor, descriptor_length));
335 pid_type = PidState::kPidTextPes;
337 case TsStreamType::kTeletextSubtitles:
338 es_parser.reset(
new EsParserTeletext(pes_pid, on_new_stream, on_emit_text,
339 descriptor, descriptor_length));
340 pid_type = PidState::kPidTextPes;
344 auto type =
static_cast<int>(stream_type);
345 DCHECK(type <= 0xff);
346 LOG_IF(ERROR, !stream_type_logged_once_[type])
347 <<
"Ignore unsupported MPEG2TS stream type 0x" << std::hex << type
349 stream_type_logged_once_[type] =
true;
355 DVLOG(1) <<
"Create a new PES state";
356 std::unique_ptr<TsSection> pes_section_parser(
357 new TsSectionPes(std::move(es_parser)));
358 std::unique_ptr<PidState> pes_pid_state(
359 new PidState(pes_pid, pid_type, std::move(pes_section_parser)));
360 pes_pid_state->Enable();
361 pids_.emplace(pes_pid, std::move(pes_pid_state));
364 pes_metadata_.insert(
365 std::make_pair(pes_pid, PesMetadata{max_bitrate, lang, audio_type}));
368 if (pid_type == PidState::kPidTextPes) {
369 text_pids_.insert(pes_pid);
373void Mp2tMediaParser::OnNewStreamInfo(
375 std::shared_ptr<StreamInfo> new_stream_info) {
376 DCHECK(!new_stream_info || new_stream_info->track_id() == pes_pid);
377 DVLOG(1) <<
"OnVideoConfigChanged for pid=" << pes_pid
378 <<
", has_info=" << (new_stream_info ?
"true" :
"false");
380 auto pid_state = pids_.find(pes_pid);
381 if (pid_state == pids_.end()) {
382 LOG(ERROR) <<
"PID State for new stream not found (pid = "
383 << new_stream_info->track_id() <<
").";
387 if (new_stream_info) {
389 auto pes_metadata = pes_metadata_.find(pes_pid);
390 DCHECK(pes_metadata != pes_metadata_.end());
391 if (!pes_metadata->second.language.empty())
392 new_stream_info->set_language(pes_metadata->second.language);
393 if (new_stream_info->stream_type() == kStreamAudio) {
394 auto* audio_info =
static_cast<AudioStreamInfo*
>(new_stream_info.get());
395 audio_info->set_max_bitrate(pes_metadata->second.max_bitrate);
400 pid_state->second->set_config(new_stream_info);
402 LOG(WARNING) <<
"Ignoring unsupported stream with pid=" << pes_pid;
403 pid_state->second->Disable();
407 FinishInitializationIfNeeded();
410bool Mp2tMediaParser::FinishInitializationIfNeeded() {
419 std::vector<std::shared_ptr<StreamInfo>> all_stream_info;
421 for (
const auto& pair : pids_) {
422 if ((pair.second->pid_type() == PidState::kPidAudioPes ||
423 pair.second->pid_type() == PidState::kPidVideoPes ||
424 pair.second->pid_type() == PidState::kPidTextPes) &&
425 pair.second->IsEnabled()) {
427 if (pair.second->config())
428 all_stream_info.push_back(pair.second->config());
431 if (num_es && (all_stream_info.size() == num_es)) {
434 init_cb_(all_stream_info);
435 DVLOG(1) <<
"Mpeg2TS stream parser initialization done";
436 is_initialized_ =
true;
441void Mp2tMediaParser::OnEmitMediaSample(
443 std::shared_ptr<MediaSample> new_sample) {
445 DVLOG(LOG_LEVEL_ES) <<
"OnEmitMediaSample: "
446 <<
" pid=" << pes_pid
447 <<
" size=" << new_sample->data_size()
448 <<
" dts=" << new_sample->dts()
449 <<
" pts=" << new_sample->pts();
452 auto pid_state = pids_.find(pes_pid);
453 if (pid_state == pids_.end()) {
454 LOG(ERROR) <<
"PID State for new sample not found (pid = " << pes_pid
461 int64_t timestamp_for_heartbeat = new_sample->pts();
462 if (pid_state->second->pid_type() == PidState::kPidVideoPes) {
465 timestamp_for_heartbeat = new_sample->dts();
466 if (timestamp_for_heartbeat == 0) {
467 timestamp_for_heartbeat = new_sample->pts();
472 update_biggest_pts(timestamp_for_heartbeat);
473 pid_state->second->media_sample_queue_.push_back(std::move(new_sample));
476void Mp2tMediaParser::OnEmitTextSample(uint32_t pes_pid,
477 std::shared_ptr<TextSample> new_sample) {
479 DVLOG(LOG_LEVEL_ES) <<
"OnEmitTextSample: "
480 <<
" pid=" << pes_pid
481 <<
" start=" << new_sample->start_time();
484 auto pid_state = pids_.find(pes_pid);
485 if (pid_state == pids_.end()) {
486 LOG(ERROR) <<
"PID State for new sample not found (pid = " << pes_pid
495 pid_state->second->text_sample_queue_.push_back(std::move(new_sample));
498bool Mp2tMediaParser::EmitRemainingSamples() {
499 DVLOG(LOG_LEVEL_ES) <<
"Mp2tMediaParser::EmitRemainingBuffers";
502 if (!is_initialized_)
506 for (
const auto& pid_pair : pids_) {
507 for (
auto sample : pid_pair.second->media_sample_queue_) {
508 RCHECK(new_media_sample_cb_(pid_pair.first, sample));
510 pid_pair.second->media_sample_queue_.clear();
512 DVLOG(2) <<
"EmitRemainingSamples: text_sample_queue_ size="
513 << pid_pair.second->text_sample_queue_.size();
514 for (
auto sample : pid_pair.second->text_sample_queue_) {
515 DVLOG(2) <<
"Emitting text sample: role="
516 <<
static_cast<int>(sample->role())
517 <<
" pts=" << sample->start_time()
518 <<
" is_empty=" << sample->is_empty();
519 bool result = new_text_sample_cb_(pid_pair.first, sample);
520 DVLOG(3) <<
"new_text_sample_cb_ returned: " << result;
523 pid_pair.second->text_sample_queue_.clear();
529void Mp2tMediaParser::update_biggest_pts(int64_t pts) {
530 if (pts >= biggest_pts_ + 9000) {
532 for (
auto pid : text_pids_) {
533 auto pid_state = pids_.find(pid);
534 if (pid_state == pids_.end()) {
535 LOG(ERROR) <<
"PID State for new sample not found (text pid = " << pid
539 TextSettings text_settings;
540 auto heartbeat = std::make_shared<TextSample>(
541 "", pts, pts, text_settings, TextFragment({},
""),
542 TextSampleRole::kMediaHeartBeat);
545 heartbeat->set_sub_stream_index(pid);
546 OnEmitTextSample(uint32_t(pid), heartbeat);
All the methods that are virtual are virtual for mocking.