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