diff --git a/docs/source/options/general_encryption_options.rst b/docs/source/options/general_encryption_options.rst index bd85337a38..474aab9755 100644 --- a/docs/source/options/general_encryption_options.rst +++ b/docs/source/options/general_encryption_options.rst @@ -6,6 +6,24 @@ General encryption options Specify a protection scheme, 'cenc' or 'cbc1' or pattern-based protection schemes 'cens' or 'cbcs'. +--crypt_byte_block + + Specify the count of the encrypted blocks in the protection pattern, where + block is of size 16-bytes. + + There are three common patterns (crypt_byte_block:skip_byte_block): + 1:9 (default), 5:5, 10:0. + + Apply to video streams with 'cbcs' and 'cens' protection schemes only; + ignored otherwise. + +--skip_byte_block + + Specify the count of the unencrypted blocks in the protection pattern. + + Apply to video streams with 'cbcs' and 'cens' protection schemes only; + ignored otherwise. + --vp9_subsample_encryption, --novp9_subsample_encryption Enable / disable VP9 subsample encryption. Enabled by default. diff --git a/packager/app/crypto_flags.cc b/packager/app/crypto_flags.cc index 70802e9c43..3c9e5daaab 100644 --- a/packager/app/crypto_flags.cc +++ b/packager/app/crypto_flags.cc @@ -12,4 +12,33 @@ DEFINE_string(protection_scheme, "cenc", "Specify a protection scheme, 'cenc' or 'cbc1' or pattern-based " "protection schemes 'cens' or 'cbcs'."); +DEFINE_int32( + crypt_byte_block, + 1, + "Specify the count of the encrypted blocks in the protection pattern, " + "where block is of size 16-bytes. There are three common " + "patterns (crypt_byte_block:skip_byte_block): 1:9 (default), 5:5, 10:0. " + "Apply to video streams with 'cbcs' and 'cens' protection schemes only; " + "ignored otherwise."); +DEFINE_int32( + skip_byte_block, + 9, + "Specify the count of the unencrypted blocks in the protection pattern. " + "Apply to video streams with 'cbcs' and 'cens' protection schemes only; " + "ignored otherwise."); DEFINE_bool(vp9_subsample_encryption, true, "Enable VP9 subsample encryption."); + +bool ValueNotGreaterThanTen(const char* flagname, int32_t value) { + if (value > 10) { + fprintf(stderr, "ERROR: %s must not be greater than 10.\n", flagname); + return false; + } + if (value < 0) { + fprintf(stderr, "ERROR: %s must be non-negative.\n", flagname); + return false; + } + return true; +} + +DEFINE_validator(crypt_byte_block, &ValueNotGreaterThanTen); +DEFINE_validator(skip_byte_block, &ValueNotGreaterThanTen); diff --git a/packager/app/crypto_flags.h b/packager/app/crypto_flags.h index 4d9e16fead..b909e65e35 100644 --- a/packager/app/crypto_flags.h +++ b/packager/app/crypto_flags.h @@ -13,6 +13,8 @@ #include DECLARE_string(protection_scheme); +DECLARE_int32(crypt_byte_block); +DECLARE_int32(skip_byte_block); DECLARE_bool(vp9_subsample_encryption); #endif // PACKAGER_APP_CRYPTO_FLAGS_H_ diff --git a/packager/app/packager_main.cc b/packager/app/packager_main.cc index 31fbb2edc4..0d193ece15 100644 --- a/packager/app/packager_main.cc +++ b/packager/app/packager_main.cc @@ -343,6 +343,9 @@ base::Optional GetPackagingParams() { encryption_params.clear_lead_in_seconds = FLAGS_clear_lead; if (!GetProtectionScheme(&encryption_params.protection_scheme)) return base::nullopt; + encryption_params.crypt_byte_block = FLAGS_crypt_byte_block; + encryption_params.skip_byte_block = FLAGS_skip_byte_block; + encryption_params.crypto_period_duration_in_seconds = FLAGS_crypto_period_duration; encryption_params.vp9_subsample_encryption = FLAGS_vp9_subsample_encryption; diff --git a/packager/app/test/packager_test.py b/packager/app/test/packager_test.py index b25f5a4e3a..3a125d5507 100755 --- a/packager/app/test/packager_test.py +++ b/packager/app/test/packager_test.py @@ -417,6 +417,8 @@ class PackagerAppTest(unittest.TestCase): encryption=False, protection_systems=None, protection_scheme=None, + crypt_byte_block=None, + skip_byte_block=None, vp9_subsample_encryption=True, decryption=False, random_iv=False, @@ -469,6 +471,11 @@ class PackagerAppTest(unittest.TestCase): if protection_scheme: flags += ['--protection_scheme', protection_scheme] + if crypt_byte_block is not None and skip_byte_block is not None: + flags += [ + '--crypt_byte_block={0}'.format(crypt_byte_block), + '--skip_byte_block={0}'.format(skip_byte_block) + ] if not vp9_subsample_encryption: flags += ['--vp9_subsample_encryption=false'] @@ -1042,6 +1049,18 @@ class PackagerFunctionalTest(PackagerAppTest): encryption=True, protection_scheme='cbcs', output_dash=True)) self._CheckTestResults('encryption-cbcs', verify_decryption=True) + def testEncryptionCbcsWithFullProtection(self): + self.assertPackageSuccess( + self._GetStreams(['audio', 'video']), + self._GetFlags( + encryption=True, + protection_scheme='cbcs', + crypt_byte_block=10, + skip_byte_block=0, + output_dash=True)) + self._CheckTestResults( + 'encryption-cbcs-with-full-protection', verify_decryption=True) + def testEncryptionAndAdCues(self): self.assertPackageSuccess( self._GetStreams(['audio', 'video'], hls=True), @@ -1774,6 +1793,17 @@ class PackagerCommandParsingTest(PackagerAppTest): # Expect the test to fail but we do not expect a crash. self.assertEqual(packaging_result, 1) + def testIncorrectEncryptionPattern(self): + packaging_result = self.packager.Package( + self._GetStreams(['audio', 'video']), + self._GetFlags( + encryption=True, + protection_scheme='cbcs', + crypt_byte_block=12, + skip_byte_block=13, + output_dash=True)) + self.assertEqual(packaging_result, 1) + if __name__ == '__main__': unittest.main() diff --git a/packager/app/test/testdata/encryption-cbcs-with-full-protection/bear-640x360-audio.mp4 b/packager/app/test/testdata/encryption-cbcs-with-full-protection/bear-640x360-audio.mp4 new file mode 100644 index 0000000000..05fe6fa48c Binary files /dev/null and b/packager/app/test/testdata/encryption-cbcs-with-full-protection/bear-640x360-audio.mp4 differ diff --git a/packager/app/test/testdata/encryption-cbcs-with-full-protection/bear-640x360-video.mp4 b/packager/app/test/testdata/encryption-cbcs-with-full-protection/bear-640x360-video.mp4 new file mode 100644 index 0000000000..b69276fb27 Binary files /dev/null and b/packager/app/test/testdata/encryption-cbcs-with-full-protection/bear-640x360-video.mp4 differ diff --git a/packager/app/test/testdata/encryption-cbcs-with-full-protection/decrypted-bear-640x360-audio-0.mp4 b/packager/app/test/testdata/encryption-cbcs-with-full-protection/decrypted-bear-640x360-audio-0.mp4 new file mode 100644 index 0000000000..87f89a93c0 Binary files /dev/null and b/packager/app/test/testdata/encryption-cbcs-with-full-protection/decrypted-bear-640x360-audio-0.mp4 differ diff --git a/packager/app/test/testdata/encryption-cbcs-with-full-protection/decrypted-bear-640x360-video-0.mp4 b/packager/app/test/testdata/encryption-cbcs-with-full-protection/decrypted-bear-640x360-video-0.mp4 new file mode 100644 index 0000000000..9bc668f8f6 Binary files /dev/null and b/packager/app/test/testdata/encryption-cbcs-with-full-protection/decrypted-bear-640x360-video-0.mp4 differ diff --git a/packager/app/test/testdata/encryption-cbcs-with-full-protection/output.mpd b/packager/app/test/testdata/encryption-cbcs-with-full-protection/output.mpd new file mode 100644 index 0000000000..55d19f794b --- /dev/null +++ b/packager/app/test/testdata/encryption-cbcs-with-full-protection/output.mpd @@ -0,0 +1,31 @@ + + + + + + + + AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== + + + bear-640x360-video.mp4 + + + + + + + + + AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== + + + + bear-640x360-audio.mp4 + + + + + + + diff --git a/packager/media/crypto/encryption_handler.cc b/packager/media/crypto/encryption_handler.cc index 4d590a2f34..0e8b234b5d 100644 --- a/packager/media/crypto/encryption_handler.cc +++ b/packager/media/crypto/encryption_handler.cc @@ -253,9 +253,8 @@ Status EncryptionHandler::ProcessMediaSample( void EncryptionHandler::SetupProtectionPattern(StreamType stream_type) { if (stream_type == kStreamVideo && IsPatternEncryptionScheme(protection_scheme_)) { - // Use 1:9 pattern. - crypt_byte_block_ = 1u; - skip_byte_block_ = 9u; + crypt_byte_block_ = encryption_params_.crypt_byte_block; + skip_byte_block_ = encryption_params_.skip_byte_block; } else { // Audio stream in pattern encryption scheme does not use pattern; it uses // whole-block full sample encryption instead. Non-pattern encryption does diff --git a/packager/media/public/crypto_params.h b/packager/media/public/crypto_params.h index 6e3b31b0e8..97fff1892a 100644 --- a/packager/media/public/crypto_params.h +++ b/packager/media/public/crypto_params.h @@ -134,6 +134,16 @@ struct EncryptionParams { static constexpr uint32_t kProtectionSchemeCens = 0x63656E73; static constexpr uint32_t kProtectionSchemeCbcs = 0x63626373; uint32_t protection_scheme = kProtectionSchemeCenc; + /// The count of the encrypted blocks in the protection pattern, where each + /// block is of size 16-bytes. There are three common patterns + /// (crypt_byte_block:skip_byte_block): 1:9 (default), 5:5, 10:0. + /// Applies to video streams with "cbcs" and "cens" protection schemes only; + /// Ignored otherwise. + uint8_t crypt_byte_block = 1; + /// The count of the unencrypted blocks in the protection pattern. + /// Applies to video streams with "cbcs" and "cens" protection schemes only; + /// Ignored otherwise. + uint8_t skip_byte_block = 9; /// Crypto period duration in seconds. A positive value means key rotation is /// enabled, the key provider must support key rotation in this case. static constexpr double kNoKeyRotation = 0;