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
This commit is contained in:
parent
2563ae7fe9
commit
aa4b573342
|
@ -337,8 +337,6 @@ base::Optional<PackagingParams> 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: {
|
||||
|
|
|
@ -98,16 +98,8 @@ std::unique_ptr<KeySource> 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() ||
|
||||
if (!playready.key_server_url.empty() ||
|
||||
!playready.program_identifier.empty()) {
|
||||
if (playready.key_server_url.empty() ||
|
||||
playready.program_identifier.empty()) {
|
||||
|
@ -128,10 +120,11 @@ std::unique_ptr<KeySource> 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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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> PlayReadyKeySource::CreateFromKeyAndKeyId(
|
||||
const std::vector<uint8_t>& key_id,
|
||||
const std::vector<uint8_t>& key) {
|
||||
std::unique_ptr<EncryptionKey> 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<uint8_t> 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<PlayReadyKeySource>(
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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<uint8_t> PlayReadyPsshGenerator::GeneratePsshFromKeyIdAndKey(
|
||||
const std::vector<uint8_t>& key_id,
|
||||
const std::vector<uint8_t>& key) {
|
||||
std::vector<uint8_t> pssh_data;
|
||||
Status status = GeneratePlayReadyPsshData(key_id, key, &pssh_data);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << status.ToString();
|
||||
return std::vector<uint8_t>();
|
||||
}
|
||||
|
||||
return pssh_data;
|
||||
}
|
||||
|
||||
bool PlayReadyPsshGenerator::SupportMultipleKeys() {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -25,10 +25,6 @@ class PlayReadyPsshGenerator : public PsshGenerator {
|
|||
PlayReadyPsshGenerator();
|
||||
~PlayReadyPsshGenerator() override;
|
||||
|
||||
static std::vector<uint8_t> GeneratePsshFromKeyIdAndKey(
|
||||
const std::vector<uint8_t>& key_id,
|
||||
const std::vector<uint8_t>& key);
|
||||
|
||||
/// @name PsshGenerator implemetation overrides.
|
||||
/// @{
|
||||
bool SupportMultipleKeys() override;
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#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<uint8_t> GetTestKey1() {
|
|||
std::vector<uint8_t> GetTestKeyId2() {
|
||||
return std::vector<uint8_t>(std::begin(kTestKeyId2), std::end(kTestKeyId2));
|
||||
}
|
||||
|
||||
std::vector<uint8_t> GetExpectedPlayReadyPsshData() {
|
||||
return std::vector<uint8_t>(std::begin(kExpectedPlayReadyPsshData),
|
||||
std::end(kExpectedPlayReadyPsshData));
|
||||
}
|
||||
|
||||
std::vector<uint8_t> GetExpectedWidevinePsshData() {
|
||||
return std::vector<uint8_t>(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<uint8_t> kTestKey = GetTestKey1();
|
||||
std::unique_ptr<PlayReadyPsshGenerator> playready_pssh_generator(
|
||||
new PlayReadyPsshGenerator());
|
||||
base::Optional<std::vector<uint8_t>> 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<uint8_t> 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<uint8_t> kExpectedPsshData = GetExpectedWidevinePsshData();
|
||||
EXPECT_EQ(kExpectedPsshData, info.pssh_data());
|
||||
EXPECT_THAT(info.pssh_data(),
|
||||
ElementsAreArray(std::begin(kExpectedWidevinePsshData),
|
||||
std::end(kExpectedWidevinePsshData)));
|
||||
}
|
||||
|
||||
TEST(PsshGeneratorTest, GenerateWidevinyPsshDataFromKeyIdAndKey) {
|
||||
|
|
|
@ -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<uint8_t> key_id;
|
||||
/// Provides a raw Playready Key.
|
||||
std::vector<uint8_t> key;
|
||||
};
|
||||
|
||||
/// Raw key encryption/decryption parameters, i.e. with key parameters provided.
|
||||
|
|
Loading…
Reference in New Issue