| Index: media/formats/mp2t/mp2t_stream_parser.cc
|
| diff --git a/media/formats/mp2t/mp2t_stream_parser.cc b/media/formats/mp2t/mp2t_stream_parser.cc
|
| index 90a2b96e887fe9e2fa3fd91ba64d55706b254943..823971fc2d7f8feb86c1cf9d8e50c12adfec6df8 100644
|
| --- a/media/formats/mp2t/mp2t_stream_parser.cc
|
| +++ b/media/formats/mp2t/mp2t_stream_parser.cc
|
| @@ -24,14 +24,39 @@
|
| #include "media/formats/mp2t/ts_section_pes.h"
|
| #include "media/formats/mp2t/ts_section_pmt.h"
|
|
|
| +#if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
|
| +#include "media/formats/mp2t/ts_section_cat.h"
|
| +#include "media/formats/mp2t/ts_section_cets_ecm.h"
|
| +#include "media/formats/mp2t/ts_section_cets_pssh.h"
|
| +#endif
|
| +
|
| namespace media {
|
| namespace mp2t {
|
|
|
| +namespace {
|
| +
|
| +#if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
|
| +const int64_t kSampleAESPrivateDataIndicatorAVC = 0x7a617663;
|
| +const int64_t kSampleAESPrivateDataIndicatorAAC = 0x61616364;
|
| +// TODO(dougsteed). Consider adding support for the following:
|
| +// const int64_t kSampleAESPrivateDataIndicatorAC3 = 0x61633364;
|
| +// const int64_t kSampleAESPrivateDataIndicatorEAC3 = 0x65633364;
|
| +#endif
|
| +
|
| +} // namespace
|
| +
|
| enum StreamType {
|
| // ISO-13818.1 / ITU H.222 Table 2.34 "Stream type assignments"
|
| kStreamTypeMpeg1Audio = 0x3,
|
| kStreamTypeAAC = 0xf,
|
| kStreamTypeAVC = 0x1b,
|
| +#if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
|
| + kStreamTypeAACWithSampleAES = 0xcf,
|
| + kStreamTypeAVCWithSampleAES = 0xdb,
|
| +// TODO(dougsteed). Consider adding support for the following:
|
| +// kStreamTypeAC3WithSampleAES = 0xc1,
|
| +// kStreamTypeEAC3WithSampleAES = 0xc2,
|
| +#endif
|
| };
|
|
|
| class PidState {
|
| @@ -41,6 +66,11 @@ class PidState {
|
| kPidPmt,
|
| kPidAudioPes,
|
| kPidVideoPes,
|
| +#if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
|
| + kPidCat,
|
| + kPidCetsEcm,
|
| + kPidCetsPssh,
|
| +#endif
|
| };
|
|
|
| PidState(int pid, PidType pid_tyoe,
|
| @@ -197,10 +227,9 @@ void Mp2tStreamParser::Flush() {
|
| DVLOG(1) << "Mp2tStreamParser::Flush";
|
|
|
| // Flush the buffers and reset the pids.
|
| - for (std::map<int, PidState*>::iterator it = pids_.begin();
|
| - it != pids_.end(); ++it) {
|
| - DVLOG(1) << "Flushing PID: " << it->first;
|
| - PidState* pid_state = it->second;
|
| + for (const auto& pid : pids_) {
|
| + DVLOG(1) << "Flushing PID: " << pid.first;
|
| + PidState* pid_state = pid.second;
|
| pid_state->Flush();
|
| delete pid_state;
|
| }
|
| @@ -278,7 +307,7 @@ bool Mp2tStreamParser::Parse(const uint8_t* buf, int size) {
|
| << " start_unit=" << ts_packet->payload_unit_start_indicator();
|
|
|
| // Parse the section.
|
| - std::map<int, 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.
|
| @@ -289,10 +318,18 @@ bool Mp2tStreamParser::Parse(const uint8_t* buf, int size) {
|
| scoped_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, PidState*>(ts_packet->pid(),
|
| - pat_pid_state.release())).first;
|
| + it =
|
| + pids_.insert(PidMapElement(ts_packet->pid(), pat_pid_state.release()))
|
| + .first;
|
| }
|
| +#if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
|
| + // We allow a CAT to appear as the first packet in the TS. This allows us to
|
| + // specify encryption metadata for HLS by injecting it as an extra TS packet
|
| + // at the front of the stream.
|
| + else if (it == pids_.end() && ts_packet->pid() == TsSection::kPidCat) {
|
| + it = RegisterCat();
|
| + }
|
| +#endif
|
|
|
| if (it != pids_.end()) {
|
| if (!it->second->PushTsPacket(*ts_packet))
|
| @@ -318,11 +355,10 @@ void Mp2tStreamParser::RegisterPmt(int program_number, int pmt_pid) {
|
|
|
| // Only one TS program is allowed. Ignore the incoming program map table,
|
| // if there is already one registered.
|
| - for (std::map<int, PidState*>::iterator it = pids_.begin();
|
| - it != pids_.end(); ++it) {
|
| - PidState* pid_state = it->second;
|
| + for (const auto& pid : pids_) {
|
| + PidState* pid_state = pid.second;
|
| if (pid_state->pid_type() == PidState::kPidPmt) {
|
| - DVLOG_IF(1, pmt_pid != it->first) << "More than one program is defined";
|
| + DVLOG_IF(1, pmt_pid != pid.first) << "More than one program is defined";
|
| return;
|
| }
|
| }
|
| @@ -337,11 +373,22 @@ void Mp2tStreamParser::RegisterPmt(int program_number, int pmt_pid) {
|
| new PidState(pmt_pid, PidState::kPidPmt, std::move(pmt_section_parser)));
|
| pmt_pid_state->Enable();
|
| pids_.insert(std::pair<int, PidState*>(pmt_pid, pmt_pid_state.release()));
|
| +
|
| +#if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
|
| + // Take the opportunity to clean up any PIDs that were involved in importing
|
| + // encryption metadata for HLS with SampleAES. This prevents the possibility
|
| + // of interference with actual PIDs that might be declared in the PMT.
|
| + // TODO(dougsteed): if in the future the appropriate PIDs are embedded in the
|
| + // source stream, this will not be necessary.
|
| + UnregisterCat();
|
| + UnregisterCencPids();
|
| +#endif
|
| }
|
|
|
| void Mp2tStreamParser::RegisterPes(int pmt_pid,
|
| int pes_pid,
|
| - int stream_type) {
|
| + int stream_type,
|
| + const Descriptors& descriptors) {
|
| // TODO(damienv): check there is no mismatch if the entry already exists.
|
| DVLOG(1) << "RegisterPes:"
|
| << " pes_pid=" << pes_pid
|
| @@ -381,6 +428,29 @@ void Mp2tStreamParser::RegisterPes(int pmt_pid,
|
| pes_pid),
|
| media_log_));
|
| is_audio = true;
|
| +#if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
|
| + } else if (stream_type == kStreamTypeAVCWithSampleAES &&
|
| + descriptors.HasPrivateDataIndicator(
|
| + kSampleAESPrivateDataIndicatorAVC)) {
|
| + es_parser.reset(new EsParserH264(
|
| + base::Bind(&Mp2tStreamParser::OnVideoConfigChanged,
|
| + base::Unretained(this), pes_pid),
|
| + base::Bind(&Mp2tStreamParser::OnEmitVideoBuffer, base::Unretained(this),
|
| + pes_pid),
|
| + base::Bind(&Mp2tStreamParser::GetDecryptConfig, base::Unretained(this)),
|
| + true));
|
| + } else if (stream_type == kStreamTypeAACWithSampleAES &&
|
| + descriptors.HasPrivateDataIndicator(
|
| + kSampleAESPrivateDataIndicatorAAC)) {
|
| + es_parser.reset(new EsParserAdts(
|
| + base::Bind(&Mp2tStreamParser::OnAudioConfigChanged,
|
| + base::Unretained(this), pes_pid),
|
| + base::Bind(&Mp2tStreamParser::OnEmitAudioBuffer, base::Unretained(this),
|
| + pes_pid),
|
| + base::Bind(&Mp2tStreamParser::GetDecryptConfig, base::Unretained(this)),
|
| + true, sbr_in_mimetype_));
|
| + is_audio = true;
|
| +#endif
|
| } else {
|
| return;
|
| }
|
| @@ -666,5 +736,72 @@ bool Mp2tStreamParser::EmitRemainingBuffers() {
|
| return true;
|
| }
|
|
|
| +#if BUILDFLAG(ENABLE_HLS_SAMPLE_AES)
|
| +std::map<int, PidState*>::iterator Mp2tStreamParser::RegisterCat() {
|
| + scoped_ptr<TsSection> cat_section_parser(new TsSectionCat(
|
| + base::Bind(&Mp2tStreamParser::RegisterCencPids, base::Unretained(this))));
|
| + scoped_ptr<PidState> cat_pid_state(new PidState(
|
| + TsSection::kPidCat, PidState::kPidCat, std::move(cat_section_parser)));
|
| + cat_pid_state->Enable();
|
| + return pids_
|
| + .insert(PidMapElement(TsSection::kPidCat, cat_pid_state.release()))
|
| + .first;
|
| +}
|
| +
|
| +void Mp2tStreamParser::UnregisterCat() {
|
| + for (auto& pid : pids_) {
|
| + if (pid.second->pid_type() == PidState::kPidCat) {
|
| + delete pid.second;
|
| + pids_.erase(pid.first);
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void Mp2tStreamParser::RegisterCencPids(int ca_pid, int pssh_pid) {
|
| + scoped_ptr<TsSectionCetsEcm> ecm_parser(new TsSectionCetsEcm(base::Bind(
|
| + &Mp2tStreamParser::RegisterDecryptConfig, base::Unretained(this))));
|
| + scoped_ptr<PidState> ecm_pid_state(
|
| + new PidState(ca_pid, PidState::kPidCetsEcm, std::move(ecm_parser)));
|
| + ecm_pid_state->Enable();
|
| + pids_.insert(PidMapElement(ca_pid, ecm_pid_state.release()));
|
| +
|
| + scoped_ptr<TsSectionCetsPssh> pssh_parser(new TsSectionCetsPssh(base::Bind(
|
| + &Mp2tStreamParser::RegisterPsshBoxes, base::Unretained(this))));
|
| + scoped_ptr<PidState> pssh_pid_state(
|
| + new PidState(pssh_pid, PidState::kPidCetsPssh, std::move(pssh_parser)));
|
| + pssh_pid_state->Enable();
|
| + pids_.insert(PidMapElement(pssh_pid, pssh_pid_state.release()));
|
| +}
|
| +
|
| +void Mp2tStreamParser::UnregisterCencPids() {
|
| + for (auto& pid : pids_) {
|
| + if (pid.second->pid_type() == PidState::kPidCetsEcm) {
|
| + delete pid.second;
|
| + pids_.erase(pid.first);
|
| + break;
|
| + }
|
| + }
|
| + for (auto& pid : pids_) {
|
| + if (pid.second->pid_type() == PidState::kPidCetsPssh) {
|
| + delete pid.second;
|
| + pids_.erase(pid.first);
|
| + break;
|
| + }
|
| + }
|
| +}
|
| +
|
| +void Mp2tStreamParser::RegisterDecryptConfig(const DecryptConfig& config) {
|
| + decrypt_config_.reset(
|
| + new DecryptConfig(config.key_id(), config.iv(), config.subsamples()));
|
| +}
|
| +
|
| +void Mp2tStreamParser::RegisterPsshBoxes(
|
| + const std::vector<uint8_t>& init_data) {
|
| + encrypted_media_init_data_cb_.Run(EmeInitDataType::CENC, init_data);
|
| +}
|
| +
|
| +#endif
|
| +
|
| } // namespace mp2t
|
| } // namespace media
|
|
|