Add TextSample handling to MP2T parser.
This also changes the callbacks a bit to (a) avoid passing references for already ref-counted types, and (b) don't pass PID since the parent knows this and gives it to the child parser. Issue #832 Change-Id: I7dd44436c8d1ad81d42a813d16f850175b85ad1a
This commit is contained in:
parent
a93eeca5db
commit
9b036b764b
|
@ -14,15 +14,15 @@ namespace media {
|
|||
|
||||
class MediaSample;
|
||||
class StreamInfo;
|
||||
class TextSample;
|
||||
|
||||
namespace mp2t {
|
||||
|
||||
class EsParser {
|
||||
public:
|
||||
typedef base::Callback<void(const std::shared_ptr<StreamInfo>&)>
|
||||
NewStreamInfoCB;
|
||||
typedef base::Callback<void(uint32_t, const std::shared_ptr<MediaSample>&)>
|
||||
EmitSampleCB;
|
||||
typedef base::Callback<void(std::shared_ptr<StreamInfo>)> NewStreamInfoCB;
|
||||
typedef base::Callback<void(std::shared_ptr<MediaSample>)> EmitSampleCB;
|
||||
typedef base::Callback<void(std::shared_ptr<TextSample>)> EmitTextSampleCB;
|
||||
|
||||
EsParser(uint32_t pid) : pid_(pid) {}
|
||||
virtual ~EsParser() {}
|
||||
|
|
|
@ -167,7 +167,7 @@ bool EsParserAudio::Parse(const uint8_t* buf,
|
|||
sample->set_pts(current_pts);
|
||||
sample->set_dts(current_pts);
|
||||
sample->set_duration(frame_duration);
|
||||
emit_sample_cb_.Run(pid(), sample);
|
||||
emit_sample_cb_.Run(sample);
|
||||
|
||||
// Update the PTS of the next frame.
|
||||
audio_timestamp_helper_->AddFrames(audio_header_->GetSamplesPerFrame());
|
||||
|
|
|
@ -124,13 +124,13 @@ class EsParserH264Test : public testing::Test {
|
|||
void LoadStream(const char* filename);
|
||||
void ProcessPesPackets(const std::vector<Packet>& pes_packets);
|
||||
|
||||
void EmitSample(uint32_t pid, const std::shared_ptr<MediaSample>& sample) {
|
||||
void EmitSample(std::shared_ptr<MediaSample> sample) {
|
||||
sample_count_++;
|
||||
if (sample_count_ == 1)
|
||||
first_frame_is_key_frame_ = sample->is_key_frame();
|
||||
}
|
||||
|
||||
void NewVideoConfig(const std::shared_ptr<StreamInfo>& config) {
|
||||
void NewVideoConfig(std::shared_ptr<StreamInfo> config) {
|
||||
DVLOG(1) << config->ToString();
|
||||
stream_map_[config->track_id()] = config;
|
||||
}
|
||||
|
|
|
@ -101,8 +101,7 @@ void EsParserH26x::Flush() {
|
|||
// Flush pending sample.
|
||||
DCHECK(pending_sample_duration_);
|
||||
pending_sample_->set_duration(pending_sample_duration_);
|
||||
emit_sample_cb_.Run(pid(), pending_sample_);
|
||||
pending_sample_ = std::shared_ptr<MediaSample>();
|
||||
emit_sample_cb_.Run(std::move(pending_sample_));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,7 +338,7 @@ bool EsParserH26x::EmitFrame(int64_t access_unit_pos,
|
|||
|
||||
pending_sample_duration_ = sample_duration;
|
||||
}
|
||||
emit_sample_cb_.Run(pid(), std::move(pending_sample_));
|
||||
emit_sample_cb_.Run(std::move(pending_sample_));
|
||||
}
|
||||
pending_sample_ = media_sample;
|
||||
|
||||
|
|
|
@ -168,7 +168,7 @@ class EsParserH26xTest : public testing::Test {
|
|||
const H26xNaluType* types,
|
||||
size_t types_count);
|
||||
|
||||
void EmitSample(uint32_t pid, const std::shared_ptr<MediaSample>& sample) {
|
||||
void EmitSample(std::shared_ptr<MediaSample> sample) {
|
||||
size_t sample_id = sample_count_;
|
||||
sample_count_++;
|
||||
if (sample_count_ == 1) {
|
||||
|
@ -181,7 +181,7 @@ class EsParserH26xTest : public testing::Test {
|
|||
EXPECT_EQ(samples_[sample_id], sample_data);
|
||||
}
|
||||
|
||||
void NewVideoConfig(const std::shared_ptr<StreamInfo>& config) {
|
||||
void NewVideoConfig(std::shared_ptr<StreamInfo> config) {
|
||||
has_stream_info_ = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
#include "packager/media/formats/mp2t/mp2t_media_parser.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "packager/base/bind.h"
|
||||
#include "packager/media/base/media_sample.h"
|
||||
#include "packager/media/base/stream_info.h"
|
||||
#include "packager/media/base/text_sample.h"
|
||||
#include "packager/media/formats/mp2t/es_parser.h"
|
||||
#include "packager/media/formats/mp2t/es_parser_audio.h"
|
||||
#include "packager/media/formats/mp2t/es_parser_h264.h"
|
||||
|
@ -59,19 +61,20 @@ class PidState {
|
|||
config_ = config;
|
||||
}
|
||||
|
||||
SampleQueue& sample_queue() { return sample_queue_; }
|
||||
|
||||
private:
|
||||
friend Mp2tMediaParser;
|
||||
void ResetState();
|
||||
|
||||
int pid_;
|
||||
PidType pid_type_;
|
||||
std::unique_ptr<TsSection> section_parser_;
|
||||
|
||||
std::deque<std::shared_ptr<MediaSample>> media_sample_queue_;
|
||||
std::deque<std::shared_ptr<TextSample>> text_sample_queue_;
|
||||
|
||||
bool enable_;
|
||||
int continuity_counter_;
|
||||
std::shared_ptr<StreamInfo> config_;
|
||||
SampleQueue sample_queue_;
|
||||
};
|
||||
|
||||
PidState::PidState(int pid,
|
||||
|
@ -157,9 +160,11 @@ void Mp2tMediaParser::Init(const InitCB& init_cb,
|
|||
DCHECK(init_cb_.is_null());
|
||||
DCHECK(!init_cb.is_null());
|
||||
DCHECK(!new_media_sample_cb.is_null());
|
||||
DCHECK(!new_text_sample_cb.is_null());
|
||||
|
||||
init_cb_ = init_cb;
|
||||
new_sample_cb_ = new_media_sample_cb;
|
||||
new_media_sample_cb_ = new_media_sample_cb;
|
||||
new_text_sample_cb_ = new_text_sample_cb;
|
||||
}
|
||||
|
||||
bool Mp2tMediaParser::Flush() {
|
||||
|
@ -215,8 +220,7 @@ bool Mp2tMediaParser::Parse(const uint8_t* buf, int size) {
|
|||
<< " start_unit=" << ts_packet->payload_unit_start_indicator();
|
||||
|
||||
// Parse the section.
|
||||
std::map<int, std::unique_ptr<PidState>>::iterator it =
|
||||
pids_.find(ts_packet->pid());
|
||||
auto it = pids_.find(ts_packet->pid());
|
||||
if (it == pids_.end() &&
|
||||
ts_packet->pid() == TsSection::kPidPat) {
|
||||
// Create the PAT state here if needed.
|
||||
|
@ -225,10 +229,7 @@ bool Mp2tMediaParser::Parse(const uint8_t* buf, int size) {
|
|||
std::unique_ptr<PidState> pat_pid_state(new PidState(
|
||||
ts_packet->pid(), PidState::kPidPat, std::move(pat_section_parser)));
|
||||
pat_pid_state->Enable();
|
||||
it = pids_
|
||||
.insert(std::pair<int, std::unique_ptr<PidState>>(
|
||||
ts_packet->pid(), std::move(pat_pid_state)))
|
||||
.first;
|
||||
it = pids_.emplace(ts_packet->pid(), std::move(pat_pid_state)).first;
|
||||
}
|
||||
|
||||
if (it != pids_.end()) {
|
||||
|
@ -267,15 +268,13 @@ void Mp2tMediaParser::RegisterPmt(int program_number, int pmt_pid) {
|
|||
std::unique_ptr<PidState> pmt_pid_state(
|
||||
new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser)));
|
||||
pmt_pid_state->Enable();
|
||||
pids_.insert(std::pair<int, std::unique_ptr<PidState>>(
|
||||
pmt_pid, std::move(pmt_pid_state)));
|
||||
pids_.emplace(pmt_pid, std::move(pmt_pid_state));
|
||||
}
|
||||
|
||||
void Mp2tMediaParser::RegisterPes(int pmt_pid,
|
||||
int pes_pid,
|
||||
int stream_type) {
|
||||
std::map<int, std::unique_ptr<PidState>>::iterator it = pids_.find(pes_pid);
|
||||
if (it != pids_.end())
|
||||
uint8_t stream_type) {
|
||||
if (pids_.count(pes_pid) != 0)
|
||||
return;
|
||||
DVLOG(1) << "RegisterPes:"
|
||||
<< " pes_pid=" << pes_pid << " stream_type=" << std::hex
|
||||
|
@ -286,21 +285,21 @@ void Mp2tMediaParser::RegisterPes(int pmt_pid,
|
|||
std::unique_ptr<EsParser> es_parser;
|
||||
auto on_new_stream = base::Bind(&Mp2tMediaParser::OnNewStreamInfo,
|
||||
base::Unretained(this), pes_pid);
|
||||
auto on_emit =
|
||||
base::Bind(&Mp2tMediaParser::OnEmitSample, base::Unretained(this));
|
||||
auto on_emit_media = base::Bind(&Mp2tMediaParser::OnEmitMediaSample,
|
||||
base::Unretained(this), pes_pid);
|
||||
switch (static_cast<TsStreamType>(stream_type)) {
|
||||
case TsStreamType::kAvc:
|
||||
es_parser.reset(new EsParserH264(pes_pid, on_new_stream, on_emit));
|
||||
es_parser.reset(new EsParserH264(pes_pid, on_new_stream, on_emit_media));
|
||||
break;
|
||||
case TsStreamType::kHevc:
|
||||
es_parser.reset(new EsParserH265(pes_pid, on_new_stream, on_emit));
|
||||
es_parser.reset(new EsParserH265(pes_pid, on_new_stream, on_emit_media));
|
||||
break;
|
||||
case TsStreamType::kAdtsAac:
|
||||
case TsStreamType::kMpeg1Audio:
|
||||
case TsStreamType::kAc3:
|
||||
es_parser.reset(
|
||||
new EsParserAudio(pes_pid, static_cast<TsStreamType>(stream_type),
|
||||
on_new_stream, on_emit, sbr_in_mimetype_));
|
||||
on_new_stream, on_emit_media, sbr_in_mimetype_));
|
||||
is_audio = true;
|
||||
break;
|
||||
default: {
|
||||
|
@ -321,18 +320,17 @@ void Mp2tMediaParser::RegisterPes(int pmt_pid,
|
|||
std::unique_ptr<PidState> pes_pid_state(
|
||||
new PidState(pes_pid, pid_type, std::move(pes_section_parser)));
|
||||
pes_pid_state->Enable();
|
||||
pids_.insert(std::pair<int, std::unique_ptr<PidState>>(
|
||||
pes_pid, std::move(pes_pid_state)));
|
||||
pids_.emplace(pes_pid, std::move(pes_pid_state));
|
||||
}
|
||||
|
||||
void Mp2tMediaParser::OnNewStreamInfo(
|
||||
uint32_t pes_pid,
|
||||
const std::shared_ptr<StreamInfo>& new_stream_info) {
|
||||
std::shared_ptr<StreamInfo> new_stream_info) {
|
||||
DCHECK(!new_stream_info || new_stream_info->track_id() == pes_pid);
|
||||
DVLOG(1) << "OnVideoConfigChanged for pid=" << pes_pid
|
||||
<< ", has_info=" << (new_stream_info ? "true" : "false");
|
||||
|
||||
PidMap::iterator pid_state = pids_.find(pes_pid);
|
||||
auto pid_state = pids_.find(pes_pid);
|
||||
if (pid_state == pids_.end()) {
|
||||
LOG(ERROR) << "PID State for new stream not found (pid = "
|
||||
<< new_stream_info->track_id() << ").";
|
||||
|
@ -362,14 +360,13 @@ bool Mp2tMediaParser::FinishInitializationIfNeeded() {
|
|||
|
||||
std::vector<std::shared_ptr<StreamInfo>> all_stream_info;
|
||||
uint32_t num_es(0);
|
||||
for (PidMap::const_iterator iter = pids_.begin(); iter != pids_.end();
|
||||
++iter) {
|
||||
if ((iter->second->pid_type() == PidState::kPidAudioPes ||
|
||||
iter->second->pid_type() == PidState::kPidVideoPes) &&
|
||||
iter->second->IsEnabled()) {
|
||||
for (const auto& pair : pids_) {
|
||||
if ((pair.second->pid_type() == PidState::kPidAudioPes ||
|
||||
pair.second->pid_type() == PidState::kPidVideoPes) &&
|
||||
pair.second->IsEnabled()) {
|
||||
++num_es;
|
||||
if (iter->second->config())
|
||||
all_stream_info.push_back(iter->second->config());
|
||||
if (pair.second->config())
|
||||
all_stream_info.push_back(pair.second->config());
|
||||
}
|
||||
}
|
||||
if (num_es && (all_stream_info.size() == num_es)) {
|
||||
|
@ -382,29 +379,41 @@ bool Mp2tMediaParser::FinishInitializationIfNeeded() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Mp2tMediaParser::OnEmitSample(
|
||||
void Mp2tMediaParser::OnEmitMediaSample(
|
||||
uint32_t pes_pid,
|
||||
const std::shared_ptr<MediaSample>& new_sample) {
|
||||
std::shared_ptr<MediaSample> new_sample) {
|
||||
DCHECK(new_sample);
|
||||
DVLOG(LOG_LEVEL_ES)
|
||||
<< "OnEmitSample: "
|
||||
<< " pid="
|
||||
<< pes_pid
|
||||
<< " size="
|
||||
<< new_sample->data_size()
|
||||
<< " dts="
|
||||
<< new_sample->dts()
|
||||
<< " pts="
|
||||
<< new_sample->pts();
|
||||
DVLOG(LOG_LEVEL_ES) << "OnEmitMediaSample: "
|
||||
<< " pid=" << pes_pid
|
||||
<< " size=" << new_sample->data_size()
|
||||
<< " dts=" << new_sample->dts()
|
||||
<< " pts=" << new_sample->pts();
|
||||
|
||||
// Add the sample to the appropriate PID sample queue.
|
||||
PidMap::iterator pid_state = pids_.find(pes_pid);
|
||||
auto pid_state = pids_.find(pes_pid);
|
||||
if (pid_state == pids_.end()) {
|
||||
LOG(ERROR) << "PID State for new sample not found (pid = " << pes_pid
|
||||
<< ").";
|
||||
return;
|
||||
}
|
||||
pid_state->second->media_sample_queue_.push_back(std::move(new_sample));
|
||||
}
|
||||
|
||||
void Mp2tMediaParser::OnEmitTextSample(uint32_t pes_pid,
|
||||
std::shared_ptr<TextSample> new_sample) {
|
||||
DCHECK(new_sample);
|
||||
DVLOG(LOG_LEVEL_ES) << "OnEmitTextSample: "
|
||||
<< " pid=" << pes_pid
|
||||
<< " start=" << new_sample->start_time();
|
||||
|
||||
// Add the sample to the appropriate PID sample queue.
|
||||
auto pid_state = pids_.find(pes_pid);
|
||||
if (pid_state == pids_.end()) {
|
||||
LOG(ERROR) << "PID State for new sample not found (pid = "
|
||||
<< pes_pid << ").";
|
||||
return;
|
||||
}
|
||||
pid_state->second->sample_queue().push_back(new_sample);
|
||||
pid_state->second->text_sample_queue_.push_back(std::move(new_sample));
|
||||
}
|
||||
|
||||
bool Mp2tMediaParser::EmitRemainingSamples() {
|
||||
|
@ -415,18 +424,22 @@ bool Mp2tMediaParser::EmitRemainingSamples() {
|
|||
return true;
|
||||
|
||||
// Buffer emission.
|
||||
for (PidMap::const_iterator pid_iter = pids_.begin(); pid_iter != pids_.end();
|
||||
++pid_iter) {
|
||||
SampleQueue& sample_queue = pid_iter->second->sample_queue();
|
||||
for (SampleQueue::iterator sample_iter = sample_queue.begin();
|
||||
sample_iter != sample_queue.end();
|
||||
++sample_iter) {
|
||||
if (!new_sample_cb_.Run(pid_iter->first, *sample_iter)) {
|
||||
for (const auto& pid_pair : pids_) {
|
||||
for (auto sample : pid_pair.second->media_sample_queue_) {
|
||||
if (!new_media_sample_cb_.Run(pid_pair.first, sample)) {
|
||||
// Error processing sample. Propagate error condition.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
sample_queue.clear();
|
||||
pid_pair.second->media_sample_queue_.clear();
|
||||
|
||||
for (auto sample : pid_pair.second->text_sample_queue_) {
|
||||
if (!new_text_sample_cb_.Run(pid_pair.first, sample)) {
|
||||
// Error processing sample. Propagate error condition.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
pid_pair.second->text_sample_queue_.clear();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#ifndef PACKAGER_MEDIA_FORMATS_MP2T_MP2T_MEDIA_PARSER_H_
|
||||
#define PACKAGER_MEDIA_FORMATS_MP2T_MP2T_MEDIA_PARSER_H_
|
||||
|
||||
#include <bitset>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
@ -24,8 +25,6 @@ class PidState;
|
|||
class TsPacket;
|
||||
class TsSection;
|
||||
|
||||
typedef std::deque<std::shared_ptr<MediaSample>> SampleQueue;
|
||||
|
||||
class Mp2tMediaParser : public MediaParser {
|
||||
public:
|
||||
Mp2tMediaParser();
|
||||
|
@ -42,8 +41,6 @@ class Mp2tMediaParser : public MediaParser {
|
|||
/// @}
|
||||
|
||||
private:
|
||||
typedef std::map<int, std::unique_ptr<PidState>> PidMap;
|
||||
|
||||
// Callback invoked to register a Program Map Table.
|
||||
// Note: Does nothing if the PID is already registered.
|
||||
void RegisterPmt(int program_number, int pmt_pid);
|
||||
|
@ -52,17 +49,19 @@ class Mp2tMediaParser : public MediaParser {
|
|||
// Possible values for |media_type| are defined in:
|
||||
// ISO-13818.1 / ITU H.222 Table 2.34 "Media type assignments".
|
||||
// |pes_pid| is part of the Program Map Table refered by |pmt_pid|.
|
||||
void RegisterPes(int pmt_pid, int pes_pid, int media_type);
|
||||
void RegisterPes(int pmt_pid, int pes_pid, uint8_t media_type);
|
||||
|
||||
// Callback invoked each time the audio/video decoder configuration is
|
||||
// changed.
|
||||
void OnNewStreamInfo(uint32_t pes_pid,
|
||||
const std::shared_ptr<StreamInfo>& new_stream_info);
|
||||
std::shared_ptr<StreamInfo> new_stream_info);
|
||||
|
||||
// Callback invoked by the ES media parser
|
||||
// to emit a new audio/video access unit.
|
||||
void OnEmitSample(uint32_t pes_pid,
|
||||
const std::shared_ptr<MediaSample>& new_sample);
|
||||
void OnEmitMediaSample(uint32_t pes_pid,
|
||||
std::shared_ptr<MediaSample> new_sample);
|
||||
void OnEmitTextSample(uint32_t pes_pid,
|
||||
std::shared_ptr<TextSample> new_sample);
|
||||
|
||||
// Invoke the initialization callback if needed.
|
||||
bool FinishInitializationIfNeeded();
|
||||
|
@ -72,26 +71,29 @@ class Mp2tMediaParser : public MediaParser {
|
|||
/// Set the value of the "SBR in mime-type" flag which leads to sample rate
|
||||
/// doubling. Default value is false.
|
||||
void set_sbr_in_mime_type(bool sbr_in_mimetype) {
|
||||
sbr_in_mimetype_ = sbr_in_mimetype; }
|
||||
sbr_in_mimetype_ = sbr_in_mimetype;
|
||||
}
|
||||
|
||||
// List of callbacks.
|
||||
InitCB init_cb_;
|
||||
NewMediaSampleCB new_sample_cb_;
|
||||
NewMediaSampleCB new_media_sample_cb_;
|
||||
NewTextSampleCB new_text_sample_cb_;
|
||||
|
||||
bool sbr_in_mimetype_;
|
||||
|
||||
// Bytes of the TS media.
|
||||
ByteQueue ts_byte_queue_;
|
||||
|
||||
// List of PIDs and their states.
|
||||
PidMap pids_;
|
||||
// Map of PIDs and their states. Use an ordered map so manifest generation
|
||||
// has a deterministic order.
|
||||
std::map<int, std::unique_ptr<PidState>> pids_;
|
||||
|
||||
// Whether |init_cb_| has been invoked.
|
||||
bool is_initialized_;
|
||||
|
||||
// A map used to track unsupported stream types and make sure the error is
|
||||
// only logged once.
|
||||
std::map<uint8_t, bool> stream_type_logged_once_;
|
||||
std::bitset<256> stream_type_logged_once_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Mp2tMediaParser);
|
||||
};
|
||||
|
|
|
@ -75,15 +75,14 @@ bool TsSectionPmt::ParsePsiSection(BitReader* bit_reader) {
|
|||
// The end of the PID map if 4 bytes away from the end of the section
|
||||
// (4 bytes = size of the CRC).
|
||||
int pid_map_end_marker = section_start_marker - section_length + 4;
|
||||
std::map<int, int> pid_map;
|
||||
std::map<int, uint8_t> pid_map;
|
||||
while (static_cast<int>(bit_reader->bits_available()) >
|
||||
8 * pid_map_end_marker) {
|
||||
int stream_type;
|
||||
int reserved;
|
||||
uint8_t stream_type;
|
||||
int pid_es;
|
||||
int es_info_length;
|
||||
RCHECK(bit_reader->ReadBits(8, &stream_type));
|
||||
RCHECK(bit_reader->ReadBits(3, &reserved));
|
||||
RCHECK(bit_reader->SkipBits(3)); // reserved
|
||||
RCHECK(bit_reader->ReadBits(13, &pid_es));
|
||||
RCHECK(bit_reader->ReadBits(4, &reserved));
|
||||
RCHECK(bit_reader->ReadBits(12, &es_info_length));
|
||||
|
@ -91,7 +90,7 @@ bool TsSectionPmt::ParsePsiSection(BitReader* bit_reader) {
|
|||
// Do not register the PID right away.
|
||||
// Wait for the end of the section to be fully parsed
|
||||
// to make sure there is no error.
|
||||
pid_map.insert(std::pair<int, int>(pid_es, stream_type));
|
||||
pid_map.emplace(pid_es, stream_type);
|
||||
|
||||
// Read the ES info descriptors.
|
||||
// Defined in section 2.6 of ISO-13818.
|
||||
|
@ -103,9 +102,8 @@ bool TsSectionPmt::ParsePsiSection(BitReader* bit_reader) {
|
|||
RCHECK(bit_reader->ReadBits(32, &crc32));
|
||||
|
||||
// Once the PMT has been proved to be correct, register the PIDs.
|
||||
for (std::map<int, int>::iterator it = pid_map.begin();
|
||||
it != pid_map.end(); ++it)
|
||||
register_pes_cb_.Run(it->first, it->second);
|
||||
for (auto& pair : pid_map)
|
||||
register_pes_cb_.Run(pair.first, pair.second);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ class TsSectionPmt : public TsSectionPsi {
|
|||
// RegisterPesCb::Run(int pes_pid, int stream_type);
|
||||
// Stream type is defined in
|
||||
// "Table 2-34 – Stream type assignments" in H.222
|
||||
typedef base::Callback<void(int, int)> RegisterPesCb;
|
||||
typedef base::Callback<void(int, uint8_t)> RegisterPesCb;
|
||||
|
||||
explicit TsSectionPmt(const RegisterPesCb& register_pes_cb);
|
||||
~TsSectionPmt() override;
|
||||
|
|
Loading…
Reference in New Issue