From aa4b5733420e9e1a74a2c59650dbab1aeeec77f6 Mon Sep 17 00:00:00 2001 From: Haoming Chen Date: Fri, 20 Apr 2018 10:46:14 -0700 Subject: [PATCH] Implement multi DRM support. (Part 3) - Allow including Widevine and Common SystemID PSSH boxes for PlayReadyKeySource. - --playready_key_id and --playready_key flags are deprecated. - --enable_raw_key_encryption already supports playready PSSH generation. Addresses issue #245 Change-Id: I072d4f43a3239875959e4c5b1eb6854415d7367e --- packager/app/packager_main.cc | 2 - packager/app/packager_util.cc | 19 +++----- .../app/playready_key_encryption_flags.cc | 33 ++----------- packager/app/playready_key_encryption_flags.h | 2 - packager/app/retired_flags.cc | 10 ++++ packager/app/retired_flags.h | 2 + packager/media/base/playready_key_source.cc | 46 +++++++------------ packager/media/base/playready_key_source.h | 10 +++- .../media/base/playready_pssh_generator.cc | 16 ------- .../media/base/playready_pssh_generator.h | 4 -- .../media/base/pssh_generator_unittest.cc | 30 +++++------- packager/media/public/crypto_params.h | 6 --- 12 files changed, 60 insertions(+), 120 deletions(-) diff --git a/packager/app/packager_main.cc b/packager/app/packager_main.cc index ffab1f41ca..e5a86e8227 100644 --- a/packager/app/packager_main.cc +++ b/packager/app/packager_main.cc @@ -337,8 +337,6 @@ base::Optional GetPackagingParams() { FLAGS_client_cert_private_key_file; playready.client_cert_private_key_password = FLAGS_client_cert_private_key_password; - playready.key_id = FLAGS_playready_key_id_bytes; - playready.key = FLAGS_playready_key_bytes; break; } case KeyProvider::kRawKey: { diff --git a/packager/app/packager_util.cc b/packager/app/packager_util.cc index 7905690306..cd63a80a6e 100644 --- a/packager/app/packager_util.cc +++ b/packager/app/packager_util.cc @@ -98,17 +98,9 @@ std::unique_ptr CreateEncryptionKeySource( break; } case KeyProvider::kPlayready: { - // TODO(hmchen): add multiple DRM support for playready key source. const PlayreadyEncryptionParams& playready = encryption_params.playready; - if (!playready.key_id.empty() || !playready.key.empty()) { - if (playready.key_id.empty() || playready.key.empty()) { - LOG(ERROR) << "Either playready key_id or key is not set."; - return nullptr; - } - encryption_key_source = PlayReadyKeySource::CreateFromKeyAndKeyId( - playready.key_id, playready.key); - } else if (!playready.key_server_url.empty() || - !playready.program_identifier.empty()) { + if (!playready.key_server_url.empty() || + !playready.program_identifier.empty()) { if (playready.key_server_url.empty() || playready.program_identifier.empty()) { LOG(ERROR) << "Either playready key_server_url or program_identifier " @@ -128,10 +120,11 @@ std::unique_ptr CreateEncryptionKeySource( playready_key_source.reset(new PlayReadyKeySource( playready.key_server_url, playready.client_cert_file, playready.client_cert_private_key_file, - playready.client_cert_private_key_password)); + playready.client_cert_private_key_password, + protection_systems_flags)); } else { - playready_key_source.reset( - new PlayReadyKeySource(playready.key_server_url)); + playready_key_source.reset(new PlayReadyKeySource( + playready.key_server_url, protection_systems_flags)); } if (!playready.ca_file.empty()) { playready_key_source->SetCaFile(playready.ca_file); diff --git a/packager/app/playready_key_encryption_flags.cc b/packager/app/playready_key_encryption_flags.cc index b192120d7e..10d1ae12fd 100644 --- a/packager/app/playready_key_encryption_flags.cc +++ b/packager/app/playready_key_encryption_flags.cc @@ -16,8 +16,6 @@ DEFINE_bool(enable_playready_encryption, DEFINE_string(playready_server_url, "", "PlayReady packaging server url."); DEFINE_string(program_identifier, "", "Program identifier for packaging request."); -DEFINE_hex_bytes(playready_key_id, "", "PlayReady key id in hex."); -DEFINE_hex_bytes(playready_key, "", "PlayReady key in hex."); DEFINE_string(ca_file, "", "Absolute path to the Certificate Authority file for the " "server cert. PEM format"); @@ -29,6 +27,9 @@ DEFINE_string(client_cert_private_key_password, "", "Password to the private key file."); namespace shaka { +namespace { +const bool kFlagIsOptional = true; +} bool ValidatePRCryptoFlags() { bool success = true; @@ -36,35 +37,11 @@ bool ValidatePRCryptoFlags() { const char playready_label[] = "--enable_playready_encryption"; bool playready_enabled = FLAGS_enable_playready_encryption; if (!ValidateFlag("playready_server_url", FLAGS_playready_server_url, - playready_enabled, true, playready_label)) { + playready_enabled, !kFlagIsOptional, playready_label)) { success = false; } if (!ValidateFlag("program_identifier", FLAGS_program_identifier, - playready_enabled, true, playready_label)) { - success = false; - } - bool use_packaging = !FLAGS_playready_server_url.empty() && - !FLAGS_program_identifier.empty(); - if (!ValidateFlag("playready_key_id", FLAGS_playready_key_id_bytes, - playready_enabled, true, playready_label)) { - success = false; - } - if (!ValidateFlag("playready_key", FLAGS_playready_key_bytes, - playready_enabled, true, playready_label)) { - success = false; - } - bool use_raw_key = !FLAGS_playready_key_id_bytes.empty() && - !FLAGS_playready_key_bytes.empty(); - - if (playready_enabled && !use_packaging && !use_raw_key) { - PrintError("combination of --playready_server_url and " - "--program_identifier or --playready_key_id and playready_key are " - "required"); - success = false; - } - if (use_packaging && use_raw_key) { - PrintError("combination of --playready_server_url, --program_identifier, " - "--playready_key_id, and playready_key is not valid"); + playready_enabled, !kFlagIsOptional, playready_label)) { success = false; } return success; diff --git a/packager/app/playready_key_encryption_flags.h b/packager/app/playready_key_encryption_flags.h index 7540040633..cdbe76ca16 100644 --- a/packager/app/playready_key_encryption_flags.h +++ b/packager/app/playready_key_encryption_flags.h @@ -16,8 +16,6 @@ DECLARE_bool(enable_playready_encryption); DECLARE_string(playready_server_url); DECLARE_string(program_identifier); -DECLARE_hex_bytes(playready_key_id); -DECLARE_hex_bytes(playready_key); DECLARE_string(ca_file); DECLARE_string(client_cert_file); DECLARE_string(client_cert_private_key_file); diff --git a/packager/app/retired_flags.cc b/packager/app/retired_flags.cc index ad33f3679f..1c626cbb15 100644 --- a/packager/app/retired_flags.cc +++ b/packager/app/retired_flags.cc @@ -20,6 +20,14 @@ DEFINE_double(availability_time_offset, 0, "This flag is deprecated. Use suggested_presentation_delay " "instead which can achieve similar effect."); +DEFINE_string(playready_key_id, + "", + "This flag is deprecated. Use --enable_raw_key_encryption with " + "--generate_playready_pssh to generate PlayReady PSSH."); +DEFINE_string(playready_key, + "", + "This flag is deprecated. Use --enable_raw_key_encryption with " + "--generate_playready_pssh to generate PlayReady PSSH."); // The current gflags library does not provide a way to check whether a flag is // set in command line. If a flag has a different value to its default value, @@ -47,3 +55,5 @@ DEFINE_validator(profile, &InformRetiredStringFlag); DEFINE_validator(single_segment, &InformRetiredDefaultTrueFlag); DEFINE_validator(webm_subsample_encryption, &InformRetiredDefaultTrueFlag); DEFINE_validator(availability_time_offset, &InformRetiredDefaultDoubleFlag); +DEFINE_validator(playready_key_id, &InformRetiredStringFlag); +DEFINE_validator(playready_key, &InformRetiredStringFlag); diff --git a/packager/app/retired_flags.h b/packager/app/retired_flags.h index 829660f2fb..e45ac97cfd 100644 --- a/packager/app/retired_flags.h +++ b/packager/app/retired_flags.h @@ -10,3 +10,5 @@ DECLARE_string(profile); DECLARE_bool(single_segment); DECLARE_bool(webm_subsample_encryption); DECLARE_double(availability_time_offset); +DECLARE_string(playready_key_id); +DECLARE_string(playready_key); diff --git a/packager/media/base/playready_key_source.cc b/packager/media/base/playready_key_source.cc index c8a55e2da8..3ee855a91d 100644 --- a/packager/media/base/playready_key_source.cc +++ b/packager/media/base/playready_key_source.cc @@ -60,8 +60,10 @@ bool Base64StringToBytes(const std::string& base64_string, } } -PlayReadyKeySource::PlayReadyKeySource(const std::string& server_url) - : KeySource(PLAYREADY_PROTECTION_SYSTEM_FLAG), +PlayReadyKeySource::PlayReadyKeySource(const std::string& server_url, + int protection_system_flags) + // Playready PSSH is retrived from Playready server response. + : KeySource(protection_system_flags & ~PLAYREADY_PROTECTION_SYSTEM_FLAG), encryption_key_(new EncryptionKey), server_url_(server_url) {} @@ -69,8 +71,10 @@ PlayReadyKeySource::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) - : KeySource(PLAYREADY_PROTECTION_SYSTEM_FLAG), + const std::string& client_cert_private_key_password, + int protection_system_flags) + // Playready PSSH is retrived from Playready server response. + : KeySource(protection_system_flags & ~PLAYREADY_PROTECTION_SYSTEM_FLAG), encryption_key_(new EncryptionKey), server_url_(server_url), client_cert_file_(client_cert_file), @@ -84,30 +88,6 @@ PlayReadyKeySource::PlayReadyKeySource( PlayReadyKeySource::~PlayReadyKeySource() {} -std::unique_ptr PlayReadyKeySource::CreateFromKeyAndKeyId( - const std::vector& key_id, - const std::vector& key) { - std::unique_ptr encryption_key(new EncryptionKey); - encryption_key->key_id = key_id; - encryption_key->key = key; - - ProtectionSystemSpecificInfo info; - info.add_key_id(key_id); - info.set_system_id(kPlayReadySystemId, arraysize(kPlayReadySystemId)); - - std::vector pssh_data = - PlayReadyPsshGenerator::GeneratePsshFromKeyIdAndKey(key_id, key); - if (pssh_data.empty()) { - DLOG(INFO) << "Fail to generate PlayReady PSSH."; - return nullptr; - } - info.set_pssh_data(pssh_data); - - encryption_key->key_system_info.push_back(info); - return std::unique_ptr( - new PlayReadyKeySource(std::move(encryption_key))); -} - Status RetrieveTextInXMLElement(const std::string& element, const std::string& xml, std::string* value) { @@ -203,7 +183,15 @@ Status PlayReadyKeySource::FetchKeysWithProgramIdentifier( } status = SetKeyInformationFromServerResponse(acquire_license_response, encryption_key.get()); - encryption_key_ = std::move(encryption_key); + // Playready does not specify different streams. + const char kEmptyDrmLabel[] = ""; + EncryptionKeyMap encryption_key_map; + encryption_key_map[kEmptyDrmLabel] = std::move(encryption_key); + status = UpdateProtectionSystemInfo(&encryption_key_map); + if (!status.ok()) { + return status; + } + encryption_key_ = std::move(encryption_key_map[kEmptyDrmLabel]); return Status::OK; } diff --git a/packager/media/base/playready_key_source.h b/packager/media/base/playready_key_source.h index e95fa81498..1d2f7c45d6 100644 --- a/packager/media/base/playready_key_source.h +++ b/packager/media/base/playready_key_source.h @@ -21,17 +21,23 @@ class PlayReadyKeySource : public KeySource { public: /// Creates a new PlayReadyKeySource from the given packaging information. /// @param server_url PlayReady packaging server url. - PlayReadyKeySource(const std::string& server_url); + /// @param proteciton_systems_flags is the flags indicating which PSSH should + /// be included. + PlayReadyKeySource(const std::string& server_url, + int protection_scheme_flags); /// 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 + /// be included. 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); + const std::string& client_cert_private_key_password, + int protection_scheme_flags); ~PlayReadyKeySource() override; /// @name KeySource implementation overrides. diff --git a/packager/media/base/playready_pssh_generator.cc b/packager/media/base/playready_pssh_generator.cc index b6801feedc..fe8f21ba36 100644 --- a/packager/media/base/playready_pssh_generator.cc +++ b/packager/media/base/playready_pssh_generator.cc @@ -133,22 +133,6 @@ PlayReadyPsshGenerator::PlayReadyPsshGenerator() PlayReadyPsshGenerator::~PlayReadyPsshGenerator() {} -// TODO(hmchen): remove this static function when implementing the multi -// DRM support for PlayReadyKeySource. -// static -std::vector PlayReadyPsshGenerator::GeneratePsshFromKeyIdAndKey( - const std::vector& key_id, - const std::vector& key) { - std::vector pssh_data; - Status status = GeneratePlayReadyPsshData(key_id, key, &pssh_data); - if (!status.ok()) { - LOG(ERROR) << status.ToString(); - return std::vector(); - } - - return pssh_data; -} - bool PlayReadyPsshGenerator::SupportMultipleKeys() { return false; } diff --git a/packager/media/base/playready_pssh_generator.h b/packager/media/base/playready_pssh_generator.h index ff5a163b3e..1bbeb68e5a 100644 --- a/packager/media/base/playready_pssh_generator.h +++ b/packager/media/base/playready_pssh_generator.h @@ -25,10 +25,6 @@ class PlayReadyPsshGenerator : public PsshGenerator { PlayReadyPsshGenerator(); ~PlayReadyPsshGenerator() override; - static std::vector GeneratePsshFromKeyIdAndKey( - const std::vector& key_id, - const std::vector& key); - /// @name PsshGenerator implemetation overrides. /// @{ bool SupportMultipleKeys() override; diff --git a/packager/media/base/pssh_generator_unittest.cc b/packager/media/base/pssh_generator_unittest.cc index 87c25ba833..4099fed14c 100644 --- a/packager/media/base/pssh_generator_unittest.cc +++ b/packager/media/base/pssh_generator_unittest.cc @@ -4,6 +4,7 @@ // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd +#include #include #include "packager/media/base/playready_pssh_generator.h" @@ -11,6 +12,8 @@ #include "packager/media/base/widevine_pssh_generator.h" #include "packager/status_test_util.h" +using ::testing::ElementsAreArray; + namespace shaka { namespace media { namespace { @@ -94,16 +97,6 @@ std::vector GetTestKey1() { std::vector GetTestKeyId2() { return std::vector(std::begin(kTestKeyId2), std::end(kTestKeyId2)); } - -std::vector GetExpectedPlayReadyPsshData() { - return std::vector(std::begin(kExpectedPlayReadyPsshData), - std::end(kExpectedPlayReadyPsshData)); -} - -std::vector GetExpectedWidevinePsshData() { - return std::vector(std::begin(kExpectedWidevinePsshData), - std::end(kExpectedWidevinePsshData)); -} } // namespace // Folowing tests test PlayReady, RawKey and Widevine PSSH generators. Note @@ -132,13 +125,13 @@ TEST(PsshGeneratorTest, GeneratePlayReadyPsshDataFromKeyIdAndKey) { const std::vector kTestKey = GetTestKey1(); std::unique_ptr playready_pssh_generator( new PlayReadyPsshGenerator()); - base::Optional> pssh_data = - playready_pssh_generator->GeneratePsshDataFromKeyIdAndKey(kTestKeyId, - kTestKey); - ASSERT_TRUE(pssh_data); + ProtectionSystemSpecificInfo info; + EXPECT_OK(playready_pssh_generator->GeneratePsshFromKeyIdAndKey( + kTestKeyId, kTestKey, &info)); - const std::vector kExpectedPsshData = GetExpectedPlayReadyPsshData(); - EXPECT_EQ(kExpectedPsshData, pssh_data.value()); + EXPECT_THAT(info.pssh_data(), + ElementsAreArray(std::begin(kExpectedPlayReadyPsshData), + std::end(kExpectedPlayReadyPsshData))); } TEST(PsshGeneratorTest, GenerateRawKeyPsshDataFromKeyIds) { @@ -171,8 +164,9 @@ TEST(PsshGeneratorTest, GenerateWidevinePsshDataFromKeyIds) { ASSERT_OK( widevine_pssh_generator->GeneratePsshFromKeyIds(kTestKeyIds, &info)); - const std::vector kExpectedPsshData = GetExpectedWidevinePsshData(); - EXPECT_EQ(kExpectedPsshData, info.pssh_data()); + EXPECT_THAT(info.pssh_data(), + ElementsAreArray(std::begin(kExpectedWidevinePsshData), + std::end(kExpectedWidevinePsshData))); } TEST(PsshGeneratorTest, GenerateWidevinyPsshDataFromKeyIdAndKey) { diff --git a/packager/media/public/crypto_params.h b/packager/media/public/crypto_params.h index 4a97d959b2..7a507a87b8 100644 --- a/packager/media/public/crypto_params.h +++ b/packager/media/public/crypto_params.h @@ -82,12 +82,6 @@ struct PlayreadyEncryptionParams { std::string client_cert_private_key_file; /// Password to the private key file. std::string client_cert_private_key_password; - - // TODO(kqyang): move raw playready key generation to RawKey. - /// Provides a raw Playready KeyId. - std::vector key_id; - /// Provides a raw Playready Key. - std::vector key; }; /// Raw key encryption/decryption parameters, i.e. with key parameters provided.