Fix pattern signaling in seig for key rotation with cbcs

Closes #460.
Bug: 112769382

Change-Id: Id2277edf9ac1ca637354f3a585666ad139ed8ee2
This commit is contained in:
KongQun Yang 2018-08-20 15:45:02 -07:00
parent 9b655189cf
commit 40a3b42980
13 changed files with 70 additions and 32 deletions

View File

@ -1409,6 +1409,16 @@ class PackagerFunctionalTest(PackagerAppTest):
self._GetFlags(encryption=True, key_rotation=True, output_dash=True))
self._CheckTestResults('live-profile-and-key-rotation')
def testLiveProfileAndKeyRotationCbcs(self):
self.assertPackageSuccess(
self._GetStreams(['audio', 'video'], segmented=True),
self._GetFlags(
encryption=True,
protection_scheme='cbcs',
key_rotation=True,
output_dash=True))
self._CheckTestResults('live-profile-and-key-rotation-cbcs')
def testLiveProfileAndKeyRotationAndNoPsshInStream(self):
self.assertPackageSuccess(
self._GetStreams(['audio', 'video'], segmented=True),

View File

@ -0,0 +1,32 @@
<?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" xmlns:xlink="http://www.w3.org/1999/xlink" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-live:2011" minBufferTime="PT2S" type="dynamic" publishTime="some_time" availabilityStartTime="some_time" minimumUpdatePeriod="PT5S" timeShiftBufferDepth="PT1800S">
<Period id="0" start="PT0S">
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" segmentAlignment="true" par="16:9">
<ContentProtection value="cbcs" schemeIdUri="urn:mpeg:dash:mp4protection:2011"/>
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"/>
<Representation id="0" bandwidth="977527" codecs="avc1.64001e" mimeType="video/mp4" sar="1:1">
<SegmentTemplate timescale="30000" initialization="bear-640x360-video-init.mp4" media="bear-640x360-video-$Number$.m4s" startNumber="1">
<SegmentTimeline>
<S t="0" d="30030" r="1"/>
<S t="60060" d="22022"/>
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
<AdaptationSet id="1" contentType="audio" segmentAlignment="true">
<ContentProtection value="cbcs" schemeIdUri="urn:mpeg:dash:mp4protection:2011"/>
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b"/>
<Representation id="1" bandwidth="134336" codecs="mp4a.40.2" mimeType="audio/mp4" audioSamplingRate="44100">
<AudioChannelConfiguration schemeIdUri="urn:mpeg:dash:23003:3:audio_channel_configuration:2011" value="2"/>
<SegmentTemplate timescale="44100" initialization="bear-640x360-audio-init.mp4" media="bear-640x360-audio-$Number$.m4s" startNumber="1">
<SegmentTimeline>
<S t="0" d="45056"/>
<S t="45056" d="44032"/>
<S t="89088" d="31744"/>
</SegmentTimeline>
</SegmentTemplate>
</Representation>
</AdaptationSet>
</Period>
</MPD>

View File

@ -22,6 +22,7 @@
#include "packager/media/codecs/vp8_parser.h"
#include "packager/media/codecs/vp9_parser.h"
#include "packager/media/crypto/sample_aes_ec3_cryptor.h"
#include "packager/status_macros.h"
namespace shaka {
namespace media {
@ -32,10 +33,17 @@ const size_t kCencBlockSize = 16u;
// The encryption handler only supports a single output.
const size_t kStreamIndex = 0;
// The default KID for key rotation is all 0s.
// The default KID, KEY and IV for key rotation are all 0s.
// They are placeholders and are not really being used to encrypt data.
const uint8_t kKeyRotationDefaultKeyId[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
const uint8_t kKeyRotationDefaultKey[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
const uint8_t kKeyRotationDefaultIv[] = {
0, 0, 0, 0, 0, 0, 0, 0,
};
// Adds one or more subsamples to |*decrypt_config|. This may add more than one
// if one of the values overflows the integer in the subsample.
@ -179,25 +187,21 @@ Status EncryptionHandler::ProcessStreamInfo(const StreamInfo& clear_info) {
}
}
Status status = SetupProtectionPattern(stream_info->stream_type());
if (!status.ok())
return status;
RETURN_IF_ERROR(SetupProtectionPattern(stream_info->stream_type()));
EncryptionKey encryption_key;
const bool key_rotation_enabled = crypto_period_duration_ != 0;
if (key_rotation_enabled) {
check_new_crypto_period_ = true;
// Setup dummy key id and key to signal encryption for key rotation.
encryption_key.key_id.assign(
kKeyRotationDefaultKeyId,
kKeyRotationDefaultKeyId + sizeof(kKeyRotationDefaultKeyId));
// The key is not really used to encrypt any data. It is there just for
// convenience.
encryption_key.key = encryption_key.key_id;
// Setup dummy key id, key and iv to signal encryption for key rotation.
encryption_key.key_id.assign(std::begin(kKeyRotationDefaultKeyId),
std::end(kKeyRotationDefaultKeyId));
encryption_key.key.assign(std::begin(kKeyRotationDefaultKey),
std::end(kKeyRotationDefaultKey));
encryption_key.iv.assign(std::begin(kKeyRotationDefaultIv),
std::end(kKeyRotationDefaultIv));
} else {
status = key_source_->GetKey(stream_label_, &encryption_key);
if (!status.ok())
return status;
RETURN_IF_ERROR(key_source_->GetKey(stream_label_, &encryption_key));
}
if (!CreateEncryptor(encryption_key))
return Status(error::ENCRYPTION_FAILURE, "Failed to create encryptor");
@ -233,10 +237,8 @@ Status EncryptionHandler::ProcessMediaSample(
const int64_t current_crypto_period_index = dts / crypto_period_duration_;
if (current_crypto_period_index != prev_crypto_period_index_) {
EncryptionKey encryption_key;
Status status = key_source_->GetCryptoPeriodKey(
current_crypto_period_index, stream_label_, &encryption_key);
if (!status.ok())
return status;
RETURN_IF_ERROR(key_source_->GetCryptoPeriodKey(
current_crypto_period_index, stream_label_, &encryption_key));
if (!CreateEncryptor(encryption_key))
return Status(error::ENCRYPTION_FAILURE, "Failed to create encryptor");
prev_crypto_period_index_ = current_crypto_period_index;
@ -355,14 +357,13 @@ Status EncryptionHandler::SetupProtectionPattern(StreamType stream_type) {
skip_byte_block_ = 9u;
} else {
// Tracks other than video are protected using whole-block full-sample
// encryption, which is essentially a pattern of 1:0. Note that this may
// not be the same as the non-pattern based encryption counterparts,
// e.g. in 'cens' for full sample encryption, the whole sample is
// encrypted up to the last 16-byte boundary, see 23001-7:2016(E) 9.7;
// while in 'cenc' for full sample encryption, the last partial 16-byte
// block is also encrypted, see 23001-7:2016(E) 9.4.2. Another
// difference is the use of constant iv.
crypt_byte_block_ = 1u;
// encryption. Note that this may not be the same as the non-pattern
// based encryption counterparts, e.g. in 'cens' whole-block full sample
// encryption, the whole sample is encrypted up to the last 16-byte
// boundary, see 23001-7:2016(E) 9.7; while in 'cenc' full sample
// encryption, the last partial 16-byte block is also encrypted, see
// 23001-7:2016(E) 9.4.2. Another difference is the use of constant iv.
crypt_byte_block_ = 0u;
skip_byte_block_ = 0u;
}
break;

View File

@ -406,7 +406,7 @@ class EncryptionHandlerEncryptionTest
return 0;
case FOURCC_cens:
case FOURCC_cbcs:
return 1;
return codec_ == kCodecAAC ? 0 : 1;
default:
return 0;
}

View File

@ -114,11 +114,6 @@ void GenerateSinf(FourCC old_type,
break;
case FOURCC_cbcs:
case FOURCC_cens:
if (track_encryption.default_skip_byte_block == 0) {
// Some clients, e.g. Safari v11.0.3 does not like having
// crypt_byte_block as a non-zero value when skip_byte_block is zero.
track_encryption.default_crypt_byte_block = 0;
}
// CENCv3 10.3 cens AES-CTR subsample pattern encryption scheme and
// 10.4 cbcs AES-CBC subsample pattern encryption scheme:
// The version of the Track Encryption Box (tenc) SHALL be 1.