Support Widevine PSSH with protection scheme generation

Issue #245.

Change-Id: Ieabdd3cdc55eb5bd4b7a145c9d041cc918101f18
This commit is contained in:
KongQun Yang 2018-08-07 14:43:42 -07:00
parent db076d6892
commit 6f66132aa9
14 changed files with 127 additions and 59 deletions

View File

@ -88,8 +88,7 @@ std::unique_ptr<KeySource> CreateEncryptionKeySource(
}
std::unique_ptr<WidevineKeySource> 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<RequestSigner> request_signer(
CreateSigner(widevine.signer));
@ -112,8 +111,9 @@ std::unique_ptr<KeySource> 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<KeySource> 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<KeySource> CreateDecryptionKeySource(
LOG(ERROR) << "'key_server_url' should not be empty.";
return std::unique_ptr<KeySource>();
}
std::unique_ptr<WidevineKeySource> widevine_key_source(new WidevineKeySource(
widevine.key_server_url,
WIDEVINE_PROTECTION_SYSTEM_FLAG /* value does not matter here */));
std::unique_ptr<WidevineKeySource> 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<RequestSigner> request_signer(
CreateSigner(widevine.signer));
@ -190,7 +193,8 @@ std::unique_ptr<KeySource> 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:

View File

@ -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) {

View File

@ -12,6 +12,7 @@
#include <string>
#include <vector>
#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<std::string, std::unique_ptr<EncryptionKey>> 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();

View File

@ -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),

View File

@ -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.

View File

@ -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<uint8_t> GetTestKeyId1() {
return std::vector<uint8_t>(std::begin(kTestKeyId1), std::end(kTestKeyId1));
}
@ -178,7 +190,7 @@ TEST(PsshGeneratorTest, GenerateWidevinePsshFromKeyIds) {
const std::vector<std::vector<uint8_t>> kTestKeyIds = {GetTestKeyId1(),
GetTestKeyId2()};
std::unique_ptr<WidevinePsshGenerator> 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<std::vector<uint8_t>> kTestKeyIds = {GetTestKeyId1(),
GetTestKeyId2()};
std::unique_ptr<WidevinePsshGenerator> 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<uint8_t> kTestKeyId = GetTestKeyId1();
const std::vector<uint8_t> kTestKey = GetTestKey1();
std::unique_ptr<WidevinePsshGenerator> widevine_pssh_generator(
new WidevinePsshGenerator());
new WidevinePsshGenerator(FOURCC_NULL));
ProtectionSystemSpecificInfo info;
EXPECT_NOT_OK(widevine_pssh_generator->GeneratePsshFromKeyIdAndKey(
kTestKeyId, kTestKey, &info));

View File

@ -96,9 +96,9 @@ Status RawKeySource::GetCryptoPeriodKey(uint32_t crypto_period_index,
return Status::OK;
}
std::unique_ptr<RawKeySource> RawKeySource::Create(
const RawKeyParams& raw_key,
int protection_systems_flags) {
std::unique_ptr<RawKeySource> RawKeySource::Create(const RawKeyParams& raw_key,
int protection_systems_flags,
FourCC protection_scheme) {
std::vector<ProtectionSystemSpecificInfo> key_system_info;
bool pssh_provided = false;
if (!raw_key.pssh.empty()) {
@ -141,14 +141,18 @@ std::unique_ptr<RawKeySource> RawKeySource::Create(
protection_systems_flags = COMMON_PROTECTION_SYSTEM_FLAG;
}
return std::unique_ptr<RawKeySource>(new RawKeySource(
std::move(encryption_key_map), protection_systems_flags));
return std::unique_ptr<RawKeySource>(
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_);
}

View File

@ -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<RawKeySource> 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;

View File

@ -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<RawKeySource> key_source =
RawKeySource::Create(raw_key_params, kNoProtectionSystemFlag);
std::unique_ptr<RawKeySource> 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<RawKeySource> key_source =
RawKeySource::Create(raw_key_params, kNoProtectionSystemFlag);
std::unique_ptr<RawKeySource> 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<RawKeySource> key_source =
RawKeySource::Create(raw_key_params, kNoProtectionSystemFlag);
std::unique_ptr<RawKeySource> 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);
}

View File

@ -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),

View File

@ -29,10 +29,14 @@ template <class T> 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<uint8_t>& 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<RequestSigner> signer);

View File

@ -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_));
}

View File

@ -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<uint8_t> StringToBytes(const std::string& string) {
return std::vector<uint8_t>(string.begin(), string.end());
}
} // namespace
WidevinePsshGenerator::WidevinePsshGenerator()
WidevinePsshGenerator::WidevinePsshGenerator(FourCC protection_scheme)
: PsshGenerator(std::vector<uint8_t>(std::begin(kWidevineSystemId),
std::end(kWidevineSystemId)),
kWidevinePsshBoxVersion) {}
kWidevinePsshBoxVersion),
protection_scheme_(protection_scheme) {}
WidevinePsshGenerator::~WidevinePsshGenerator() {}
@ -29,7 +34,12 @@ bool WidevinePsshGenerator::SupportMultipleKeys() {
base::Optional<std::vector<uint8_t>>
WidevinePsshGenerator::GeneratePsshDataFromKeyIds(
const std::vector<std::vector<uint8_t>>& key_ids) const {
return GenerateWidevinePsshDataFromKeyIds(key_ids);
media::WidevinePsshData widevine_pssh_data;
for (const std::vector<uint8_t>& 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<std::vector<uint8_t>>

View File

@ -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<std::vector<uint8_t>> GeneratePsshDataFromKeyIdAndKey(
const std::vector<uint8_t>& key_id,
const std::vector<uint8_t>& key) const override;
FourCC protection_scheme_ = FOURCC_NULL;
};
} // namespace media