diff --git a/packager/app/test/testdata/bear-640x360-a-cenc-golden.mp4.media_info b/packager/app/test/testdata/bear-640x360-a-cenc-golden.mp4.media_info index 2b9b668d29..71fef03aa9 100644 --- a/packager/app/test/testdata/bear-640x360-a-cenc-golden.mp4.media_info +++ b/packager/app/test/testdata/bear-640x360-a-cenc-golden.mp4.media_info @@ -24,4 +24,5 @@ protected_content { uuid: "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed" pssh: "\000\000\0000pssh\000\000\000\000\355\357\213\251y\326J\316\243\310\'\334\325\035!\355\000\000\000\0201234567890123456" } + protection_scheme: "cenc" } diff --git a/packager/app/test/testdata/bear-640x360-v-cenc-golden.mp4.media_info b/packager/app/test/testdata/bear-640x360-v-cenc-golden.mp4.media_info index d04cb8f287..541a1241cb 100644 --- a/packager/app/test/testdata/bear-640x360-v-cenc-golden.mp4.media_info +++ b/packager/app/test/testdata/bear-640x360-v-cenc-golden.mp4.media_info @@ -27,4 +27,5 @@ protected_content { uuid: "edef8ba9-79d6-4ace-a3c8-27dcd51d21ed" pssh: "\000\000\0000pssh\000\000\000\000\355\357\213\251y\326J\316\243\310\'\334\325\035!\355\000\000\000\0201234567890123456" } + protection_scheme: "cenc" } diff --git a/packager/media/event/hls_notify_muxer_listener.cc b/packager/media/event/hls_notify_muxer_listener.cc index 88104913a9..5a9186a887 100644 --- a/packager/media/event/hls_notify_muxer_listener.cc +++ b/packager/media/event/hls_notify_muxer_listener.cc @@ -26,6 +26,7 @@ HlsNotifyMuxerListener::~HlsNotifyMuxerListener() {} void HlsNotifyMuxerListener::OnEncryptionInfoReady( bool is_initial_encryption_info, + FourCC protection_scheme, const std::vector& key_id, const std::vector& iv, const std::vector& key_system_infos) { diff --git a/packager/media/event/hls_notify_muxer_listener.h b/packager/media/event/hls_notify_muxer_listener.h index 9a7d10e13a..8e4d18d9cf 100644 --- a/packager/media/event/hls_notify_muxer_listener.h +++ b/packager/media/event/hls_notify_muxer_listener.h @@ -32,6 +32,7 @@ class HlsNotifyMuxerListener : public MuxerListener { /// @name MuxerListener implementation overrides. /// @{ void OnEncryptionInfoReady(bool is_initial_encryption_info, + FourCC protection_scheme, const std::vector& key_id, const std::vector& iv, const std::vector& diff --git a/packager/media/event/hls_notify_muxer_listener_unittest.cc b/packager/media/event/hls_notify_muxer_listener_unittest.cc index f3d509a2f1..dac3b247b5 100644 --- a/packager/media/event/hls_notify_muxer_listener_unittest.cc +++ b/packager/media/event/hls_notify_muxer_listener_unittest.cc @@ -95,8 +95,8 @@ TEST_F(HlsNotifyMuxerListenerTest, OnEncryptionInfoReady) { EXPECT_CALL(mock_notifier_, NotifyEncryptionUpdate(_, key_id, system_id, iv, pssh_data)) .WillOnce(Return(true)); - listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, key_id, iv, - key_system_infos); + listener_.OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, key_id, + iv, key_system_infos); } TEST_F(HlsNotifyMuxerListenerTest, OnMediaStart) { diff --git a/packager/media/event/mock_muxer_listener.h b/packager/media/event/mock_muxer_listener.h index b55393df0b..88331c0964 100644 --- a/packager/media/event/mock_muxer_listener.h +++ b/packager/media/event/mock_muxer_listener.h @@ -22,9 +22,10 @@ class MockMuxerListener : public MuxerListener { MockMuxerListener(); ~MockMuxerListener() override; - MOCK_METHOD4( + MOCK_METHOD5( OnEncryptionInfoReady, void(bool is_initial_encryption_info, + FourCC protection_scheme, const std::vector& key_id, const std::vector& iv, const std::vector& key_system_info)); diff --git a/packager/media/event/mpd_notify_muxer_listener.cc b/packager/media/event/mpd_notify_muxer_listener.cc index 44d01c5db6..c232e5e746 100644 --- a/packager/media/event/mpd_notify_muxer_listener.cc +++ b/packager/media/event/mpd_notify_muxer_listener.cc @@ -30,17 +30,20 @@ MpdNotifyMuxerListener::~MpdNotifyMuxerListener() {} void MpdNotifyMuxerListener::OnEncryptionInfoReady( bool is_initial_encryption_info, + FourCC protection_scheme, const std::vector& key_id, const std::vector& iv, const std::vector& key_system_info) { if (is_initial_encryption_info) { LOG_IF(WARNING, is_encrypted_) << "Updating initial encryption information."; + protection_scheme_ = protection_scheme; default_key_id_.assign(key_id.begin(), key_id.end()); key_system_info_ = key_system_info; is_encrypted_ = true; return; } + DCHECK_EQ(protection_scheme, protection_scheme_); for (const ProtectionSystemSpecificInfo& info : key_system_info) { std::string drm_uuid = internal::CreateUUIDString(info.system_id()); @@ -67,8 +70,8 @@ void MpdNotifyMuxerListener::OnMediaStart( } if (is_encrypted_) { - internal::SetContentProtectionFields(default_key_id_, key_system_info_, - media_info.get()); + internal::SetContentProtectionFields(protection_scheme_, default_key_id_, + key_system_info_, media_info.get()); } if (mpd_notifier_->dash_profile() == kLiveProfile) { diff --git a/packager/media/event/mpd_notify_muxer_listener.h b/packager/media/event/mpd_notify_muxer_listener.h index 4fb6c9dcde..afca244a2e 100644 --- a/packager/media/event/mpd_notify_muxer_listener.h +++ b/packager/media/event/mpd_notify_muxer_listener.h @@ -34,6 +34,7 @@ class MpdNotifyMuxerListener : public MuxerListener { /// @name MuxerListener implementation overrides. /// @{ void OnEncryptionInfoReady(bool is_initial_encryption_info, + FourCC protection_scheme, const std::vector& key_id, const std::vector& iv, const std::vector& @@ -71,6 +72,7 @@ class MpdNotifyMuxerListener : public MuxerListener { bool is_encrypted_; // Storage for values passed to OnEncryptionInfoReady(). + FourCC protection_scheme_; std::string default_key_id_; std::vector key_system_info_; diff --git a/packager/media/event/mpd_notify_muxer_listener_unittest.cc b/packager/media/event/mpd_notify_muxer_listener_unittest.cc index 605b5a49d1..a0c4a719b6 100644 --- a/packager/media/event/mpd_notify_muxer_listener_unittest.cc +++ b/packager/media/event/mpd_notify_muxer_listener_unittest.cc @@ -158,6 +158,7 @@ TEST_F(MpdNotifyMuxerListenerTest, VodEncryptedContent) { const std::string kExpectedMediaInfo = std::string(kExpectedDefaultMediaInfo) + "protected_content {\n" + " protection_scheme: 'cenc'\n" " content_protection_entry {\n" " uuid: '00010203-0405-0607-0809-0a0b0c0d0e0f'\n" " pssh: '" + std::string(kExpectedDefaultPsshBox) + "'\n" @@ -168,7 +169,8 @@ TEST_F(MpdNotifyMuxerListenerTest, VodEncryptedContent) { EXPECT_CALL(*notifier_, NotifyNewContainer(_, _)).Times(0); std::vector iv(kBogusIv, kBogusIv + arraysize(kBogusIv)); - listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, default_key_id, iv, + listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cenc, + default_key_id, iv, GetDefaultKeySystemInfo()); listener_->OnMediaStart(muxer_options, *video_stream_info, @@ -296,6 +298,7 @@ TEST_F(MpdNotifyMuxerListenerTest, LiveNoKeyRotation) { " uuid: '00010203-0405-0607-0809-0a0b0c0d0e0f'\n" " pssh: \"" + std::string(kExpectedDefaultPsshBox) + "\"\n" " }\n" + " protection_scheme: 'cbcs'\n" "}\n"; const uint64_t kStartTime1 = 0u; @@ -320,7 +323,8 @@ TEST_F(MpdNotifyMuxerListenerTest, LiveNoKeyRotation) { EXPECT_CALL(*notifier_, Flush()); std::vector iv(kBogusIv, kBogusIv + arraysize(kBogusIv)); - listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, default_key_id, iv, + listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbcs, + default_key_id, iv, GetDefaultKeySystemInfo()); listener_->OnMediaStart(muxer_options, *video_stream_info, kDefaultReferenceTimeScale, @@ -359,6 +363,7 @@ TEST_F(MpdNotifyMuxerListenerTest, LiveWithKeyRotation) { "container_type: CONTAINER_MP4\n" "protected_content {\n" " default_key_id: \"defaultkeyid\"\n" + " protection_scheme: 'cbc1'\n" "}\n"; const uint64_t kStartTime1 = 0u; @@ -383,12 +388,13 @@ TEST_F(MpdNotifyMuxerListenerTest, LiveWithKeyRotation) { EXPECT_CALL(*notifier_, Flush()); std::vector iv(kBogusIv, kBogusIv + arraysize(kBogusIv)); - listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, default_key_id, iv, + listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cbc1, + default_key_id, iv, std::vector()); listener_->OnMediaStart(muxer_options, *video_stream_info, kDefaultReferenceTimeScale, MuxerListener::kContainerMp4); - listener_->OnEncryptionInfoReady(kNonInitialEncryptionInfo, + listener_->OnEncryptionInfoReady(kNonInitialEncryptionInfo, FOURCC_cbc1, std::vector(), iv, GetDefaultKeySystemInfo()); listener_->OnNewSegment("", kStartTime1, kDuration1, kSegmentFileSize1); diff --git a/packager/media/event/muxer_listener.h b/packager/media/event/muxer_listener.h index aee537eb2b..e3c597bb27 100644 --- a/packager/media/event/muxer_listener.h +++ b/packager/media/event/muxer_listener.h @@ -14,6 +14,8 @@ #include #include +#include "packager/media/base/fourccs.h" + namespace edash_packager { namespace media { @@ -48,6 +50,8 @@ class MuxerListener { /// @param is_initial_encryption_info is true if this is the first encryption /// info for the media. In general, this flag should always be true for /// non-key-rotated media and should be called only once. + /// @param protection_scheme specifies the protection scheme: 'cenc', 'cens', + /// 'cbc1', 'cbcs'. /// @param key_id is the key ID for the media. The format should be a vector /// of uint8_t, i.e. not (necessarily) human readable hex string. /// @param iv is the initialization vector. For most cases this should be 16 @@ -55,6 +59,7 @@ class MuxerListener { /// implementation. virtual void OnEncryptionInfoReady( bool is_initial_encryption_info, + FourCC protection_scheme, const std::vector& key_id, const std::vector& iv, const std::vector& key_system_info) = 0; diff --git a/packager/media/event/muxer_listener_internal.cc b/packager/media/event/muxer_listener_internal.cc index fd3f531e16..f2f1663954 100644 --- a/packager/media/event/muxer_listener_internal.cc +++ b/packager/media/event/muxer_listener_internal.cc @@ -216,6 +216,7 @@ bool SetVodInformation(bool has_init_range, } void SetContentProtectionFields( + FourCC protection_scheme, const std::string& default_key_id, const std::vector& key_system_info, MediaInfo* media_info) { @@ -223,6 +224,10 @@ void SetContentProtectionFields( MediaInfo::ProtectedContent* protected_content = media_info->mutable_protected_content(); + DCHECK(protection_scheme == FOURCC_cenc || protection_scheme == FOURCC_cbc1 || + protection_scheme == FOURCC_cens || protection_scheme == FOURCC_cbcs); + protected_content->set_protection_scheme(FourCCToString(protection_scheme)); + if (!default_key_id.empty()) protected_content->set_default_key_id(default_key_id); diff --git a/packager/media/event/muxer_listener_internal.h b/packager/media/event/muxer_listener_internal.h index 5e16c688a7..30143a2cd6 100644 --- a/packager/media/event/muxer_listener_internal.h +++ b/packager/media/event/muxer_listener_internal.h @@ -45,12 +45,15 @@ bool SetVodInformation(bool has_init_range, uint64_t file_size, MediaInfo* media_info); +/// @param protection_scheme specifies the protection scheme: 'cenc', 'cens', +/// 'cbc1', 'cbcs'. /// @param default_key_id is the key ID for this media in hex (i.e. non-human /// readable, typically 16 bytes.) /// @param key_system_info the key-system specific info for the media. /// @param media_info is where the content protection information is stored and /// cannot be null. void SetContentProtectionFields( + FourCC protection_scheme, const std::string& default_key_id, const std::vector& key_system_info, MediaInfo* media_info); diff --git a/packager/media/event/vod_media_info_dump_muxer_listener.cc b/packager/media/event/vod_media_info_dump_muxer_listener.cc index 675d2895cc..722b9961a1 100644 --- a/packager/media/event/vod_media_info_dump_muxer_listener.cc +++ b/packager/media/event/vod_media_info_dump_muxer_listener.cc @@ -27,12 +27,14 @@ VodMediaInfoDumpMuxerListener::~VodMediaInfoDumpMuxerListener() {} void VodMediaInfoDumpMuxerListener::OnEncryptionInfoReady( bool is_initial_encryption_info, + FourCC protection_scheme, const std::vector& default_key_id, const std::vector& iv, const std::vector& key_system_info) { LOG_IF(WARNING, !is_initial_encryption_info) << "Updating (non initial) encryption info is not supported by " "this module."; + protection_scheme_ = protection_scheme; default_key_id_.assign(default_key_id.begin(), default_key_id.end()); key_system_info_ = key_system_info; is_encrypted_ = true; @@ -55,8 +57,8 @@ void VodMediaInfoDumpMuxerListener::OnMediaStart( } if (is_encrypted_) { - internal::SetContentProtectionFields( - default_key_id_, key_system_info_, media_info_.get()); + internal::SetContentProtectionFields(protection_scheme_, default_key_id_, + key_system_info_, media_info_.get()); } } diff --git a/packager/media/event/vod_media_info_dump_muxer_listener.h b/packager/media/event/vod_media_info_dump_muxer_listener.h index c8fafec66f..249cedadd7 100644 --- a/packager/media/event/vod_media_info_dump_muxer_listener.h +++ b/packager/media/event/vod_media_info_dump_muxer_listener.h @@ -33,6 +33,7 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener { /// @name MuxerListener implementation overrides. /// @{ void OnEncryptionInfoReady(bool is_initial_encryption_info, + FourCC protection_scheme, const std::vector& default_key_id, const std::vector& iv, const std::vector& @@ -72,6 +73,7 @@ class VodMediaInfoDumpMuxerListener : public MuxerListener { bool is_encrypted_; // Storage for values passed to OnEncryptionInfoReady(). + FourCC protection_scheme_; std::string default_key_id_; std::vector key_system_info_; diff --git a/packager/media/event/vod_media_info_dump_muxer_listener_unittest.cc b/packager/media/event/vod_media_info_dump_muxer_listener_unittest.cc index a65a2a3019..c4f9c770e7 100644 --- a/packager/media/event/vod_media_info_dump_muxer_listener_unittest.cc +++ b/packager/media/event/vod_media_info_dump_muxer_listener_unittest.cc @@ -11,6 +11,7 @@ #include "packager/base/files/file_util.h" #include "packager/base/files/file_path.h" +#include "packager/media/base/fourccs.h" #include "packager/media/base/muxer_options.h" #include "packager/media/base/video_stream_info.h" #include "packager/media/event/muxer_listener_test_helper.h" @@ -83,7 +84,7 @@ class VodMediaInfoDumpMuxerListenerTest : public ::testing::Test { kBogusDefaultKeyId + arraysize(kBogusDefaultKeyId)); std::vector bogus_iv(kBogusIv, kBogusIv + arraysize(kBogusIv)); - listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, + listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, FOURCC_cenc, bogus_default_key_id, bogus_iv, GetDefaultKeySystemInfo()); } @@ -189,6 +190,7 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, EncryptedStream_Normal) { " pssh: '" + std::string(kExpectedDefaultPsshBox) + "'\n" " }\n" " default_key_id: '_default_key_id_'\n" + " protection_scheme: 'cenc'\n" "}\n"; ASSERT_NO_FATAL_FAILURE(ExpectTempFileToEqual(kExpectedProtobufOutput)); diff --git a/packager/media/formats/mp4/key_rotation_fragmenter.cc b/packager/media/formats/mp4/key_rotation_fragmenter.cc index 221c1efbf0..a080304507 100644 --- a/packager/media/formats/mp4/key_rotation_fragmenter.cc +++ b/packager/media/formats/mp4/key_rotation_fragmenter.cc @@ -79,10 +79,9 @@ Status KeyRotationFragmenter::PrepareFragmentForEncryption( } if (muxer_listener_) { - muxer_listener_->OnEncryptionInfoReady(!kInitialEncryptionInfo, - encryption_key()->key_id, - encryption_key()->iv, - encryption_key()->key_system_info); + muxer_listener_->OnEncryptionInfoReady( + !kInitialEncryptionInfo, protection_scheme(), encryption_key()->key_id, + encryption_key()->iv, encryption_key()->key_system_info); } // Skip the following steps if the current fragment is not going to be diff --git a/packager/media/formats/mp4/segmenter.cc b/packager/media/formats/mp4/segmenter.cc index 62b1339bc8..b4d48f75e9 100644 --- a/packager/media/formats/mp4/segmenter.cc +++ b/packager/media/formats/mp4/segmenter.cc @@ -215,7 +215,8 @@ Status Segmenter::Initialize(const std::vector& streams, local_protection_scheme, &description); if (muxer_listener_) { muxer_listener_->OnEncryptionInfoReady( - kInitialEncryptionInfo, encryption_key.key_id, encryption_key.iv, + kInitialEncryptionInfo, local_protection_scheme, + encryption_key.key_id, encryption_key.iv, encryption_key.key_system_info); } @@ -251,10 +252,10 @@ Status Segmenter::Initialize(const std::vector& streams, } if (muxer_listener_) { - muxer_listener_->OnEncryptionInfoReady(kInitialEncryptionInfo, - encryption_key->key_id, - encryption_key->iv, - encryption_key->key_system_info); + muxer_listener_->OnEncryptionInfoReady( + kInitialEncryptionInfo, local_protection_scheme, + encryption_key->key_id, encryption_key->iv, + encryption_key->key_system_info); } } diff --git a/packager/media/formats/mp4/segmenter.h b/packager/media/formats/mp4/segmenter.h index 8adda270ce..f346c8d4cb 100644 --- a/packager/media/formats/mp4/segmenter.h +++ b/packager/media/formats/mp4/segmenter.h @@ -59,7 +59,7 @@ class Segmenter { /// pixels per frame than max_sd_pixels, it is HD, SD otherwise. /// @param clear_time specifies clear lead duration in seconds. /// @param crypto_period_duration specifies crypto period duration in seconds. - /// @param protection_scheme specifies the protection scheme: 'senc', 'sens', + /// @param protection_scheme specifies the protection scheme: 'cenc', 'cens', /// 'cbc1', 'cbcs'. /// @return OK on success, an error status otherwise. Status Initialize(const std::vector& streams, diff --git a/packager/media/formats/webm/encryptor.cc b/packager/media/formats/webm/encryptor.cc index 954b9cb5aa..58aa85f31e 100644 --- a/packager/media/formats/webm/encryptor.cc +++ b/packager/media/formats/webm/encryptor.cc @@ -118,10 +118,9 @@ Status Encryptor::CreateEncryptor(MuxerListener* muxer_listener, if (muxer_listener) { const bool kInitialEncryptionInfo = true; - muxer_listener->OnEncryptionInfoReady(kInitialEncryptionInfo, - encryption_key->key_id, - encryptor->iv(), - encryption_key->key_system_info); + muxer_listener->OnEncryptionInfoReady( + kInitialEncryptionInfo, FOURCC_cenc, encryption_key->key_id, + encryptor->iv(), encryption_key->key_system_info); } key_ = encryption_key.Pass(); diff --git a/packager/mpd/base/media_info.proto b/packager/mpd/base/media_info.proto index 6ca28e90e6..94facab15f 100644 --- a/packager/mpd/base/media_info.proto +++ b/packager/mpd/base/media_info.proto @@ -83,6 +83,8 @@ message MediaInfo { // The default key ID for the encrypted media. optional bytes default_key_id = 1; repeated ContentProtectionEntry content_protection_entry = 2; + // Specifies the protection scheme: 'cenc', 'cens', 'cbc1', 'cbcs'. + optional string protection_scheme = 3 [default = 'cenc']; } // TODO(rkuroiwa): Remove this. element that must be added diff --git a/packager/mpd/base/mpd_utils.cc b/packager/mpd/base/mpd_utils.cc index 99b576fc12..9338d01e3c 100644 --- a/packager/mpd/base/mpd_utils.cc +++ b/packager/mpd/base/mpd_utils.cc @@ -288,7 +288,7 @@ void AddContentProtectionElementsHelperTemplated( if (is_mp4_container) { ContentProtectionElement mp4_content_protection; mp4_content_protection.scheme_id_uri = kEncryptedMp4Scheme; - mp4_content_protection.value = kEncryptedMp4Value; + mp4_content_protection.value = protected_content.protection_scheme(); if (!key_id_uuid_format.empty()) { mp4_content_protection.additional_attributes["cenc:default_KID"] = key_id_uuid_format; diff --git a/packager/mpd/base/mpd_utils.h b/packager/mpd/base/mpd_utils.h index 970e17730f..7ef21b1107 100644 --- a/packager/mpd/base/mpd_utils.h +++ b/packager/mpd/base/mpd_utils.h @@ -28,7 +28,6 @@ struct SegmentInfo; const char kEncryptedMp4Scheme[] = "urn:mpeg:dash:mp4protection:2011"; const char kPsshElementName[] = "cenc:pssh"; -const char kEncryptedMp4Value[] = "cenc"; bool HasVODOnlyFields(const MediaInfo& media_info);