Allow specifying protection pattern for pattern encryption

Added --crypt_byte_block, --skip_byte_block to allow users to specify
protection pattern other than 1:9 for pattern based encryption scheme,
e.g. cbcs and cens.

Closes #710.
b/147307451

Change-Id: I9f64a7639170c737f138572689b28d17286325c7
This commit is contained in:
KongQun Yang 2020-02-10 00:31:45 -08:00
parent 1ca873f453
commit 4028bf727b
12 changed files with 125 additions and 3 deletions

View File

@ -6,6 +6,24 @@ General encryption options
Specify a protection scheme, 'cenc' or 'cbc1' or pattern-based protection Specify a protection scheme, 'cenc' or 'cbc1' or pattern-based protection
schemes 'cens' or 'cbcs'. 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 --vp9_subsample_encryption, --novp9_subsample_encryption
Enable / disable VP9 subsample encryption. Enabled by default. Enable / disable VP9 subsample encryption. Enabled by default.

View File

@ -12,4 +12,33 @@ DEFINE_string(protection_scheme,
"cenc", "cenc",
"Specify a protection scheme, 'cenc' or 'cbc1' or pattern-based " "Specify a protection scheme, 'cenc' or 'cbc1' or pattern-based "
"protection schemes 'cens' or 'cbcs'."); "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."); 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);

View File

@ -13,6 +13,8 @@
#include <gflags/gflags.h> #include <gflags/gflags.h>
DECLARE_string(protection_scheme); DECLARE_string(protection_scheme);
DECLARE_int32(crypt_byte_block);
DECLARE_int32(skip_byte_block);
DECLARE_bool(vp9_subsample_encryption); DECLARE_bool(vp9_subsample_encryption);
#endif // PACKAGER_APP_CRYPTO_FLAGS_H_ #endif // PACKAGER_APP_CRYPTO_FLAGS_H_

View File

@ -343,6 +343,9 @@ base::Optional<PackagingParams> GetPackagingParams() {
encryption_params.clear_lead_in_seconds = FLAGS_clear_lead; encryption_params.clear_lead_in_seconds = FLAGS_clear_lead;
if (!GetProtectionScheme(&encryption_params.protection_scheme)) if (!GetProtectionScheme(&encryption_params.protection_scheme))
return base::nullopt; 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 = encryption_params.crypto_period_duration_in_seconds =
FLAGS_crypto_period_duration; FLAGS_crypto_period_duration;
encryption_params.vp9_subsample_encryption = FLAGS_vp9_subsample_encryption; encryption_params.vp9_subsample_encryption = FLAGS_vp9_subsample_encryption;

View File

@ -417,6 +417,8 @@ class PackagerAppTest(unittest.TestCase):
encryption=False, encryption=False,
protection_systems=None, protection_systems=None,
protection_scheme=None, protection_scheme=None,
crypt_byte_block=None,
skip_byte_block=None,
vp9_subsample_encryption=True, vp9_subsample_encryption=True,
decryption=False, decryption=False,
random_iv=False, random_iv=False,
@ -469,6 +471,11 @@ class PackagerAppTest(unittest.TestCase):
if protection_scheme: if protection_scheme:
flags += ['--protection_scheme', 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: if not vp9_subsample_encryption:
flags += ['--vp9_subsample_encryption=false'] flags += ['--vp9_subsample_encryption=false']
@ -1042,6 +1049,18 @@ class PackagerFunctionalTest(PackagerAppTest):
encryption=True, protection_scheme='cbcs', output_dash=True)) encryption=True, protection_scheme='cbcs', output_dash=True))
self._CheckTestResults('encryption-cbcs', verify_decryption=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): def testEncryptionAndAdCues(self):
self.assertPackageSuccess( self.assertPackageSuccess(
self._GetStreams(['audio', 'video'], hls=True), 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. # Expect the test to fail but we do not expect a crash.
self.assertEqual(packaging_result, 1) 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__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--Generated with https://github.com/google/shaka-packager version <tag>-<hash>-<test>-->
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.7360665798187256S">
<Period id="0">
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
<ContentProtection value="cbcs" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA==</cenc:pssh>
</ContentProtection>
<Representation id="0" bandwidth="975825" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
<BaseURL>bear-640x360-video.mp4</BaseURL>
<SegmentBase indexRange="1136-1203" timescale="30000">
<Initialization range="0-1135"/>
</SegmentBase>
</Representation>
</AdaptationSet>
<AdaptationSet id="1" contentType="audio" subsegmentAlignment="true">
<ContentProtection value="cbcs" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
<cenc:pssh>AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA==</cenc:pssh>
</ContentProtection>
<Representation id="1" bandwidth="133334" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
<BaseURL>bear-640x360-audio.mp4</BaseURL>
<SegmentBase indexRange="1012-1079" timescale="44100">
<Initialization range="0-1011"/>
</SegmentBase>
</Representation>
</AdaptationSet>
</Period>
</MPD>

View File

@ -253,9 +253,8 @@ Status EncryptionHandler::ProcessMediaSample(
void EncryptionHandler::SetupProtectionPattern(StreamType stream_type) { void EncryptionHandler::SetupProtectionPattern(StreamType stream_type) {
if (stream_type == kStreamVideo && if (stream_type == kStreamVideo &&
IsPatternEncryptionScheme(protection_scheme_)) { IsPatternEncryptionScheme(protection_scheme_)) {
// Use 1:9 pattern. crypt_byte_block_ = encryption_params_.crypt_byte_block;
crypt_byte_block_ = 1u; skip_byte_block_ = encryption_params_.skip_byte_block;
skip_byte_block_ = 9u;
} else { } else {
// Audio stream in pattern encryption scheme does not use pattern; it uses // Audio stream in pattern encryption scheme does not use pattern; it uses
// whole-block full sample encryption instead. Non-pattern encryption does // whole-block full sample encryption instead. Non-pattern encryption does

View File

@ -134,6 +134,16 @@ struct EncryptionParams {
static constexpr uint32_t kProtectionSchemeCens = 0x63656E73; static constexpr uint32_t kProtectionSchemeCens = 0x63656E73;
static constexpr uint32_t kProtectionSchemeCbcs = 0x63626373; static constexpr uint32_t kProtectionSchemeCbcs = 0x63626373;
uint32_t protection_scheme = kProtectionSchemeCenc; 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 /// Crypto period duration in seconds. A positive value means key rotation is
/// enabled, the key provider must support key rotation in this case. /// enabled, the key provider must support key rotation in this case.
static constexpr double kNoKeyRotation = 0; static constexpr double kNoKeyRotation = 0;