From 6f66132aa9f5d13b8a18fb4acafedb025fb5ff3d Mon Sep 17 00:00:00 2001 From: KongQun Yang Date: Tue, 7 Aug 2018 14:43:42 -0700 Subject: [PATCH] Support Widevine PSSH with protection scheme generation Issue #245. Change-Id: Ieabdd3cdc55eb5bd4b7a145c9d041cc918101f18 --- packager/app/packager_util.cc | 24 ++++++++------- packager/media/base/key_source.cc | 4 +-- packager/media/base/key_source.h | 3 +- packager/media/base/playready_key_source.cc | 12 +++++--- packager/media/base/playready_key_source.h | 16 +++++++--- .../media/base/pssh_generator_unittest.cc | 30 +++++++++++++++++-- packager/media/base/raw_key_source.cc | 20 ++++++++----- packager/media/base/raw_key_source.h | 13 ++++++-- .../media/base/raw_key_source_unittest.cc | 15 +++++----- packager/media/base/widevine_key_source.cc | 8 +++-- packager/media/base/widevine_key_source.h | 13 ++++---- .../base/widevine_key_source_unittest.cc | 5 ++-- .../media/base/widevine_pssh_generator.cc | 18 ++++++++--- packager/media/base/widevine_pssh_generator.h | 5 +++- 14 files changed, 127 insertions(+), 59 deletions(-) diff --git a/packager/app/packager_util.cc b/packager/app/packager_util.cc index 5fbc81f91c..c034fbeb24 100644 --- a/packager/app/packager_util.cc +++ b/packager/app/packager_util.cc @@ -88,8 +88,7 @@ std::unique_ptr CreateEncryptionKeySource( } std::unique_ptr widevine_key_source( new WidevineKeySource(widevine.key_server_url, - protection_systems_flags)); - widevine_key_source->set_protection_scheme(protection_scheme); + protection_systems_flags, protection_scheme)); if (!widevine.signer.signer_name.empty()) { std::unique_ptr request_signer( CreateSigner(widevine.signer)); @@ -112,8 +111,9 @@ std::unique_ptr CreateEncryptionKeySource( break; } case KeyProvider::kRawKey: { - encryption_key_source = RawKeySource::Create(encryption_params.raw_key, - protection_systems_flags); + encryption_key_source = + RawKeySource::Create(encryption_params.raw_key, + protection_systems_flags, protection_scheme); break; } case KeyProvider::kPlayReady: { @@ -140,10 +140,11 @@ std::unique_ptr CreateEncryptionKeySource( playready.key_server_url, playready.client_cert_file, playready.client_cert_private_key_file, playready.client_cert_private_key_password, - protection_systems_flags)); + protection_systems_flags, protection_scheme)); } else { playready_key_source.reset(new PlayReadyKeySource( - playready.key_server_url, protection_systems_flags)); + playready.key_server_url, protection_systems_flags, + protection_scheme)); } if (!playready.ca_file.empty()) { playready_key_source->SetCaFile(playready.ca_file); @@ -173,9 +174,11 @@ std::unique_ptr CreateDecryptionKeySource( LOG(ERROR) << "'key_server_url' should not be empty."; return std::unique_ptr(); } - std::unique_ptr widevine_key_source(new WidevineKeySource( - widevine.key_server_url, - WIDEVINE_PROTECTION_SYSTEM_FLAG /* value does not matter here */)); + std::unique_ptr widevine_key_source( + new WidevineKeySource( + widevine.key_server_url, + WIDEVINE_PROTECTION_SYSTEM_FLAG /* value does not matter here */, + FOURCC_NULL /* value does not matter here */)); if (!widevine.signer.signer_name.empty()) { std::unique_ptr request_signer( CreateSigner(widevine.signer)); @@ -190,7 +193,8 @@ std::unique_ptr CreateDecryptionKeySource( case KeyProvider::kRawKey: { decryption_key_source = RawKeySource::Create( decryption_params.raw_key, - COMMON_PROTECTION_SYSTEM_FLAG /* value does not matter here*/); + COMMON_PROTECTION_SYSTEM_FLAG /* value does not matter here */, + FOURCC_NULL /* value does not matter here */); break; } case KeyProvider::kNone: diff --git a/packager/media/base/key_source.cc b/packager/media/base/key_source.cc index ee43585620..72b280f5bc 100644 --- a/packager/media/base/key_source.cc +++ b/packager/media/base/key_source.cc @@ -19,7 +19,7 @@ EncryptionKey::EncryptionKey() {} EncryptionKey::~EncryptionKey() {} -KeySource::KeySource(int protection_systems_flags) { +KeySource::KeySource(int protection_systems_flags, FourCC protection_scheme) { if (protection_systems_flags & COMMON_PROTECTION_SYSTEM_FLAG) { pssh_generators_.emplace_back(new RawKeyPsshGenerator()); } @@ -29,7 +29,7 @@ KeySource::KeySource(int protection_systems_flags) { } if (protection_systems_flags & WIDEVINE_PROTECTION_SYSTEM_FLAG) { - pssh_generators_.emplace_back(new WidevinePsshGenerator()); + pssh_generators_.emplace_back(new WidevinePsshGenerator(protection_scheme)); } if (protection_systems_flags & FAIRPLAY_PROTECTION_SYSTEM_FLAG) { diff --git a/packager/media/base/key_source.h b/packager/media/base/key_source.h index a18b0ad28f..a21b287768 100644 --- a/packager/media/base/key_source.h +++ b/packager/media/base/key_source.h @@ -12,6 +12,7 @@ #include #include +#include "packager/media/base/fourccs.h" #include "packager/media/base/protection_system_specific_info.h" #include "packager/media/base/pssh_generator.h" #include "packager/status.h" @@ -49,7 +50,7 @@ typedef std::map> EncryptionKeyMap; /// KeySource is responsible for encryption key acquisition. class KeySource { public: - explicit KeySource(int protection_systems_flags); + KeySource(int protection_systems_flags, FourCC protection_scheme); virtual ~KeySource(); diff --git a/packager/media/base/playready_key_source.cc b/packager/media/base/playready_key_source.cc index 899a601ca6..517d31349d 100644 --- a/packager/media/base/playready_key_source.cc +++ b/packager/media/base/playready_key_source.cc @@ -61,9 +61,11 @@ bool Base64StringToBytes(const std::string& base64_string, } PlayReadyKeySource::PlayReadyKeySource(const std::string& server_url, - int protection_system_flags) + int protection_system_flags, + FourCC protection_scheme) // PlayReady PSSH is retrived from PlayReady server response. - : KeySource(protection_system_flags & ~PLAYREADY_PROTECTION_SYSTEM_FLAG), + : KeySource(protection_system_flags & ~PLAYREADY_PROTECTION_SYSTEM_FLAG, + protection_scheme), encryption_key_(new EncryptionKey), server_url_(server_url) {} @@ -72,9 +74,11 @@ PlayReadyKeySource::PlayReadyKeySource( const std::string& client_cert_file, const std::string& client_cert_private_key_file, const std::string& client_cert_private_key_password, - int protection_system_flags) + int protection_system_flags, + FourCC protection_scheme) // PlayReady PSSH is retrived from PlayReady server response. - : KeySource(protection_system_flags & ~PLAYREADY_PROTECTION_SYSTEM_FLAG), + : KeySource(protection_system_flags & ~PLAYREADY_PROTECTION_SYSTEM_FLAG, + protection_scheme), encryption_key_(new EncryptionKey), server_url_(server_url), client_cert_file_(client_cert_file), diff --git a/packager/media/base/playready_key_source.h b/packager/media/base/playready_key_source.h index 02f7b400b7..971c9d367d 100644 --- a/packager/media/base/playready_key_source.h +++ b/packager/media/base/playready_key_source.h @@ -21,23 +21,31 @@ class PlayReadyKeySource : public KeySource { public: /// Creates a new PlayReadyKeySource from the given packaging information. /// @param server_url PlayReady packaging server url. - /// @param proteciton_systems_flags is the flags indicating which PSSH should + /// @param protection_systems_flags is the flags indicating which PSSH should /// be included. + /// @param protection_scheme is the Protection Scheme to be used for + /// encryption. It needs to be signalled in Widevine PSSH. This + /// argument can be ignored if Widevine PSSH is not generated. PlayReadyKeySource(const std::string& server_url, - int protection_systems_flags); + int protection_systems_flags, + FourCC protection_scheme); /// Creates a new PlayReadyKeySource from the given packaging information. /// @param server_url PlayReady packaging server url. /// @param client_cert_file absolute path to a client certificate. /// @param client_cert_private_key_file absolute path to the private file /// for the client certificate. /// @param client_cert_private_key_password password for the private key. - /// @param proteciton_systems_flags is the flags indicating which PSSH should + /// @param protection_systems_flags is the flags indicating which PSSH should /// be included. + /// @param protection_scheme is the Protection Scheme to be used for + /// encryption. It needs to be signalled in Widevine PSSH. This + /// argument can be ignored if Widevine PSSH is not generated. PlayReadyKeySource(const std::string& server_url, const std::string& client_cert_file, const std::string& client_cert_private_key_file, const std::string& client_cert_private_key_password, - int protection_systems_flags); + int protection_systems_flags, + FourCC protection_scheme); ~PlayReadyKeySource() override; /// @name KeySource implementation overrides. diff --git a/packager/media/base/pssh_generator_unittest.cc b/packager/media/base/pssh_generator_unittest.cc index c023edff8e..216a846932 100644 --- a/packager/media/base/pssh_generator_unittest.cc +++ b/packager/media/base/pssh_generator_unittest.cc @@ -115,6 +115,18 @@ const char kExpectedWidevinePssh[] = { '~', '~', '~', '~', '~', }; +const char kExpectedWidevinePsshCbcs[] = { + '\x0', '\x0', '\x0', '\x4A', 'p', 's', 's', 'h', '\x0', + '\x0', '\x0', '\x0', '\xED', '\xEF', '\x8B', '\xA9', '\x79', '\xD6', + '\x4A', '\xCE', '\xA3', '\xC8', '\x27', '\xDC', '\xD5', '\x1D', '\x21', + '\xED', '\x0', '\x0', '\x0', '\x2A', '\x12', '\x10', 'k', 'e', + 'y', 'i', 'd', '1', '~', '~', '~', '~', '~', + '~', '~', '~', '~', '~', '\x12', '\x10', 'k', 'e', + 'y', 'i', 'd', '2', '~', '~', '~', '~', '~', + '~', '~', '~', '~', '~', '\x48', '\xF3', '\xC6', '\x89', + '\x9B', '\x06', +}; + std::vector GetTestKeyId1() { return std::vector(std::begin(kTestKeyId1), std::end(kTestKeyId1)); } @@ -178,7 +190,7 @@ TEST(PsshGeneratorTest, GenerateWidevinePsshFromKeyIds) { const std::vector> kTestKeyIds = {GetTestKeyId1(), GetTestKeyId2()}; std::unique_ptr widevine_pssh_generator( - new WidevinePsshGenerator()); + new WidevinePsshGenerator(FOURCC_NULL)); ProtectionSystemSpecificInfo info; ASSERT_OK( widevine_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info)); @@ -187,11 +199,25 @@ TEST(PsshGeneratorTest, GenerateWidevinePsshFromKeyIds) { std::end(kExpectedWidevinePssh))); } +TEST(PsshGeneratorTest, GenerateWidevinePsshFromKeyIdsWithProtectionScheme) { + const std::vector> kTestKeyIds = {GetTestKeyId1(), + GetTestKeyId2()}; + std::unique_ptr widevine_pssh_generator( + new WidevinePsshGenerator(FOURCC_cbcs)); + ProtectionSystemSpecificInfo info; + ASSERT_OK( + widevine_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info)); + + EXPECT_THAT(info.psshs, + ElementsAreArray(std::begin(kExpectedWidevinePsshCbcs), + std::end(kExpectedWidevinePsshCbcs))); +} + TEST(PsshGeneratorTest, GenerateWidevinyPsshFromKeyIdAndKey) { const std::vector kTestKeyId = GetTestKeyId1(); const std::vector kTestKey = GetTestKey1(); std::unique_ptr widevine_pssh_generator( - new WidevinePsshGenerator()); + new WidevinePsshGenerator(FOURCC_NULL)); ProtectionSystemSpecificInfo info; EXPECT_NOT_OK(widevine_pssh_generator->GeneratePsshFromKeyIdAndKey( kTestKeyId, kTestKey, &info)); diff --git a/packager/media/base/raw_key_source.cc b/packager/media/base/raw_key_source.cc index 32e5d114ee..f49b63a995 100644 --- a/packager/media/base/raw_key_source.cc +++ b/packager/media/base/raw_key_source.cc @@ -96,9 +96,9 @@ Status RawKeySource::GetCryptoPeriodKey(uint32_t crypto_period_index, return Status::OK; } -std::unique_ptr RawKeySource::Create( - const RawKeyParams& raw_key, - int protection_systems_flags) { +std::unique_ptr RawKeySource::Create(const RawKeyParams& raw_key, + int protection_systems_flags, + FourCC protection_scheme) { std::vector key_system_info; bool pssh_provided = false; if (!raw_key.pssh.empty()) { @@ -141,14 +141,18 @@ std::unique_ptr RawKeySource::Create( protection_systems_flags = COMMON_PROTECTION_SYSTEM_FLAG; } - return std::unique_ptr(new RawKeySource( - std::move(encryption_key_map), protection_systems_flags)); + return std::unique_ptr( + new RawKeySource(std::move(encryption_key_map), protection_systems_flags, + protection_scheme)); } -RawKeySource::RawKeySource() : KeySource(NO_PROTECTION_SYSTEM_FLAG) {} +RawKeySource::RawKeySource() + : KeySource(NO_PROTECTION_SYSTEM_FLAG, FOURCC_NULL) {} + RawKeySource::RawKeySource(EncryptionKeyMap&& encryption_key_map, - int protection_systems_flags) - : KeySource(protection_systems_flags), + int protection_systems_flags, + FourCC protection_scheme) + : KeySource(protection_systems_flags, protection_scheme), encryption_key_map_(std::move(encryption_key_map)) { UpdateProtectionSystemInfo(&encryption_key_map_); } diff --git a/packager/media/base/raw_key_source.h b/packager/media/base/raw_key_source.h index a59c238357..1a088468b0 100644 --- a/packager/media/base/raw_key_source.h +++ b/packager/media/base/raw_key_source.h @@ -37,16 +37,23 @@ class RawKeySource : public KeySource { /// Creates a new RawKeySource from the given data. Returns null /// if the parameter is malformed. /// @param raw_key contains parameters to setup the key source. + /// @param protection_systems_flags is the flags indicating which PSSH should + /// be included. + /// @param protection_scheme is the Protection Scheme to be used for + /// encryption. It needs to be signalled in Widevine PSSH. This + /// argument can be ignored if Widevine PSSH is not generated. static std::unique_ptr Create(const RawKeyParams& raw_key, - int protection_system_flags); + int protection_system_flags, + FourCC protection_scheme); protected: // Allow default constructor for mock key sources. RawKeySource(); private: - explicit RawKeySource(EncryptionKeyMap&& encryption_key_map, - int protection_systems_flags); + RawKeySource(EncryptionKeyMap&& encryption_key_map, + int protection_systems_flags, + FourCC protection_scheme); RawKeySource(const RawKeySource&) = delete; RawKeySource& operator=(const RawKeySource&) = delete; diff --git a/packager/media/base/raw_key_source_unittest.cc b/packager/media/base/raw_key_source_unittest.cc index f18c84b7f8..59f587c2c8 100644 --- a/packager/media/base/raw_key_source_unittest.cc +++ b/packager/media/base/raw_key_source_unittest.cc @@ -70,8 +70,8 @@ TEST(RawKeySourceTest, Success) { raw_key_params.iv = HexStringToVector(kIvHex); raw_key_params.pssh = HexStringToVector(std::string(kPsshBox1Hex) + kPsshBox2Hex); - std::unique_ptr key_source = - RawKeySource::Create(raw_key_params, kNoProtectionSystemFlag); + std::unique_ptr key_source = RawKeySource::Create( + raw_key_params, kNoProtectionSystemFlag, FOURCC_NULL); ASSERT_NE(nullptr, key_source); EncryptionKey key_from_drm_label; @@ -108,8 +108,8 @@ TEST(RawKeySourceTest, EmptyPssh) { HexStringToVector(kKeyId2Hex); raw_key_params.key_map[kAnotherDrmLabel].key = HexStringToVector(kKey2Hex); raw_key_params.iv = HexStringToVector(kIvHex); - std::unique_ptr key_source = - RawKeySource::Create(raw_key_params, kNoProtectionSystemFlag); + std::unique_ptr key_source = RawKeySource::Create( + raw_key_params, kNoProtectionSystemFlag, FOURCC_NULL); ASSERT_NE(nullptr, key_source); EncryptionKey key; @@ -129,14 +129,15 @@ TEST(RawKeySourceTest, Failure) { raw_key_params.key_map[kEmptyDrmLabel].key = HexStringToVector(kKeyHex); raw_key_params.pssh = HexStringToVector(kPsshBox1Hex); raw_key_params.iv = HexStringToVector(kIvHex); - std::unique_ptr key_source = - RawKeySource::Create(raw_key_params, kNoProtectionSystemFlag); + std::unique_ptr key_source = RawKeySource::Create( + raw_key_params, kNoProtectionSystemFlag, FOURCC_NULL); EXPECT_EQ(nullptr, key_source); // Invalid pssh box. raw_key_params.key_map[kEmptyDrmLabel].key_id = HexStringToVector(kKeyIdHex); raw_key_params.pssh = HexStringToVector("000102030405"); - key_source = RawKeySource::Create(raw_key_params, kNoProtectionSystemFlag); + key_source = RawKeySource::Create(raw_key_params, kNoProtectionSystemFlag, + FOURCC_NULL); EXPECT_EQ(nullptr, key_source); } diff --git a/packager/media/base/widevine_key_source.cc b/packager/media/base/widevine_key_source.cc index c914d1926d..67c74944b0 100644 --- a/packager/media/base/widevine_key_source.cc +++ b/packager/media/base/widevine_key_source.cc @@ -78,16 +78,18 @@ ProtectionSystemSpecificInfo ProtectionSystemInfoFromPsshProto( } // namespace WidevineKeySource::WidevineKeySource(const std::string& server_url, - int protection_system_flags) + int protection_system_flags, + FourCC protection_scheme) // Widevine PSSH is fetched from Widevine license server. - : KeySource(protection_system_flags & ~WIDEVINE_PROTECTION_SYSTEM_FLAG), + : KeySource(protection_system_flags & ~WIDEVINE_PROTECTION_SYSTEM_FLAG, + protection_scheme), key_production_thread_("KeyProductionThread", base::Bind(&WidevineKeySource::FetchKeysTask, base::Unretained(this))), key_fetcher_(new HttpKeyFetcher(kKeyFetchTimeoutInSeconds)), server_url_(server_url), crypto_period_count_(kDefaultCryptoPeriodCount), - protection_scheme_(FOURCC_cenc), + protection_scheme_(protection_scheme), key_production_started_(false), start_key_production_(base::WaitableEvent::ResetPolicy::AUTOMATIC, base::WaitableEvent::InitialState::NOT_SIGNALED), diff --git a/packager/media/base/widevine_key_source.h b/packager/media/base/widevine_key_source.h index d0221a9bb3..2c73d48c66 100644 --- a/packager/media/base/widevine_key_source.h +++ b/packager/media/base/widevine_key_source.h @@ -29,10 +29,14 @@ template class ProducerConsumerQueue; class WidevineKeySource : public KeySource { public: /// @param server_url is the Widevine common encryption server url. - /// @param proteciton_systems_flags is the flags indicating which PSSH should + /// @param protection_systems_flags is the flags indicating which PSSH should /// be included. + /// @param protection_scheme is the Protection Scheme to be used for + /// encryption. It needs to be signalled in Widevine PSSH. This + /// argument can be ignored if Widevine PSSH is not generated. WidevineKeySource(const std::string& server_url, - int protection_systems_flags); + int protection_systems_flags, + FourCC protection_scheme); ~WidevineKeySource() override; @@ -55,11 +59,6 @@ class WidevineKeySource : public KeySource { Status FetchKeys(const std::vector& content_id, const std::string& policy); - /// Set the protection scheme for the key source. - void set_protection_scheme(FourCC protection_scheme) { - protection_scheme_ = protection_scheme; - } - /// Set signer for the key source. /// @param signer signs the request message. void set_signer(std::unique_ptr signer); diff --git a/packager/media/base/widevine_key_source_unittest.cc b/packager/media/base/widevine_key_source_unittest.cc index a0f11f7639..f46e55e4d3 100644 --- a/packager/media/base/widevine_key_source_unittest.cc +++ b/packager/media/base/widevine_key_source_unittest.cc @@ -233,9 +233,8 @@ class WidevineKeySourceTest : public Test { protection_system_flags |= COMMON_PROTECTION_SYSTEM_FLAG; if (add_playready_pssh_) protection_system_flags |= PLAYREADY_PROTECTION_SYSTEM_FLAG; - widevine_key_source_.reset( - new WidevineKeySource(kServerUrl, protection_system_flags)); - widevine_key_source_->set_protection_scheme(protection_scheme_); + widevine_key_source_.reset(new WidevineKeySource( + kServerUrl, protection_system_flags, protection_scheme_)); widevine_key_source_->set_key_fetcher(std::move(mock_key_fetcher_)); } diff --git a/packager/media/base/widevine_pssh_generator.cc b/packager/media/base/widevine_pssh_generator.cc index 7b0d827f4b..83b360f056 100644 --- a/packager/media/base/widevine_pssh_generator.cc +++ b/packager/media/base/widevine_pssh_generator.cc @@ -6,19 +6,24 @@ #include "packager/media/base/widevine_pssh_generator.h" -#include "packager/media/base/pssh_generator_util.h" +#include "packager/media/base/widevine_pssh_data.pb.h" namespace shaka { namespace media { namespace { // Use version 0 for backward compatibility. const uint8_t kWidevinePsshBoxVersion = 0; + +std::vector StringToBytes(const std::string& string) { + return std::vector(string.begin(), string.end()); +} } // namespace -WidevinePsshGenerator::WidevinePsshGenerator() +WidevinePsshGenerator::WidevinePsshGenerator(FourCC protection_scheme) : PsshGenerator(std::vector(std::begin(kWidevineSystemId), std::end(kWidevineSystemId)), - kWidevinePsshBoxVersion) {} + kWidevinePsshBoxVersion), + protection_scheme_(protection_scheme) {} WidevinePsshGenerator::~WidevinePsshGenerator() {} @@ -29,7 +34,12 @@ bool WidevinePsshGenerator::SupportMultipleKeys() { base::Optional> WidevinePsshGenerator::GeneratePsshDataFromKeyIds( const std::vector>& key_ids) const { - return GenerateWidevinePsshDataFromKeyIds(key_ids); + media::WidevinePsshData widevine_pssh_data; + for (const std::vector& key_id : key_ids) + widevine_pssh_data.add_key_id(key_id.data(), key_id.size()); + if (protection_scheme_ != FOURCC_NULL) + widevine_pssh_data.set_protection_scheme(protection_scheme_); + return StringToBytes(widevine_pssh_data.SerializeAsString()); } base::Optional> diff --git a/packager/media/base/widevine_pssh_generator.h b/packager/media/base/widevine_pssh_generator.h index a632fad015..b0aedbc225 100644 --- a/packager/media/base/widevine_pssh_generator.h +++ b/packager/media/base/widevine_pssh_generator.h @@ -7,6 +7,7 @@ #ifndef MEDIA_BASE_WIDEVINE_PSSH_GENERATOR_H_ #define MEDIA_BASE_WIDEVINE_PSSH_GENERATOR_H_ +#include "packager/media/base/fourccs.h" #include "packager/media/base/pssh_generator.h" namespace shaka { @@ -18,7 +19,7 @@ const uint8_t kWidevineSystemId[] = {0xed, 0xef, 0x8b, 0xa9, 0x79, 0xd6, class WidevinePsshGenerator : public PsshGenerator { public: - WidevinePsshGenerator(); + explicit WidevinePsshGenerator(FourCC protection_scheme); ~WidevinePsshGenerator() override; /// @name PsshGenerator implemetation overrides. @@ -38,6 +39,8 @@ class WidevinePsshGenerator : public PsshGenerator { base::Optional> GeneratePsshDataFromKeyIdAndKey( const std::vector& key_id, const std::vector& key) const override; + + FourCC protection_scheme_ = FOURCC_NULL; }; } // namespace media