KeySource changes to support media decryption.
Renamed EncryptionKeySource and WidevineEncryptionKeySource to KeySource and WidevineKeySource respectively. Replaced Initialize method with FetchKeys. Added unit tests. content_id parameter is now binary. Specified in command line with hex string. Change-Id: I8010ca62d036cefb3a7c105e0eefee25bbf06d61
This commit is contained in:
parent
38c3569011
commit
65e558b19c
23
README.md
23
README.md
|
@ -64,7 +64,7 @@ Demuxer is responsible for extracting elementary stream samples from a multimedi
|
|||
|
||||
Demuxer reads from source through the File interface. A concrete LocalFile class is already implemented. The users may also implement their own File class if they want to read/write using a different kinds of protocol, e.g. network storage, http etc.
|
||||
|
||||
Muxer is responsible for taking elementary stream samples and producing media segments. An optional EncryptionKeySource can be provided to Muxer to generate encrypted outputs. Muxer writes to output using the same File interface as Demuxer.
|
||||
Muxer is responsible for taking elementary stream samples and producing media segments. An optional KeySource can be provided to Muxer to generate encrypted outputs. Muxer writes to output using the same File interface as Demuxer.
|
||||
|
||||
Demuxer and Muxer are connected using MediaStream. MediaStream wraps the elementary streams and is responsible for the interaction between Demuxer and Muxer. A demuxer can transmits multiple MediaStreams; similarly, A muxer is able to accept and mux multiple MediaStreams, not necessarily from the same Demuxer.
|
||||
|
||||
|
@ -203,17 +203,17 @@ muxer_options.temp_dir = …;
|
|||
muxer_options.bandwidth = 0;
|
||||
```
|
||||
|
||||
##Creating EncryptionKeySource##
|
||||
##Creating KeySource##
|
||||
|
||||
```C++
|
||||
// An EncryptionKeySource is optional. The stream won’t be encrypted if an
|
||||
// EncryptionKeySource is not provided.
|
||||
// A KeySource is optional. The stream won’t be encrypted if an
|
||||
// KeySource is not provided.
|
||||
```
|
||||
|
||||
###WidevineEncryptionKeySource###
|
||||
###WidevineKeySource###
|
||||
|
||||
```C++
|
||||
// Users may use WidevineEncryptionKeySource to fetch keys from Widevine
|
||||
// Users may use WidevineKeySource to fetch keys from Widevine
|
||||
// common encryption server.
|
||||
|
||||
// A request signer is required to sign the common encryption request.
|
||||
|
@ -221,12 +221,11 @@ scoped_ptr<RequestSigner> signer(
|
|||
RsaRequestSigner::CreateSigner(signer, pkcs1_rsa_private_key));
|
||||
if (!signer) { … }
|
||||
|
||||
scoped_ptr<WidevineEncryptionKeySource> widevine_encryption_key_source(
|
||||
new WidevineEncryptionKeySource(
|
||||
key_server_url, content_id, track_type, policy, signer.Pass()));
|
||||
scoped_ptr<WidevineKeySource> widevine_encryption_key_source(
|
||||
new WidevineKeySource(key_server_url, signer.Pass()));
|
||||
|
||||
// Intialize widevine encryption key source.
|
||||
status = widevine_encryption_key_source->Initialize();
|
||||
// Grab keys for the content.
|
||||
status = widevine_encryption_key_source->FetchKeys(content_id, policy));
|
||||
if (!status.ok()) { … }
|
||||
|
||||
// Set encryption key source to muxer.
|
||||
|
@ -236,7 +235,7 @@ if (!status.ok()) { … }
|
|||
// |clear_lead| specifies clear lead duration in seconds.
|
||||
// |crypto_period_duration| if not zero, enable key rotation with specified
|
||||
// crypto period.
|
||||
muxer->SetEncryptionKeySource(
|
||||
muxer->SetKeySource(
|
||||
widevine_encryption_key_source.get(), max_sd_pixels,
|
||||
clear_lead, crypto_period_duration);
|
||||
```
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "base/strings/stringprintf.h"
|
||||
#include "base/threading/simple_thread.h"
|
||||
#include "media/base/demuxer.h"
|
||||
#include "media/base/encryption_key_source.h"
|
||||
#include "media/base/key_source.h"
|
||||
#include "media/base/muxer_options.h"
|
||||
#include "media/base/muxer_util.h"
|
||||
#include "media/event/mpd_notify_muxer_listener.h"
|
||||
|
@ -96,7 +96,7 @@ class RemuxJob : public base::SimpleThread {
|
|||
|
||||
bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
||||
const MuxerOptions& muxer_options,
|
||||
EncryptionKeySource* key_source,
|
||||
KeySource* key_source,
|
||||
MpdNotifier* mpd_notifier,
|
||||
std::vector<MuxerListener*>* muxer_listeners,
|
||||
std::vector<RemuxJob*>* remux_jobs) {
|
||||
|
@ -142,7 +142,7 @@ bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
|
|||
|
||||
scoped_ptr<Muxer> muxer(new mp4::MP4Muxer(stream_muxer_options));
|
||||
if (key_source) {
|
||||
muxer->SetEncryptionKeySource(key_source,
|
||||
muxer->SetKeySource(key_source,
|
||||
FLAGS_max_sd_pixels,
|
||||
FLAGS_clear_lead,
|
||||
FLAGS_crypto_period_duration);
|
||||
|
@ -239,7 +239,7 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) {
|
|||
return false;
|
||||
|
||||
// Create encryption key source if needed.
|
||||
scoped_ptr<EncryptionKeySource> encryption_key_source;
|
||||
scoped_ptr<KeySource> encryption_key_source;
|
||||
if (FLAGS_enable_widevine_encryption || FLAGS_enable_fixed_key_encryption) {
|
||||
encryption_key_source = CreateEncryptionKeySource();
|
||||
if (!encryption_key_source)
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include "media/base/muxer_options.h"
|
||||
#include "media/base/request_signer.h"
|
||||
#include "media/base/stream_info.h"
|
||||
#include "media/base/widevine_encryption_key_source.h"
|
||||
#include "media/base/widevine_key_source.h"
|
||||
#include "media/file/file.h"
|
||||
#include "mpd/base/mpd_builder.h"
|
||||
|
||||
|
@ -34,13 +34,9 @@ void DumpStreamInfo(const std::vector<MediaStream*>& streams) {
|
|||
printf("Stream [%zu] %s\n", i, streams[i]->info()->ToString().c_str());
|
||||
}
|
||||
|
||||
// Create and initialize encryptor source.
|
||||
scoped_ptr<EncryptionKeySource> CreateEncryptionKeySource() {
|
||||
scoped_ptr<EncryptionKeySource> encryption_key_source;
|
||||
if (FLAGS_enable_widevine_encryption) {
|
||||
scoped_ptr<RequestSigner> CreateSigner() {
|
||||
scoped_ptr<RequestSigner> signer;
|
||||
DCHECK(!FLAGS_aes_signing_key.empty() ||
|
||||
!FLAGS_rsa_signing_key_path.empty());
|
||||
if (FLAGS_enable_widevine_encryption || FLAGS_enable_widevine_decryption) {
|
||||
if (!FLAGS_aes_signing_key.empty()) {
|
||||
signer.reset(
|
||||
AesRequestSigner::CreateSigner(FLAGS_signer, FLAGS_aes_signing_key,
|
||||
|
@ -49,7 +45,7 @@ scoped_ptr<EncryptionKeySource> CreateEncryptionKeySource() {
|
|||
LOG(ERROR) << "Cannot create an AES signer object from '"
|
||||
<< FLAGS_aes_signing_key << "':'" << FLAGS_aes_signing_iv
|
||||
<< "'.";
|
||||
return scoped_ptr<EncryptionKeySource>();
|
||||
return scoped_ptr<RequestSigner>();
|
||||
}
|
||||
} else if (!FLAGS_rsa_signing_key_path.empty()) {
|
||||
std::string rsa_private_key;
|
||||
|
@ -57,38 +53,57 @@ scoped_ptr<EncryptionKeySource> CreateEncryptionKeySource() {
|
|||
&rsa_private_key)) {
|
||||
LOG(ERROR) << "Failed to read from '" << FLAGS_rsa_signing_key_path
|
||||
<< "'.";
|
||||
return scoped_ptr<EncryptionKeySource>();
|
||||
return scoped_ptr<RequestSigner>();
|
||||
}
|
||||
|
||||
signer.reset(
|
||||
RsaRequestSigner::CreateSigner(FLAGS_signer, rsa_private_key));
|
||||
if (!signer) {
|
||||
LOG(ERROR) << "Cannot create a RSA signer object from '"
|
||||
<< FLAGS_rsa_signing_key_path << "'.";
|
||||
return scoped_ptr<EncryptionKeySource>();
|
||||
return scoped_ptr<RequestSigner>();
|
||||
}
|
||||
}
|
||||
}
|
||||
return signer.Pass();
|
||||
}
|
||||
|
||||
scoped_ptr<WidevineEncryptionKeySource> widevine_encryption_key_source(
|
||||
new WidevineEncryptionKeySource(
|
||||
FLAGS_key_server_url,
|
||||
FLAGS_content_id,
|
||||
FLAGS_policy,
|
||||
scoped_ptr<KeySource> CreateEncryptionKeySource() {
|
||||
scoped_ptr<KeySource> encryption_key_source;
|
||||
if (FLAGS_enable_widevine_encryption) {
|
||||
scoped_ptr<RequestSigner> signer(CreateSigner());
|
||||
std::vector<uint8> content_id;
|
||||
if (!base::HexStringToBytes(FLAGS_content_id, &content_id)) {
|
||||
LOG(ERROR) << "Invalid content_id hex string specified.";
|
||||
return scoped_ptr<KeySource>();
|
||||
}
|
||||
scoped_ptr<WidevineKeySource> widevine_encryption_key_source(
|
||||
new WidevineKeySource(FLAGS_key_server_url,
|
||||
signer.Pass()));
|
||||
Status status = widevine_encryption_key_source->Initialize();
|
||||
Status status = widevine_encryption_key_source->FetchKeys(content_id,
|
||||
FLAGS_policy);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Widevine encryption key source failed to initialize: "
|
||||
LOG(ERROR) << "Widevine encryption key source failed to fetch keys: "
|
||||
<< status.ToString();
|
||||
return scoped_ptr<EncryptionKeySource>();
|
||||
return scoped_ptr<KeySource>();
|
||||
}
|
||||
encryption_key_source = widevine_encryption_key_source.Pass();
|
||||
} else if (FLAGS_enable_fixed_key_encryption) {
|
||||
encryption_key_source = EncryptionKeySource::CreateFromHexStrings(
|
||||
encryption_key_source = KeySource::CreateFromHexStrings(
|
||||
FLAGS_key_id, FLAGS_key, FLAGS_pssh, "");
|
||||
}
|
||||
return encryption_key_source.Pass();
|
||||
}
|
||||
|
||||
scoped_ptr<KeySource> CreateDecryptionKeySource() {
|
||||
scoped_ptr<KeySource> decryption_key_source;
|
||||
if (FLAGS_enable_widevine_decryption) {
|
||||
scoped_ptr<RequestSigner> signer(CreateSigner());
|
||||
decryption_key_source.reset(new WidevineKeySource(FLAGS_key_server_url,
|
||||
signer.Pass()));
|
||||
}
|
||||
return decryption_key_source.Pass();
|
||||
}
|
||||
|
||||
bool AssignFlagsFromProfile() {
|
||||
bool single_segment = FLAGS_single_segment;
|
||||
if (FLAGS_profile == "on-demand") {
|
||||
|
|
|
@ -23,7 +23,7 @@ struct MpdOptions;
|
|||
|
||||
namespace media {
|
||||
|
||||
class EncryptionKeySource;
|
||||
class KeySource;
|
||||
class MediaInfo;
|
||||
class MediaStream;
|
||||
class Muxer;
|
||||
|
@ -32,10 +32,17 @@ struct MuxerOptions;
|
|||
/// Print all the stream info for the provided strings to standard output.
|
||||
void DumpStreamInfo(const std::vector<MediaStream*>& streams);
|
||||
|
||||
/// Create EncryptionKeySource based on provided command line options.
|
||||
/// @return A scoped_ptr containig a new EncryptionKeySource, or NULL if
|
||||
/// Create KeySource based on provided command line options for content
|
||||
/// encryption. Also fetches keys.
|
||||
/// @return A scoped_ptr containing a new KeySource, or NULL if
|
||||
/// encryption is not required.
|
||||
scoped_ptr<EncryptionKeySource> CreateEncryptionKeySource();
|
||||
scoped_ptr<KeySource> CreateEncryptionKeySource();
|
||||
|
||||
/// Create KeySource based on provided command line options for content
|
||||
/// decryption. Does not fetch keys.
|
||||
/// @return A scoped_ptr containing a new KeySource, or NULL if decryption
|
||||
/// is not required.
|
||||
scoped_ptr<KeySource> CreateDecryptionKeySource();
|
||||
|
||||
/// Set flags according to profile.
|
||||
bool AssignFlagsFromProfile();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "app/widevine_encryption_flags.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
|
||||
DEFINE_bool(enable_widevine_encryption,
|
||||
|
@ -15,8 +16,14 @@ DEFINE_bool(enable_widevine_encryption,
|
|||
"Enable encryption 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_string(key_server_url, "", "Key server url.");
|
||||
DEFINE_string(content_id, "", "Content Id.");
|
||||
DEFINE_bool(enable_widevine_decryption,
|
||||
false,
|
||||
"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_string(key_server_url, "", "Key server url. Required for encryption and "
|
||||
"decryption");
|
||||
DEFINE_string(content_id, "", "Content Id (hex).");
|
||||
DEFINE_string(policy,
|
||||
"",
|
||||
"The name of a stored policy, which specifies DRM content "
|
||||
|
@ -44,9 +51,44 @@ DEFINE_int32(crypto_period_duration,
|
|||
|
||||
namespace {
|
||||
|
||||
static bool IsNotEmptyWithWidevineEncryption(const char* flag_name,
|
||||
static bool VerifyEncryptionAndDecryptionParams(const char* flag_name,
|
||||
const std::string& flag_value) {
|
||||
return FLAGS_enable_widevine_encryption ? !flag_value.empty() : true;
|
||||
DCHECK(flag_name);
|
||||
|
||||
if (FLAGS_enable_widevine_encryption) {
|
||||
if (flag_value.empty()) {
|
||||
fprintf(stderr,
|
||||
"ERROR: %s required if enable_widevine_encryption is true\n",
|
||||
flag_name);
|
||||
return false;
|
||||
}
|
||||
} else if (FLAGS_enable_widevine_decryption) {
|
||||
const std::string flag_name_str = flag_name;
|
||||
if (flag_name_str == "key_server_url") {
|
||||
if (flag_value.empty()) {
|
||||
fprintf(stderr,
|
||||
"ERROR: %s required if --enable_widevine_decryption is true\n",
|
||||
flag_name);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!flag_value.empty()) {
|
||||
fprintf(stderr, "ERROR: %s should only be specified if "
|
||||
"--enable_widevine_decryption is true\n", flag_name);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!flag_value.empty()) {
|
||||
const std::string flag_name_str = flag_name;
|
||||
fprintf(stderr, "ERROR: %s should only be specified if %s"
|
||||
" is true\n", flag_name, flag_name_str == "key_server_url" ?
|
||||
"--enable_widevine_encryption or --enable_widevine_decryption" :
|
||||
"--enable_widevine_encryption");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsPositive(const char* flag_name, int flag_value) {
|
||||
|
@ -83,15 +125,15 @@ static bool VerifyAesRsaKey(const char* flag_name,
|
|||
|
||||
bool dummy_key_server_url_validator =
|
||||
google::RegisterFlagValidator(&FLAGS_key_server_url,
|
||||
&IsNotEmptyWithWidevineEncryption);
|
||||
&VerifyEncryptionAndDecryptionParams);
|
||||
bool dummy_content_id_validator =
|
||||
google::RegisterFlagValidator(&FLAGS_content_id,
|
||||
&IsNotEmptyWithWidevineEncryption);
|
||||
&VerifyEncryptionAndDecryptionParams);
|
||||
bool dummy_track_type_validator =
|
||||
google::RegisterFlagValidator(&FLAGS_max_sd_pixels, &IsPositive);
|
||||
bool dummy_signer_validator =
|
||||
google::RegisterFlagValidator(&FLAGS_signer,
|
||||
&IsNotEmptyWithWidevineEncryption);
|
||||
&VerifyEncryptionAndDecryptionParams);
|
||||
bool dummy_aes_iv_validator =
|
||||
google::RegisterFlagValidator(&FLAGS_aes_signing_iv,
|
||||
&VerifyAesRsaKey);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <gflags/gflags.h>
|
||||
|
||||
DECLARE_bool(enable_widevine_encryption);
|
||||
DECLARE_bool(enable_widevine_decryption);
|
||||
DECLARE_string(key_server_url);
|
||||
DECLARE_string(content_id);
|
||||
DECLARE_string(policy);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include "media/base/encryption_key_source.h"
|
||||
#include "media/base/key_source.h"
|
||||
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "media/base/aes_encryptor.h"
|
||||
|
@ -21,23 +21,42 @@ namespace media {
|
|||
EncryptionKey::EncryptionKey() {}
|
||||
EncryptionKey::~EncryptionKey() {}
|
||||
|
||||
EncryptionKeySource::~EncryptionKeySource() {}
|
||||
KeySource::~KeySource() {}
|
||||
|
||||
Status EncryptionKeySource::GetKey(TrackType track_type, EncryptionKey* key) {
|
||||
Status KeySource::FetchKeys(const std::vector<uint8>& content_id,
|
||||
const std::string& policy) {
|
||||
NOTREACHED();
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
Status KeySource::FetchKeys(const std::vector<uint8>& pssh_data) {
|
||||
NOTREACHED();
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
Status KeySource::GetKey(TrackType track_type, EncryptionKey* key) {
|
||||
DCHECK(key);
|
||||
DCHECK(encryption_key_);
|
||||
*key = *encryption_key_;
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
Status EncryptionKeySource::GetCryptoPeriodKey(uint32 crypto_period_index,
|
||||
Status KeySource::GetKey(const std::vector<uint8>& key_id,
|
||||
EncryptionKey* key) {
|
||||
DCHECK(key);
|
||||
DCHECK(encryption_key_);
|
||||
*key = *encryption_key_;
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
Status KeySource::GetCryptoPeriodKey(uint32 crypto_period_index,
|
||||
TrackType track_type,
|
||||
EncryptionKey* key) {
|
||||
NOTIMPLEMENTED();
|
||||
return Status(error::UNIMPLEMENTED, "");
|
||||
}
|
||||
|
||||
scoped_ptr<EncryptionKeySource> EncryptionKeySource::CreateFromHexStrings(
|
||||
scoped_ptr<KeySource> KeySource::CreateFromHexStrings(
|
||||
const std::string& key_id_hex,
|
||||
const std::string& key_hex,
|
||||
const std::string& pssh_data_hex,
|
||||
|
@ -46,33 +65,33 @@ scoped_ptr<EncryptionKeySource> EncryptionKeySource::CreateFromHexStrings(
|
|||
|
||||
if (!base::HexStringToBytes(key_id_hex, &encryption_key->key_id)) {
|
||||
LOG(ERROR) << "Cannot parse key_id_hex " << key_id_hex;
|
||||
return scoped_ptr<EncryptionKeySource>();
|
||||
return scoped_ptr<KeySource>();
|
||||
}
|
||||
|
||||
if (!base::HexStringToBytes(key_hex, &encryption_key->key)) {
|
||||
LOG(ERROR) << "Cannot parse key_hex " << key_hex;
|
||||
return scoped_ptr<EncryptionKeySource>();
|
||||
return scoped_ptr<KeySource>();
|
||||
}
|
||||
|
||||
std::vector<uint8> pssh_data;
|
||||
if (!base::HexStringToBytes(pssh_data_hex, &pssh_data)) {
|
||||
LOG(ERROR) << "Cannot parse pssh_hex " << pssh_data_hex;
|
||||
return scoped_ptr<EncryptionKeySource>();
|
||||
return scoped_ptr<KeySource>();
|
||||
}
|
||||
|
||||
if (!iv_hex.empty()) {
|
||||
if (!base::HexStringToBytes(iv_hex, &encryption_key->iv)) {
|
||||
LOG(ERROR) << "Cannot parse iv_hex " << iv_hex;
|
||||
return scoped_ptr<EncryptionKeySource>();
|
||||
return scoped_ptr<KeySource>();
|
||||
}
|
||||
}
|
||||
|
||||
encryption_key->pssh = PsshBoxFromPsshData(pssh_data);
|
||||
return scoped_ptr<EncryptionKeySource>(
|
||||
new EncryptionKeySource(encryption_key.Pass()));
|
||||
return scoped_ptr<KeySource>(
|
||||
new KeySource(encryption_key.Pass()));
|
||||
}
|
||||
|
||||
EncryptionKeySource::TrackType EncryptionKeySource::GetTrackTypeFromString(
|
||||
KeySource::TrackType KeySource::GetTrackTypeFromString(
|
||||
const std::string& track_type_string) {
|
||||
if (track_type_string == "SD")
|
||||
return TRACK_TYPE_SD;
|
||||
|
@ -84,7 +103,7 @@ EncryptionKeySource::TrackType EncryptionKeySource::GetTrackTypeFromString(
|
|||
return TRACK_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
std::string EncryptionKeySource::TrackTypeToString(TrackType track_type) {
|
||||
std::string KeySource::TrackTypeToString(TrackType track_type) {
|
||||
switch (track_type) {
|
||||
case TRACK_TYPE_SD:
|
||||
return "SD";
|
||||
|
@ -98,7 +117,7 @@ std::string EncryptionKeySource::TrackTypeToString(TrackType track_type) {
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<uint8> EncryptionKeySource::PsshBoxFromPsshData(
|
||||
std::vector<uint8> KeySource::PsshBoxFromPsshData(
|
||||
const std::vector<uint8>& pssh_data) {
|
||||
const uint8 kPsshFourCC[] = {'p', 's', 's', 'h'};
|
||||
const uint32 kVersionAndFlags = 0;
|
||||
|
@ -118,9 +137,8 @@ std::vector<uint8> EncryptionKeySource::PsshBoxFromPsshData(
|
|||
return std::vector<uint8>(writer.Buffer(), writer.Buffer() + writer.Size());
|
||||
}
|
||||
|
||||
EncryptionKeySource::EncryptionKeySource() {}
|
||||
EncryptionKeySource::EncryptionKeySource(
|
||||
scoped_ptr<EncryptionKey> encryption_key)
|
||||
KeySource::KeySource() {}
|
||||
KeySource::KeySource(scoped_ptr<EncryptionKey> encryption_key)
|
||||
: encryption_key_(encryption_key.Pass()) {
|
||||
DCHECK(encryption_key_);
|
||||
}
|
|
@ -4,8 +4,8 @@
|
|||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef MEDIA_BASE_ENCRYPTION_KEY_SOURCE_H_
|
||||
#define MEDIA_BASE_ENCRYPTION_KEY_SOURCE_H_
|
||||
#ifndef MEDIA_BASE_KEY_SOURCE_H_
|
||||
#define MEDIA_BASE_KEY_SOURCE_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
@ -24,8 +24,8 @@ struct EncryptionKey {
|
|||
std::vector<uint8> iv;
|
||||
};
|
||||
|
||||
/// EncryptionKeySource is responsible for encryption key acquisition.
|
||||
class EncryptionKeySource {
|
||||
/// KeySource is responsible for encryption key acquisition.
|
||||
class KeySource {
|
||||
public:
|
||||
enum TrackType {
|
||||
TRACK_TYPE_UNKNOWN = 0,
|
||||
|
@ -35,19 +35,47 @@ class EncryptionKeySource {
|
|||
NUM_VALID_TRACK_TYPES = 3
|
||||
};
|
||||
|
||||
virtual ~EncryptionKeySource();
|
||||
virtual ~KeySource();
|
||||
|
||||
/// Fetch keys for CENC from the key server.
|
||||
/// @param content_id the unique id identify the content.
|
||||
/// @param policy specifies the DRM content rights.
|
||||
/// @return OK on success, an error status otherwise.
|
||||
virtual Status FetchKeys(const std::vector<uint8>& content_id,
|
||||
const std::string& policy);
|
||||
|
||||
/// Fetch keys for CENC from the key server.
|
||||
/// @param pssh_data is the Data portion of the PSSH box for the content
|
||||
/// to be decrypted.
|
||||
/// @return OK on success, an error status otherwise.
|
||||
virtual Status FetchKeys(const std::vector<uint8>& pssh_data);
|
||||
|
||||
/// Get encryption key of the specified track type.
|
||||
/// @param track_type is the type of track for which retrieving the key.
|
||||
/// @param key is a pointer to the EncryptionKey which will hold the retrieved
|
||||
/// key. Owner retains ownership, and may not be NULL.
|
||||
/// @return OK on success, an error status otherwise.
|
||||
virtual Status GetKey(TrackType track_type, EncryptionKey* key);
|
||||
|
||||
/// Get the encryption key specified by the CENC key ID.
|
||||
/// @param key_id is the unique identifier for the key being retreived.
|
||||
/// @param key is a pointer to the EncryptionKey which will hold the retrieved
|
||||
/// key. Owner retains ownership, and may not be NULL.
|
||||
/// @return OK on success, or an error status otherwise.
|
||||
virtual Status GetKey(const std::vector<uint8>& key_id, EncryptionKey* key);
|
||||
|
||||
/// Get encryption key of the specified track type at the specified index.
|
||||
/// @param crypto_period_index is the sequence number of the key rotation
|
||||
/// period for which the key is being retrieved.
|
||||
/// @param track_type is the type of track for which retrieving the key.
|
||||
/// @param key is a pointer to the EncryptionKey which will hold the retrieved
|
||||
/// key. Owner retains ownership, and may not be NULL.
|
||||
/// @return OK on success, an error status otherwise.
|
||||
virtual Status GetCryptoPeriodKey(uint32 crypto_period_index,
|
||||
TrackType track_type,
|
||||
EncryptionKey* key);
|
||||
|
||||
/// Create EncryptionKeySource object from hex strings.
|
||||
/// Create KeySource object from hex strings.
|
||||
/// @param key_id_hex is the key id in hex string.
|
||||
/// @param key_hex is the key in hex string.
|
||||
/// @param pssh_data_hex is the pssh_data in hex string.
|
||||
|
@ -55,7 +83,7 @@ class EncryptionKeySource {
|
|||
/// generated IV with the default length will be used.
|
||||
/// Note: GetKey on the created key source will always return the same key
|
||||
/// for all track types.
|
||||
static scoped_ptr<EncryptionKeySource> CreateFromHexStrings(
|
||||
static scoped_ptr<KeySource> CreateFromHexStrings(
|
||||
const std::string& key_id_hex,
|
||||
const std::string& key_hex,
|
||||
const std::string& pssh_data_hex,
|
||||
|
@ -68,7 +96,7 @@ class EncryptionKeySource {
|
|||
static std::string TrackTypeToString(TrackType track_type);
|
||||
|
||||
protected:
|
||||
EncryptionKeySource();
|
||||
KeySource();
|
||||
|
||||
/// @return the raw bytes of the pssh box with system ID and box header
|
||||
/// included.
|
||||
|
@ -76,13 +104,13 @@ class EncryptionKeySource {
|
|||
const std::vector<uint8>& pssh_data);
|
||||
|
||||
private:
|
||||
explicit EncryptionKeySource(scoped_ptr<EncryptionKey> encryption_key);
|
||||
explicit KeySource(scoped_ptr<EncryptionKey> encryption_key);
|
||||
|
||||
scoped_ptr<EncryptionKey> encryption_key_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(EncryptionKeySource);
|
||||
DISALLOW_COPY_AND_ASSIGN(KeySource);
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
|
||||
#endif // MEDIA_BASE_ENCRYPTION_KEY_SOURCE_H_
|
||||
#endif // MEDIA_BASE_KEY_SOURCE_H_
|
|
@ -36,10 +36,10 @@
|
|||
'decrypt_config.cc',
|
||||
'decrypt_config.h',
|
||||
'decryptor_source.h',
|
||||
'encryption_key_source.cc',
|
||||
'encryption_key_source.h',
|
||||
'http_fetcher.cc',
|
||||
'http_fetcher.h',
|
||||
'key_source.cc',
|
||||
'key_source.h',
|
||||
'limits.h',
|
||||
'media_parser.h',
|
||||
'media_sample.cc',
|
||||
|
@ -67,8 +67,8 @@
|
|||
'timestamp.h',
|
||||
'video_stream_info.cc',
|
||||
'video_stream_info.h',
|
||||
'widevine_encryption_key_source.cc',
|
||||
'widevine_encryption_key_source.h',
|
||||
'widevine_key_source.cc',
|
||||
'widevine_key_source.h',
|
||||
],
|
||||
'dependencies': [
|
||||
'../../base/base.gyp:base',
|
||||
|
@ -98,7 +98,7 @@
|
|||
'status_test_util.h',
|
||||
'status_test_util_unittest.cc',
|
||||
'status_unittest.cc',
|
||||
'widevine_encryption_key_source_unittest.cc',
|
||||
'widevine_key_source_unittest.cc',
|
||||
],
|
||||
'dependencies': [
|
||||
'../../testing/gtest.gyp:gtest',
|
||||
|
|
|
@ -23,7 +23,7 @@ Muxer::Muxer(const MuxerOptions& options)
|
|||
|
||||
Muxer::~Muxer() {}
|
||||
|
||||
void Muxer::SetEncryptionKeySource(EncryptionKeySource* encryption_key_source,
|
||||
void Muxer::SetKeySource(KeySource* encryption_key_source,
|
||||
uint32 max_sd_pixels,
|
||||
double clear_lead_in_seconds,
|
||||
double crypto_period_duration_in_seconds) {
|
||||
|
|
|
@ -22,7 +22,7 @@ class Clock;
|
|||
|
||||
namespace media {
|
||||
|
||||
class EncryptionKeySource;
|
||||
class KeySource;
|
||||
class MediaSample;
|
||||
class MediaStream;
|
||||
|
||||
|
@ -31,7 +31,7 @@ class MuxerListener;
|
|||
}
|
||||
|
||||
/// Muxer is responsible for taking elementary stream samples and producing
|
||||
/// media containers. An optional EncryptionKeySource can be provided to Muxer
|
||||
/// media containers. An optional KeySource can be provided to Muxer
|
||||
/// to generate encrypted outputs.
|
||||
class Muxer {
|
||||
public:
|
||||
|
@ -39,8 +39,8 @@ class Muxer {
|
|||
virtual ~Muxer();
|
||||
|
||||
/// Set encryption key source.
|
||||
/// @param encryption_key_source points to the encryption key source to be
|
||||
/// injected. Should not be NULL.
|
||||
/// @param encryption_key_source points to the encryption key source. The
|
||||
/// caller retains ownership, and should not be NULL.
|
||||
/// @param max_sd_pixels specifies the threshold to determine whether a video
|
||||
/// track should be considered as SD or HD. If the track has more
|
||||
/// pixels per frame than max_sd_pixels, it is HD, SD otherwise.
|
||||
|
@ -48,7 +48,7 @@ class Muxer {
|
|||
/// @param crypto_period_duration_in_seconds specifies crypto period duration
|
||||
/// in seconds. A positive value means key rotation is enabled, the
|
||||
/// key source must support key rotation in this case.
|
||||
void SetEncryptionKeySource(EncryptionKeySource* encryption_key_source,
|
||||
void SetKeySource(KeySource* encryption_key_source,
|
||||
uint32 max_sd_pixels,
|
||||
double clear_lead_in_seconds,
|
||||
double crypto_period_duration_in_seconds);
|
||||
|
@ -77,7 +77,7 @@ class Muxer {
|
|||
|
||||
protected:
|
||||
const MuxerOptions& options() const { return options_; }
|
||||
EncryptionKeySource* encryption_key_source() {
|
||||
KeySource* encryption_key_source() {
|
||||
return encryption_key_source_;
|
||||
}
|
||||
uint32 max_sd_pixels() const { return max_sd_pixels_; }
|
||||
|
@ -108,7 +108,7 @@ class Muxer {
|
|||
MuxerOptions options_;
|
||||
bool initialized_;
|
||||
std::vector<MediaStream*> streams_;
|
||||
EncryptionKeySource* encryption_key_source_;
|
||||
KeySource* encryption_key_source_;
|
||||
uint32 max_sd_pixels_;
|
||||
double clear_lead_in_seconds_;
|
||||
double crypto_period_duration_in_seconds_;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#include "media/base/widevine_encryption_key_source.h"
|
||||
#include "media/base/widevine_key_source.h"
|
||||
|
||||
#include "base/base64.h"
|
||||
#include "base/bind.h"
|
||||
|
@ -12,7 +12,6 @@
|
|||
#include "base/json/json_writer.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/values.h"
|
||||
#include "media/base/http_fetcher.h"
|
||||
#include "media/base/producer_consumer_queue.h"
|
||||
#include "media/base/request_signer.h"
|
||||
|
@ -55,26 +54,35 @@ bool Base64StringToBytes(const std::string& base64_string,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GetKeyAndKeyId(const base::DictionaryValue& track_dict,
|
||||
std::vector<uint8>* key,
|
||||
std::vector<uint8>* key_id) {
|
||||
DCHECK(key);
|
||||
DCHECK(key_id);
|
||||
void BytesToBase64String(const std::vector<uint8>& bytes,
|
||||
std::string* base64_string) {
|
||||
DCHECK(base64_string);
|
||||
base::Base64Encode(base::StringPiece(reinterpret_cast<const char*>
|
||||
(bytes.data()), bytes.size()),
|
||||
base64_string);
|
||||
}
|
||||
|
||||
bool GetKeyFromTrack(const base::DictionaryValue& track_dict,
|
||||
std::vector<uint8>* key) {
|
||||
DCHECK(key);
|
||||
std::string key_base64_string;
|
||||
RCHECK(track_dict.GetString("key", &key_base64_string));
|
||||
VLOG(2) << "Key:" << key_base64_string;
|
||||
RCHECK(Base64StringToBytes(key_base64_string, key));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetKeyIdFromTrack(const base::DictionaryValue& track_dict,
|
||||
std::vector<uint8>* key_id) {
|
||||
DCHECK(key_id);
|
||||
std::string key_id_base64_string;
|
||||
RCHECK(track_dict.GetString("key_id", &key_id_base64_string));
|
||||
VLOG(2) << "Keyid:" << key_id_base64_string;
|
||||
RCHECK(Base64StringToBytes(key_id_base64_string, key_id));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetPsshData(const base::DictionaryValue& track_dict,
|
||||
bool GetPsshDataFromTrack(const base::DictionaryValue& track_dict,
|
||||
std::vector<uint8>* pssh_data) {
|
||||
DCHECK(pssh_data);
|
||||
|
||||
|
@ -105,7 +113,7 @@ bool GetPsshData(const base::DictionaryValue& track_dict,
|
|||
namespace media {
|
||||
|
||||
// A ref counted wrapper for EncryptionKeyMap.
|
||||
class WidevineEncryptionKeySource::RefCountedEncryptionKeyMap
|
||||
class WidevineKeySource::RefCountedEncryptionKeyMap
|
||||
: public base::RefCountedThreadSafe<RefCountedEncryptionKeyMap> {
|
||||
public:
|
||||
explicit RefCountedEncryptionKeyMap(EncryptionKeyMap* encryption_key_map) {
|
||||
|
@ -113,7 +121,7 @@ class WidevineEncryptionKeySource::RefCountedEncryptionKeyMap
|
|||
encryption_key_map_.swap(*encryption_key_map);
|
||||
}
|
||||
|
||||
std::map<EncryptionKeySource::TrackType, EncryptionKey*>& map() {
|
||||
std::map<KeySource::TrackType, EncryptionKey*>& map() {
|
||||
return encryption_key_map_;
|
||||
}
|
||||
|
||||
|
@ -127,15 +135,11 @@ class WidevineEncryptionKeySource::RefCountedEncryptionKeyMap
|
|||
DISALLOW_COPY_AND_ASSIGN(RefCountedEncryptionKeyMap);
|
||||
};
|
||||
|
||||
WidevineEncryptionKeySource::WidevineEncryptionKeySource(
|
||||
WidevineKeySource::WidevineKeySource(
|
||||
const std::string& server_url,
|
||||
const std::string& content_id,
|
||||
const std::string& policy,
|
||||
scoped_ptr<RequestSigner> signer)
|
||||
: http_fetcher_(new SimpleHttpFetcher(kHttpTimeoutInSeconds)),
|
||||
server_url_(server_url),
|
||||
content_id_(content_id),
|
||||
policy_(policy),
|
||||
signer_(signer.Pass()),
|
||||
crypto_period_count_(kDefaultCryptoPeriodCount),
|
||||
key_production_started_(false),
|
||||
|
@ -143,12 +147,12 @@ WidevineEncryptionKeySource::WidevineEncryptionKeySource(
|
|||
first_crypto_period_index_(0),
|
||||
key_production_thread_(
|
||||
"KeyProductionThread",
|
||||
base::Bind(&WidevineEncryptionKeySource::FetchKeysTask,
|
||||
base::Bind(&WidevineKeySource::FetchKeysTask,
|
||||
base::Unretained(this))) {
|
||||
DCHECK(signer_);
|
||||
}
|
||||
|
||||
WidevineEncryptionKeySource::~WidevineEncryptionKeySource() {
|
||||
WidevineKeySource::~WidevineKeySource() {
|
||||
if (key_pool_)
|
||||
key_pool_->Stop();
|
||||
if (key_production_thread_.HasBeenStarted()) {
|
||||
|
@ -159,16 +163,46 @@ WidevineEncryptionKeySource::~WidevineEncryptionKeySource() {
|
|||
}
|
||||
}
|
||||
|
||||
Status WidevineEncryptionKeySource::Initialize() {
|
||||
Status WidevineKeySource::FetchKeys(const std::vector<uint8>& content_id,
|
||||
const std::string& policy) {
|
||||
base::AutoLock scoped_lock(lock_);
|
||||
request_dict_.Clear();
|
||||
std::string content_id_base64_string;
|
||||
BytesToBase64String(content_id, &content_id_base64_string);
|
||||
request_dict_.SetString("content_id", content_id_base64_string);
|
||||
request_dict_.SetString("policy", policy);
|
||||
return FetchKeysCommon(false);
|
||||
}
|
||||
|
||||
Status WidevineKeySource::FetchKeys(
|
||||
const std::vector<uint8>& pssh_data) {
|
||||
base::AutoLock scoped_lock(lock_);
|
||||
request_dict_.Clear();
|
||||
std::string pssh_data_base64_string;
|
||||
BytesToBase64String(pssh_data, &pssh_data_base64_string);
|
||||
request_dict_.SetString("pssh_data", pssh_data_base64_string);
|
||||
return FetchKeysCommon(false);
|
||||
}
|
||||
|
||||
Status WidevineKeySource::FetchKeys(uint32 asset_id) {
|
||||
base::AutoLock scoped_lock(lock_);
|
||||
request_dict_.Clear();
|
||||
request_dict_.SetInteger("asset_id", asset_id);
|
||||
return FetchKeysCommon(true);
|
||||
}
|
||||
|
||||
Status WidevineKeySource::FetchKeysCommon(bool widevine_classic) {
|
||||
// TODO(tinskip): Make this method callable multiple times to fetch
|
||||
// different keys.
|
||||
DCHECK(!key_production_thread_.HasBeenStarted());
|
||||
key_production_thread_.Start();
|
||||
|
||||
// Perform a fetch request to find out if the key source is healthy.
|
||||
// It also stores the keys fetched for consumption later.
|
||||
return FetchKeys(!kEnableKeyRotation, 0);
|
||||
return FetchKeysInternal(!kEnableKeyRotation, 0, widevine_classic);
|
||||
}
|
||||
|
||||
Status WidevineEncryptionKeySource::GetKey(TrackType track_type,
|
||||
Status WidevineKeySource::GetKey(TrackType track_type,
|
||||
EncryptionKey* key) {
|
||||
DCHECK(key);
|
||||
if (encryption_key_map_.find(track_type) == encryption_key_map_.end()) {
|
||||
|
@ -179,7 +213,23 @@ Status WidevineEncryptionKeySource::GetKey(TrackType track_type,
|
|||
return Status::OK;
|
||||
}
|
||||
|
||||
Status WidevineEncryptionKeySource::GetCryptoPeriodKey(
|
||||
Status WidevineKeySource::GetKey(const std::vector<uint8>& key_id,
|
||||
EncryptionKey* key) {
|
||||
DCHECK(key);
|
||||
for (std::map<TrackType, EncryptionKey*>::iterator iter =
|
||||
encryption_key_map_.begin();
|
||||
iter != encryption_key_map_.end();
|
||||
++iter) {
|
||||
if (iter->second->key_id == key_id) {
|
||||
*key = *iter->second;
|
||||
return Status::OK;
|
||||
}
|
||||
}
|
||||
return Status(error::INTERNAL_ERROR,
|
||||
"Cannot find key with specified key ID");
|
||||
}
|
||||
|
||||
Status WidevineKeySource::GetCryptoPeriodKey(
|
||||
uint32 crypto_period_index,
|
||||
TrackType track_type,
|
||||
EncryptionKey* key) {
|
||||
|
@ -201,12 +251,12 @@ Status WidevineEncryptionKeySource::GetCryptoPeriodKey(
|
|||
return GetKeyInternal(crypto_period_index, track_type, key);
|
||||
}
|
||||
|
||||
void WidevineEncryptionKeySource::set_http_fetcher(
|
||||
void WidevineKeySource::set_http_fetcher(
|
||||
scoped_ptr<HttpFetcher> http_fetcher) {
|
||||
http_fetcher_ = http_fetcher.Pass();
|
||||
}
|
||||
|
||||
Status WidevineEncryptionKeySource::GetKeyInternal(
|
||||
Status WidevineKeySource::GetKeyInternal(
|
||||
uint32 crypto_period_index,
|
||||
TrackType track_type,
|
||||
EncryptionKey* key) {
|
||||
|
@ -236,25 +286,31 @@ Status WidevineEncryptionKeySource::GetKeyInternal(
|
|||
return Status::OK;
|
||||
}
|
||||
|
||||
void WidevineEncryptionKeySource::FetchKeysTask() {
|
||||
void WidevineKeySource::FetchKeysTask() {
|
||||
// Wait until key production is signaled.
|
||||
start_key_production_.Wait();
|
||||
if (!key_pool_ || key_pool_->Stopped())
|
||||
return;
|
||||
|
||||
Status status = FetchKeys(kEnableKeyRotation, first_crypto_period_index_);
|
||||
Status status = FetchKeysInternal(kEnableKeyRotation,
|
||||
first_crypto_period_index_,
|
||||
false);
|
||||
while (status.ok()) {
|
||||
first_crypto_period_index_ += crypto_period_count_;
|
||||
status = FetchKeys(kEnableKeyRotation, first_crypto_period_index_);
|
||||
status = FetchKeysInternal(kEnableKeyRotation,
|
||||
first_crypto_period_index_,
|
||||
false);
|
||||
}
|
||||
common_encryption_request_status_ = status;
|
||||
key_pool_->Stop();
|
||||
}
|
||||
|
||||
Status WidevineEncryptionKeySource::FetchKeys(
|
||||
bool enable_key_rotation, uint32 first_crypto_period_index) {
|
||||
Status WidevineKeySource::FetchKeysInternal(bool enable_key_rotation,
|
||||
uint32 first_crypto_period_index,
|
||||
bool widevine_classic) {
|
||||
std::string request;
|
||||
FillRequest(content_id_, enable_key_rotation, first_crypto_period_index,
|
||||
FillRequest(enable_key_rotation,
|
||||
first_crypto_period_index,
|
||||
&request);
|
||||
|
||||
std::string message;
|
||||
|
@ -280,7 +336,10 @@ Status WidevineEncryptionKeySource::FetchKeys(
|
|||
}
|
||||
|
||||
bool transient_error = false;
|
||||
if (ExtractEncryptionKey(enable_key_rotation, response, &transient_error))
|
||||
if (ExtractEncryptionKey(enable_key_rotation,
|
||||
widevine_classic,
|
||||
response,
|
||||
&transient_error))
|
||||
return Status::OK;
|
||||
|
||||
if (!transient_error) {
|
||||
|
@ -303,18 +362,11 @@ Status WidevineEncryptionKeySource::FetchKeys(
|
|||
"Failed to recover from server internal error.");
|
||||
}
|
||||
|
||||
void WidevineEncryptionKeySource::FillRequest(const std::string& content_id,
|
||||
bool enable_key_rotation,
|
||||
void WidevineKeySource::FillRequest(bool enable_key_rotation,
|
||||
uint32 first_crypto_period_index,
|
||||
std::string* request) {
|
||||
DCHECK(request);
|
||||
|
||||
std::string content_id_base64_string;
|
||||
base::Base64Encode(content_id, &content_id_base64_string);
|
||||
|
||||
base::DictionaryValue request_dict;
|
||||
request_dict.SetString("content_id", content_id_base64_string);
|
||||
request_dict.SetString("policy", policy_);
|
||||
DCHECK(!request_dict_.empty());
|
||||
|
||||
// Build tracks.
|
||||
base::ListValue* tracks = new base::ListValue();
|
||||
|
@ -329,24 +381,24 @@ void WidevineEncryptionKeySource::FillRequest(const std::string& content_id,
|
|||
track_audio->SetString("type", "AUDIO");
|
||||
tracks->Append(track_audio);
|
||||
|
||||
request_dict.Set("tracks", tracks);
|
||||
request_dict_.Set("tracks", tracks);
|
||||
|
||||
// Build DRM types.
|
||||
base::ListValue* drm_types = new base::ListValue();
|
||||
drm_types->AppendString("WIDEVINE");
|
||||
request_dict.Set("drm_types", drm_types);
|
||||
request_dict_.Set("drm_types", drm_types);
|
||||
|
||||
// Build key rotation fields.
|
||||
if (enable_key_rotation) {
|
||||
request_dict.SetInteger("first_crypto_period_index",
|
||||
request_dict_.SetInteger("first_crypto_period_index",
|
||||
first_crypto_period_index);
|
||||
request_dict.SetInteger("crypto_period_count", crypto_period_count_);
|
||||
request_dict_.SetInteger("crypto_period_count", crypto_period_count_);
|
||||
}
|
||||
|
||||
base::JSONWriter::Write(&request_dict, request);
|
||||
base::JSONWriter::Write(&request_dict_, request);
|
||||
}
|
||||
|
||||
Status WidevineEncryptionKeySource::SignRequest(const std::string& request,
|
||||
Status WidevineKeySource::SignRequest(const std::string& request,
|
||||
std::string* signed_request) {
|
||||
DCHECK(signed_request);
|
||||
|
||||
|
@ -371,7 +423,7 @@ Status WidevineEncryptionKeySource::SignRequest(const std::string& request,
|
|||
return Status::OK;
|
||||
}
|
||||
|
||||
bool WidevineEncryptionKeySource::DecodeResponse(
|
||||
bool WidevineKeySource::DecodeResponse(
|
||||
const std::string& raw_response,
|
||||
std::string* response) {
|
||||
DCHECK(response);
|
||||
|
@ -391,8 +443,9 @@ bool WidevineEncryptionKeySource::DecodeResponse(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WidevineEncryptionKeySource::ExtractEncryptionKey(
|
||||
bool WidevineKeySource::ExtractEncryptionKey(
|
||||
bool enable_key_rotation,
|
||||
bool widevine_classic,
|
||||
const std::string& response,
|
||||
bool* transient_error) {
|
||||
DCHECK(transient_error);
|
||||
|
@ -453,12 +506,20 @@ bool WidevineEncryptionKeySource::ExtractEncryptionKey(
|
|||
RCHECK(encryption_key_map.find(track_type) == encryption_key_map.end());
|
||||
|
||||
scoped_ptr<EncryptionKey> encryption_key(new EncryptionKey());
|
||||
|
||||
if (!GetKeyFromTrack(*track_dict, &encryption_key->key))
|
||||
return false;
|
||||
|
||||
// Get key ID and PSSH data for CENC content only.
|
||||
if (!widevine_classic) {
|
||||
if (!GetKeyIdFromTrack(*track_dict, &encryption_key->key_id))
|
||||
return false;
|
||||
|
||||
std::vector<uint8> pssh_data;
|
||||
if (!GetKeyAndKeyId(
|
||||
*track_dict, &encryption_key->key, &encryption_key->key_id) ||
|
||||
!GetPsshData(*track_dict, &pssh_data))
|
||||
if (!GetPsshDataFromTrack(*track_dict, &pssh_data))
|
||||
return false;
|
||||
encryption_key->pssh = PsshBoxFromPsshData(pssh_data);
|
||||
}
|
||||
encryption_key_map[track_type] = encryption_key.release();
|
||||
}
|
||||
|
||||
|
@ -470,7 +531,7 @@ bool WidevineEncryptionKeySource::ExtractEncryptionKey(
|
|||
return PushToKeyPool(&encryption_key_map);
|
||||
}
|
||||
|
||||
bool WidevineEncryptionKeySource::PushToKeyPool(
|
||||
bool WidevineKeySource::PushToKeyPool(
|
||||
EncryptionKeyMap* encryption_key_map) {
|
||||
DCHECK(key_pool_);
|
||||
DCHECK(encryption_key_map);
|
|
@ -4,44 +4,43 @@
|
|||
// license that can be found in the LICENSE file or at
|
||||
// https://developers.google.com/open-source/licenses/bsd
|
||||
|
||||
#ifndef MEDIA_BASE_WIDEVINE_ENCRYPTION_KEY_SOURCE_H_
|
||||
#define MEDIA_BASE_WIDEVINE_ENCRYPTION_KEY_SOURCE_H_
|
||||
#ifndef MEDIA_BASE_WIDEVINE_KEY_SOURCE_H_
|
||||
#define MEDIA_BASE_WIDEVINE_KEY_SOURCE_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "base/synchronization/waitable_event.h"
|
||||
#include "base/values.h"
|
||||
#include "media/base/closure_thread.h"
|
||||
#include "media/base/encryption_key_source.h"
|
||||
#include "media/base/key_source.h"
|
||||
|
||||
namespace media {
|
||||
class HttpFetcher;
|
||||
class RequestSigner;
|
||||
template <class T> class ProducerConsumerQueue;
|
||||
|
||||
/// WidevineEncryptionKeySource talks to the Widevine encryption service to
|
||||
/// WidevineKeySource talks to the Widevine encryption service to
|
||||
/// acquire the encryption keys.
|
||||
class WidevineEncryptionKeySource : public EncryptionKeySource {
|
||||
class WidevineKeySource : public KeySource {
|
||||
public:
|
||||
/// @param server_url is the Widevine common encryption server url.
|
||||
/// @param content_id the unique id identify the content to be encrypted.
|
||||
/// @param policy specifies the DRM content rights.
|
||||
/// @param signer signs the request message. It should not be NULL.
|
||||
WidevineEncryptionKeySource(const std::string& server_url,
|
||||
const std::string& content_id,
|
||||
const std::string& policy,
|
||||
WidevineKeySource(const std::string& server_url,
|
||||
scoped_ptr<RequestSigner> signer);
|
||||
virtual ~WidevineEncryptionKeySource();
|
||||
|
||||
/// Initialize the key source. Must be called before calling GetKey or
|
||||
/// GetCryptoPeriodKey.
|
||||
/// @return OK on success, an error status otherwise.
|
||||
Status Initialize();
|
||||
virtual ~WidevineKeySource();
|
||||
|
||||
/// @name EncryptionKeySource implementation overrides.
|
||||
/// @name KeySource implementation overrides.
|
||||
/// @{
|
||||
virtual Status FetchKeys(const std::vector<uint8>& content_id,
|
||||
const std::string& policy) OVERRIDE;
|
||||
virtual Status FetchKeys(const std::vector<uint8>& pssh_data) OVERRIDE;
|
||||
Status FetchKeys(uint32 asset_id);
|
||||
|
||||
virtual Status GetKey(TrackType track_type, EncryptionKey* key) OVERRIDE;
|
||||
virtual Status GetKey(const std::vector<uint8>& key_id,
|
||||
EncryptionKey* key) OVERRIDE;
|
||||
virtual Status GetCryptoPeriodKey(uint32 crypto_period_index,
|
||||
TrackType track_type,
|
||||
EncryptionKey* key) OVERRIDE;
|
||||
|
@ -62,16 +61,20 @@ class WidevineEncryptionKeySource : public EncryptionKeySource {
|
|||
TrackType track_type,
|
||||
EncryptionKey* key);
|
||||
|
||||
// Common implementation of FetchKeys methods above.
|
||||
Status FetchKeysCommon(bool widevine_classic);
|
||||
|
||||
// The closure task to fetch keys repeatedly.
|
||||
void FetchKeysTask();
|
||||
|
||||
// Fetch keys from server.
|
||||
Status FetchKeys(bool enable_key_rotation, uint32 first_crypto_period_index);
|
||||
Status FetchKeysInternal(bool enable_key_rotation,
|
||||
uint32 first_crypto_period_index,
|
||||
bool widevine_classic);
|
||||
|
||||
// Fill |request| with necessary fields for Widevine encryption request.
|
||||
// |request| should not be NULL.
|
||||
void FillRequest(const std::string& content_id,
|
||||
bool enable_key_rotation,
|
||||
void FillRequest(bool enable_key_rotation,
|
||||
uint32 first_crypto_period_index,
|
||||
std::string* request);
|
||||
// Sign and properly format |request|.
|
||||
|
@ -85,7 +88,9 @@ class WidevineEncryptionKeySource : public EncryptionKeySource {
|
|||
// failure is because of a transient error from the server. |transient_error|
|
||||
// should not be NULL.
|
||||
bool ExtractEncryptionKey(bool enable_key_rotation,
|
||||
const std::string& response, bool* transient_error);
|
||||
bool widevine_classic,
|
||||
const std::string& response,
|
||||
bool* transient_error);
|
||||
// Push the keys to the key pool.
|
||||
bool PushToKeyPool(EncryptionKeyMap* encryption_key_map);
|
||||
|
||||
|
@ -94,9 +99,8 @@ class WidevineEncryptionKeySource : public EncryptionKeySource {
|
|||
// Can be overridden using set_http_fetcher for testing or other purposes.
|
||||
scoped_ptr<HttpFetcher> http_fetcher_;
|
||||
std::string server_url_;
|
||||
std::string content_id_;
|
||||
std::string policy_;
|
||||
scoped_ptr<RequestSigner> signer_;
|
||||
base::DictionaryValue request_dict_;
|
||||
|
||||
const uint32 crypto_period_count_;
|
||||
base::Lock lock_;
|
||||
|
@ -108,9 +112,9 @@ class WidevineEncryptionKeySource : public EncryptionKeySource {
|
|||
EncryptionKeyMap encryption_key_map_; // For non key rotation request.
|
||||
Status common_encryption_request_status_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(WidevineEncryptionKeySource);
|
||||
DISALLOW_COPY_AND_ASSIGN(WidevineKeySource);
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
|
||||
#endif // MEDIA_BASE_WIDEVINE_ENCRYPTION_KEY_SOURCE_H_
|
||||
#endif // MEDIA_BASE_WIDEVINE_KEY_SOURCE_H_
|
|
@ -13,7 +13,7 @@
|
|||
#include "media/base/http_fetcher.h"
|
||||
#include "media/base/request_signer.h"
|
||||
#include "media/base/status_test_util.h"
|
||||
#include "media/base/widevine_encryption_key_source.h"
|
||||
#include "media/base/widevine_key_source.h"
|
||||
|
||||
namespace {
|
||||
const char kServerUrl[] = "http://www.foo.com/getcontentkey";
|
||||
|
@ -25,9 +25,9 @@ const char kMockSignature[] = "MockSignature";
|
|||
|
||||
// The license service may return an error indicating a transient error has
|
||||
// just happened in the server, or other types of errors.
|
||||
// WidevineEncryptionKeySource will perform a number of retries on transient
|
||||
// WidevineKeySource will perform a number of retries on transient
|
||||
// errors;
|
||||
// WidevineEncryptionKeySource does not know about other errors and retries are
|
||||
// WidevineKeySource does not know about other errors and retries are
|
||||
// not performed.
|
||||
const char kLicenseStatusTransientError[] = "INTERNAL_ERROR";
|
||||
const char kLicenseStatusUnknownError[] = "UNKNOWN_ERROR";
|
||||
|
@ -40,8 +40,11 @@ const char kExpectedSignedMessageFormat[] =
|
|||
const char kTrackFormat[] =
|
||||
"{\"type\":\"%s\",\"key_id\":\"%s\",\"key\":"
|
||||
"\"%s\",\"pssh\":[{\"drm_type\":\"WIDEVINE\",\"data\":\"%s\"}]}";
|
||||
const char kClassicTrackFormat[] = "{\"type\":\"%s\",\"key\":\"%s\"}";
|
||||
const char kLicenseResponseFormat[] = "{\"status\":\"%s\",\"tracks\":[%s]}";
|
||||
const char kHttpResponseFormat[] = "{\"response\":\"%s\"}";
|
||||
const char kRequestPsshData[] = "PSSH data";
|
||||
const uint32 kClassicAssetId = 1234;
|
||||
|
||||
std::string Base64Encode(const std::string& input) {
|
||||
std::string output;
|
||||
|
@ -81,6 +84,20 @@ std::string GenerateMockLicenseResponse() {
|
|||
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
||||
}
|
||||
|
||||
std::string GenerateMockClassicLicenseResponse() {
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
|
||||
std::string tracks;
|
||||
for (size_t i = 0; i < 3; ++i) {
|
||||
if (!tracks.empty())
|
||||
tracks += ",";
|
||||
tracks += base::StringPrintf(
|
||||
kClassicTrackFormat,
|
||||
kTrackTypes[i].c_str(),
|
||||
Base64Encode(GetMockKey(kTrackTypes[i])).c_str());
|
||||
}
|
||||
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str());
|
||||
}
|
||||
|
||||
std::string GetPsshDataFromPsshBox(const std::string& pssh_box) {
|
||||
const size_t kPsshDataOffset = 32u;
|
||||
DCHECK_LT(kPsshDataOffset, pssh_box.size());
|
||||
|
@ -125,68 +142,75 @@ class MockHttpFetcher : public HttpFetcher {
|
|||
DISALLOW_COPY_AND_ASSIGN(MockHttpFetcher);
|
||||
};
|
||||
|
||||
class WidevineEncryptionKeySourceTest : public ::testing::Test {
|
||||
class WidevineKeySourceTest : public ::testing::Test {
|
||||
public:
|
||||
WidevineEncryptionKeySourceTest()
|
||||
WidevineKeySourceTest()
|
||||
: mock_request_signer_(new MockRequestSigner(kSignerName)),
|
||||
mock_http_fetcher_(new MockHttpFetcher()) {}
|
||||
|
||||
void SetUp() OVERRIDE {
|
||||
content_id_.assign(reinterpret_cast<const uint8*>(kContentId),
|
||||
reinterpret_cast<const uint8*>(kContentId) +
|
||||
strlen(kContentId));
|
||||
}
|
||||
|
||||
protected:
|
||||
void CreateWidevineEncryptionKeySource() {
|
||||
widevine_encryption_key_source_.reset(new WidevineEncryptionKeySource(
|
||||
void CreateWidevineKeySource() {
|
||||
widevine_key_source_.reset(new WidevineKeySource(
|
||||
kServerUrl,
|
||||
kContentId,
|
||||
kPolicy,
|
||||
mock_request_signer_.PassAs<RequestSigner>()));
|
||||
widevine_encryption_key_source_->set_http_fetcher(
|
||||
widevine_key_source_->set_http_fetcher(
|
||||
mock_http_fetcher_.PassAs<HttpFetcher>());
|
||||
}
|
||||
|
||||
void VerifyKeys() {
|
||||
void VerifyKeys(bool classic) {
|
||||
EncryptionKey encryption_key;
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
|
||||
for (size_t i = 0; i < arraysize(kTrackTypes); ++i) {
|
||||
ASSERT_OK(widevine_encryption_key_source_->GetKey(
|
||||
EncryptionKeySource::GetTrackTypeFromString(kTrackTypes[i]),
|
||||
ASSERT_OK(widevine_key_source_->GetKey(
|
||||
KeySource::GetTrackTypeFromString(kTrackTypes[i]),
|
||||
&encryption_key));
|
||||
EXPECT_EQ(GetMockKeyId(kTrackTypes[i]), ToString(encryption_key.key_id));
|
||||
EXPECT_EQ(GetMockKey(kTrackTypes[i]), ToString(encryption_key.key));
|
||||
if (!classic) {
|
||||
EXPECT_EQ(GetMockKeyId(kTrackTypes[i]),
|
||||
ToString(encryption_key.key_id));
|
||||
EXPECT_EQ(GetMockPsshData(kTrackTypes[i]),
|
||||
GetPsshDataFromPsshBox(ToString(encryption_key.pssh)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
scoped_ptr<MockRequestSigner> mock_request_signer_;
|
||||
scoped_ptr<MockHttpFetcher> mock_http_fetcher_;
|
||||
scoped_ptr<WidevineEncryptionKeySource> widevine_encryption_key_source_;
|
||||
scoped_ptr<WidevineKeySource> widevine_key_source_;
|
||||
std::vector<uint8> content_id_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(WidevineEncryptionKeySourceTest);
|
||||
DISALLOW_COPY_AND_ASSIGN(WidevineKeySourceTest);
|
||||
};
|
||||
|
||||
TEST_F(WidevineEncryptionKeySourceTest, GetTrackTypeFromString) {
|
||||
EXPECT_EQ(EncryptionKeySource::TRACK_TYPE_SD,
|
||||
EncryptionKeySource::GetTrackTypeFromString("SD"));
|
||||
EXPECT_EQ(EncryptionKeySource::TRACK_TYPE_HD,
|
||||
EncryptionKeySource::GetTrackTypeFromString("HD"));
|
||||
EXPECT_EQ(EncryptionKeySource::TRACK_TYPE_AUDIO,
|
||||
EncryptionKeySource::GetTrackTypeFromString("AUDIO"));
|
||||
EXPECT_EQ(EncryptionKeySource::TRACK_TYPE_UNKNOWN,
|
||||
EncryptionKeySource::GetTrackTypeFromString("FOO"));
|
||||
TEST_F(WidevineKeySourceTest, GetTrackTypeFromString) {
|
||||
EXPECT_EQ(KeySource::TRACK_TYPE_SD,
|
||||
KeySource::GetTrackTypeFromString("SD"));
|
||||
EXPECT_EQ(KeySource::TRACK_TYPE_HD,
|
||||
KeySource::GetTrackTypeFromString("HD"));
|
||||
EXPECT_EQ(KeySource::TRACK_TYPE_AUDIO,
|
||||
KeySource::GetTrackTypeFromString("AUDIO"));
|
||||
EXPECT_EQ(KeySource::TRACK_TYPE_UNKNOWN,
|
||||
KeySource::GetTrackTypeFromString("FOO"));
|
||||
}
|
||||
|
||||
TEST_F(WidevineEncryptionKeySourceTest, GenerateSignatureFailure) {
|
||||
TEST_F(WidevineKeySourceTest, GenerateSignatureFailure) {
|
||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||
.WillOnce(Return(false));
|
||||
|
||||
CreateWidevineEncryptionKeySource();
|
||||
CreateWidevineKeySource();
|
||||
ASSERT_EQ(Status(error::INTERNAL_ERROR, "Signature generation failed."),
|
||||
widevine_encryption_key_source_->Initialize());
|
||||
widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
||||
}
|
||||
|
||||
// Check whether expected request message and post data was generated and
|
||||
// verify the correct behavior on http failure.
|
||||
TEST_F(WidevineEncryptionKeySourceTest, HttpPostFailure) {
|
||||
TEST_F(WidevineKeySourceTest, HttpPostFailure) {
|
||||
std::string expected_message = base::StringPrintf(
|
||||
kExpectedRequestMessageFormat, Base64Encode(kContentId).c_str(), kPolicy);
|
||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(expected_message, _))
|
||||
|
@ -201,12 +225,12 @@ TEST_F(WidevineEncryptionKeySourceTest, HttpPostFailure) {
|
|||
EXPECT_CALL(*mock_http_fetcher_, Post(kServerUrl, expected_post_data, _))
|
||||
.WillOnce(Return(kMockStatus));
|
||||
|
||||
CreateWidevineEncryptionKeySource();
|
||||
CreateWidevineKeySource();
|
||||
ASSERT_EQ(kMockStatus,
|
||||
widevine_encryption_key_source_->Initialize());
|
||||
widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
||||
}
|
||||
|
||||
TEST_F(WidevineEncryptionKeySourceTest, LicenseStatusOK) {
|
||||
TEST_F(WidevineKeySourceTest, LicenseStatusCencOK) {
|
||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
|
@ -216,12 +240,63 @@ TEST_F(WidevineEncryptionKeySourceTest, LicenseStatusOK) {
|
|||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||
|
||||
CreateWidevineEncryptionKeySource();
|
||||
ASSERT_OK(widevine_encryption_key_source_->Initialize());
|
||||
VerifyKeys();
|
||||
CreateWidevineKeySource();
|
||||
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
||||
VerifyKeys(false);
|
||||
}
|
||||
|
||||
TEST_F(WidevineEncryptionKeySourceTest, RetryOnHttpTimeout) {
|
||||
TEST_F(WidevineKeySourceTest, LicenseStatusCencNotOK) {
|
||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
std::string mock_response = base::StringPrintf(
|
||||
kHttpResponseFormat, Base64Encode(
|
||||
GenerateMockClassicLicenseResponse()).c_str());
|
||||
|
||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||
|
||||
CreateWidevineKeySource();
|
||||
ASSERT_EQ(error::SERVER_ERROR,
|
||||
widevine_key_source_->FetchKeys(content_id_, kPolicy)
|
||||
.error_code());
|
||||
}
|
||||
|
||||
TEST_F(WidevineKeySourceTest, LicenseStatusCencWithPsshDataOK) {
|
||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
std::string mock_response = base::StringPrintf(
|
||||
kHttpResponseFormat, Base64Encode(GenerateMockLicenseResponse()).c_str());
|
||||
|
||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||
|
||||
CreateWidevineKeySource();
|
||||
std::vector<uint8> pssh_data(
|
||||
reinterpret_cast<const uint8*>(kRequestPsshData),
|
||||
reinterpret_cast<const uint8*>(kRequestPsshData) + strlen(kContentId));
|
||||
ASSERT_OK(widevine_key_source_->FetchKeys(pssh_data));
|
||||
VerifyKeys(false);
|
||||
}
|
||||
|
||||
TEST_F(WidevineKeySourceTest, LicenseStatusClassicOK) {
|
||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
std::string mock_response = base::StringPrintf(
|
||||
kHttpResponseFormat, Base64Encode(
|
||||
GenerateMockClassicLicenseResponse()).c_str());
|
||||
|
||||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||
|
||||
CreateWidevineKeySource();
|
||||
ASSERT_OK(widevine_key_source_->FetchKeys(kClassicAssetId));
|
||||
VerifyKeys(true);
|
||||
}
|
||||
|
||||
TEST_F(WidevineKeySourceTest, RetryOnHttpTimeout) {
|
||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
|
@ -233,12 +308,12 @@ TEST_F(WidevineEncryptionKeySourceTest, RetryOnHttpTimeout) {
|
|||
.WillOnce(Return(Status(error::TIME_OUT, "")))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||
|
||||
CreateWidevineEncryptionKeySource();
|
||||
ASSERT_OK(widevine_encryption_key_source_->Initialize());
|
||||
VerifyKeys();
|
||||
CreateWidevineKeySource();
|
||||
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
||||
VerifyKeys(false);
|
||||
}
|
||||
|
||||
TEST_F(WidevineEncryptionKeySourceTest, RetryOnTransientError) {
|
||||
TEST_F(WidevineKeySourceTest, RetryOnTransientError) {
|
||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
|
@ -256,12 +331,12 @@ TEST_F(WidevineEncryptionKeySourceTest, RetryOnTransientError) {
|
|||
.WillOnce(DoAll(SetArgPointee<2>(expected_retried_response),
|
||||
Return(Status::OK)));
|
||||
|
||||
CreateWidevineEncryptionKeySource();
|
||||
ASSERT_OK(widevine_encryption_key_source_->Initialize());
|
||||
VerifyKeys();
|
||||
CreateWidevineKeySource();
|
||||
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
||||
VerifyKeys(false);
|
||||
}
|
||||
|
||||
TEST_F(WidevineEncryptionKeySourceTest, NoRetryOnUnknownError) {
|
||||
TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) {
|
||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||
.WillOnce(Return(true));
|
||||
|
||||
|
@ -273,9 +348,9 @@ TEST_F(WidevineEncryptionKeySourceTest, NoRetryOnUnknownError) {
|
|||
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||
|
||||
CreateWidevineEncryptionKeySource();
|
||||
CreateWidevineKeySource();
|
||||
ASSERT_EQ(error::SERVER_ERROR,
|
||||
widevine_encryption_key_source_->Initialize().error_code());
|
||||
widevine_key_source_->FetchKeys(content_id_, kPolicy).error_code());
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -316,7 +391,7 @@ std::string GenerateMockKeyRotationLicenseResponse(
|
|||
|
||||
} // namespace
|
||||
|
||||
TEST_F(WidevineEncryptionKeySourceTest, KeyRotationTest) {
|
||||
TEST_F(WidevineKeySourceTest, KeyRotationTest) {
|
||||
const uint32 kFirstCryptoPeriodIndex = 8;
|
||||
const uint32 kCryptoPeriodCount = 10;
|
||||
// Array of indexes to be checked.
|
||||
|
@ -328,7 +403,7 @@ TEST_F(WidevineEncryptionKeySourceTest, KeyRotationTest) {
|
|||
// Generate expectations in sequence.
|
||||
InSequence dummy;
|
||||
|
||||
// Expecting a non-key rotation enabled request on Initialize().
|
||||
// Expecting a non-key rotation enabled request on FetchKeys().
|
||||
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
|
||||
.WillOnce(Return(true));
|
||||
std::string mock_response = base::StringPrintf(
|
||||
|
@ -357,16 +432,16 @@ TEST_F(WidevineEncryptionKeySourceTest, KeyRotationTest) {
|
|||
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
|
||||
}
|
||||
|
||||
CreateWidevineEncryptionKeySource();
|
||||
ASSERT_OK(widevine_encryption_key_source_->Initialize());
|
||||
CreateWidevineKeySource();
|
||||
ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
|
||||
|
||||
EncryptionKey encryption_key;
|
||||
for (size_t i = 0; i < arraysize(kCryptoPeriodIndexes); ++i) {
|
||||
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
|
||||
for (size_t j = 0; j < 3; ++j) {
|
||||
ASSERT_OK(widevine_encryption_key_source_->GetCryptoPeriodKey(
|
||||
ASSERT_OK(widevine_key_source_->GetCryptoPeriodKey(
|
||||
kCryptoPeriodIndexes[i],
|
||||
EncryptionKeySource::GetTrackTypeFromString(kTrackTypes[j]),
|
||||
KeySource::GetTrackTypeFromString(kTrackTypes[j]),
|
||||
&encryption_key));
|
||||
EXPECT_EQ(GetMockKey(kTrackTypes[j], kCryptoPeriodIndexes[i]),
|
||||
ToString(encryption_key.key));
|
||||
|
@ -374,9 +449,9 @@ TEST_F(WidevineEncryptionKeySourceTest, KeyRotationTest) {
|
|||
}
|
||||
|
||||
// The old crypto period indexes should have been garbage collected.
|
||||
Status status = widevine_encryption_key_source_->GetCryptoPeriodKey(
|
||||
Status status = widevine_key_source_->GetCryptoPeriodKey(
|
||||
kFirstCryptoPeriodIndex,
|
||||
EncryptionKeySource::TRACK_TYPE_SD,
|
||||
KeySource::TRACK_TYPE_SD,
|
||||
&encryption_key);
|
||||
EXPECT_EQ(error::INVALID_ARGUMENT, status.error_code());
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include "media/base/aes_encryptor.h"
|
||||
#include "media/base/buffer_reader.h"
|
||||
#include "media/base/encryption_key_source.h"
|
||||
#include "media/base/key_source.h"
|
||||
#include "media/base/media_sample.h"
|
||||
#include "media/formats/mp4/box_definitions.h"
|
||||
#include "media/formats/mp4/cenc.h"
|
||||
|
|
|
@ -15,8 +15,8 @@ namespace mp4 {
|
|||
KeyRotationFragmenter::KeyRotationFragmenter(
|
||||
MovieFragment* moof,
|
||||
TrackFragment* traf,
|
||||
EncryptionKeySource* encryption_key_source,
|
||||
EncryptionKeySource::TrackType track_type,
|
||||
KeySource* encryption_key_source,
|
||||
KeySource::TrackType track_type,
|
||||
int64 crypto_period_duration,
|
||||
int64 clear_time,
|
||||
uint8 nalu_length_size)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
#ifndef MEDIA_FORMATS_MP4_KEY_ROTATION_FRAGMENTER_H_
|
||||
#define MEDIA_FORMATS_MP4_KEY_ROTATION_FRAGMENTER_H_
|
||||
|
||||
#include "media/base/encryption_key_source.h"
|
||||
#include "media/base/key_source.h"
|
||||
#include "media/formats/mp4/encrypting_fragmenter.h"
|
||||
|
||||
namespace media {
|
||||
|
@ -33,8 +33,8 @@ class KeyRotationFragmenter : public EncryptingFragmenter {
|
|||
/// encryption.
|
||||
KeyRotationFragmenter(MovieFragment* moof,
|
||||
TrackFragment* traf,
|
||||
EncryptionKeySource* encryption_key_source,
|
||||
EncryptionKeySource::TrackType track_type,
|
||||
KeySource* encryption_key_source,
|
||||
KeySource::TrackType track_type,
|
||||
int64 crypto_period_duration,
|
||||
int64 clear_time,
|
||||
uint8 nalu_length_size);
|
||||
|
@ -50,8 +50,8 @@ class KeyRotationFragmenter : public EncryptingFragmenter {
|
|||
private:
|
||||
MovieFragment* moof_;
|
||||
|
||||
EncryptionKeySource* encryption_key_source_;
|
||||
EncryptionKeySource::TrackType track_type_;
|
||||
KeySource* encryption_key_source_;
|
||||
KeySource::TrackType track_type_;
|
||||
const int64 crypto_period_duration_;
|
||||
size_t prev_crypto_period_index_;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "base/time/time.h"
|
||||
#include "media/base/aes_encryptor.h"
|
||||
#include "media/base/audio_stream_info.h"
|
||||
#include "media/base/encryption_key_source.h"
|
||||
#include "media/base/key_source.h"
|
||||
#include "media/base/media_sample.h"
|
||||
#include "media/base/media_stream.h"
|
||||
#include "media/base/video_stream_info.h"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#include "base/stl_util.h"
|
||||
#include "media/base/buffer_writer.h"
|
||||
#include "media/base/encryption_key_source.h"
|
||||
#include "media/base/key_source.h"
|
||||
#include "media/base/media_sample.h"
|
||||
#include "media/base/media_stream.h"
|
||||
#include "media/base/muxer_options.h"
|
||||
|
@ -94,17 +94,17 @@ uint8 GetNaluLengthSize(const StreamInfo& stream_info) {
|
|||
return video_stream_info.nalu_length_size();
|
||||
}
|
||||
|
||||
EncryptionKeySource::TrackType GetTrackTypeForEncryption(
|
||||
KeySource::TrackType GetTrackTypeForEncryption(
|
||||
const StreamInfo& stream_info, uint32 max_sd_pixels) {
|
||||
if (stream_info.stream_type() == kStreamAudio)
|
||||
return EncryptionKeySource::TRACK_TYPE_AUDIO;
|
||||
return KeySource::TRACK_TYPE_AUDIO;
|
||||
|
||||
DCHECK_EQ(kStreamVideo, stream_info.stream_type());
|
||||
const VideoStreamInfo& video_stream_info =
|
||||
static_cast<const VideoStreamInfo&>(stream_info);
|
||||
uint32 pixels = video_stream_info.width() * video_stream_info.height();
|
||||
return (pixels > max_sd_pixels) ? EncryptionKeySource::TRACK_TYPE_HD
|
||||
: EncryptionKeySource::TRACK_TYPE_SD;
|
||||
return (pixels > max_sd_pixels) ? KeySource::TRACK_TYPE_HD
|
||||
: KeySource::TRACK_TYPE_SD;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -126,7 +126,7 @@ Segmenter::~Segmenter() { STLDeleteElements(&fragmenters_); }
|
|||
|
||||
Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
||||
event::MuxerListener* muxer_listener,
|
||||
EncryptionKeySource* encryption_key_source,
|
||||
KeySource* encryption_key_source,
|
||||
uint32 max_sd_pixels,
|
||||
double clear_lead_in_seconds,
|
||||
double crypto_period_duration_in_seconds) {
|
||||
|
@ -151,7 +151,7 @@ Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
|
|||
}
|
||||
|
||||
uint8 nalu_length_size = GetNaluLengthSize(*streams[i]->info());
|
||||
EncryptionKeySource::TrackType track_type =
|
||||
KeySource::TrackType track_type =
|
||||
GetTrackTypeForEncryption(*streams[i]->info(), max_sd_pixels);
|
||||
SampleDescription& description =
|
||||
moov_->tracks[i].media.information.sample_table.description;
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace media {
|
|||
struct MuxerOptions;
|
||||
|
||||
class BufferWriter;
|
||||
class EncryptionKeySource;
|
||||
class KeySource;
|
||||
class MediaSample;
|
||||
class MediaStream;
|
||||
|
||||
|
@ -64,7 +64,7 @@ class Segmenter {
|
|||
/// @return OK on success, an error status otherwise.
|
||||
Status Initialize(const std::vector<MediaStream*>& streams,
|
||||
event::MuxerListener* muxer_listener,
|
||||
EncryptionKeySource* encryption_key_source,
|
||||
KeySource* encryption_key_source,
|
||||
uint32 max_sd_pixels,
|
||||
double clear_lead_in_seconds,
|
||||
double crypto_period_duration_in_seconds);
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include "base/strings/stringprintf.h"
|
||||
#include "base/time/clock.h"
|
||||
#include "media/base/demuxer.h"
|
||||
#include "media/base/encryption_key_source.h"
|
||||
#include "media/base/key_source.h"
|
||||
#include "media/base/media_stream.h"
|
||||
#include "media/base/muxer.h"
|
||||
#include "media/base/status_test_util.h"
|
||||
|
@ -151,8 +151,8 @@ void PackagerTestBasic::Remux(const std::string& input,
|
|||
Demuxer demuxer(GetFullPath(input), decryptor_source_);
|
||||
ASSERT_OK(demuxer.Initialize());
|
||||
|
||||
scoped_ptr<EncryptionKeySource> encryption_key_source(
|
||||
EncryptionKeySource::CreateFromHexStrings(
|
||||
scoped_ptr<KeySource> encryption_key_source(
|
||||
KeySource::CreateFromHexStrings(
|
||||
kKeyIdHex, kKeyHex, kPsshHex, ""));
|
||||
DCHECK(encryption_key_source);
|
||||
|
||||
|
@ -165,8 +165,8 @@ void PackagerTestBasic::Remux(const std::string& input,
|
|||
muxer_video->AddStream(FindFirstVideoStream(demuxer.streams()));
|
||||
|
||||
if (enable_encryption) {
|
||||
muxer_video->SetEncryptionKeySource(encryption_key_source.get(),
|
||||
EncryptionKeySource::TRACK_TYPE_SD,
|
||||
muxer_video->SetKeySource(encryption_key_source.get(),
|
||||
KeySource::TRACK_TYPE_SD,
|
||||
kClearLeadInSeconds,
|
||||
kCryptoDurationInSeconds);
|
||||
}
|
||||
|
@ -181,8 +181,8 @@ void PackagerTestBasic::Remux(const std::string& input,
|
|||
muxer_audio->AddStream(FindFirstAudioStream(demuxer.streams()));
|
||||
|
||||
if (enable_encryption) {
|
||||
muxer_audio->SetEncryptionKeySource(encryption_key_source.get(),
|
||||
EncryptionKeySource::TRACK_TYPE_SD,
|
||||
muxer_audio->SetKeySource(encryption_key_source.get(),
|
||||
KeySource::TRACK_TYPE_SD,
|
||||
kClearLeadInSeconds,
|
||||
kCryptoDurationInSeconds);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue