diff --git a/packager/app/fixed_key_encryption_flags.cc b/packager/app/fixed_key_encryption_flags.cc index 2553fb06f8..15b537cb9d 100644 --- a/packager/app/fixed_key_encryption_flags.cc +++ b/packager/app/fixed_key_encryption_flags.cc @@ -18,6 +18,10 @@ DEFINE_bool(enable_fixed_key_decryption, "Enable decryption with fixed key."); DEFINE_string(key_id, "", "Key id in hex string format."); DEFINE_string(key, "", "Key in hex string format."); +DEFINE_string(iv, + "", + "Iv in hex string format. If not specified, a random iv will be " + "generated. This flag should only be used for testing."); DEFINE_string(pssh, "", "PSSH in hex string format."); namespace edash_packager { @@ -38,6 +42,10 @@ bool ValidateFixedCryptoFlags() { "key", FLAGS_key, fixed_crypto, false, fixed_crypto_label)) { success = false; } + if (!ValidateFlag("iv", FLAGS_iv, FLAGS_enable_fixed_key_encryption, true, + "--enable_fixed_key_encryption")) { + success = false; + } // --pssh is associated with --enable_fix_key_encryption. if (!ValidateFlag("pssh", diff --git a/packager/app/fixed_key_encryption_flags.h b/packager/app/fixed_key_encryption_flags.h index 032da12f31..ea3a6941aa 100644 --- a/packager/app/fixed_key_encryption_flags.h +++ b/packager/app/fixed_key_encryption_flags.h @@ -15,6 +15,7 @@ DECLARE_bool(enable_fixed_key_encryption); DECLARE_bool(enable_fixed_key_decryption); DECLARE_string(key_id); DECLARE_string(key); +DECLARE_string(iv); DECLARE_string(pssh); namespace edash_packager { diff --git a/packager/app/packager_main.cc b/packager/app/packager_main.cc index 1c8fb550fb..d2549de3e8 100644 --- a/packager/app/packager_main.cc +++ b/packager/app/packager_main.cc @@ -4,6 +4,7 @@ // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd +#include #include #include "packager/app/fixed_key_encryption_flags.h" @@ -18,6 +19,7 @@ #include "packager/base/strings/string_split.h" #include "packager/base/strings/stringprintf.h" #include "packager/base/threading/simple_thread.h" +#include "packager/base/time/clock.h" #include "packager/media/base/demuxer.h" #include "packager/media/base/key_source.h" #include "packager/media/base/muxer_options.h" @@ -29,6 +31,12 @@ #include "packager/mpd/base/mpd_builder.h" #include "packager/mpd/base/simple_mpd_notifier.h" +DEFINE_bool(use_fake_clock_for_muxer, + false, + "Set to true to use a fake clock for muxer. With this flag set, " + "creation time and modification time in outputs are set to 0. " + "Should only be used for testing."); + namespace { const char kUsage[] = "Packager driver program. Sample Usage:\n" @@ -66,6 +74,13 @@ enum ExitStatus { namespace edash_packager { namespace media { +// A fake clock that always return time 0 (epoch). Should only be used for +// testing. +class FakeClock : public base::Clock { + public: + virtual base::Time Now() OVERRIDE { return base::Time(); } +}; + // Demux, Mux(es) and worker thread used to remux a source file/stream. class RemuxJob : public base::SimpleThread { public: @@ -99,6 +114,7 @@ class RemuxJob : public base::SimpleThread { bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors, const MuxerOptions& muxer_options, + FakeClock* fake_clock, KeySource* key_source, MpdNotifier* mpd_notifier, std::vector* remux_jobs) { @@ -149,6 +165,8 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors, DCHECK(!remux_jobs->empty()); scoped_ptr muxer(new mp4::MP4Muxer(stream_muxer_options)); + if (FLAGS_use_fake_clock_for_muxer) muxer->set_clock(fake_clock); + if (key_source) { muxer->SetKeySource(key_source, FLAGS_max_sd_pixels, @@ -274,10 +292,9 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) { std::vector remux_jobs; STLElementDeleter > scoped_jobs_deleter(&remux_jobs); - if (!CreateRemuxJobs(stream_descriptors, - muxer_options, - encryption_key_source.get(), - mpd_notifier.get(), + FakeClock fake_clock; + if (!CreateRemuxJobs(stream_descriptors, muxer_options, &fake_clock, + encryption_key_source.get(), mpd_notifier.get(), &remux_jobs)) { return false; } diff --git a/packager/app/packager_util.cc b/packager/app/packager_util.cc index 05a8ba65d0..4b52f071dc 100644 --- a/packager/app/packager_util.cc +++ b/packager/app/packager_util.cc @@ -91,7 +91,7 @@ scoped_ptr CreateEncryptionKeySource() { encryption_key_source = widevine_key_source.Pass(); } else if (FLAGS_enable_fixed_key_encryption) { encryption_key_source = KeySource::CreateFromHexStrings( - FLAGS_key_id, FLAGS_key, FLAGS_pssh, ""); + FLAGS_key_id, FLAGS_key, FLAGS_pssh, FLAGS_iv); } return encryption_key_source.Pass(); } diff --git a/packager/app/widevine_encryption_flags.cc b/packager/app/widevine_encryption_flags.cc index efa06381b3..1448bc8098 100644 --- a/packager/app/widevine_encryption_flags.cc +++ b/packager/app/widevine_encryption_flags.cc @@ -142,12 +142,6 @@ bool ValidateWidevineCryptoFlags() { if (FLAGS_crypto_period_duration < 0) { PrintError("--crypto_period_duration should not be negative."); success = false; - } else if (FLAGS_crypto_period_duration > 0 && - !FLAGS_enable_widevine_encryption) { - PrintError( - "--crypto_period_duration should be specified only if " - "--enable_widevine_encryption."); - success = false; } return success; } diff --git a/packager/media/base/audio_stream_info.cc b/packager/media/base/audio_stream_info.cc index 1af46c0f54..3f9d50618c 100644 --- a/packager/media/base/audio_stream_info.cc +++ b/packager/media/base/audio_stream_info.cc @@ -90,12 +90,9 @@ bool AudioStreamInfo::IsValidConfig() const { std::string AudioStreamInfo::ToString() const { return base::StringPrintf( "%s codec: %s\n sample_bits: %d\n num_channels: %d\n " - "sampling_frequency: %d\n", - StreamInfo::ToString().c_str(), - AudioCodecToString(codec_).c_str(), - sample_bits_, - num_channels_, - sampling_frequency_); + "sampling_frequency: %d\n language: %s\n", + StreamInfo::ToString().c_str(), AudioCodecToString(codec_).c_str(), + sample_bits_, num_channels_, sampling_frequency_, language().c_str()); } std::string AudioStreamInfo::GetCodecString(AudioCodec codec, diff --git a/packager/media/base/key_source.cc b/packager/media/base/key_source.cc index 5ae56209e8..a25a9d624f 100644 --- a/packager/media/base/key_source.cc +++ b/packager/media/base/key_source.cc @@ -14,7 +14,8 @@ namespace { const uint8_t kWidevineSystemId[] = {0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, 0x4a, 0xce, 0xa3, 0xc8, 0x27, 0xdc, 0xd5, 0x1d, 0x21, 0xed}; -const char kDefaultUUID[] = ""; +// TODO(kqyang): Consider making it configurable. +const char kDefaultUUID[] = "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed"; const char kDefaultSystemName[] = ""; } // namespace @@ -65,8 +66,27 @@ Status KeySource::GetKey(const std::vector& key_id, Status KeySource::GetCryptoPeriodKey(uint32_t crypto_period_index, TrackType track_type, EncryptionKey* key) { - NOTIMPLEMENTED(); - return Status(error::UNIMPLEMENTED, ""); + *key = *encryption_key_; + // A naive key rotation algorithm is implemented here by left rotating the + // key, key_id and pssh. Note that this implementation is only intended for + // testing purpose. The actual key rotation algorithm can be much more + // complicated. + LOG(WARNING) + << "This naive key rotation algorithm should not be used in production."; + std::rotate(key->key_id.begin(), + key->key_id.begin() + (crypto_period_index % key->key_id.size()), + key->key_id.end()); + std::rotate(key->key.begin(), + key->key.begin() + (crypto_period_index % key->key.size()), + key->key.end()); + const size_t kPsshHeaderSize = 32u; + std::vector pssh_data(key->pssh.begin() + kPsshHeaderSize, + key->pssh.end()); + std::rotate(pssh_data.begin(), + pssh_data.begin() + (crypto_period_index % pssh_data.size()), + pssh_data.end()); + key->pssh = PsshBoxFromPsshData(pssh_data); + return Status::OK; } std::string KeySource::UUID() { diff --git a/packager/media/base/stream_info.cc b/packager/media/base/stream_info.cc index 29a9baf694..93645d07af 100644 --- a/packager/media/base/stream_info.cc +++ b/packager/media/base/stream_info.cc @@ -40,11 +40,11 @@ StreamInfo::~StreamInfo() {} std::string StreamInfo::ToString() const { return base::StringPrintf( "type: %s\n codec_string: %s\n time_scale: %d\n duration: " - "%" PRIu64 " (%.1f seconds)\n language: %s\n is_encrypted: %s\n", + "%" PRIu64 " (%.1f seconds)\n is_encrypted: %s\n", (stream_type_ == kStreamAudio ? "Audio" : "Video"), codec_string_.c_str(), time_scale_, duration_, - static_cast(duration_) / time_scale_, language_.c_str(), + static_cast(duration_) / time_scale_, is_encrypted_ ? "true" : "false"); } diff --git a/packager/media/base/video_stream_info.cc b/packager/media/base/video_stream_info.cc index 99f0704a0f..f81a219446 100644 --- a/packager/media/base/video_stream_info.cc +++ b/packager/media/base/video_stream_info.cc @@ -85,13 +85,11 @@ bool VideoStreamInfo::IsValidConfig() const { std::string VideoStreamInfo::ToString() const { return base::StringPrintf( - "%s codec: %s\n width: %d\n height: %d\n pixel_width: %d\n pixel_height: " - "%d\n trick_play_rate: %d\n nalu_length_size: %d\n", - StreamInfo::ToString().c_str(), - VideoCodecToString(codec_).c_str(), - width_, height_, - pixel_width_, pixel_height_, - trick_play_rate_, nalu_length_size_); + "%s codec: %s\n width: %d\n height: %d\n pixel aspect ratio: %d:%d\n " + "trick_play_rate: %d\n nalu_length_size: %d\n", + StreamInfo::ToString().c_str(), VideoCodecToString(codec_).c_str(), + width_, height_, pixel_width_, pixel_height_, trick_play_rate_, + nalu_length_size_); } std::string VideoStreamInfo::GetCodecString(VideoCodec codec,