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

Unified Diff: media/formats/mp4/track_run_iterator.cc

Issue 1998333002: MP4 support for Common Encryption 'cbcs' scheme. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: handle comments Created 4 years, 6 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/mp4/track_run_iterator.cc
diff --git a/media/formats/mp4/track_run_iterator.cc b/media/formats/mp4/track_run_iterator.cc
index 7193b3d26dd9d5eb03b47ef298bc8d4d99ec11c6..f48d2fce258090b35bb5540eb9b40ddece3644e2 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 {
@@ -282,11 +283,11 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
const std::vector<uint8_t>& sample_encryption_data =
traf.sample_encryption.sample_encryption_data;
std::unique_ptr<BufferReader> sample_encryption_reader;
- uint32_t sample_encrytion_entries_count = 0;
+ uint32_t sample_encryption_entries_count = 0;
if (!sample_encryption_data.empty()) {
sample_encryption_reader.reset(new BufferReader(
sample_encryption_data.data(), sample_encryption_data.size()));
- RCHECK(sample_encryption_reader->Read4(&sample_encrytion_entries_count));
+ RCHECK(sample_encryption_reader->Read4(&sample_encryption_entries_count));
}
// Process edit list to remove CTS offset introduced in the presence of
@@ -323,26 +324,23 @@ 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_encrytion_entries_count == 0 &&
+ if (sample_encryption_entries_count == 0 &&
traf.auxiliary_offset.offsets.size() > j) {
// Collect information from the auxiliary_offset entry with the same
// index in the 'saiz' container as the current run's index in the
@@ -402,18 +400,44 @@ bool TrackRunIterator::Init(const MovieFragment& moof) {
RCHECK(GetSampleEncryptionInfoEntry(tri, index));
is_sample_to_group_valid = sample_to_group_itr.Advance();
}
- if (sample_encrytion_entries_count > 0) {
- RCHECK(sample_encrytion_entries_count >=
+ if (sample_encryption_entries_count > 0) {
+ RCHECK(sample_encryption_entries_count >=
sample_count_sum + trun.sample_count);
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.
ddorwin 2016/06/17 23:32:41 nit: If
dougsteed 2016/10/10 18:18:02 Done.
+ bool is_encrypted = index == 0 ? track_encryption->is_encrypted
+ : info_entry->is_encrypted;
+ 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);
+ }
+ // We only support setting the pattern values in the 'tenc' box for
ddorwin 2016/06/17 23:32:41 nit: Is this dependent on the logic above? If not
dougsteed 2016/10/10 18:18:02 Done.
+ // 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(info_entry->crypt_byte_block ==
ddorwin 2016/06/17 23:32:41 If this is legal but not supported, it would be ni
dougsteed 2016/10/10 18:18:02 RCHECK will log this.
ddorwin 2016/11/06 00:57:51 RCHECK DLOGs. RCHECK_MEDIA_LOGGED probably logs to
dougsteed 2016/12/01 19:45:31 Done.
+ track_encryption->default_crypt_byte_block);
+ RCHECK(info_entry->skip_byte_block ==
+ track_encryption->default_skip_byte_block);
+ }
+#endif
}
}
runs_.push_back(tri);
@@ -474,8 +498,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 +622,29 @@ 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)
+ // Later editions of the CENC standard, notably the 'cbcs' scheme, allow
ddorwin 2016/06/17 23:32:41 Specify the first edition. Or maybe you don't actu
dougsteed 2016/10/10 18:18:02 Done.
+ // empty aux info when a constant IV is in use with full sample encryption.
+ // That case will fall through to here.
ddorwin 2016/06/17 23:32:41 Should we DCHECK that the scheme is not CENC (outs
dougsteed 2016/10/10 18:18:02 I'm not sure we independently know the scheme in t
+ 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()),
ddorwin 2016/06/17 23:32:41 is kid guaranteed not to be empty?
dougsteed 2016/10/10 18:18:02 I believe so, same usage as in (new) line 661.
+ 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 +657,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 +692,25 @@ 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 {
+ if (!IsSampleEncrypted(sample_index))
+ return true;
ddorwin 2016/06/17 23:32:41 Explain why?
+ 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;
ddorwin 2016/06/17 23:32:41 GetSampleEncryptionInfoEntry can return nullptr. Y
dougsteed 2016/10/10 18:18:02 This mimics the logic in the previous two function
+ RCHECK(constant_iv_size != 0);
+ const uint8_t* constant_iv =
+ index == 0 ? track_encryption().default_constant_iv
+ : GetSampleEncryptionInfoEntry(*run_itr_, index)->constant_iv;
ddorwin 2016/06/17 23:32:41 ditto
dougsteed 2016/10/10 18:18:02 ditto
+ RCHECK(constant_iv != nullptr);
+ memcpy(entry.initialization_vector, constant_iv, constant_iv_size);
+ return true;
+}
+#endif
+
} // namespace mp4
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698