Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1284)

Unified Diff: media/formats/mp2t/mp2t_stream_parser.cc

Issue 1517473002: Support HLS MPEG2 TS with SAMPLE-AES encryption. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@encryption_scheme
Patch Set: rebase Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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

Powered by Google App Engine
This is Rietveld 408576698