Add packager flag to include common PSSH with Widevine.
The flag --include_common_pssh will add another PSSH box in addition to the Widevine one which will contain the key IDs of all the keys. Closes #88 Change-Id: Ic719b19747530f0e4856cfb36471a644d572a734
This commit is contained in:
parent
94b4c52bf5
commit
6f8cbf90b9
|
@ -80,7 +80,7 @@ scoped_ptr<KeySource> CreateEncryptionKeySource() {
|
|||
scoped_ptr<KeySource> encryption_key_source;
|
||||
if (FLAGS_enable_widevine_encryption) {
|
||||
scoped_ptr<WidevineKeySource> widevine_key_source(
|
||||
new WidevineKeySource(FLAGS_key_server_url));
|
||||
new WidevineKeySource(FLAGS_key_server_url, FLAGS_include_common_pssh));
|
||||
if (!FLAGS_signer.empty()) {
|
||||
scoped_ptr<RequestSigner> request_signer(CreateSigner());
|
||||
if (!request_signer)
|
||||
|
@ -111,7 +111,7 @@ scoped_ptr<KeySource> CreateDecryptionKeySource() {
|
|||
scoped_ptr<KeySource> decryption_key_source;
|
||||
if (FLAGS_enable_widevine_decryption) {
|
||||
scoped_ptr<WidevineKeySource> widevine_key_source(
|
||||
new WidevineKeySource(FLAGS_key_server_url));
|
||||
new WidevineKeySource(FLAGS_key_server_url, FLAGS_include_common_pssh));
|
||||
if (!FLAGS_signer.empty()) {
|
||||
scoped_ptr<RequestSigner> request_signer(CreateSigner());
|
||||
if (!request_signer)
|
||||
|
|
|
@ -23,6 +23,11 @@ DEFINE_bool(enable_widevine_decryption,
|
|||
"Enable decryption with Widevine license server/proxy. User should "
|
||||
"provide either AES signing key (--aes_signing_key, "
|
||||
"--aes_signing_iv) or RSA signing key (--rsa_signing_key_path).");
|
||||
DEFINE_bool(include_common_pssh,
|
||||
false,
|
||||
"When using Widevine encryption, include an additional v1 PSSH box "
|
||||
"for the common system ID that includes the key IDs. See: "
|
||||
"http://goo.gl/PHZDAF");
|
||||
DEFINE_string(key_server_url, "", "Key server url. Required for encryption and "
|
||||
"decryption");
|
||||
DEFINE_string(content_id, "", "Content Id (hex).");
|
||||
|
@ -104,6 +109,11 @@ bool ValidateWidevineCryptoFlags() {
|
|||
widevine_encryption_label)) {
|
||||
success = false;
|
||||
}
|
||||
if (FLAGS_include_common_pssh && !FLAGS_enable_widevine_encryption) {
|
||||
PrintError("--include_common_pssh is only valid with "
|
||||
"--enable_widevine_encryption");
|
||||
success = false;
|
||||
}
|
||||
|
||||
if (FLAGS_max_sd_pixels <= 0) {
|
||||
PrintError("--max_sd_pixels must be positive.");
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
DECLARE_bool(enable_widevine_encryption);
|
||||
DECLARE_bool(enable_widevine_decryption);
|
||||
DECLARE_bool(include_common_pssh);
|
||||
DECLARE_string(key_server_url);
|
||||
DECLARE_string(content_id);
|
||||
DECLARE_string(policy);
|
||||
|
|
|
@ -12,15 +12,6 @@
|
|||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
namespace {
|
||||
// Common SystemID defined by EME, which requires Key System implementations
|
||||
// supporting ISO Common Encryption to support this SystemID and format.
|
||||
// http://goo.gl/PHZDAF
|
||||
const uint8_t kCommonSystemId[] = {0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2,
|
||||
0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
|
||||
0x52, 0xe2, 0xfb, 0x4b};
|
||||
} // namespace
|
||||
|
||||
FixedKeySource::~FixedKeySource() {}
|
||||
|
||||
Status FixedKeySource::FetchKeys(const std::vector<uint8_t>& pssh_box) {
|
||||
|
|
|
@ -16,6 +16,13 @@
|
|||
namespace edash_packager {
|
||||
namespace media {
|
||||
|
||||
// Common SystemID defined by EME, which requires Key System implementations
|
||||
// supporting ISO Common Encryption to support this SystemID and format.
|
||||
// http://goo.gl/PHZDAF
|
||||
const uint8_t kCommonSystemId[] = {0x10, 0x77, 0xef, 0xec, 0xc0, 0xb2,
|
||||
0x4d, 0x02, 0xac, 0xe3, 0x3c, 0x1e,
|
||||
0x52, 0xe2, 0xfb, 0x4b};
|
||||
|
||||
/// A key source that uses fixed keys for encryption.
|
||||
class FixedKeySource : public KeySource {
|
||||
public:
|
||||
|
|
|
@ -6,12 +6,15 @@
|
|||
|
||||
#include "packager/media/base/widevine_key_source.h"
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "packager/base/base64.h"
|
||||
#include "packager/base/bind.h"
|
||||
#include "packager/base/json/json_reader.h"
|
||||
#include "packager/base/json/json_writer.h"
|
||||
#include "packager/base/memory/ref_counted.h"
|
||||
#include "packager/base/stl_util.h"
|
||||
#include "packager/media/base/fixed_key_source.h"
|
||||
#include "packager/media/base/http_key_fetcher.h"
|
||||
#include "packager/media/base/producer_consumer_queue.h"
|
||||
#include "packager/media/base/protection_system_specific_info.h"
|
||||
|
@ -142,13 +145,15 @@ class WidevineKeySource::RefCountedEncryptionKeyMap
|
|||
DISALLOW_COPY_AND_ASSIGN(RefCountedEncryptionKeyMap);
|
||||
};
|
||||
|
||||
WidevineKeySource::WidevineKeySource(const std::string& server_url)
|
||||
WidevineKeySource::WidevineKeySource(const std::string& server_url,
|
||||
bool add_common_pssh)
|
||||
: key_production_thread_("KeyProductionThread",
|
||||
base::Bind(&WidevineKeySource::FetchKeysTask,
|
||||
base::Unretained(this))),
|
||||
key_fetcher_(new HttpKeyFetcher(kKeyFetchTimeoutInSeconds)),
|
||||
server_url_(server_url),
|
||||
crypto_period_count_(kDefaultCryptoPeriodCount),
|
||||
add_common_pssh_(add_common_pssh),
|
||||
key_production_started_(false),
|
||||
start_key_production_(false, false),
|
||||
first_crypto_period_index_(0) {
|
||||
|
@ -572,8 +577,27 @@ bool WidevineKeySource::ExtractEncryptionKey(
|
|||
encryption_key_map[track_type] = encryption_key.release();
|
||||
}
|
||||
|
||||
// NOTE: To support version 1 pssh, update ProtectionSystemSpecificInfo to
|
||||
// include all key IDs in |encryption_key_map|.
|
||||
// If the flag exists, create a common system ID PSSH box that contains the
|
||||
// key IDs of all the keys.
|
||||
if (add_common_pssh_ && !widevine_classic) {
|
||||
std::set<std::vector<uint8_t>> key_ids;
|
||||
for (const EncryptionKeyMap::value_type& pair : encryption_key_map) {
|
||||
key_ids.insert(pair.second->key_id);
|
||||
}
|
||||
|
||||
// Create a common system PSSH box.
|
||||
ProtectionSystemSpecificInfo info;
|
||||
info.set_system_id(kCommonSystemId, arraysize(kCommonSystemId));
|
||||
info.set_pssh_box_version(1);
|
||||
for (const std::vector<uint8_t>& key_id : key_ids) {
|
||||
info.add_key_id(key_id);
|
||||
}
|
||||
|
||||
for (const EncryptionKeyMap::value_type& pair : encryption_key_map) {
|
||||
pair.second->key_system_info.push_back(info);
|
||||
}
|
||||
}
|
||||
|
||||
DCHECK(!encryption_key_map.empty());
|
||||
if (!enable_key_rotation) {
|
||||
encryption_key_map_ = encryption_key_map;
|
||||
|
|
|
@ -26,7 +26,7 @@ template <class T> class ProducerConsumerQueue;
|
|||
class WidevineKeySource : public KeySource {
|
||||
public:
|
||||
/// @param server_url is the Widevine common encryption server url.
|
||||
explicit WidevineKeySource(const std::string& server_url);
|
||||
WidevineKeySource(const std::string& server_url, bool add_common_pssh);
|
||||
|
||||
~WidevineKeySource() override;
|
||||
|
||||
|
@ -113,6 +113,7 @@ class WidevineKeySource : public KeySource {
|
|||
|
||||
const uint32_t crypto_period_count_;
|
||||
base::Lock lock_;
|
||||
bool add_common_pssh_;
|
||||
bool key_production_started_;
|
||||
base::WaitableEvent start_key_production_;
|
||||
uint32_t first_crypto_period_index_;
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
#include <gmock/gmock.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "packager/base/base64.h"
|
||||
#include "packager/base/strings/string_number_conversions.h"
|
||||
#include "packager/base/strings/stringprintf.h"
|
||||
#include "packager/media/base/fixed_key_source.h"
|
||||
#include "packager/media/base/key_fetcher.h"
|
||||
#include "packager/media/base/request_signer.h"
|
||||
#include "packager/media/base/test/status_test_util.h"
|
||||
|
@ -156,7 +159,8 @@ class MockKeyFetcher : public KeyFetcher {
|
|||
DISALLOW_COPY_AND_ASSIGN(MockKeyFetcher);
|
||||
};
|
||||
|
||||
class WidevineKeySourceTest : public ::testing::Test {
|
||||
class WidevineKeySourceTest : public ::testing::Test,
|
||||
public ::testing::WithParamInterface<bool> {
|
||||
public:
|
||||
WidevineKeySourceTest()
|
||||
: mock_request_signer_(new MockRequestSigner(kSignerName)),
|
||||
|
@ -170,7 +174,7 @@ class WidevineKeySourceTest : public ::testing::Test {
|
|||
|
||||
protected:
|
||||
void CreateWidevineKeySource() {
|
||||
widevine_key_source_.reset(new WidevineKeySource(kServerUrl));
|
||||
widevine_key_source_.reset(new WidevineKeySource(kServerUrl, GetParam()));
|
||||
widevine_key_source_->set_key_fetcher(mock_key_fetcher_.Pass());
|
||||
}
|
||||
|
||||
|
@ -183,11 +187,30 @@ class WidevineKeySourceTest : public ::testing::Test {
|
|||
&encryption_key));
|
||||
EXPECT_EQ(GetMockKey(kTrackTypes[i]), ToString(encryption_key.key));
|
||||
if (!classic) {
|
||||
ASSERT_EQ(1u, encryption_key.key_system_info.size());
|
||||
ASSERT_EQ(GetParam() ? 2u : 1u, encryption_key.key_system_info.size());
|
||||
EXPECT_EQ(GetMockKeyId(kTrackTypes[i]),
|
||||
ToString(encryption_key.key_id));
|
||||
EXPECT_EQ(GetMockPsshData(kTrackTypes[i]),
|
||||
ToString(encryption_key.key_system_info[0].pssh_data()));
|
||||
|
||||
if (GetParam()) {
|
||||
// Each of the keys contains all the key IDs.
|
||||
const std::vector<uint8_t> common_system_id(
|
||||
kCommonSystemId, kCommonSystemId + arraysize(kCommonSystemId));
|
||||
ASSERT_EQ(common_system_id,
|
||||
encryption_key.key_system_info[1].system_id());
|
||||
|
||||
const std::vector<std::vector<uint8_t>>& key_ids =
|
||||
encryption_key.key_system_info[1].key_ids();
|
||||
ASSERT_EQ(arraysize(kTrackTypes), key_ids.size());
|
||||
for (size_t j = 0; j < arraysize(kTrackTypes); ++j) {
|
||||
// Because they are stored in a std::set, the order may change.
|
||||
const std::string key_id_str = GetMockKeyId(kTrackTypes[j]);
|
||||
const std::vector<uint8_t> key_id(key_id_str.begin(),
|
||||
key_id_str.end());
|
||||
EXPECT_THAT(key_ids, testing::Contains(key_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,7 +223,7 @@ class WidevineKeySourceTest : public ::testing::Test {
|
|||
DISALLOW_COPY_AND_ASSIGN(WidevineKeySourceTest);
|
||||
};
|
||||
|
||||
TEST_F(WidevineKeySourceTest, GetTrackTypeFromString) {
|
||||
TEST_P(WidevineKeySourceTest, GetTrackTypeFromString) {
|
||||
EXPECT_EQ(KeySource::TRACK_TYPE_SD,
|
||||
KeySource::GetTrackTypeFromString("SD"));
|
||||
EXPECT_EQ(KeySource::TRACK_TYPE_HD,
|
||||
|
@ -211,7 +234,7 @@ TEST_F(WidevineKeySourceTest, GetTrackTypeFromString) {
|
|||
KeySource::GetTrackTypeFromString("FOO"));
|
||||
}
|
||||
|
||||
TEST_F(WidevineKeySourceTest, GenerateSignatureFailure) {
|
||||
TEST_P(WidevineKeySourceTest, GenerateSignatureFailure) {
|
||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||
.WillOnce(Return(false));
|
||||
|
||||
|
@ -223,7 +246,7 @@ TEST_F(WidevineKeySourceTest, GenerateSignatureFailure) {
|
|||
|
||||
// Check whether expected request message and post data was generated and
|
||||
// verify the correct behavior on http failure.
|
||||
TEST_F(WidevineKeySourceTest, HttpFetchFailure) {
|
||||
TEST_P(WidevineKeySourceTest, HttpFetchFailure) {
|
||||
std::string expected_message = base::StringPrintf(
|
||||
kExpectedRequestMessageFormat, Base64Encode(kContentId).c_str(), kPolicy);
|
||||
EXPECT_CALL(*mock_request_signer_,
|
||||
|
@ -246,7 +269,7 @@ TEST_F(WidevineKeySourceTest, HttpFetchFailure) {
|
|||
widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
||||
}
|
||||
|
||||
TEST_F(WidevineKeySourceTest, LicenseStatusCencOK) {
|
||||
TEST_P(WidevineKeySourceTest, LicenseStatusCencOK) {
|
||||
std::string mock_response = base::StringPrintf(
|
||||
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
||||
|
||||
|
@ -258,7 +281,7 @@ TEST_F(WidevineKeySourceTest, LicenseStatusCencOK) {
|
|||
VerifyKeys(false);
|
||||
}
|
||||
|
||||
TEST_F(WidevineKeySourceTest, LicenseStatusCencNotOK) {
|
||||
TEST_P(WidevineKeySourceTest, LicenseStatusCencNotOK) {
|
||||
std::string mock_response = base::StringPrintf(
|
||||
kHttpResponseFormat, Base64Encode(
|
||||
GenerateMockClassicLicenseResponse()).c_str());
|
||||
|
@ -272,7 +295,7 @@ TEST_F(WidevineKeySourceTest, LicenseStatusCencNotOK) {
|
|||
.error_code());
|
||||
}
|
||||
|
||||
TEST_F(WidevineKeySourceTest, LicenseStatusCencWithPsshBoxOK) {
|
||||
TEST_P(WidevineKeySourceTest, LicenseStatusCencWithPsshBoxOK) {
|
||||
std::string expected_message =
|
||||
base::StringPrintf(kExpectedRequestMessageWithPsshFormat,
|
||||
Base64Encode(kRequestPsshData).c_str());
|
||||
|
@ -293,7 +316,7 @@ TEST_F(WidevineKeySourceTest, LicenseStatusCencWithPsshBoxOK) {
|
|||
VerifyKeys(false);
|
||||
}
|
||||
|
||||
TEST_F(WidevineKeySourceTest, LicenseStatusCencWithKeyIdsOK) {
|
||||
TEST_P(WidevineKeySourceTest, LicenseStatusCencWithKeyIdsOK) {
|
||||
std::string expected_pssh_data(
|
||||
kRequestPsshDataFromKeyIds,
|
||||
kRequestPsshDataFromKeyIds + arraysize(kRequestPsshDataFromKeyIds));
|
||||
|
@ -318,7 +341,7 @@ TEST_F(WidevineKeySourceTest, LicenseStatusCencWithKeyIdsOK) {
|
|||
VerifyKeys(false);
|
||||
}
|
||||
|
||||
TEST_F(WidevineKeySourceTest, LicenseStatusClassicOK) {
|
||||
TEST_P(WidevineKeySourceTest, LicenseStatusClassicOK) {
|
||||
std::string expected_message = base::StringPrintf(
|
||||
kExpectedRequestMessageWithAssetIdFormat, kClassicAssetId);
|
||||
EXPECT_CALL(*mock_request_signer_,
|
||||
|
@ -337,7 +360,7 @@ TEST_F(WidevineKeySourceTest, LicenseStatusClassicOK) {
|
|||
VerifyKeys(true);
|
||||
}
|
||||
|
||||
TEST_F(WidevineKeySourceTest, RetryOnHttpTimeout) {
|
||||
TEST_P(WidevineKeySourceTest, RetryOnHttpTimeout) {
|
||||
std::string mock_response = base::StringPrintf(
|
||||
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
||||
|
||||
|
@ -351,7 +374,7 @@ TEST_F(WidevineKeySourceTest, RetryOnHttpTimeout) {
|
|||
VerifyKeys(false);
|
||||
}
|
||||
|
||||
TEST_F(WidevineKeySourceTest, RetryOnTransientError) {
|
||||
TEST_P(WidevineKeySourceTest, RetryOnTransientError) {
|
||||
std::string mock_license_status = base::StringPrintf(
|
||||
kLicenseResponseFormat, kLicenseStatusTransientError, "");
|
||||
std::string mock_response = base::StringPrintf(
|
||||
|
@ -371,7 +394,7 @@ TEST_F(WidevineKeySourceTest, RetryOnTransientError) {
|
|||
VerifyKeys(false);
|
||||
}
|
||||
|
||||
TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) {
|
||||
TEST_P(WidevineKeySourceTest, NoRetryOnUnknownError) {
|
||||
std::string mock_license_status = base::StringPrintf(
|
||||
kLicenseResponseFormat, kLicenseStatusUnknownError, "");
|
||||
std::string mock_response = base::StringPrintf(
|
||||
|
@ -425,7 +448,7 @@ std::string GenerateMockKeyRotationLicenseResponse(
|
|||
|
||||
} // namespace
|
||||
|
||||
TEST_F(WidevineKeySourceTest, KeyRotationTest) {
|
||||
TEST_P(WidevineKeySourceTest, KeyRotationTest) {
|
||||
const uint32_t kFirstCryptoPeriodIndex = 8;
|
||||
const uint32_t kCryptoPeriodCount = 10;
|
||||
// Array of indexes to be checked.
|
||||
|
@ -491,5 +514,9 @@ TEST_F(WidevineKeySourceTest, KeyRotationTest) {
|
|||
EXPECT_EQ(error::INVALID_ARGUMENT, status.error_code());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(WidevineKeySourceInstance,
|
||||
WidevineKeySourceTest,
|
||||
::testing::Bool());
|
||||
|
||||
} // namespace media
|
||||
} // namespace edash_packager
|
||||
|
|
Loading…
Reference in New Issue