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:
Jacob Trimble 2020-10-16 14:18:35 -07:00
parent a93eeca5db
commit 9b036b764b
9 changed files with 99 additions and 87 deletions

View File

@ -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() {}

View File

@ -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());

View File

@ -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;
} }

View File

@ -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;

View File

@ -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;
} }

View File

@ -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;

View File

@ -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);
}; };

View File

@ -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;
} }

View File

@ -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;