diff --git a/packager/app/crypto_flags.cc b/packager/app/crypto_flags.cc new file mode 100644 index 0000000000..70802e9c43 --- /dev/null +++ b/packager/app/crypto_flags.cc @@ -0,0 +1,15 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd + +#include "packager/app/crypto_flags.h" + +#include + +DEFINE_string(protection_scheme, + "cenc", + "Specify a protection scheme, 'cenc' or 'cbc1' or pattern-based " + "protection schemes 'cens' or 'cbcs'."); +DEFINE_bool(vp9_subsample_encryption, true, "Enable VP9 subsample encryption."); diff --git a/packager/app/crypto_flags.h b/packager/app/crypto_flags.h new file mode 100644 index 0000000000..d1bd891677 --- /dev/null +++ b/packager/app/crypto_flags.h @@ -0,0 +1,18 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd +// +// Defines common command line flags for encryption and decryption, which +// applies to all key sources, i.e. fixed key, widevine and playready. + +#ifndef PACKAGER_APP_CRYPTO_FLAGS_H_ +#define PACKAGER_APP_CRYPTO_FLAGS_H_ + +#include + +DECLARE_string(protection_scheme); +DECLARE_bool(vp9_subsample_encryption); + +#endif // PACKAGER_APP_CRYPTO_FLAGS_H_ diff --git a/packager/app/muxer_flags.cc b/packager/app/muxer_flags.cc index 4ef5e27aa5..0fcd349258 100644 --- a/packager/app/muxer_flags.cc +++ b/packager/app/muxer_flags.cc @@ -41,5 +41,3 @@ DEFINE_string(temp_dir, "", "Specify a directory in which to store temporary (intermediate) " " files. Used only if single_segment=true."); -DEFINE_bool(webm_subsample_encryption, true, - "Enable WebM subsample encryption."); diff --git a/packager/app/muxer_flags.h b/packager/app/muxer_flags.h index a053794f31..650e4601e0 100644 --- a/packager/app/muxer_flags.h +++ b/packager/app/muxer_flags.h @@ -18,6 +18,5 @@ DECLARE_double(fragment_duration); DECLARE_bool(fragment_sap_aligned); DECLARE_int32(num_subsegments_per_sidx); DECLARE_string(temp_dir); -DECLARE_bool(webm_subsample_encryption); #endif // APP_MUXER_FLAGS_H_ diff --git a/packager/app/packager_util.cc b/packager/app/packager_util.cc index f82d4dc547..177d4ad182 100644 --- a/packager/app/packager_util.cc +++ b/packager/app/packager_util.cc @@ -9,6 +9,7 @@ #include #include +#include "packager/app/crypto_flags.h" #include "packager/app/fixed_key_encryption_flags.h" #include "packager/app/playready_key_encryption_flags.h" #include "packager/app/mpd_flags.h" @@ -185,13 +186,13 @@ EncryptionOptions GetEncryptionOptions() { encryption_options.max_uhd1_pixels = FLAGS_max_uhd1_pixels; encryption_options.crypto_period_duration_in_seconds = FLAGS_crypto_period_duration; + encryption_options.vp9_subsample_encryption = FLAGS_vp9_subsample_encryption; return encryption_options; } MuxerOptions GetMuxerOptions() { MuxerOptions muxer_options; muxer_options.num_subsegments_per_sidx = FLAGS_num_subsegments_per_sidx; - muxer_options.webm_subsample_encryption = FLAGS_webm_subsample_encryption; if (FLAGS_mp4_use_decoding_timestamp_in_timeline) { LOG(WARNING) << "Flag --mp4_use_decoding_timestamp_in_timeline is set. " "Note that it is a temporary hack to workaround Chromium " diff --git a/packager/app/retired_flags.cc b/packager/app/retired_flags.cc index fb0eb08fd8..88e4e85899 100644 --- a/packager/app/retired_flags.cc +++ b/packager/app/retired_flags.cc @@ -13,6 +13,9 @@ DEFINE_string(profile, "", "This flag is deprecated. Do not use."); DEFINE_bool(single_segment, true, "This flag is deprecated. Do not use."); +DEFINE_bool(webm_subsample_encryption, + true, + "This flag is deprecated. Use vp9_subsample_encryption instead."); // The current gflags library does not provide a way to check whether a flag is // set in command line. If a flag has a different value to its default value, @@ -32,3 +35,4 @@ bool InformRetiredDefaultTrueFlag(const char* flagname, bool value) { DEFINE_validator(profile, &InformRetiredStringFlag); DEFINE_validator(single_segment, &InformRetiredDefaultTrueFlag); +DEFINE_validator(webm_subsample_encryption, &InformRetiredDefaultTrueFlag); diff --git a/packager/app/retired_flags.h b/packager/app/retired_flags.h index ae91a335e3..4a2e7fe93f 100644 --- a/packager/app/retired_flags.h +++ b/packager/app/retired_flags.h @@ -8,3 +8,4 @@ DECLARE_string(profile); DECLARE_bool(single_segment); +DECLARE_bool(webm_subsample_encryption); diff --git a/packager/app/test/packager_test.py b/packager/app/test/packager_test.py index fd39bf3c98..dbc5191b34 100755 --- a/packager/app/test/packager_test.py +++ b/packager/app/test/packager_test.py @@ -230,6 +230,17 @@ class PackagerAppTest(unittest.TestCase): self._VerifyDecryption(self.output[0], 'bear-640x360-vp9-altref-dec-golden.webm') + def testPackageWithWebmVp9FullSampleEncryption(self): + self.packager.Package( + self._GetStreams(['video'], + output_format='webm', + test_files=['bear-640x360-vp9-altref.webm']), + self._GetFlags(encryption=True, vp9_subsample_encryption=False)) + self._DiffGold(self.output[0], + 'bear-640x360-vp9-fullsample-enc-golden.webm') + self._VerifyDecryption(self.output[0], + 'bear-640x360-vp9-altref-dec-golden.webm') + def testPackageAvcTsWithEncryption(self): # Currently we only support live packaging for ts. self.packager.Package( @@ -532,6 +543,7 @@ class PackagerAppTest(unittest.TestCase): def _GetFlags(self, encryption=False, protection_scheme=None, + vp9_subsample_encryption=True, decryption=False, encryption_key='32333435363738393021323334353637', encryption_iv='3334353637383930', @@ -564,6 +576,8 @@ class PackagerAppTest(unittest.TestCase): flags.append('--iv=' + encryption_iv) if protection_scheme: flags += ['--protection_scheme', protection_scheme] + if not vp9_subsample_encryption: + flags += ['--vp9_subsample_encryption=false'] if decryption: flags += ['--enable_fixed_key_decryption', diff --git a/packager/app/test/testdata/bear-640x360-vp9-fullsample-dec-golden.webm b/packager/app/test/testdata/bear-640x360-vp9-fullsample-dec-golden.webm new file mode 100644 index 0000000000..ae1c97b480 Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-vp9-fullsample-dec-golden.webm differ diff --git a/packager/app/test/testdata/bear-640x360-vp9-fullsample-enc-golden.webm b/packager/app/test/testdata/bear-640x360-vp9-fullsample-enc-golden.webm new file mode 100644 index 0000000000..b08ea493af Binary files /dev/null and b/packager/app/test/testdata/bear-640x360-vp9-fullsample-enc-golden.webm differ diff --git a/packager/app/widevine_encryption_flags.cc b/packager/app/widevine_encryption_flags.cc index d8c444d79a..7abc4eb6ac 100644 --- a/packager/app/widevine_encryption_flags.cc +++ b/packager/app/widevine_encryption_flags.cc @@ -65,10 +65,6 @@ DEFINE_int32(crypto_period_duration, 0, "Crypto period duration in seconds. If it is non-zero, key " "rotation is enabled."); -DEFINE_string(protection_scheme, - "cenc", - "Choose protection scheme, 'cenc' or 'cbc1' or pattern-based " - "protection schemes 'cens' or 'cbcs'."); namespace shaka { diff --git a/packager/app/widevine_encryption_flags.h b/packager/app/widevine_encryption_flags.h index 8218fabd6c..966d8118a6 100644 --- a/packager/app/widevine_encryption_flags.h +++ b/packager/app/widevine_encryption_flags.h @@ -25,7 +25,6 @@ DECLARE_string(aes_signing_key); DECLARE_string(aes_signing_iv); DECLARE_string(rsa_signing_key_path); DECLARE_int32(crypto_period_duration); -DECLARE_string(protection_scheme); namespace shaka { diff --git a/packager/media/base/muxer_options.h b/packager/media/base/muxer_options.h index 14dc73b6f2..11e37a88d1 100644 --- a/packager/media/base/muxer_options.h +++ b/packager/media/base/muxer_options.h @@ -50,9 +50,6 @@ struct MuxerOptions { /// User-specified bit rate for the media stream. If zero, the muxer will /// attempt to estimate. uint32_t bandwidth = 0; - - // Enable/disable subsample encryption for WebM containers. - bool webm_subsample_encryption = true; }; } // namespace media diff --git a/packager/media/crypto/encryption_handler.cc b/packager/media/crypto/encryption_handler.cc index da4ffd9ff7..41471e248f 100644 --- a/packager/media/crypto/encryption_handler.cc +++ b/packager/media/crypto/encryption_handler.cc @@ -146,7 +146,8 @@ Status EncryptionHandler::ProcessStreamInfo(StreamInfo* stream_info) { encryption_options_.max_hd_pixels, encryption_options_.max_uhd1_pixels); switch (codec_) { case kCodecVP9: - vpx_parser_.reset(new VP9Parser); + if (encryption_options_.vp9_subsample_encryption) + vpx_parser_.reset(new VP9Parser); break; case kCodecH264: header_parser_.reset(new H264VideoSliceHeaderParser); @@ -246,8 +247,6 @@ Status EncryptionHandler::ProcessMediaSample(MediaSample* sample) { sample->data_size()); } } else { - DCHECK_LE(crypt_byte_block_, 1u); - DCHECK_EQ(skip_byte_block_, 0u); if (sample->data_size() > leading_clear_bytes_size_) { EncryptBytes(sample->writable_data() + leading_clear_bytes_size_, sample->data_size() - leading_clear_bytes_size_); diff --git a/packager/media/crypto/encryption_handler.h b/packager/media/crypto/encryption_handler.h index e541ba0629..e825280e62 100644 --- a/packager/media/crypto/encryption_handler.h +++ b/packager/media/crypto/encryption_handler.h @@ -41,6 +41,8 @@ struct EncryptionOptions { /// Crypto period duration in seconds. A positive value means key rotation is /// enabled, the key source must support key rotation in this case. double crypto_period_duration_in_seconds = 0; + // Enable/disable subsample encryption for VP9. + bool vp9_subsample_encryption = true; }; class EncryptionHandler : public MediaHandler { diff --git a/packager/media/crypto/encryption_handler_unittest.cc b/packager/media/crypto/encryption_handler_unittest.cc index 1c6d5e4de0..9341ab2f49 100644 --- a/packager/media/crypto/encryption_handler_unittest.cc +++ b/packager/media/crypto/encryption_handler_unittest.cc @@ -133,6 +133,7 @@ TEST_F(EncryptionHandlerTest, OnlyOneInput) { namespace { +const bool kVp9SubsampleEncryption = true; const bool kIsKeyFrame = true; const bool kIsSubsegment = true; const bool kEncrypted = true; @@ -205,11 +206,12 @@ inline bool operator==(const SubsampleEntry& lhs, const SubsampleEntry& rhs) { class EncryptionHandlerEncryptionTest : public EncryptionHandlerTest, - public WithParamInterface> { + public WithParamInterface> { public: void SetUp() override { protection_scheme_ = std::tr1::get<0>(GetParam()); codec_ = std::tr1::get<1>(GetParam()); + vp9_subsample_encryption_ = std::tr1::get<2>(GetParam()); } std::vector GetMockVpxFrameInfo() { @@ -225,8 +227,10 @@ class EncryptionHandlerEncryptionTest // The subsamples values should match |GetMockVpxFrameInfo| above. std::vector GetExpectedSubsamples() { std::vector subsamples; - if (codec_ == kCodecAAC) + if (codec_ == kCodecAAC || + (codec_ == kCodecVP9 && !vp9_subsample_encryption_)) { return subsamples; + } if (protection_scheme_ == kAppleSampleAesProtectionScheme) { subsamples.emplace_back(static_cast(kSampleAesClearSize1), static_cast(kSampleAesCipherSize1)); @@ -265,14 +269,15 @@ class EncryptionHandlerEncryptionTest // Inject vpx parser / video slice header parser if needed. void InjectCodecParser() { switch (codec_) { - case kCodecVP9: { - std::unique_ptr mock_vpx_parser(new MockVpxParser); - EXPECT_CALL(*mock_vpx_parser, Parse(_, sizeof(kData), _)) - .WillRepeatedly( - DoAll(SetArgPointee<2>(GetMockVpxFrameInfo()), Return(true))); - InjectVpxParserForTesting(std::move(mock_vpx_parser)); + case kCodecVP9: + if (vp9_subsample_encryption_) { + std::unique_ptr mock_vpx_parser(new MockVpxParser); + EXPECT_CALL(*mock_vpx_parser, Parse(_, sizeof(kData), _)) + .WillRepeatedly( + DoAll(SetArgPointee<2>(GetMockVpxFrameInfo()), Return(true))); + InjectVpxParserForTesting(std::move(mock_vpx_parser)); + } break; - } case kCodecH264: { std::unique_ptr mock_header_parser( new MockVideoSliceHeaderParser); @@ -441,6 +446,7 @@ class EncryptionHandlerEncryptionTest protected: FourCC protection_scheme_; Codec codec_; + bool vp9_subsample_encryption_; }; TEST_P(EncryptionHandlerEncryptionTest, ClearLeadWithNoKeyRotation) { @@ -448,6 +454,7 @@ TEST_P(EncryptionHandlerEncryptionTest, ClearLeadWithNoKeyRotation) { EncryptionOptions encryption_options; encryption_options.protection_scheme = protection_scheme_; encryption_options.clear_lead_in_seconds = kClearLeadInSeconds; + encryption_options.vp9_subsample_encryption = vp9_subsample_encryption_; SetUpEncryptionHandler(encryption_options); const EncryptionKey mock_encryption_key = GetMockEncryptionKey(); @@ -498,6 +505,7 @@ TEST_P(EncryptionHandlerEncryptionTest, ClearLeadWithKeyRotation) { encryption_options.clear_lead_in_seconds = kClearLeadInSeconds; encryption_options.crypto_period_duration_in_seconds = kCryptoPeriodDurationInSeconds; + encryption_options.vp9_subsample_encryption = vp9_subsample_encryption_; SetUpEncryptionHandler(encryption_options); ASSERT_OK(Process(GetStreamInfoStreamData(kStreamIndex, codec_, kTimeScale))); @@ -549,6 +557,7 @@ TEST_P(EncryptionHandlerEncryptionTest, ClearLeadWithKeyRotation) { TEST_P(EncryptionHandlerEncryptionTest, Encrypt) { EncryptionOptions encryption_options; encryption_options.protection_scheme = protection_scheme_; + encryption_options.vp9_subsample_encryption = vp9_subsample_encryption_; SetUpEncryptionHandler(encryption_options); const EncryptionKey mock_encryption_key = GetMockEncryptionKey(); @@ -597,11 +606,13 @@ INSTANTIATE_TEST_CASE_P( CencProtectionSchemes, EncryptionHandlerEncryptionTest, Combine(Values(FOURCC_cenc, FOURCC_cens, FOURCC_cbc1, FOURCC_cbcs), - Values(kCodecAAC, kCodecH264, kCodecVP9))); + Values(kCodecAAC, kCodecH264, kCodecVP9), + Values(kVp9SubsampleEncryption, !kVp9SubsampleEncryption))); INSTANTIATE_TEST_CASE_P(AppleSampleAes, EncryptionHandlerEncryptionTest, Combine(Values(kAppleSampleAesProtectionScheme), - Values(kCodecAAC, kCodecH264))); + Values(kCodecAAC, kCodecH264), + Values(kVp9SubsampleEncryption))); namespace { diff --git a/packager/packager.gyp b/packager/packager.gyp index 304ad3af88..09a21fde6e 100644 --- a/packager/packager.gyp +++ b/packager/packager.gyp @@ -13,6 +13,8 @@ 'target_name': 'packager', 'type': 'executable', 'sources': [ + 'app/crypto_flags.cc', + 'app/crypto_flags.h', 'app/fixed_key_encryption_flags.cc', 'app/fixed_key_encryption_flags.h', 'app/hls_flags.cc',