Chromium Code Reviews| 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 |