Chromium Code Reviews| 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 041bc0d1d0ef7199eadc7f81e046785b2ca2166c..383cc393156f8d10c36af2e08e95a0f536a23a1a 100644 |
| --- a/media/formats/mp2t/mp2t_stream_parser.cc |
| +++ b/media/formats/mp2t/mp2t_stream_parser.cc |
| @@ -25,14 +25,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 { |
| @@ -42,6 +67,11 @@ class PidState { |
| kPidPmt, |
| kPidAudioPes, |
| kPidVideoPes, |
| +#if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) |
| + kPidCat, |
| + kPidCetsEcm, |
| + kPidCetsPssh, |
| +#endif |
| }; |
| PidState(int pid, |
| @@ -202,10 +232,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; |
| } |
| @@ -284,7 +313,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. |
| @@ -293,10 +322,18 @@ bool Mp2tStreamParser::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, 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)) |
| @@ -322,11 +359,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; |
| } |
| } |
| @@ -339,11 +375,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 |
| @@ -383,6 +430,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), |
| + true, base::Bind(&Mp2tStreamParser::GetDecryptConfig, |
| + base::Unretained(this)))); |
| + } 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), |
| + sbr_in_mimetype_, true, base::Bind(&Mp2tStreamParser::GetDecryptConfig, |
| + base::Unretained(this)))); |
| + is_audio = true; |
| +#endif |
| } else { |
| return; |
| } |
| @@ -677,5 +747,73 @@ bool Mp2tStreamParser::EmitRemainingBuffers() { |
| return true; |
| } |
| +#if BUILDFLAG(ENABLE_HLS_SAMPLE_AES) |
| +std::map<int, PidState*>::iterator Mp2tStreamParser::RegisterCat() { |
| + std::unique_ptr<TsSection> cat_section_parser(new TsSectionCat( |
| + base::Bind(&Mp2tStreamParser::RegisterCencPids, base::Unretained(this)))); |
| + std::unique_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())) |
|
yucliu1
2016/05/26 23:28:47
nit: Replace insert with emplace?
And I think pid
dougsteed
2016/09/25 21:52:29
Can't replace insert with emplace. Agree with the
|
| + .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) { |
| + std::unique_ptr<TsSectionCetsEcm> ecm_parser(new TsSectionCetsEcm(base::Bind( |
| + &Mp2tStreamParser::RegisterDecryptConfig, base::Unretained(this)))); |
| + std::unique_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())); |
|
yucliu1
2016/05/26 23:28:47
ditto.
dougsteed
2016/09/25 21:52:29
ditto
|
| + |
| + std::unique_ptr<TsSectionCetsPssh> pssh_parser( |
| + new TsSectionCetsPssh(base::Bind(&Mp2tStreamParser::RegisterPsshBoxes, |
| + base::Unretained(this)))); |
| + std::unique_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())); |
|
yucliu1
2016/05/26 23:28:47
ditto.
dougsteed
2016/09/25 21:52:29
ditto
|
| +} |
| + |
| +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 |