Index: media/formats/mp4/track_run_iterator.cc |
diff --git a/media/formats/mp4/track_run_iterator.cc b/media/formats/mp4/track_run_iterator.cc |
index bdd4e07dd9a3cd6d2ff6d1847d8df517d9778301..b2f6e7399f9cfb633164203dadec2685a5ff4476 100644 |
--- a/media/formats/mp4/track_run_iterator.cc |
+++ b/media/formats/mp4/track_run_iterator.cc |
@@ -12,6 +12,7 @@ |
#include "base/macros.h" |
#include "media/formats/mp4/rcheck.h" |
#include "media/formats/mp4/sample_to_group_iterator.h" |
+#include "media/media_features.h" |
namespace media { |
namespace mp4 { |
@@ -323,24 +324,21 @@ bool TrackRunIterator::Init(const MovieFragment& moof) { |
tri.fragment_sample_encryption_info = |
traf.sample_group_description.entries; |
- uint8_t default_iv_size = 0; |
+ const TrackEncryption* track_encryption; |
tri.is_audio = (stsd.type == kAudio); |
if (tri.is_audio) { |
RCHECK(!stsd.audio_entries.empty()); |
if (desc_idx > stsd.audio_entries.size()) |
desc_idx = 0; |
tri.audio_description = &stsd.audio_entries[desc_idx]; |
- default_iv_size = |
- tri.audio_description->sinf.info.track_encryption.default_iv_size; |
+ track_encryption = &tri.audio_description->sinf.info.track_encryption; |
} else { |
RCHECK(!stsd.video_entries.empty()); |
if (desc_idx > stsd.video_entries.size()) |
desc_idx = 0; |
tri.video_description = &stsd.video_entries[desc_idx]; |
- default_iv_size = |
- tri.video_description->sinf.info.track_encryption.default_iv_size; |
+ track_encryption = &tri.video_description->sinf.info.track_encryption; |
} |
- |
// Initialize aux_info variables only if no sample encryption entries. |
if (sample_encryption_entries_count == 0 && |
traf.auxiliary_offset.offsets.size() > j) { |
@@ -408,12 +406,46 @@ bool TrackRunIterator::Init(const MovieFragment& moof) { |
tri.sample_encryption_entries.resize(trun.sample_count); |
for (size_t k = 0; k < trun.sample_count; k++) { |
uint32_t index = tri.samples[k].cenc_group_description_index; |
- const uint8_t iv_size = |
- index == 0 ? default_iv_size |
- : GetSampleEncryptionInfoEntry(tri, index)->iv_size; |
- RCHECK(tri.sample_encryption_entries[k].Parse( |
- sample_encryption_reader.get(), iv_size, |
- traf.sample_encryption.use_subsample_encryption)); |
+ const CencSampleEncryptionInfoEntry* info_entry = |
+ index == 0 ? nullptr : GetSampleEncryptionInfoEntry(tri, index); |
+ const uint8_t iv_size = index == 0 ? track_encryption->default_iv_size |
+ : info_entry->iv_size; |
+ SampleEncryptionEntry& entry = tri.sample_encryption_entries[k]; |
+ RCHECK(entry.Parse(sample_encryption_reader.get(), iv_size, |
+ traf.sample_encryption.use_subsample_encryption)); |
+#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) |
+ // If we don't have a per-sample IV, get the constant IV. |
+ bool is_encrypted = index == 0 ? track_encryption->is_encrypted |
+ : info_entry->is_encrypted; |
+ // We only support setting the pattern values in the 'tenc' box for |
+ // the track (not varying on per sample group basis). |
+ // Thus we need to verify that the settings in the sample group match |
+ // those in the 'tenc'. |
+ if (is_encrypted && index != 0) { |
+ RCHECK_MEDIA_LOGGED(info_entry->crypt_byte_block == |
+ track_encryption->default_crypt_byte_block, |
+ media_log_, |
+ "Pattern value (crypt byte block) for the " |
+ "sample group does not match that in the tenc " |
+ "box . This is not currently supported."); |
+ RCHECK_MEDIA_LOGGED(info_entry->skip_byte_block == |
+ track_encryption->default_skip_byte_block, |
+ media_log_, |
+ "Pattern value (skip byte block) for the " |
+ "sample group does not match that in the tenc " |
+ "box . This is not currently supported."); |
+ } |
+ if (is_encrypted && !iv_size) { |
+ const uint8_t constant_iv_size = |
+ index == 0 ? track_encryption->default_constant_iv_size |
+ : info_entry->constant_iv_size; |
+ RCHECK(constant_iv_size != 0); |
+ const uint8_t* constant_iv = |
+ index == 0 ? track_encryption->default_constant_iv |
+ : info_entry->constant_iv; |
+ memcpy(entry.initialization_vector, constant_iv, constant_iv_size); |
+ } |
+#endif |
} |
} |
runs_.push_back(tri); |
@@ -474,8 +506,14 @@ bool TrackRunIterator::CacheAuxInfo(const uint8_t* buf, int buf_size) { |
BufferReader reader(buf + pos, info_size); |
const uint8_t iv_size = GetIvSize(i); |
const bool has_subsamples = info_size > iv_size; |
- RCHECK( |
- sample_encryption_entries[i].Parse(&reader, iv_size, has_subsamples)); |
+ SampleEncryptionEntry& entry = sample_encryption_entries[i]; |
+ RCHECK(entry.Parse(&reader, iv_size, has_subsamples)); |
+#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) |
+ // if we don't have a per-sample IV, get the constant IV. |
+ if (!iv_size) { |
+ RCHECK(ApplyConstantIv(i, &entry)); |
+ } |
+#endif |
} |
pos += info_size; |
} |
@@ -592,14 +630,28 @@ const TrackEncryption& TrackRunIterator::track_encryption() const { |
std::unique_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { |
DCHECK(is_encrypted()); |
+ size_t sample_idx = sample_itr_ - run_itr_->samples.begin(); |
+ const std::vector<uint8_t>& kid = GetKeyId(sample_idx); |
if (run_itr_->sample_encryption_entries.empty()) { |
DCHECK_EQ(0, aux_info_size()); |
+#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) |
+ // The 'cbcs' scheme allows empty aux info when a constant IV is in use |
+ // with full sample encryption. That case will fall through to here. |
+ SampleEncryptionEntry sample_encryption_entry; |
+ if (ApplyConstantIv(sample_idx, &sample_encryption_entry)) { |
+ return std::unique_ptr<DecryptConfig>(new DecryptConfig( |
+ std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()), |
+ std::string(reinterpret_cast<const char*>( |
+ sample_encryption_entry.initialization_vector), |
+ arraysize(sample_encryption_entry.initialization_vector)), |
+ sample_encryption_entry.subsamples)); |
+ } |
+#endif |
MEDIA_LOG(ERROR, media_log_) << "Sample encryption info is not available."; |
return std::unique_ptr<DecryptConfig>(); |
} |
- size_t sample_idx = sample_itr_ - run_itr_->samples.begin(); |
DCHECK_LT(sample_idx, run_itr_->sample_encryption_entries.size()); |
const SampleEncryptionEntry& sample_encryption_entry = |
run_itr_->sample_encryption_entries[sample_idx]; |
@@ -612,7 +664,6 @@ std::unique_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { |
return std::unique_ptr<DecryptConfig>(); |
} |
- const std::vector<uint8_t>& kid = GetKeyId(sample_idx); |
return std::unique_ptr<DecryptConfig>(new DecryptConfig( |
std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()), |
std::string(reinterpret_cast<const char*>( |
@@ -648,5 +699,24 @@ uint8_t TrackRunIterator::GetIvSize(size_t sample_index) const { |
: GetSampleEncryptionInfoEntry(*run_itr_, index)->iv_size; |
} |
+#if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME) |
+bool TrackRunIterator::ApplyConstantIv(size_t sample_index, |
+ SampleEncryptionEntry* entry) const { |
+ DCHECK(IsSampleEncrypted(sample_index)); |
+ uint32_t index = GetGroupDescriptionIndex(sample_index); |
+ const uint8_t constant_iv_size = |
+ index == 0 |
+ ? track_encryption().default_constant_iv_size |
+ : GetSampleEncryptionInfoEntry(*run_itr_, index)->constant_iv_size; |
+ RCHECK(constant_iv_size != 0); |
+ const uint8_t* constant_iv = |
+ index == 0 ? track_encryption().default_constant_iv |
+ : GetSampleEncryptionInfoEntry(*run_itr_, index)->constant_iv; |
+ RCHECK(constant_iv != nullptr); |
+ memcpy(entry->initialization_vector, constant_iv, kInitializationVectorSize); |
+ return true; |
+} |
+#endif |
+ |
} // namespace mp4 |
} // namespace media |