5 #include "packager/media/formats/mp2t/mp2t_media_parser.h"
9 #include "packager/base/bind.h"
10 #include "packager/media/base/media_sample.h"
11 #include "packager/media/base/stream_info.h"
12 #include "packager/media/base/text_sample.h"
13 #include "packager/media/formats/mp2t/es_parser.h"
14 #include "packager/media/formats/mp2t/es_parser_audio.h"
15 #include "packager/media/formats/mp2t/es_parser_dvb.h"
16 #include "packager/media/formats/mp2t/es_parser_h264.h"
17 #include "packager/media/formats/mp2t/es_parser_h265.h"
18 #include "packager/media/formats/mp2t/mp2t_common.h"
19 #include "packager/media/formats/mp2t/ts_packet.h"
20 #include "packager/media/formats/mp2t/ts_section.h"
21 #include "packager/media/formats/mp2t/ts_section_pat.h"
22 #include "packager/media/formats/mp2t/ts_section_pes.h"
23 #include "packager/media/formats/mp2t/ts_section_pmt.h"
24 #include "packager/media/formats/mp2t/ts_stream_type.h"
42 std::unique_ptr<TsSection> section_parser);
46 bool PushTsPacket(
const TsPacket& ts_packet);
57 bool IsEnabled()
const;
59 PidType pid_type()
const {
return pid_type_; }
61 std::shared_ptr<StreamInfo>& config() {
return config_; }
62 void set_config(
const std::shared_ptr<StreamInfo>& config) {
67 friend Mp2tMediaParser;
72 std::unique_ptr<TsSection> section_parser_;
74 std::deque<std::shared_ptr<MediaSample>> media_sample_queue_;
75 std::deque<std::shared_ptr<TextSample>> text_sample_queue_;
78 int continuity_counter_;
79 std::shared_ptr<StreamInfo> config_;
82 PidState::PidState(
int pid,
84 std::unique_ptr<TsSection> section_parser)
87 section_parser_(std::move(section_parser)),
89 continuity_counter_(-1) {
90 DCHECK(section_parser_);
93 bool PidState::PushTsPacket(
const TsPacket& ts_packet) {
94 DCHECK_EQ(ts_packet.pid(), pid_);
101 int expected_continuity_counter = (continuity_counter_ + 1) % 16;
102 if (continuity_counter_ >= 0 &&
103 ts_packet.continuity_counter() != expected_continuity_counter) {
104 LOG(ERROR) <<
"TS discontinuity detected for pid: " << pid_;
109 bool status = section_parser_->Parse(
110 ts_packet.payload_unit_start_indicator(),
112 ts_packet.payload_size());
117 LOG(ERROR) <<
"Parsing failed for pid = " << pid_ <<
", type=" << pid_type_;
124 bool PidState::Flush() {
125 RCHECK(section_parser_->Flush());
130 void PidState::Enable() {
134 void PidState::Disable() {
142 bool PidState::IsEnabled()
const {
146 void PidState::ResetState() {
147 section_parser_->Reset();
148 continuity_counter_ = -1;
151 Mp2tMediaParser::Mp2tMediaParser()
152 : sbr_in_mimetype_(false),
153 is_initialized_(false) {
156 Mp2tMediaParser::~Mp2tMediaParser() {}
158 void Mp2tMediaParser::Init(
const InitCB& init_cb,
162 DCHECK(!is_initialized_);
163 DCHECK(init_cb_.is_null());
164 DCHECK(!init_cb.is_null());
165 DCHECK(!new_media_sample_cb.is_null());
166 DCHECK(!new_text_sample_cb.is_null());
169 new_media_sample_cb_ = new_media_sample_cb;
170 new_text_sample_cb_ = new_text_sample_cb;
173 bool Mp2tMediaParser::Flush() {
174 DVLOG(1) <<
"Mp2tMediaParser::Flush";
177 for (
const auto& pair : pids_) {
178 DVLOG(1) <<
"Flushing PID: " << pair.first;
179 PidState* pid_state = pair.second.get();
180 RCHECK(pid_state->Flush());
182 bool result = EmitRemainingSamples();
187 ts_byte_queue_.Reset();
191 bool Mp2tMediaParser::Parse(
const uint8_t* buf,
int size) {
192 DVLOG(2) <<
"Mp2tMediaParser::Parse size=" << size;
195 ts_byte_queue_.Push(buf, size);
198 const uint8_t* ts_buffer;
200 ts_byte_queue_.Peek(&ts_buffer, &ts_buffer_size);
201 if (ts_buffer_size < TsPacket::kPacketSize)
205 int skipped_bytes = TsPacket::Sync(ts_buffer, ts_buffer_size);
206 if (skipped_bytes > 0) {
207 DVLOG(1) <<
"Packet not aligned on a TS syncword:"
208 <<
" skipped_bytes=" << skipped_bytes;
209 ts_byte_queue_.Pop(skipped_bytes);
214 std::unique_ptr<TsPacket> ts_packet(
215 TsPacket::Parse(ts_buffer, ts_buffer_size));
217 DVLOG(1) <<
"Error: invalid TS packet";
218 ts_byte_queue_.Pop(1);
222 <<
"Processing PID=" << ts_packet->pid()
223 <<
" start_unit=" << ts_packet->payload_unit_start_indicator();
226 auto it = pids_.find(ts_packet->pid());
227 if (it == pids_.end() &&
228 ts_packet->pid() == TsSection::kPidPat) {
230 std::unique_ptr<TsSection> pat_section_parser(
new TsSectionPat(
231 base::Bind(&Mp2tMediaParser::RegisterPmt, base::Unretained(
this))));
232 std::unique_ptr<PidState> pat_pid_state(
new PidState(
233 ts_packet->pid(), PidState::kPidPat, std::move(pat_section_parser)));
234 pat_pid_state->Enable();
235 it = pids_.emplace(ts_packet->pid(), std::move(pat_pid_state)).first;
238 if (it != pids_.end()) {
239 RCHECK(it->second->PushTsPacket(*ts_packet));
241 DVLOG(LOG_LEVEL_TS) <<
"Ignoring TS packet for pid: " << ts_packet->pid();
245 ts_byte_queue_.Pop(TsPacket::kPacketSize);
249 return EmitRemainingSamples();
252 void Mp2tMediaParser::RegisterPmt(
int program_number,
int pmt_pid) {
253 DVLOG(1) <<
"RegisterPmt:"
254 <<
" program_number=" << program_number
255 <<
" pmt_pid=" << pmt_pid;
259 for (
const auto& pair : pids_) {
260 if (pair.second->pid_type() == PidState::kPidPmt) {
261 DVLOG_IF(1, pmt_pid != pair.first) <<
"More than one program is defined";
267 DVLOG(1) <<
"Create a new PMT parser";
268 std::unique_ptr<TsSection> pmt_section_parser(
new TsSectionPmt(base::Bind(
269 &Mp2tMediaParser::RegisterPes, base::Unretained(
this), pmt_pid)));
270 std::unique_ptr<PidState> pmt_pid_state(
271 new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser)));
272 pmt_pid_state->Enable();
273 pids_.emplace(pmt_pid, std::move(pmt_pid_state));
276 void Mp2tMediaParser::RegisterPes(
int pmt_pid,
278 TsStreamType stream_type,
279 const uint8_t* descriptor,
280 size_t descriptor_length) {
281 if (pids_.count(pes_pid) != 0)
283 DVLOG(1) <<
"RegisterPes:"
284 <<
" pes_pid=" << pes_pid <<
" stream_type=" << std::hex
285 <<
static_cast<int>(stream_type) << std::dec;
288 PidState::PidType pid_type = PidState::kPidVideoPes;
289 std::unique_ptr<EsParser> es_parser;
290 auto on_new_stream = base::Bind(&Mp2tMediaParser::OnNewStreamInfo,
291 base::Unretained(
this), pes_pid);
292 auto on_emit_media = base::Bind(&Mp2tMediaParser::OnEmitMediaSample,
293 base::Unretained(
this), pes_pid);
294 auto on_emit_text = base::Bind(&Mp2tMediaParser::OnEmitTextSample,
295 base::Unretained(
this), pes_pid);
296 switch (stream_type) {
297 case TsStreamType::kAvc:
298 es_parser.reset(
new EsParserH264(pes_pid, on_new_stream, on_emit_media));
300 case TsStreamType::kHevc:
301 es_parser.reset(
new EsParserH265(pes_pid, on_new_stream, on_emit_media));
303 case TsStreamType::kAdtsAac:
304 case TsStreamType::kMpeg1Audio:
305 case TsStreamType::kAc3:
307 new EsParserAudio(pes_pid,
static_cast<TsStreamType
>(stream_type),
308 on_new_stream, on_emit_media, sbr_in_mimetype_));
309 pid_type = PidState::kPidAudioPes;
311 case TsStreamType::kDvbSubtitles:
312 es_parser.reset(
new EsParserDvb(pes_pid, on_new_stream, on_emit_text,
313 descriptor, descriptor_length));
314 pid_type = PidState::kPidTextPes;
317 auto type =
static_cast<int>(stream_type);
318 DCHECK(type <= 0xff);
319 LOG_IF(ERROR, !stream_type_logged_once_[type])
320 <<
"Ignore unsupported MPEG2TS stream type 0x" << std::hex << type
322 stream_type_logged_once_[type] =
true;
328 DVLOG(1) <<
"Create a new PES state";
329 std::unique_ptr<TsSection> pes_section_parser(
330 new TsSectionPes(std::move(es_parser)));
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_.emplace(pes_pid, std::move(pes_pid_state));
337 void Mp2tMediaParser::OnNewStreamInfo(
339 std::shared_ptr<StreamInfo> new_stream_info) {
340 DCHECK(!new_stream_info || new_stream_info->track_id() == pes_pid);
341 DVLOG(1) <<
"OnVideoConfigChanged for pid=" << pes_pid
342 <<
", has_info=" << (new_stream_info ?
"true" :
"false");
344 auto pid_state = pids_.find(pes_pid);
345 if (pid_state == pids_.end()) {
346 LOG(ERROR) <<
"PID State for new stream not found (pid = "
347 << new_stream_info->track_id() <<
").";
351 if (new_stream_info) {
353 pid_state->second->set_config(new_stream_info);
355 LOG(WARNING) <<
"Ignoring unsupported stream with pid=" << pes_pid;
356 pid_state->second->Disable();
360 FinishInitializationIfNeeded();
363 bool Mp2tMediaParser::FinishInitializationIfNeeded() {
372 std::vector<std::shared_ptr<StreamInfo>> all_stream_info;
374 for (
const auto& pair : pids_) {
375 if ((pair.second->pid_type() == PidState::kPidAudioPes ||
376 pair.second->pid_type() == PidState::kPidVideoPes ||
377 pair.second->pid_type() == PidState::kPidTextPes) &&
378 pair.second->IsEnabled()) {
380 if (pair.second->config())
381 all_stream_info.push_back(pair.second->config());
384 if (num_es && (all_stream_info.size() == num_es)) {
387 init_cb_.Run(all_stream_info);
388 DVLOG(1) <<
"Mpeg2TS stream parser initialization done";
389 is_initialized_ =
true;
394 void Mp2tMediaParser::OnEmitMediaSample(
396 std::shared_ptr<MediaSample> new_sample) {
398 DVLOG(LOG_LEVEL_ES) <<
"OnEmitMediaSample: "
399 <<
" pid=" << pes_pid
400 <<
" size=" << new_sample->data_size()
401 <<
" dts=" << new_sample->dts()
402 <<
" pts=" << new_sample->pts();
405 auto pid_state = pids_.find(pes_pid);
406 if (pid_state == pids_.end()) {
407 LOG(ERROR) <<
"PID State for new sample not found (pid = " << pes_pid
411 pid_state->second->media_sample_queue_.push_back(std::move(new_sample));
414 void Mp2tMediaParser::OnEmitTextSample(uint32_t pes_pid,
415 std::shared_ptr<TextSample> new_sample) {
417 DVLOG(LOG_LEVEL_ES) <<
"OnEmitTextSample: "
418 <<
" pid=" << pes_pid
419 <<
" start=" << new_sample->start_time();
422 auto pid_state = pids_.find(pes_pid);
423 if (pid_state == pids_.end()) {
424 LOG(ERROR) <<
"PID State for new sample not found (pid = "
428 pid_state->second->text_sample_queue_.push_back(std::move(new_sample));
431 bool Mp2tMediaParser::EmitRemainingSamples() {
432 DVLOG(LOG_LEVEL_ES) <<
"Mp2tMediaParser::EmitRemainingBuffers";
435 if (!is_initialized_)
439 for (
const auto& pid_pair : pids_) {
440 for (
auto sample : pid_pair.second->media_sample_queue_) {
441 RCHECK(new_media_sample_cb_.Run(pid_pair.first, sample));
443 pid_pair.second->media_sample_queue_.clear();
445 for (
auto sample : pid_pair.second->text_sample_queue_) {
446 RCHECK(new_text_sample_cb_.Run(pid_pair.first, sample));
448 pid_pair.second->text_sample_queue_.clear();
All the methods that are virtual are virtual for mocking.