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

Side by Side 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: ddorwin more detailed comments Created 4 years, 2 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 unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/formats/mp4/track_run_iterator.h" 5 #include "media/formats/mp4/track_run_iterator.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <iomanip> 8 #include <iomanip>
9 #include <limits> 9 #include <limits>
10 #include <memory> 10 #include <memory>
11 11
12 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "media/formats/mp4/rcheck.h" 13 #include "media/formats/mp4/rcheck.h"
14 #include "media/formats/mp4/sample_to_group_iterator.h" 14 #include "media/formats/mp4/sample_to_group_iterator.h"
15 #include "media/media_features.h"
15 16
16 namespace media { 17 namespace media {
17 namespace mp4 { 18 namespace mp4 {
18 19
19 struct SampleInfo { 20 struct SampleInfo {
20 int size; 21 int size;
21 int duration; 22 int duration;
22 int cts_offset; 23 int cts_offset;
23 bool is_keyframe; 24 bool is_keyframe;
24 uint32_t cenc_group_description_index; 25 uint32_t cenc_group_description_index;
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 TrackRunInfo tri; 317 TrackRunInfo tri;
317 tri.track_id = traf.header.track_id; 318 tri.track_id = traf.header.track_id;
318 tri.timescale = trak->media.header.timescale; 319 tri.timescale = trak->media.header.timescale;
319 tri.start_dts = run_start_dts; 320 tri.start_dts = run_start_dts;
320 tri.sample_start_offset = trun.data_offset; 321 tri.sample_start_offset = trun.data_offset;
321 tri.track_sample_encryption_group = 322 tri.track_sample_encryption_group =
322 &trak->media.information.sample_table.sample_group_description; 323 &trak->media.information.sample_table.sample_group_description;
323 tri.fragment_sample_encryption_info = 324 tri.fragment_sample_encryption_info =
324 traf.sample_group_description.entries; 325 traf.sample_group_description.entries;
325 326
326 uint8_t default_iv_size = 0; 327 const TrackEncryption* track_encryption;
327 tri.is_audio = (stsd.type == kAudio); 328 tri.is_audio = (stsd.type == kAudio);
328 if (tri.is_audio) { 329 if (tri.is_audio) {
329 RCHECK(!stsd.audio_entries.empty()); 330 RCHECK(!stsd.audio_entries.empty());
330 if (desc_idx > stsd.audio_entries.size()) 331 if (desc_idx > stsd.audio_entries.size())
331 desc_idx = 0; 332 desc_idx = 0;
332 tri.audio_description = &stsd.audio_entries[desc_idx]; 333 tri.audio_description = &stsd.audio_entries[desc_idx];
333 default_iv_size = 334 track_encryption = &tri.audio_description->sinf.info.track_encryption;
334 tri.audio_description->sinf.info.track_encryption.default_iv_size;
335 } else { 335 } else {
336 RCHECK(!stsd.video_entries.empty()); 336 RCHECK(!stsd.video_entries.empty());
337 if (desc_idx > stsd.video_entries.size()) 337 if (desc_idx > stsd.video_entries.size())
338 desc_idx = 0; 338 desc_idx = 0;
339 tri.video_description = &stsd.video_entries[desc_idx]; 339 tri.video_description = &stsd.video_entries[desc_idx];
340 default_iv_size = 340 track_encryption = &tri.video_description->sinf.info.track_encryption;
341 tri.video_description->sinf.info.track_encryption.default_iv_size;
342 } 341 }
343
344 // Initialize aux_info variables only if no sample encryption entries. 342 // Initialize aux_info variables only if no sample encryption entries.
345 if (sample_encryption_entries_count == 0 && 343 if (sample_encryption_entries_count == 0 &&
346 traf.auxiliary_offset.offsets.size() > j) { 344 traf.auxiliary_offset.offsets.size() > j) {
347 // Collect information from the auxiliary_offset entry with the same 345 // Collect information from the auxiliary_offset entry with the same
348 // index in the 'saiz' container as the current run's index in the 346 // index in the 'saiz' container as the current run's index in the
349 // 'trun' container, if it is present. 347 // 'trun' container, if it is present.
350 // There should be an auxiliary info entry corresponding to each sample 348 // There should be an auxiliary info entry corresponding to each sample
351 // in the auxiliary offset entry's corresponding track run. 349 // in the auxiliary offset entry's corresponding track run.
352 RCHECK(traf.auxiliary_size.sample_count >= 350 RCHECK(traf.auxiliary_size.sample_count >=
353 sample_count_sum + trun.sample_count); 351 sample_count_sum + trun.sample_count);
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
401 if (index != 0) 399 if (index != 0)
402 RCHECK(GetSampleEncryptionInfoEntry(tri, index)); 400 RCHECK(GetSampleEncryptionInfoEntry(tri, index));
403 is_sample_to_group_valid = sample_to_group_itr.Advance(); 401 is_sample_to_group_valid = sample_to_group_itr.Advance();
404 } 402 }
405 if (sample_encryption_entries_count > 0) { 403 if (sample_encryption_entries_count > 0) {
406 RCHECK(sample_encryption_entries_count >= 404 RCHECK(sample_encryption_entries_count >=
407 sample_count_sum + trun.sample_count); 405 sample_count_sum + trun.sample_count);
408 tri.sample_encryption_entries.resize(trun.sample_count); 406 tri.sample_encryption_entries.resize(trun.sample_count);
409 for (size_t k = 0; k < trun.sample_count; k++) { 407 for (size_t k = 0; k < trun.sample_count; k++) {
410 uint32_t index = tri.samples[k].cenc_group_description_index; 408 uint32_t index = tri.samples[k].cenc_group_description_index;
411 const uint8_t iv_size = 409 const CencSampleEncryptionInfoEntry* info_entry =
412 index == 0 ? default_iv_size 410 index == 0 ? nullptr : GetSampleEncryptionInfoEntry(tri, index);
413 : GetSampleEncryptionInfoEntry(tri, index)->iv_size; 411 const uint8_t iv_size = index == 0 ? track_encryption->default_iv_size
414 RCHECK(tri.sample_encryption_entries[k].Parse( 412 : info_entry->iv_size;
415 sample_encryption_reader.get(), iv_size, 413 SampleEncryptionEntry& entry = tri.sample_encryption_entries[k];
416 traf.sample_encryption.use_subsample_encryption)); 414 RCHECK(entry.Parse(sample_encryption_reader.get(), iv_size,
415 traf.sample_encryption.use_subsample_encryption));
416 #if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME)
417 // If we don't have a per-sample IV, get the constant IV.
418 bool is_encrypted = index == 0 ? track_encryption->is_encrypted
419 : info_entry->is_encrypted;
420 // We only support setting the pattern values in the 'tenc' box for
421 // the track (not varying on per sample group basis).
422 // Thus we need to verify that the settings in the sample group match
423 // those in the 'tenc'.
424 if (is_encrypted && index != 0) {
425 RCHECK(info_entry->crypt_byte_block ==
426 track_encryption->default_crypt_byte_block);
427 RCHECK(info_entry->skip_byte_block ==
428 track_encryption->default_skip_byte_block);
429 }
430 if (is_encrypted && !iv_size) {
431 const uint8_t constant_iv_size =
432 index == 0 ? track_encryption->default_constant_iv_size
433 : info_entry->constant_iv_size;
434 RCHECK(constant_iv_size != 0);
435 const uint8_t* constant_iv =
436 index == 0 ? track_encryption->default_constant_iv
437 : info_entry->constant_iv;
438 memcpy(entry.initialization_vector, constant_iv, constant_iv_size);
439 }
440 #endif
417 } 441 }
418 } 442 }
419 runs_.push_back(tri); 443 runs_.push_back(tri);
420 sample_count_sum += trun.sample_count; 444 sample_count_sum += trun.sample_count;
421 } 445 }
422 446
423 // We should have iterated through all samples in SampleToGroup Box. 447 // We should have iterated through all samples in SampleToGroup Box.
424 RCHECK(!sample_to_group_itr.IsValid()); 448 RCHECK(!sample_to_group_itr.IsValid());
425 } 449 }
426 450
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 int64_t pos = 0; 491 int64_t pos = 0;
468 for (size_t i = 0; i < run_itr_->samples.size(); i++) { 492 for (size_t i = 0; i < run_itr_->samples.size(); i++) {
469 int info_size = run_itr_->aux_info_default_size; 493 int info_size = run_itr_->aux_info_default_size;
470 if (!info_size) 494 if (!info_size)
471 info_size = run_itr_->aux_info_sizes[i]; 495 info_size = run_itr_->aux_info_sizes[i];
472 496
473 if (IsSampleEncrypted(i)) { 497 if (IsSampleEncrypted(i)) {
474 BufferReader reader(buf + pos, info_size); 498 BufferReader reader(buf + pos, info_size);
475 const uint8_t iv_size = GetIvSize(i); 499 const uint8_t iv_size = GetIvSize(i);
476 const bool has_subsamples = info_size > iv_size; 500 const bool has_subsamples = info_size > iv_size;
477 RCHECK( 501 SampleEncryptionEntry& entry = sample_encryption_entries[i];
478 sample_encryption_entries[i].Parse(&reader, iv_size, has_subsamples)); 502 RCHECK(entry.Parse(&reader, iv_size, has_subsamples));
503 #if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME)
504 // if we don't have a per-sample IV, get the constant IV.
505 if (!iv_size) {
506 RCHECK(ApplyConstantIv(i, entry));
507 }
508 #endif
479 } 509 }
480 pos += info_size; 510 pos += info_size;
481 } 511 }
482 512
483 return true; 513 return true;
484 } 514 }
485 515
486 bool TrackRunIterator::IsRunValid() const { 516 bool TrackRunIterator::IsRunValid() const {
487 return run_itr_ != runs_.end(); 517 return run_itr_ != runs_.end();
488 } 518 }
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
585 } 615 }
586 616
587 const TrackEncryption& TrackRunIterator::track_encryption() const { 617 const TrackEncryption& TrackRunIterator::track_encryption() const {
588 if (is_audio()) 618 if (is_audio())
589 return audio_description().sinf.info.track_encryption; 619 return audio_description().sinf.info.track_encryption;
590 return video_description().sinf.info.track_encryption; 620 return video_description().sinf.info.track_encryption;
591 } 621 }
592 622
593 std::unique_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() { 623 std::unique_ptr<DecryptConfig> TrackRunIterator::GetDecryptConfig() {
594 DCHECK(is_encrypted()); 624 DCHECK(is_encrypted());
625 size_t sample_idx = sample_itr_ - run_itr_->samples.begin();
626 const std::vector<uint8_t>& kid = GetKeyId(sample_idx);
595 627
596 if (run_itr_->sample_encryption_entries.empty()) { 628 if (run_itr_->sample_encryption_entries.empty()) {
597 DCHECK_EQ(0, aux_info_size()); 629 DCHECK_EQ(0, aux_info_size());
630 #if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME)
631 // The 'cbcs' scheme allows empty aux info when a constant IV is in use
632 // with full sample encryption. That case will fall through to here.
633 SampleEncryptionEntry sample_encryption_entry;
634 if (ApplyConstantIv(sample_idx, sample_encryption_entry)) {
635 return std::unique_ptr<DecryptConfig>(new DecryptConfig(
636 std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()),
637 std::string(reinterpret_cast<const char*>(
638 sample_encryption_entry.initialization_vector),
639 arraysize(sample_encryption_entry.initialization_vector)),
640 sample_encryption_entry.subsamples));
641 }
642 #endif
598 MEDIA_LOG(ERROR, media_log_) << "Sample encryption info is not available."; 643 MEDIA_LOG(ERROR, media_log_) << "Sample encryption info is not available.";
599 return std::unique_ptr<DecryptConfig>(); 644 return std::unique_ptr<DecryptConfig>();
600 } 645 }
601 646
602 size_t sample_idx = sample_itr_ - run_itr_->samples.begin();
603 DCHECK_LT(sample_idx, run_itr_->sample_encryption_entries.size()); 647 DCHECK_LT(sample_idx, run_itr_->sample_encryption_entries.size());
604 const SampleEncryptionEntry& sample_encryption_entry = 648 const SampleEncryptionEntry& sample_encryption_entry =
605 run_itr_->sample_encryption_entries[sample_idx]; 649 run_itr_->sample_encryption_entries[sample_idx];
606 650
607 size_t total_size = 0; 651 size_t total_size = 0;
608 if (!sample_encryption_entry.subsamples.empty() && 652 if (!sample_encryption_entry.subsamples.empty() &&
609 (!sample_encryption_entry.GetTotalSizeOfSubsamples(&total_size) || 653 (!sample_encryption_entry.GetTotalSizeOfSubsamples(&total_size) ||
610 total_size != static_cast<size_t>(sample_size()))) { 654 total_size != static_cast<size_t>(sample_size()))) {
611 MEDIA_LOG(ERROR, media_log_) << "Incorrect CENC subsample size."; 655 MEDIA_LOG(ERROR, media_log_) << "Incorrect CENC subsample size.";
612 return std::unique_ptr<DecryptConfig>(); 656 return std::unique_ptr<DecryptConfig>();
613 } 657 }
614 658
615 const std::vector<uint8_t>& kid = GetKeyId(sample_idx);
616 return std::unique_ptr<DecryptConfig>(new DecryptConfig( 659 return std::unique_ptr<DecryptConfig>(new DecryptConfig(
617 std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()), 660 std::string(reinterpret_cast<const char*>(&kid[0]), kid.size()),
618 std::string(reinterpret_cast<const char*>( 661 std::string(reinterpret_cast<const char*>(
619 sample_encryption_entry.initialization_vector), 662 sample_encryption_entry.initialization_vector),
620 arraysize(sample_encryption_entry.initialization_vector)), 663 arraysize(sample_encryption_entry.initialization_vector)),
621 sample_encryption_entry.subsamples)); 664 sample_encryption_entry.subsamples));
622 } 665 }
623 666
624 uint32_t TrackRunIterator::GetGroupDescriptionIndex( 667 uint32_t TrackRunIterator::GetGroupDescriptionIndex(
625 uint32_t sample_index) const { 668 uint32_t sample_index) const {
(...skipping 15 matching lines...) Expand all
641 return (index == 0) ? track_encryption().default_kid 684 return (index == 0) ? track_encryption().default_kid
642 : GetSampleEncryptionInfoEntry(*run_itr_, index)->key_id; 685 : GetSampleEncryptionInfoEntry(*run_itr_, index)->key_id;
643 } 686 }
644 687
645 uint8_t TrackRunIterator::GetIvSize(size_t sample_index) const { 688 uint8_t TrackRunIterator::GetIvSize(size_t sample_index) const {
646 uint32_t index = GetGroupDescriptionIndex(sample_index); 689 uint32_t index = GetGroupDescriptionIndex(sample_index);
647 return (index == 0) ? track_encryption().default_iv_size 690 return (index == 0) ? track_encryption().default_iv_size
648 : GetSampleEncryptionInfoEntry(*run_itr_, index)->iv_size; 691 : GetSampleEncryptionInfoEntry(*run_itr_, index)->iv_size;
649 } 692 }
650 693
694 #if BUILDFLAG(ENABLE_CBCS_ENCRYPTION_SCHEME)
695 bool TrackRunIterator::ApplyConstantIv(size_t sample_index,
696 SampleEncryptionEntry& entry) const {
697 if (!IsSampleEncrypted(sample_index))
698 return true;
699 uint32_t index = GetGroupDescriptionIndex(sample_index);
700 const uint8_t constant_iv_size =
701 index == 0
702 ? track_encryption().default_constant_iv_size
703 : GetSampleEncryptionInfoEntry(*run_itr_, index)->constant_iv_size;
704 RCHECK(constant_iv_size != 0);
705 const uint8_t* constant_iv =
706 index == 0 ? track_encryption().default_constant_iv
707 : GetSampleEncryptionInfoEntry(*run_itr_, index)->constant_iv;
708 RCHECK(constant_iv != nullptr);
709 memcpy(entry.initialization_vector, constant_iv, constant_iv_size);
kqyang 2016/10/12 22:16:52 It is safer to do: memcpy(entry.initialization_ve
710 return true;
711 }
712 #endif
713
651 } // namespace mp4 714 } // namespace mp4
652 } // namespace media 715 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698