diff --git a/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm b/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm index 63cc98e9e4..a9a1e21725 100644 Binary files a/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm and b/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm differ diff --git a/packager/media/formats/webm/encrypted_segmenter_unittest.cc b/packager/media/formats/webm/encrypted_segmenter_unittest.cc index cb02d9cad9..7e0a537d26 100644 --- a/packager/media/formats/webm/encrypted_segmenter_unittest.cc +++ b/packager/media/formats/webm/encrypted_segmenter_unittest.cc @@ -19,7 +19,6 @@ const std::string kKeyId = "4c6f72656d20697073756d20646f6c6f"; const std::string kIv = "0123456789012345"; const std::string kKey = "01234567890123456789012345678901"; const std::string kPsshData = ""; - const uint8_t kBasicSupportData[] = { // ID: EBML Header, Payload Size: 31 0x1a, 0x45, 0xdf, 0xa3, 0x9f, @@ -37,8 +36,8 @@ const uint8_t kBasicSupportData[] = { 0x42, 0x87, 0x81, 0x02, // DocTypeReadVersion: 2 0x42, 0x85, 0x81, 0x02, - // ID: Segment, Payload Size: 411 - 0x18, 0x53, 0x80, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x9b, + // ID: Segment, Payload Size: 432 + 0x18, 0x53, 0x80, 0x67, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb0, // ID: SeekHead, Payload Size: 58 0x11, 0x4d, 0x9b, 0x74, 0xba, // ID: Seek, Payload Size: 11 @@ -63,8 +62,8 @@ const uint8_t kBasicSupportData[] = { 0x4d, 0xbb, 0x8c, // SeekID: binary(4) (Cues) 0x53, 0xab, 0x84, 0x1c, 0x53, 0xbb, 0x6b, - // SeekPosition: 392 - 0x53, 0xac, 0x82, 0x01, 0x88, + // SeekPosition: 398 + 0x53, 0xac, 0x82, 0x01, 0x8e, // ID: Void, Payload Size: 24 0xec, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -131,8 +130,8 @@ const uint8_t kBasicSupportData[] = { 0x54, 0xb0, 0x81, 0x64, // DisplayHeight: 100 0x54, 0xba, 0x81, 0x64, - // ID: Cluster, Payload Size: 101 - 0x1f, 0x43, 0xb6, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, + // ID: Cluster, Payload Size: 45 + 0x1f, 0x43, 0xb6, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, // Timecode: 0 0xe7, 0x81, 0x00, // ID: SimpleBlock, Payload Size: 10 @@ -141,44 +140,48 @@ const uint8_t kBasicSupportData[] = { 0x00, // Frame Data: 0xde, 0xad, 0xbe, 0xef, 0x00, - // ID: SimpleBlock, Payload Size: 18 - 0xa3, 0x92, 0x81, 0x03, 0xe8, 0x80, + // ID: SimpleBlock, Payload Size: 10 + 0xa3, 0x8a, 0x81, 0x03, 0xe8, 0x80, + // Signal Byte: Clear + 0x00, + // Frame Data: + 0xde, 0xad, 0xbe, 0xef, 0x00, + // ID: BlockGroup, Payload Size: 16 + 0xa0, 0x90, + // ID: Block, Payload Size: 10 + 0xa1, 0x8a, 0x81, 0x07, 0xd0, 0x00, + // Signal Byte: Clear + 0x00, + // Frame Data: + 0xde, 0xad, 0xbe, 0xef, 0x00, + // BlockDuration: 1000 + 0x9b, 0x82, 0x03, 0xe8, + // ID: Cluster, Payload Size: 50 + 0x1f, 0x43, 0xb6, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, + // Timecode: 3000 + 0xe7, 0x82, 0x0b, 0xb8, + // ID: SimpleBlock: Payload Size: 18 + 0xa3, 0x92, 0x81, 0x00,0x00, 0x80, // Signal Byte: Encrypted 0x01, // IV: 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45, // Frame Data: 0xcc, 0x03, 0xef, 0xc4, 0xf4, - // ID: SimpleBlock, Payload Size: 18 - 0xa3, 0x92, 0x81, 0x07, 0xd0, 0x80, - // Signal Byte: Encrypted - 0x01, - // IV: - 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x46, - // Frame Data: - 0xbf, 0x38, 0x72, 0x20, 0xac, - // ID: SimpleBlock, Payload Size: 18 - 0xa3, 0x92, 0x81, 0x0b, 0xb8, 0x80, - // Signal Byte: Encrypted - 0x01, - // IV: - 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x47, - // Frame Data: - 0x0d, 0x8e, 0xae, 0xbe, 0xd0, // ID: BlockGroup, Payload Size: 24 0xa0, 0x98, // ID: Block, Payload Size: 18 - 0xa1, 0x92, 0x81, 0x0f, 0xa0, 0x00, + 0xa1, 0x92, 0x81, 0x03, 0xe8, 0x00, // Signal Byte: Encrypted 0x01, // IV: - 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x48, + 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x46, // Frame Data: - 0xa5, 0x97, 0xf8, 0x9e, 0x87, + 0xbf, 0x38, 0x72, 0x20, 0xac, // BlockDuration: 1000 0x9b, 0x82, 0x03, 0xe8, - // ID: Cues, Payload Size: 14 - 0x1c, 0x53, 0xbb, 0x6b, 0x8e, + // ID: Cues, Payload Size: 29 + 0x1c, 0x53, 0xbb, 0x6b, 0x9d, // ID: CuePoint, Payload Size: 12 0xbb, 0x8c, // CueTime: 0 @@ -188,7 +191,17 @@ const uint8_t kBasicSupportData[] = { // CueTrack: 1 0xf7, 0x81, 0x01, // CueClusterPosition: 279 - 0xf1, 0x82, 0x01, 0x17 + 0xf1, 0x82, 0x01, 0x17, + // ID: CuePoint, Payload Size: 13 + 0xbb, 0x8d, + // CueTime: 3000 + 0xb3, 0x82, 0x0b, 0xb8, + // ID: CueTrackPositions, Payload Size: 7 + 0xb7, 0x87, + // CueTrack: 1 + 0xf7, 0x81, 0x01, + // CueClusterPosition: 336 + 0xf1, 0x82, 0x01, 0x50, }; } // namespace @@ -213,9 +226,12 @@ class EncrypedSegmenterTest : public SegmentTestBase { TEST_F(EncrypedSegmenterTest, BasicSupport) { MuxerOptions options = CreateMuxerOptions(); + options.segment_duration = 3.0; ASSERT_NO_FATAL_FAILURE(InitializeSegmenter(options)); // Write the samples to the Segmenter. + // There should be 2 segments with the first segment in clear and the second + // segment encrypted. for (int i = 0; i < 5; i++) { scoped_refptr sample = CreateSample(kKeyFrame, kDuration, kNoSideData); @@ -228,4 +244,3 @@ TEST_F(EncrypedSegmenterTest, BasicSupport) { } // namespace media } // namespace shaka - diff --git a/packager/media/formats/webm/segmenter.cc b/packager/media/formats/webm/segmenter.cc index 044418dcd0..b94ae57ab3 100644 --- a/packager/media/formats/webm/segmenter.cc +++ b/packager/media/formats/webm/segmenter.cc @@ -32,6 +32,8 @@ int64_t kSecondsToNs = 1000000000L; Segmenter::Segmenter(const MuxerOptions& options) : reference_frame_timestamp_(0), options_(options), + clear_lead_(0), + enable_encryption_(false), info_(NULL), muxer_listener_(NULL), progress_listener_(NULL), @@ -144,6 +146,15 @@ Status Segmenter::AddSample(scoped_refptr sample) { segment_length_sec_ = 0; cluster_length_sec_ = 0; wrote_frame = true; + + if (encryptor_ && !enable_encryption_) { + if (sample->pts() - first_timestamp_ >= + clear_lead_ * info_->time_scale()) { + enable_encryption_ = true; + if (muxer_listener_) + muxer_listener_->OnEncryptionStart(); + } + } } } else if (cluster_length_sec_ >= options_.fragment_duration) { if (sample->is_key_frame() || !options_.fragment_sap_aligned) { @@ -161,20 +172,13 @@ Status Segmenter::AddSample(scoped_refptr sample) { // Encrypt the frame. if (encryptor_) { - const bool encrypt_frame = - static_cast(sample->pts() - first_timestamp_) / - info_->time_scale() >= - clear_lead_; - status = encryptor_->EncryptFrame(sample, encrypt_frame); + status = encryptor_->EncryptFrame(sample, enable_encryption_); if (!status.ok()) { LOG(ERROR) << "Error encrypting frame."; return status; } - if (encrypt_frame && muxer_listener_) - muxer_listener_->OnEncryptionStart(); } - // Add the sample to the durations even though we have not written the frame // yet. This is needed to make sure we split Clusters at the correct point. // These are only used in this method. diff --git a/packager/media/formats/webm/segmenter.h b/packager/media/formats/webm/segmenter.h index 2bf03a11ac..a5697d802b 100644 --- a/packager/media/formats/webm/segmenter.h +++ b/packager/media/formats/webm/segmenter.h @@ -135,6 +135,7 @@ class Segmenter { const MuxerOptions& options_; std::unique_ptr encryptor_; double clear_lead_; + bool enable_encryption_; // Encryption is enabled only after clear_lead_. std::unique_ptr cluster_; mkvmuxer::Cues cues_;