diff --git a/packager/app/test/packager_test.py b/packager/app/test/packager_test.py index 56b5524376..5237167380 100755 --- a/packager/app/test/packager_test.py +++ b/packager/app/test/packager_test.py @@ -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), diff --git a/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-audio-1.m4s b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-audio-1.m4s new file mode 100644 index 0000000000..f88b004a5e Binary files /dev/null and b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-audio-1.m4s differ diff --git a/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-audio-2.m4s b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-audio-2.m4s new file mode 100644 index 0000000000..8ce5fdb11b Binary files /dev/null and b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-audio-2.m4s differ diff --git a/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-audio-3.m4s b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-audio-3.m4s new file mode 100644 index 0000000000..49c6767ad7 Binary files /dev/null and b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-audio-3.m4s differ diff --git a/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-audio-init.mp4 b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-audio-init.mp4 new file mode 100644 index 0000000000..136514d671 Binary files /dev/null and b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-audio-init.mp4 differ diff --git a/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-video-1.m4s b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-video-1.m4s new file mode 100644 index 0000000000..5c18184d26 Binary files /dev/null and b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-video-1.m4s differ diff --git a/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-video-2.m4s b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-video-2.m4s new file mode 100644 index 0000000000..2a2982dac4 Binary files /dev/null and b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-video-2.m4s differ diff --git a/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-video-3.m4s b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-video-3.m4s new file mode 100644 index 0000000000..789a556256 Binary files /dev/null and b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-video-3.m4s differ diff --git a/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-video-init.mp4 b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-video-init.mp4 new file mode 100644 index 0000000000..4df1c9fb42 Binary files /dev/null and b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/bear-640x360-video-init.mp4 differ diff --git a/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/output.mpd b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/output.mpd new file mode 100644 index 0000000000..894a5ae5d1 --- /dev/null +++ b/packager/app/test/testdata/live-profile-and-key-rotation-cbcs/output.mpd @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packager/media/crypto/encryption_handler.cc b/packager/media/crypto/encryption_handler.cc index 3d23acf952..5690001010 100644 --- a/packager/media/crypto/encryption_handler.cc +++ b/packager/media/crypto/encryption_handler.cc @@ -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; diff --git a/packager/media/crypto/encryption_handler_unittest.cc b/packager/media/crypto/encryption_handler_unittest.cc index 3a396e8a6c..b595d4bf3a 100644 --- a/packager/media/crypto/encryption_handler_unittest.cc +++ b/packager/media/crypto/encryption_handler_unittest.cc @@ -406,7 +406,7 @@ class EncryptionHandlerEncryptionTest return 0; case FOURCC_cens: case FOURCC_cbcs: - return 1; + return codec_ == kCodecAAC ? 0 : 1; default: return 0; } diff --git a/packager/media/formats/mp4/mp4_muxer.cc b/packager/media/formats/mp4/mp4_muxer.cc index 3c4309e6c3..404ebbb841 100644 --- a/packager/media/formats/mp4/mp4_muxer.cc +++ b/packager/media/formats/mp4/mp4_muxer.cc @@ -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.