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:
Thomas Inskip 2014-08-20 16:51:15 -07:00
parent 38c3569011
commit 65e558b19c
21 changed files with 526 additions and 276 deletions

View File

@ -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. 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. 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; muxer_options.bandwidth = 0;
``` ```
##Creating EncryptionKeySource## ##Creating KeySource##
```C++ ```C++
// An EncryptionKeySource is optional. The stream wont be encrypted if an // A KeySource is optional. The stream wont be encrypted if an
// EncryptionKeySource is not provided. // KeySource is not provided.
``` ```
###WidevineEncryptionKeySource### ###WidevineKeySource###
```C++ ```C++
// Users may use WidevineEncryptionKeySource to fetch keys from Widevine // Users may use WidevineKeySource to fetch keys from Widevine
// common encryption server. // common encryption server.
// A request signer is required to sign the common encryption request. // 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)); RsaRequestSigner::CreateSigner(signer, pkcs1_rsa_private_key));
if (!signer) { … } if (!signer) { … }
scoped_ptr<WidevineEncryptionKeySource> widevine_encryption_key_source( scoped_ptr<WidevineKeySource> widevine_encryption_key_source(
new WidevineEncryptionKeySource( new WidevineKeySource(key_server_url, signer.Pass()));
key_server_url, content_id, track_type, policy, signer.Pass()));
// Intialize widevine encryption key source. // Grab keys for the content.
status = widevine_encryption_key_source->Initialize(); status = widevine_encryption_key_source->FetchKeys(content_id, policy));
if (!status.ok()) { … } if (!status.ok()) { … }
// Set encryption key source to muxer. // Set encryption key source to muxer.
@ -236,7 +235,7 @@ if (!status.ok()) { … }
// |clear_lead| specifies clear lead duration in seconds. // |clear_lead| specifies clear lead duration in seconds.
// |crypto_period_duration| if not zero, enable key rotation with specified // |crypto_period_duration| if not zero, enable key rotation with specified
// crypto period. // crypto period.
muxer->SetEncryptionKeySource( muxer->SetKeySource(
widevine_encryption_key_source.get(), max_sd_pixels, widevine_encryption_key_source.get(), max_sd_pixels,
clear_lead, crypto_period_duration); clear_lead, crypto_period_duration);
``` ```

View File

@ -19,7 +19,7 @@
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/threading/simple_thread.h" #include "base/threading/simple_thread.h"
#include "media/base/demuxer.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_options.h"
#include "media/base/muxer_util.h" #include "media/base/muxer_util.h"
#include "media/event/mpd_notify_muxer_listener.h" #include "media/event/mpd_notify_muxer_listener.h"
@ -96,7 +96,7 @@ class RemuxJob : public base::SimpleThread {
bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors, bool CreateRemuxJobs(const StreamDescriptorList& stream_descriptors,
const MuxerOptions& muxer_options, const MuxerOptions& muxer_options,
EncryptionKeySource* key_source, KeySource* key_source,
MpdNotifier* mpd_notifier, MpdNotifier* mpd_notifier,
std::vector<MuxerListener*>* muxer_listeners, std::vector<MuxerListener*>* muxer_listeners,
std::vector<RemuxJob*>* remux_jobs) { 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)); scoped_ptr<Muxer> muxer(new mp4::MP4Muxer(stream_muxer_options));
if (key_source) { if (key_source) {
muxer->SetEncryptionKeySource(key_source, muxer->SetKeySource(key_source,
FLAGS_max_sd_pixels, FLAGS_max_sd_pixels,
FLAGS_clear_lead, FLAGS_clear_lead,
FLAGS_crypto_period_duration); FLAGS_crypto_period_duration);
@ -239,7 +239,7 @@ bool RunPackager(const StreamDescriptorList& stream_descriptors) {
return false; return false;
// Create encryption key source if needed. // 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) { if (FLAGS_enable_widevine_encryption || FLAGS_enable_fixed_key_encryption) {
encryption_key_source = CreateEncryptionKeySource(); encryption_key_source = CreateEncryptionKeySource();
if (!encryption_key_source) if (!encryption_key_source)

View File

@ -18,7 +18,7 @@
#include "media/base/muxer_options.h" #include "media/base/muxer_options.h"
#include "media/base/request_signer.h" #include "media/base/request_signer.h"
#include "media/base/stream_info.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 "media/file/file.h"
#include "mpd/base/mpd_builder.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()); printf("Stream [%zu] %s\n", i, streams[i]->info()->ToString().c_str());
} }
// Create and initialize encryptor source. scoped_ptr<RequestSigner> CreateSigner() {
scoped_ptr<EncryptionKeySource> CreateEncryptionKeySource() {
scoped_ptr<EncryptionKeySource> encryption_key_source;
if (FLAGS_enable_widevine_encryption) {
scoped_ptr<RequestSigner> signer; scoped_ptr<RequestSigner> signer;
DCHECK(!FLAGS_aes_signing_key.empty() || if (FLAGS_enable_widevine_encryption || FLAGS_enable_widevine_decryption) {
!FLAGS_rsa_signing_key_path.empty());
if (!FLAGS_aes_signing_key.empty()) { if (!FLAGS_aes_signing_key.empty()) {
signer.reset( signer.reset(
AesRequestSigner::CreateSigner(FLAGS_signer, FLAGS_aes_signing_key, 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 '" LOG(ERROR) << "Cannot create an AES signer object from '"
<< FLAGS_aes_signing_key << "':'" << FLAGS_aes_signing_iv << FLAGS_aes_signing_key << "':'" << FLAGS_aes_signing_iv
<< "'."; << "'.";
return scoped_ptr<EncryptionKeySource>(); return scoped_ptr<RequestSigner>();
} }
} else if (!FLAGS_rsa_signing_key_path.empty()) { } else if (!FLAGS_rsa_signing_key_path.empty()) {
std::string rsa_private_key; std::string rsa_private_key;
@ -57,38 +53,57 @@ scoped_ptr<EncryptionKeySource> CreateEncryptionKeySource() {
&rsa_private_key)) { &rsa_private_key)) {
LOG(ERROR) << "Failed to read from '" << FLAGS_rsa_signing_key_path LOG(ERROR) << "Failed to read from '" << FLAGS_rsa_signing_key_path
<< "'."; << "'.";
return scoped_ptr<EncryptionKeySource>(); return scoped_ptr<RequestSigner>();
} }
signer.reset( signer.reset(
RsaRequestSigner::CreateSigner(FLAGS_signer, rsa_private_key)); RsaRequestSigner::CreateSigner(FLAGS_signer, rsa_private_key));
if (!signer) { if (!signer) {
LOG(ERROR) << "Cannot create a RSA signer object from '" LOG(ERROR) << "Cannot create a RSA signer object from '"
<< FLAGS_rsa_signing_key_path << "'."; << FLAGS_rsa_signing_key_path << "'.";
return scoped_ptr<EncryptionKeySource>(); return scoped_ptr<RequestSigner>();
} }
} }
}
return signer.Pass();
}
scoped_ptr<WidevineEncryptionKeySource> widevine_encryption_key_source( scoped_ptr<KeySource> CreateEncryptionKeySource() {
new WidevineEncryptionKeySource( scoped_ptr<KeySource> encryption_key_source;
FLAGS_key_server_url, if (FLAGS_enable_widevine_encryption) {
FLAGS_content_id, scoped_ptr<RequestSigner> signer(CreateSigner());
FLAGS_policy, 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())); signer.Pass()));
Status status = widevine_encryption_key_source->Initialize(); Status status = widevine_encryption_key_source->FetchKeys(content_id,
FLAGS_policy);
if (!status.ok()) { if (!status.ok()) {
LOG(ERROR) << "Widevine encryption key source failed to initialize: " LOG(ERROR) << "Widevine encryption key source failed to fetch keys: "
<< status.ToString(); << status.ToString();
return scoped_ptr<EncryptionKeySource>(); return scoped_ptr<KeySource>();
} }
encryption_key_source = widevine_encryption_key_source.Pass(); encryption_key_source = widevine_encryption_key_source.Pass();
} else if (FLAGS_enable_fixed_key_encryption) { } else if (FLAGS_enable_fixed_key_encryption) {
encryption_key_source = EncryptionKeySource::CreateFromHexStrings( encryption_key_source = KeySource::CreateFromHexStrings(
FLAGS_key_id, FLAGS_key, FLAGS_pssh, ""); FLAGS_key_id, FLAGS_key, FLAGS_pssh, "");
} }
return encryption_key_source.Pass(); 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 AssignFlagsFromProfile() {
bool single_segment = FLAGS_single_segment; bool single_segment = FLAGS_single_segment;
if (FLAGS_profile == "on-demand") { if (FLAGS_profile == "on-demand") {

View File

@ -23,7 +23,7 @@ struct MpdOptions;
namespace media { namespace media {
class EncryptionKeySource; class KeySource;
class MediaInfo; class MediaInfo;
class MediaStream; class MediaStream;
class Muxer; class Muxer;
@ -32,10 +32,17 @@ struct MuxerOptions;
/// Print all the stream info for the provided strings to standard output. /// Print all the stream info for the provided strings to standard output.
void DumpStreamInfo(const std::vector<MediaStream*>& streams); void DumpStreamInfo(const std::vector<MediaStream*>& streams);
/// Create EncryptionKeySource based on provided command line options. /// Create KeySource based on provided command line options for content
/// @return A scoped_ptr containig a new EncryptionKeySource, or NULL if /// encryption. Also fetches keys.
/// @return A scoped_ptr containing a new KeySource, or NULL if
/// encryption is not required. /// 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. /// Set flags according to profile.
bool AssignFlagsFromProfile(); bool AssignFlagsFromProfile();

View File

@ -8,6 +8,7 @@
#include "app/widevine_encryption_flags.h" #include "app/widevine_encryption_flags.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
DEFINE_bool(enable_widevine_encryption, DEFINE_bool(enable_widevine_encryption,
@ -15,8 +16,14 @@ DEFINE_bool(enable_widevine_encryption,
"Enable encryption with Widevine license server/proxy. User should " "Enable encryption with Widevine license server/proxy. User should "
"provide either AES signing key (--aes_signing_key, " "provide either AES signing key (--aes_signing_key, "
"--aes_signing_iv) or RSA signing key (--rsa_signing_key_path)."); "--aes_signing_iv) or RSA signing key (--rsa_signing_key_path).");
DEFINE_string(key_server_url, "", "Key server url."); DEFINE_bool(enable_widevine_decryption,
DEFINE_string(content_id, "", "Content Id."); 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, DEFINE_string(policy,
"", "",
"The name of a stored policy, which specifies DRM content " "The name of a stored policy, which specifies DRM content "
@ -44,9 +51,44 @@ DEFINE_int32(crypto_period_duration,
namespace { namespace {
static bool IsNotEmptyWithWidevineEncryption(const char* flag_name, static bool VerifyEncryptionAndDecryptionParams(const char* flag_name,
const std::string& flag_value) { 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) { 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 = bool dummy_key_server_url_validator =
google::RegisterFlagValidator(&FLAGS_key_server_url, google::RegisterFlagValidator(&FLAGS_key_server_url,
&IsNotEmptyWithWidevineEncryption); &VerifyEncryptionAndDecryptionParams);
bool dummy_content_id_validator = bool dummy_content_id_validator =
google::RegisterFlagValidator(&FLAGS_content_id, google::RegisterFlagValidator(&FLAGS_content_id,
&IsNotEmptyWithWidevineEncryption); &VerifyEncryptionAndDecryptionParams);
bool dummy_track_type_validator = bool dummy_track_type_validator =
google::RegisterFlagValidator(&FLAGS_max_sd_pixels, &IsPositive); google::RegisterFlagValidator(&FLAGS_max_sd_pixels, &IsPositive);
bool dummy_signer_validator = bool dummy_signer_validator =
google::RegisterFlagValidator(&FLAGS_signer, google::RegisterFlagValidator(&FLAGS_signer,
&IsNotEmptyWithWidevineEncryption); &VerifyEncryptionAndDecryptionParams);
bool dummy_aes_iv_validator = bool dummy_aes_iv_validator =
google::RegisterFlagValidator(&FLAGS_aes_signing_iv, google::RegisterFlagValidator(&FLAGS_aes_signing_iv,
&VerifyAesRsaKey); &VerifyAesRsaKey);

View File

@ -12,6 +12,7 @@
#include <gflags/gflags.h> #include <gflags/gflags.h>
DECLARE_bool(enable_widevine_encryption); DECLARE_bool(enable_widevine_encryption);
DECLARE_bool(enable_widevine_decryption);
DECLARE_string(key_server_url); DECLARE_string(key_server_url);
DECLARE_string(content_id); DECLARE_string(content_id);
DECLARE_string(policy); DECLARE_string(policy);

View File

@ -4,7 +4,7 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd // 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 "base/strings/string_number_conversions.h"
#include "media/base/aes_encryptor.h" #include "media/base/aes_encryptor.h"
@ -21,23 +21,42 @@ namespace media {
EncryptionKey::EncryptionKey() {} EncryptionKey::EncryptionKey() {}
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(key);
DCHECK(encryption_key_); DCHECK(encryption_key_);
*key = *encryption_key_; *key = *encryption_key_;
return Status::OK; 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, TrackType track_type,
EncryptionKey* key) { EncryptionKey* key) {
NOTIMPLEMENTED(); NOTIMPLEMENTED();
return Status(error::UNIMPLEMENTED, ""); return Status(error::UNIMPLEMENTED, "");
} }
scoped_ptr<EncryptionKeySource> EncryptionKeySource::CreateFromHexStrings( scoped_ptr<KeySource> KeySource::CreateFromHexStrings(
const std::string& key_id_hex, const std::string& key_id_hex,
const std::string& key_hex, const std::string& key_hex,
const std::string& pssh_data_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)) { if (!base::HexStringToBytes(key_id_hex, &encryption_key->key_id)) {
LOG(ERROR) << "Cannot parse key_id_hex " << key_id_hex; 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)) { if (!base::HexStringToBytes(key_hex, &encryption_key->key)) {
LOG(ERROR) << "Cannot parse key_hex " << key_hex; LOG(ERROR) << "Cannot parse key_hex " << key_hex;
return scoped_ptr<EncryptionKeySource>(); return scoped_ptr<KeySource>();
} }
std::vector<uint8> pssh_data; std::vector<uint8> pssh_data;
if (!base::HexStringToBytes(pssh_data_hex, &pssh_data)) { if (!base::HexStringToBytes(pssh_data_hex, &pssh_data)) {
LOG(ERROR) << "Cannot parse pssh_hex " << pssh_data_hex; LOG(ERROR) << "Cannot parse pssh_hex " << pssh_data_hex;
return scoped_ptr<EncryptionKeySource>(); return scoped_ptr<KeySource>();
} }
if (!iv_hex.empty()) { if (!iv_hex.empty()) {
if (!base::HexStringToBytes(iv_hex, &encryption_key->iv)) { if (!base::HexStringToBytes(iv_hex, &encryption_key->iv)) {
LOG(ERROR) << "Cannot parse iv_hex " << iv_hex; LOG(ERROR) << "Cannot parse iv_hex " << iv_hex;
return scoped_ptr<EncryptionKeySource>(); return scoped_ptr<KeySource>();
} }
} }
encryption_key->pssh = PsshBoxFromPsshData(pssh_data); encryption_key->pssh = PsshBoxFromPsshData(pssh_data);
return scoped_ptr<EncryptionKeySource>( return scoped_ptr<KeySource>(
new EncryptionKeySource(encryption_key.Pass())); new KeySource(encryption_key.Pass()));
} }
EncryptionKeySource::TrackType EncryptionKeySource::GetTrackTypeFromString( KeySource::TrackType KeySource::GetTrackTypeFromString(
const std::string& track_type_string) { const std::string& track_type_string) {
if (track_type_string == "SD") if (track_type_string == "SD")
return TRACK_TYPE_SD; return TRACK_TYPE_SD;
@ -84,7 +103,7 @@ EncryptionKeySource::TrackType EncryptionKeySource::GetTrackTypeFromString(
return TRACK_TYPE_UNKNOWN; return TRACK_TYPE_UNKNOWN;
} }
std::string EncryptionKeySource::TrackTypeToString(TrackType track_type) { std::string KeySource::TrackTypeToString(TrackType track_type) {
switch (track_type) { switch (track_type) {
case TRACK_TYPE_SD: case TRACK_TYPE_SD:
return "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 std::vector<uint8>& pssh_data) {
const uint8 kPsshFourCC[] = {'p', 's', 's', 'h'}; const uint8 kPsshFourCC[] = {'p', 's', 's', 'h'};
const uint32 kVersionAndFlags = 0; const uint32 kVersionAndFlags = 0;
@ -118,9 +137,8 @@ std::vector<uint8> EncryptionKeySource::PsshBoxFromPsshData(
return std::vector<uint8>(writer.Buffer(), writer.Buffer() + writer.Size()); return std::vector<uint8>(writer.Buffer(), writer.Buffer() + writer.Size());
} }
EncryptionKeySource::EncryptionKeySource() {} KeySource::KeySource() {}
EncryptionKeySource::EncryptionKeySource( KeySource::KeySource(scoped_ptr<EncryptionKey> encryption_key)
scoped_ptr<EncryptionKey> encryption_key)
: encryption_key_(encryption_key.Pass()) { : encryption_key_(encryption_key.Pass()) {
DCHECK(encryption_key_); DCHECK(encryption_key_);
} }

View File

@ -4,8 +4,8 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd // https://developers.google.com/open-source/licenses/bsd
#ifndef MEDIA_BASE_ENCRYPTION_KEY_SOURCE_H_ #ifndef MEDIA_BASE_KEY_SOURCE_H_
#define MEDIA_BASE_ENCRYPTION_KEY_SOURCE_H_ #define MEDIA_BASE_KEY_SOURCE_H_
#include <vector> #include <vector>
@ -24,8 +24,8 @@ struct EncryptionKey {
std::vector<uint8> iv; std::vector<uint8> iv;
}; };
/// EncryptionKeySource is responsible for encryption key acquisition. /// KeySource is responsible for encryption key acquisition.
class EncryptionKeySource { class KeySource {
public: public:
enum TrackType { enum TrackType {
TRACK_TYPE_UNKNOWN = 0, TRACK_TYPE_UNKNOWN = 0,
@ -35,19 +35,47 @@ class EncryptionKeySource {
NUM_VALID_TRACK_TYPES = 3 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. /// 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. /// @return OK on success, an error status otherwise.
virtual Status GetKey(TrackType track_type, EncryptionKey* key); 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. /// 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. /// @return OK on success, an error status otherwise.
virtual Status GetCryptoPeriodKey(uint32 crypto_period_index, virtual Status GetCryptoPeriodKey(uint32 crypto_period_index,
TrackType track_type, TrackType track_type,
EncryptionKey* key); 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_id_hex is the key id in hex string.
/// @param key_hex is the key in hex string. /// @param key_hex is the key in hex string.
/// @param pssh_data_hex is the pssh_data 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. /// generated IV with the default length will be used.
/// Note: GetKey on the created key source will always return the same key /// Note: GetKey on the created key source will always return the same key
/// for all track types. /// for all track types.
static scoped_ptr<EncryptionKeySource> CreateFromHexStrings( static scoped_ptr<KeySource> CreateFromHexStrings(
const std::string& key_id_hex, const std::string& key_id_hex,
const std::string& key_hex, const std::string& key_hex,
const std::string& pssh_data_hex, const std::string& pssh_data_hex,
@ -68,7 +96,7 @@ class EncryptionKeySource {
static std::string TrackTypeToString(TrackType track_type); static std::string TrackTypeToString(TrackType track_type);
protected: protected:
EncryptionKeySource(); KeySource();
/// @return the raw bytes of the pssh box with system ID and box header /// @return the raw bytes of the pssh box with system ID and box header
/// included. /// included.
@ -76,13 +104,13 @@ class EncryptionKeySource {
const std::vector<uint8>& pssh_data); const std::vector<uint8>& pssh_data);
private: private:
explicit EncryptionKeySource(scoped_ptr<EncryptionKey> encryption_key); explicit KeySource(scoped_ptr<EncryptionKey> encryption_key);
scoped_ptr<EncryptionKey> encryption_key_; scoped_ptr<EncryptionKey> encryption_key_;
DISALLOW_COPY_AND_ASSIGN(EncryptionKeySource); DISALLOW_COPY_AND_ASSIGN(KeySource);
}; };
} // namespace media } // namespace media
#endif // MEDIA_BASE_ENCRYPTION_KEY_SOURCE_H_ #endif // MEDIA_BASE_KEY_SOURCE_H_

View File

@ -36,10 +36,10 @@
'decrypt_config.cc', 'decrypt_config.cc',
'decrypt_config.h', 'decrypt_config.h',
'decryptor_source.h', 'decryptor_source.h',
'encryption_key_source.cc',
'encryption_key_source.h',
'http_fetcher.cc', 'http_fetcher.cc',
'http_fetcher.h', 'http_fetcher.h',
'key_source.cc',
'key_source.h',
'limits.h', 'limits.h',
'media_parser.h', 'media_parser.h',
'media_sample.cc', 'media_sample.cc',
@ -67,8 +67,8 @@
'timestamp.h', 'timestamp.h',
'video_stream_info.cc', 'video_stream_info.cc',
'video_stream_info.h', 'video_stream_info.h',
'widevine_encryption_key_source.cc', 'widevine_key_source.cc',
'widevine_encryption_key_source.h', 'widevine_key_source.h',
], ],
'dependencies': [ 'dependencies': [
'../../base/base.gyp:base', '../../base/base.gyp:base',
@ -98,7 +98,7 @@
'status_test_util.h', 'status_test_util.h',
'status_test_util_unittest.cc', 'status_test_util_unittest.cc',
'status_unittest.cc', 'status_unittest.cc',
'widevine_encryption_key_source_unittest.cc', 'widevine_key_source_unittest.cc',
], ],
'dependencies': [ 'dependencies': [
'../../testing/gtest.gyp:gtest', '../../testing/gtest.gyp:gtest',

View File

@ -23,7 +23,7 @@ Muxer::Muxer(const MuxerOptions& options)
Muxer::~Muxer() {} Muxer::~Muxer() {}
void Muxer::SetEncryptionKeySource(EncryptionKeySource* encryption_key_source, void Muxer::SetKeySource(KeySource* encryption_key_source,
uint32 max_sd_pixels, uint32 max_sd_pixels,
double clear_lead_in_seconds, double clear_lead_in_seconds,
double crypto_period_duration_in_seconds) { double crypto_period_duration_in_seconds) {

View File

@ -22,7 +22,7 @@ class Clock;
namespace media { namespace media {
class EncryptionKeySource; class KeySource;
class MediaSample; class MediaSample;
class MediaStream; class MediaStream;
@ -31,7 +31,7 @@ class MuxerListener;
} }
/// Muxer is responsible for taking elementary stream samples and producing /// 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. /// to generate encrypted outputs.
class Muxer { class Muxer {
public: public:
@ -39,8 +39,8 @@ class Muxer {
virtual ~Muxer(); virtual ~Muxer();
/// Set encryption key source. /// Set encryption key source.
/// @param encryption_key_source points to the encryption key source to be /// @param encryption_key_source points to the encryption key source. The
/// injected. Should not be NULL. /// caller retains ownership, and should not be NULL.
/// @param max_sd_pixels specifies the threshold to determine whether a video /// @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 /// 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. /// 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 /// @param crypto_period_duration_in_seconds specifies crypto period duration
/// in seconds. A positive value means key rotation is enabled, the /// in seconds. A positive value means key rotation is enabled, the
/// key source must support key rotation in this case. /// 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, uint32 max_sd_pixels,
double clear_lead_in_seconds, double clear_lead_in_seconds,
double crypto_period_duration_in_seconds); double crypto_period_duration_in_seconds);
@ -77,7 +77,7 @@ class Muxer {
protected: protected:
const MuxerOptions& options() const { return options_; } const MuxerOptions& options() const { return options_; }
EncryptionKeySource* encryption_key_source() { KeySource* encryption_key_source() {
return encryption_key_source_; return encryption_key_source_;
} }
uint32 max_sd_pixels() const { return max_sd_pixels_; } uint32 max_sd_pixels() const { return max_sd_pixels_; }
@ -108,7 +108,7 @@ class Muxer {
MuxerOptions options_; MuxerOptions options_;
bool initialized_; bool initialized_;
std::vector<MediaStream*> streams_; std::vector<MediaStream*> streams_;
EncryptionKeySource* encryption_key_source_; KeySource* encryption_key_source_;
uint32 max_sd_pixels_; uint32 max_sd_pixels_;
double clear_lead_in_seconds_; double clear_lead_in_seconds_;
double crypto_period_duration_in_seconds_; double crypto_period_duration_in_seconds_;

View File

@ -4,7 +4,7 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd // 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/base64.h"
#include "base/bind.h" #include "base/bind.h"
@ -12,7 +12,6 @@
#include "base/json/json_writer.h" #include "base/json/json_writer.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/values.h"
#include "media/base/http_fetcher.h" #include "media/base/http_fetcher.h"
#include "media/base/producer_consumer_queue.h" #include "media/base/producer_consumer_queue.h"
#include "media/base/request_signer.h" #include "media/base/request_signer.h"
@ -55,26 +54,35 @@ bool Base64StringToBytes(const std::string& base64_string,
return true; return true;
} }
bool GetKeyAndKeyId(const base::DictionaryValue& track_dict, void BytesToBase64String(const std::vector<uint8>& bytes,
std::vector<uint8>* key, std::string* base64_string) {
std::vector<uint8>* key_id) { DCHECK(base64_string);
DCHECK(key); base::Base64Encode(base::StringPiece(reinterpret_cast<const char*>
DCHECK(key_id); (bytes.data()), bytes.size()),
base64_string);
}
bool GetKeyFromTrack(const base::DictionaryValue& track_dict,
std::vector<uint8>* key) {
DCHECK(key);
std::string key_base64_string; std::string key_base64_string;
RCHECK(track_dict.GetString("key", &key_base64_string)); RCHECK(track_dict.GetString("key", &key_base64_string));
VLOG(2) << "Key:" << key_base64_string; VLOG(2) << "Key:" << key_base64_string;
RCHECK(Base64StringToBytes(key_base64_string, key)); 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; std::string key_id_base64_string;
RCHECK(track_dict.GetString("key_id", &key_id_base64_string)); RCHECK(track_dict.GetString("key_id", &key_id_base64_string));
VLOG(2) << "Keyid:" << key_id_base64_string; VLOG(2) << "Keyid:" << key_id_base64_string;
RCHECK(Base64StringToBytes(key_id_base64_string, key_id)); RCHECK(Base64StringToBytes(key_id_base64_string, key_id));
return true; return true;
} }
bool GetPsshData(const base::DictionaryValue& track_dict, bool GetPsshDataFromTrack(const base::DictionaryValue& track_dict,
std::vector<uint8>* pssh_data) { std::vector<uint8>* pssh_data) {
DCHECK(pssh_data); DCHECK(pssh_data);
@ -105,7 +113,7 @@ bool GetPsshData(const base::DictionaryValue& track_dict,
namespace media { namespace media {
// A ref counted wrapper for EncryptionKeyMap. // A ref counted wrapper for EncryptionKeyMap.
class WidevineEncryptionKeySource::RefCountedEncryptionKeyMap class WidevineKeySource::RefCountedEncryptionKeyMap
: public base::RefCountedThreadSafe<RefCountedEncryptionKeyMap> { : public base::RefCountedThreadSafe<RefCountedEncryptionKeyMap> {
public: public:
explicit RefCountedEncryptionKeyMap(EncryptionKeyMap* encryption_key_map) { explicit RefCountedEncryptionKeyMap(EncryptionKeyMap* encryption_key_map) {
@ -113,7 +121,7 @@ class WidevineEncryptionKeySource::RefCountedEncryptionKeyMap
encryption_key_map_.swap(*encryption_key_map); encryption_key_map_.swap(*encryption_key_map);
} }
std::map<EncryptionKeySource::TrackType, EncryptionKey*>& map() { std::map<KeySource::TrackType, EncryptionKey*>& map() {
return encryption_key_map_; return encryption_key_map_;
} }
@ -127,15 +135,11 @@ class WidevineEncryptionKeySource::RefCountedEncryptionKeyMap
DISALLOW_COPY_AND_ASSIGN(RefCountedEncryptionKeyMap); DISALLOW_COPY_AND_ASSIGN(RefCountedEncryptionKeyMap);
}; };
WidevineEncryptionKeySource::WidevineEncryptionKeySource( WidevineKeySource::WidevineKeySource(
const std::string& server_url, const std::string& server_url,
const std::string& content_id,
const std::string& policy,
scoped_ptr<RequestSigner> signer) scoped_ptr<RequestSigner> signer)
: http_fetcher_(new SimpleHttpFetcher(kHttpTimeoutInSeconds)), : http_fetcher_(new SimpleHttpFetcher(kHttpTimeoutInSeconds)),
server_url_(server_url), server_url_(server_url),
content_id_(content_id),
policy_(policy),
signer_(signer.Pass()), signer_(signer.Pass()),
crypto_period_count_(kDefaultCryptoPeriodCount), crypto_period_count_(kDefaultCryptoPeriodCount),
key_production_started_(false), key_production_started_(false),
@ -143,12 +147,12 @@ WidevineEncryptionKeySource::WidevineEncryptionKeySource(
first_crypto_period_index_(0), first_crypto_period_index_(0),
key_production_thread_( key_production_thread_(
"KeyProductionThread", "KeyProductionThread",
base::Bind(&WidevineEncryptionKeySource::FetchKeysTask, base::Bind(&WidevineKeySource::FetchKeysTask,
base::Unretained(this))) { base::Unretained(this))) {
DCHECK(signer_); DCHECK(signer_);
} }
WidevineEncryptionKeySource::~WidevineEncryptionKeySource() { WidevineKeySource::~WidevineKeySource() {
if (key_pool_) if (key_pool_)
key_pool_->Stop(); key_pool_->Stop();
if (key_production_thread_.HasBeenStarted()) { 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()); DCHECK(!key_production_thread_.HasBeenStarted());
key_production_thread_.Start(); key_production_thread_.Start();
// Perform a fetch request to find out if the key source is healthy. // Perform a fetch request to find out if the key source is healthy.
// It also stores the keys fetched for consumption later. // 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) { EncryptionKey* key) {
DCHECK(key); DCHECK(key);
if (encryption_key_map_.find(track_type) == encryption_key_map_.end()) { if (encryption_key_map_.find(track_type) == encryption_key_map_.end()) {
@ -179,7 +213,23 @@ Status WidevineEncryptionKeySource::GetKey(TrackType track_type,
return Status::OK; 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, uint32 crypto_period_index,
TrackType track_type, TrackType track_type,
EncryptionKey* key) { EncryptionKey* key) {
@ -201,12 +251,12 @@ Status WidevineEncryptionKeySource::GetCryptoPeriodKey(
return GetKeyInternal(crypto_period_index, track_type, key); return GetKeyInternal(crypto_period_index, track_type, key);
} }
void WidevineEncryptionKeySource::set_http_fetcher( void WidevineKeySource::set_http_fetcher(
scoped_ptr<HttpFetcher> http_fetcher) { scoped_ptr<HttpFetcher> http_fetcher) {
http_fetcher_ = http_fetcher.Pass(); http_fetcher_ = http_fetcher.Pass();
} }
Status WidevineEncryptionKeySource::GetKeyInternal( Status WidevineKeySource::GetKeyInternal(
uint32 crypto_period_index, uint32 crypto_period_index,
TrackType track_type, TrackType track_type,
EncryptionKey* key) { EncryptionKey* key) {
@ -236,25 +286,31 @@ Status WidevineEncryptionKeySource::GetKeyInternal(
return Status::OK; return Status::OK;
} }
void WidevineEncryptionKeySource::FetchKeysTask() { void WidevineKeySource::FetchKeysTask() {
// Wait until key production is signaled. // Wait until key production is signaled.
start_key_production_.Wait(); start_key_production_.Wait();
if (!key_pool_ || key_pool_->Stopped()) if (!key_pool_ || key_pool_->Stopped())
return; return;
Status status = FetchKeys(kEnableKeyRotation, first_crypto_period_index_); Status status = FetchKeysInternal(kEnableKeyRotation,
first_crypto_period_index_,
false);
while (status.ok()) { while (status.ok()) {
first_crypto_period_index_ += crypto_period_count_; 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; common_encryption_request_status_ = status;
key_pool_->Stop(); key_pool_->Stop();
} }
Status WidevineEncryptionKeySource::FetchKeys( Status WidevineKeySource::FetchKeysInternal(bool enable_key_rotation,
bool enable_key_rotation, uint32 first_crypto_period_index) { uint32 first_crypto_period_index,
bool widevine_classic) {
std::string request; std::string request;
FillRequest(content_id_, enable_key_rotation, first_crypto_period_index, FillRequest(enable_key_rotation,
first_crypto_period_index,
&request); &request);
std::string message; std::string message;
@ -280,7 +336,10 @@ Status WidevineEncryptionKeySource::FetchKeys(
} }
bool transient_error = false; 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; return Status::OK;
if (!transient_error) { if (!transient_error) {
@ -303,18 +362,11 @@ Status WidevineEncryptionKeySource::FetchKeys(
"Failed to recover from server internal error."); "Failed to recover from server internal error.");
} }
void WidevineEncryptionKeySource::FillRequest(const std::string& content_id, void WidevineKeySource::FillRequest(bool enable_key_rotation,
bool enable_key_rotation,
uint32 first_crypto_period_index, uint32 first_crypto_period_index,
std::string* request) { std::string* request) {
DCHECK(request); DCHECK(request);
DCHECK(!request_dict_.empty());
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_);
// Build tracks. // Build tracks.
base::ListValue* tracks = new base::ListValue(); base::ListValue* tracks = new base::ListValue();
@ -329,24 +381,24 @@ void WidevineEncryptionKeySource::FillRequest(const std::string& content_id,
track_audio->SetString("type", "AUDIO"); track_audio->SetString("type", "AUDIO");
tracks->Append(track_audio); tracks->Append(track_audio);
request_dict.Set("tracks", tracks); request_dict_.Set("tracks", tracks);
// Build DRM types. // Build DRM types.
base::ListValue* drm_types = new base::ListValue(); base::ListValue* drm_types = new base::ListValue();
drm_types->AppendString("WIDEVINE"); drm_types->AppendString("WIDEVINE");
request_dict.Set("drm_types", drm_types); request_dict_.Set("drm_types", drm_types);
// Build key rotation fields. // Build key rotation fields.
if (enable_key_rotation) { if (enable_key_rotation) {
request_dict.SetInteger("first_crypto_period_index", request_dict_.SetInteger("first_crypto_period_index",
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) { std::string* signed_request) {
DCHECK(signed_request); DCHECK(signed_request);
@ -371,7 +423,7 @@ Status WidevineEncryptionKeySource::SignRequest(const std::string& request,
return Status::OK; return Status::OK;
} }
bool WidevineEncryptionKeySource::DecodeResponse( bool WidevineKeySource::DecodeResponse(
const std::string& raw_response, const std::string& raw_response,
std::string* response) { std::string* response) {
DCHECK(response); DCHECK(response);
@ -391,8 +443,9 @@ bool WidevineEncryptionKeySource::DecodeResponse(
return true; return true;
} }
bool WidevineEncryptionKeySource::ExtractEncryptionKey( bool WidevineKeySource::ExtractEncryptionKey(
bool enable_key_rotation, bool enable_key_rotation,
bool widevine_classic,
const std::string& response, const std::string& response,
bool* transient_error) { bool* transient_error) {
DCHECK(transient_error); DCHECK(transient_error);
@ -453,12 +506,20 @@ bool WidevineEncryptionKeySource::ExtractEncryptionKey(
RCHECK(encryption_key_map.find(track_type) == encryption_key_map.end()); RCHECK(encryption_key_map.find(track_type) == encryption_key_map.end());
scoped_ptr<EncryptionKey> encryption_key(new EncryptionKey()); 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; std::vector<uint8> pssh_data;
if (!GetKeyAndKeyId( if (!GetPsshDataFromTrack(*track_dict, &pssh_data))
*track_dict, &encryption_key->key, &encryption_key->key_id) ||
!GetPsshData(*track_dict, &pssh_data))
return false; return false;
encryption_key->pssh = PsshBoxFromPsshData(pssh_data); encryption_key->pssh = PsshBoxFromPsshData(pssh_data);
}
encryption_key_map[track_type] = encryption_key.release(); encryption_key_map[track_type] = encryption_key.release();
} }
@ -470,7 +531,7 @@ bool WidevineEncryptionKeySource::ExtractEncryptionKey(
return PushToKeyPool(&encryption_key_map); return PushToKeyPool(&encryption_key_map);
} }
bool WidevineEncryptionKeySource::PushToKeyPool( bool WidevineKeySource::PushToKeyPool(
EncryptionKeyMap* encryption_key_map) { EncryptionKeyMap* encryption_key_map) {
DCHECK(key_pool_); DCHECK(key_pool_);
DCHECK(encryption_key_map); DCHECK(encryption_key_map);

View File

@ -4,44 +4,43 @@
// license that can be found in the LICENSE file or at // license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd // https://developers.google.com/open-source/licenses/bsd
#ifndef MEDIA_BASE_WIDEVINE_ENCRYPTION_KEY_SOURCE_H_ #ifndef MEDIA_BASE_WIDEVINE_KEY_SOURCE_H_
#define MEDIA_BASE_WIDEVINE_ENCRYPTION_KEY_SOURCE_H_ #define MEDIA_BASE_WIDEVINE_KEY_SOURCE_H_
#include <map> #include <map>
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/synchronization/waitable_event.h" #include "base/synchronization/waitable_event.h"
#include "base/values.h"
#include "media/base/closure_thread.h" #include "media/base/closure_thread.h"
#include "media/base/encryption_key_source.h" #include "media/base/key_source.h"
namespace media { namespace media {
class HttpFetcher; class HttpFetcher;
class RequestSigner; class RequestSigner;
template <class T> class ProducerConsumerQueue; 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. /// acquire the encryption keys.
class WidevineEncryptionKeySource : public EncryptionKeySource { class WidevineKeySource : public KeySource {
public: public:
/// @param server_url is the Widevine common encryption server url. /// @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. /// @param signer signs the request message. It should not be NULL.
WidevineEncryptionKeySource(const std::string& server_url, WidevineKeySource(const std::string& server_url,
const std::string& content_id,
const std::string& policy,
scoped_ptr<RequestSigner> signer); scoped_ptr<RequestSigner> signer);
virtual ~WidevineEncryptionKeySource();
/// Initialize the key source. Must be called before calling GetKey or virtual ~WidevineKeySource();
/// GetCryptoPeriodKey.
/// @return OK on success, an error status otherwise.
Status Initialize();
/// @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(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, virtual Status GetCryptoPeriodKey(uint32 crypto_period_index,
TrackType track_type, TrackType track_type,
EncryptionKey* key) OVERRIDE; EncryptionKey* key) OVERRIDE;
@ -62,16 +61,20 @@ class WidevineEncryptionKeySource : public EncryptionKeySource {
TrackType track_type, TrackType track_type,
EncryptionKey* key); EncryptionKey* key);
// Common implementation of FetchKeys methods above.
Status FetchKeysCommon(bool widevine_classic);
// The closure task to fetch keys repeatedly. // The closure task to fetch keys repeatedly.
void FetchKeysTask(); void FetchKeysTask();
// Fetch keys from server. // 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. // Fill |request| with necessary fields for Widevine encryption request.
// |request| should not be NULL. // |request| should not be NULL.
void FillRequest(const std::string& content_id, void FillRequest(bool enable_key_rotation,
bool enable_key_rotation,
uint32 first_crypto_period_index, uint32 first_crypto_period_index,
std::string* request); std::string* request);
// Sign and properly format |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| // failure is because of a transient error from the server. |transient_error|
// should not be NULL. // should not be NULL.
bool ExtractEncryptionKey(bool enable_key_rotation, 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. // Push the keys to the key pool.
bool PushToKeyPool(EncryptionKeyMap* encryption_key_map); 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. // Can be overridden using set_http_fetcher for testing or other purposes.
scoped_ptr<HttpFetcher> http_fetcher_; scoped_ptr<HttpFetcher> http_fetcher_;
std::string server_url_; std::string server_url_;
std::string content_id_;
std::string policy_;
scoped_ptr<RequestSigner> signer_; scoped_ptr<RequestSigner> signer_;
base::DictionaryValue request_dict_;
const uint32 crypto_period_count_; const uint32 crypto_period_count_;
base::Lock lock_; base::Lock lock_;
@ -108,9 +112,9 @@ class WidevineEncryptionKeySource : public EncryptionKeySource {
EncryptionKeyMap encryption_key_map_; // For non key rotation request. EncryptionKeyMap encryption_key_map_; // For non key rotation request.
Status common_encryption_request_status_; Status common_encryption_request_status_;
DISALLOW_COPY_AND_ASSIGN(WidevineEncryptionKeySource); DISALLOW_COPY_AND_ASSIGN(WidevineKeySource);
}; };
} // namespace media } // namespace media
#endif // MEDIA_BASE_WIDEVINE_ENCRYPTION_KEY_SOURCE_H_ #endif // MEDIA_BASE_WIDEVINE_KEY_SOURCE_H_

View File

@ -13,7 +13,7 @@
#include "media/base/http_fetcher.h" #include "media/base/http_fetcher.h"
#include "media/base/request_signer.h" #include "media/base/request_signer.h"
#include "media/base/status_test_util.h" #include "media/base/status_test_util.h"
#include "media/base/widevine_encryption_key_source.h" #include "media/base/widevine_key_source.h"
namespace { namespace {
const char kServerUrl[] = "http://www.foo.com/getcontentkey"; 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 // The license service may return an error indicating a transient error has
// just happened in the server, or other types of errors. // 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; // errors;
// WidevineEncryptionKeySource does not know about other errors and retries are // WidevineKeySource does not know about other errors and retries are
// not performed. // not performed.
const char kLicenseStatusTransientError[] = "INTERNAL_ERROR"; const char kLicenseStatusTransientError[] = "INTERNAL_ERROR";
const char kLicenseStatusUnknownError[] = "UNKNOWN_ERROR"; const char kLicenseStatusUnknownError[] = "UNKNOWN_ERROR";
@ -40,8 +40,11 @@ const char kExpectedSignedMessageFormat[] =
const char kTrackFormat[] = const char kTrackFormat[] =
"{\"type\":\"%s\",\"key_id\":\"%s\",\"key\":" "{\"type\":\"%s\",\"key_id\":\"%s\",\"key\":"
"\"%s\",\"pssh\":[{\"drm_type\":\"WIDEVINE\",\"data\":\"%s\"}]}"; "\"%s\",\"pssh\":[{\"drm_type\":\"WIDEVINE\",\"data\":\"%s\"}]}";
const char kClassicTrackFormat[] = "{\"type\":\"%s\",\"key\":\"%s\"}";
const char kLicenseResponseFormat[] = "{\"status\":\"%s\",\"tracks\":[%s]}"; const char kLicenseResponseFormat[] = "{\"status\":\"%s\",\"tracks\":[%s]}";
const char kHttpResponseFormat[] = "{\"response\":\"%s\"}"; const char kHttpResponseFormat[] = "{\"response\":\"%s\"}";
const char kRequestPsshData[] = "PSSH data";
const uint32 kClassicAssetId = 1234;
std::string Base64Encode(const std::string& input) { std::string Base64Encode(const std::string& input) {
std::string output; std::string output;
@ -81,6 +84,20 @@ std::string GenerateMockLicenseResponse() {
return base::StringPrintf(kLicenseResponseFormat, "OK", tracks.c_str()); 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) { std::string GetPsshDataFromPsshBox(const std::string& pssh_box) {
const size_t kPsshDataOffset = 32u; const size_t kPsshDataOffset = 32u;
DCHECK_LT(kPsshDataOffset, pssh_box.size()); DCHECK_LT(kPsshDataOffset, pssh_box.size());
@ -125,68 +142,75 @@ class MockHttpFetcher : public HttpFetcher {
DISALLOW_COPY_AND_ASSIGN(MockHttpFetcher); DISALLOW_COPY_AND_ASSIGN(MockHttpFetcher);
}; };
class WidevineEncryptionKeySourceTest : public ::testing::Test { class WidevineKeySourceTest : public ::testing::Test {
public: public:
WidevineEncryptionKeySourceTest() WidevineKeySourceTest()
: mock_request_signer_(new MockRequestSigner(kSignerName)), : mock_request_signer_(new MockRequestSigner(kSignerName)),
mock_http_fetcher_(new MockHttpFetcher()) {} mock_http_fetcher_(new MockHttpFetcher()) {}
void SetUp() OVERRIDE {
content_id_.assign(reinterpret_cast<const uint8*>(kContentId),
reinterpret_cast<const uint8*>(kContentId) +
strlen(kContentId));
}
protected: protected:
void CreateWidevineEncryptionKeySource() { void CreateWidevineKeySource() {
widevine_encryption_key_source_.reset(new WidevineEncryptionKeySource( widevine_key_source_.reset(new WidevineKeySource(
kServerUrl, kServerUrl,
kContentId,
kPolicy,
mock_request_signer_.PassAs<RequestSigner>())); mock_request_signer_.PassAs<RequestSigner>()));
widevine_encryption_key_source_->set_http_fetcher( widevine_key_source_->set_http_fetcher(
mock_http_fetcher_.PassAs<HttpFetcher>()); mock_http_fetcher_.PassAs<HttpFetcher>());
} }
void VerifyKeys() { void VerifyKeys(bool classic) {
EncryptionKey encryption_key; EncryptionKey encryption_key;
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"}; const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
for (size_t i = 0; i < arraysize(kTrackTypes); ++i) { for (size_t i = 0; i < arraysize(kTrackTypes); ++i) {
ASSERT_OK(widevine_encryption_key_source_->GetKey( ASSERT_OK(widevine_key_source_->GetKey(
EncryptionKeySource::GetTrackTypeFromString(kTrackTypes[i]), KeySource::GetTrackTypeFromString(kTrackTypes[i]),
&encryption_key)); &encryption_key));
EXPECT_EQ(GetMockKeyId(kTrackTypes[i]), ToString(encryption_key.key_id));
EXPECT_EQ(GetMockKey(kTrackTypes[i]), ToString(encryption_key.key)); 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]), EXPECT_EQ(GetMockPsshData(kTrackTypes[i]),
GetPsshDataFromPsshBox(ToString(encryption_key.pssh))); GetPsshDataFromPsshBox(ToString(encryption_key.pssh)));
} }
} }
}
scoped_ptr<MockRequestSigner> mock_request_signer_; scoped_ptr<MockRequestSigner> mock_request_signer_;
scoped_ptr<MockHttpFetcher> mock_http_fetcher_; 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: private:
DISALLOW_COPY_AND_ASSIGN(WidevineEncryptionKeySourceTest); DISALLOW_COPY_AND_ASSIGN(WidevineKeySourceTest);
}; };
TEST_F(WidevineEncryptionKeySourceTest, GetTrackTypeFromString) { TEST_F(WidevineKeySourceTest, GetTrackTypeFromString) {
EXPECT_EQ(EncryptionKeySource::TRACK_TYPE_SD, EXPECT_EQ(KeySource::TRACK_TYPE_SD,
EncryptionKeySource::GetTrackTypeFromString("SD")); KeySource::GetTrackTypeFromString("SD"));
EXPECT_EQ(EncryptionKeySource::TRACK_TYPE_HD, EXPECT_EQ(KeySource::TRACK_TYPE_HD,
EncryptionKeySource::GetTrackTypeFromString("HD")); KeySource::GetTrackTypeFromString("HD"));
EXPECT_EQ(EncryptionKeySource::TRACK_TYPE_AUDIO, EXPECT_EQ(KeySource::TRACK_TYPE_AUDIO,
EncryptionKeySource::GetTrackTypeFromString("AUDIO")); KeySource::GetTrackTypeFromString("AUDIO"));
EXPECT_EQ(EncryptionKeySource::TRACK_TYPE_UNKNOWN, EXPECT_EQ(KeySource::TRACK_TYPE_UNKNOWN,
EncryptionKeySource::GetTrackTypeFromString("FOO")); KeySource::GetTrackTypeFromString("FOO"));
} }
TEST_F(WidevineEncryptionKeySourceTest, GenerateSignatureFailure) { TEST_F(WidevineKeySourceTest, GenerateSignatureFailure) {
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(false)); .WillOnce(Return(false));
CreateWidevineEncryptionKeySource(); CreateWidevineKeySource();
ASSERT_EQ(Status(error::INTERNAL_ERROR, "Signature generation failed."), 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 // Check whether expected request message and post data was generated and
// verify the correct behavior on http failure. // verify the correct behavior on http failure.
TEST_F(WidevineEncryptionKeySourceTest, HttpPostFailure) { TEST_F(WidevineKeySourceTest, HttpPostFailure) {
std::string expected_message = base::StringPrintf( std::string expected_message = base::StringPrintf(
kExpectedRequestMessageFormat, Base64Encode(kContentId).c_str(), kPolicy); kExpectedRequestMessageFormat, Base64Encode(kContentId).c_str(), kPolicy);
EXPECT_CALL(*mock_request_signer_, GenerateSignature(expected_message, _)) 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, _)) EXPECT_CALL(*mock_http_fetcher_, Post(kServerUrl, expected_post_data, _))
.WillOnce(Return(kMockStatus)); .WillOnce(Return(kMockStatus));
CreateWidevineEncryptionKeySource(); CreateWidevineKeySource();
ASSERT_EQ(kMockStatus, 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(_, _)) EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(true)); .WillOnce(Return(true));
@ -216,12 +240,63 @@ TEST_F(WidevineEncryptionKeySourceTest, LicenseStatusOK) {
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _)) EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
CreateWidevineEncryptionKeySource(); CreateWidevineKeySource();
ASSERT_OK(widevine_encryption_key_source_->Initialize()); ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
VerifyKeys(); 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(_, _)) EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(true)); .WillOnce(Return(true));
@ -233,12 +308,12 @@ TEST_F(WidevineEncryptionKeySourceTest, RetryOnHttpTimeout) {
.WillOnce(Return(Status(error::TIME_OUT, ""))) .WillOnce(Return(Status(error::TIME_OUT, "")))
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
CreateWidevineEncryptionKeySource(); CreateWidevineKeySource();
ASSERT_OK(widevine_encryption_key_source_->Initialize()); ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
VerifyKeys(); VerifyKeys(false);
} }
TEST_F(WidevineEncryptionKeySourceTest, RetryOnTransientError) { TEST_F(WidevineKeySourceTest, RetryOnTransientError) {
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(true)); .WillOnce(Return(true));
@ -256,12 +331,12 @@ TEST_F(WidevineEncryptionKeySourceTest, RetryOnTransientError) {
.WillOnce(DoAll(SetArgPointee<2>(expected_retried_response), .WillOnce(DoAll(SetArgPointee<2>(expected_retried_response),
Return(Status::OK))); Return(Status::OK)));
CreateWidevineEncryptionKeySource(); CreateWidevineKeySource();
ASSERT_OK(widevine_encryption_key_source_->Initialize()); ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
VerifyKeys(); VerifyKeys(false);
} }
TEST_F(WidevineEncryptionKeySourceTest, NoRetryOnUnknownError) { TEST_F(WidevineKeySourceTest, NoRetryOnUnknownError) {
EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _)) EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(true)); .WillOnce(Return(true));
@ -273,9 +348,9 @@ TEST_F(WidevineEncryptionKeySourceTest, NoRetryOnUnknownError) {
EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _)) EXPECT_CALL(*mock_http_fetcher_, Post(_, _, _))
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
CreateWidevineEncryptionKeySource(); CreateWidevineKeySource();
ASSERT_EQ(error::SERVER_ERROR, ASSERT_EQ(error::SERVER_ERROR,
widevine_encryption_key_source_->Initialize().error_code()); widevine_key_source_->FetchKeys(content_id_, kPolicy).error_code());
} }
namespace { namespace {
@ -316,7 +391,7 @@ std::string GenerateMockKeyRotationLicenseResponse(
} // namespace } // namespace
TEST_F(WidevineEncryptionKeySourceTest, KeyRotationTest) { TEST_F(WidevineKeySourceTest, KeyRotationTest) {
const uint32 kFirstCryptoPeriodIndex = 8; const uint32 kFirstCryptoPeriodIndex = 8;
const uint32 kCryptoPeriodCount = 10; const uint32 kCryptoPeriodCount = 10;
// Array of indexes to be checked. // Array of indexes to be checked.
@ -328,7 +403,7 @@ TEST_F(WidevineEncryptionKeySourceTest, KeyRotationTest) {
// Generate expectations in sequence. // Generate expectations in sequence.
InSequence dummy; 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(_, _)) EXPECT_CALL(*mock_request_signer_, GenerateSignature(_, _))
.WillOnce(Return(true)); .WillOnce(Return(true));
std::string mock_response = base::StringPrintf( std::string mock_response = base::StringPrintf(
@ -357,16 +432,16 @@ TEST_F(WidevineEncryptionKeySourceTest, KeyRotationTest) {
.WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<2>(mock_response), Return(Status::OK)));
} }
CreateWidevineEncryptionKeySource(); CreateWidevineKeySource();
ASSERT_OK(widevine_encryption_key_source_->Initialize()); ASSERT_OK(widevine_key_source_->FetchKeys(content_id_, kPolicy));
EncryptionKey encryption_key; EncryptionKey encryption_key;
for (size_t i = 0; i < arraysize(kCryptoPeriodIndexes); ++i) { for (size_t i = 0; i < arraysize(kCryptoPeriodIndexes); ++i) {
const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"}; const std::string kTrackTypes[] = {"SD", "HD", "AUDIO"};
for (size_t j = 0; j < 3; ++j) { for (size_t j = 0; j < 3; ++j) {
ASSERT_OK(widevine_encryption_key_source_->GetCryptoPeriodKey( ASSERT_OK(widevine_key_source_->GetCryptoPeriodKey(
kCryptoPeriodIndexes[i], kCryptoPeriodIndexes[i],
EncryptionKeySource::GetTrackTypeFromString(kTrackTypes[j]), KeySource::GetTrackTypeFromString(kTrackTypes[j]),
&encryption_key)); &encryption_key));
EXPECT_EQ(GetMockKey(kTrackTypes[j], kCryptoPeriodIndexes[i]), EXPECT_EQ(GetMockKey(kTrackTypes[j], kCryptoPeriodIndexes[i]),
ToString(encryption_key.key)); ToString(encryption_key.key));
@ -374,9 +449,9 @@ TEST_F(WidevineEncryptionKeySourceTest, KeyRotationTest) {
} }
// The old crypto period indexes should have been garbage collected. // The old crypto period indexes should have been garbage collected.
Status status = widevine_encryption_key_source_->GetCryptoPeriodKey( Status status = widevine_key_source_->GetCryptoPeriodKey(
kFirstCryptoPeriodIndex, kFirstCryptoPeriodIndex,
EncryptionKeySource::TRACK_TYPE_SD, KeySource::TRACK_TYPE_SD,
&encryption_key); &encryption_key);
EXPECT_EQ(error::INVALID_ARGUMENT, status.error_code()); EXPECT_EQ(error::INVALID_ARGUMENT, status.error_code());
} }

View File

@ -8,7 +8,7 @@
#include "media/base/aes_encryptor.h" #include "media/base/aes_encryptor.h"
#include "media/base/buffer_reader.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/base/media_sample.h"
#include "media/formats/mp4/box_definitions.h" #include "media/formats/mp4/box_definitions.h"
#include "media/formats/mp4/cenc.h" #include "media/formats/mp4/cenc.h"

View File

@ -15,8 +15,8 @@ namespace mp4 {
KeyRotationFragmenter::KeyRotationFragmenter( KeyRotationFragmenter::KeyRotationFragmenter(
MovieFragment* moof, MovieFragment* moof,
TrackFragment* traf, TrackFragment* traf,
EncryptionKeySource* encryption_key_source, KeySource* encryption_key_source,
EncryptionKeySource::TrackType track_type, KeySource::TrackType track_type,
int64 crypto_period_duration, int64 crypto_period_duration,
int64 clear_time, int64 clear_time,
uint8 nalu_length_size) uint8 nalu_length_size)

View File

@ -7,7 +7,7 @@
#ifndef MEDIA_FORMATS_MP4_KEY_ROTATION_FRAGMENTER_H_ #ifndef MEDIA_FORMATS_MP4_KEY_ROTATION_FRAGMENTER_H_
#define 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" #include "media/formats/mp4/encrypting_fragmenter.h"
namespace media { namespace media {
@ -33,8 +33,8 @@ class KeyRotationFragmenter : public EncryptingFragmenter {
/// encryption. /// encryption.
KeyRotationFragmenter(MovieFragment* moof, KeyRotationFragmenter(MovieFragment* moof,
TrackFragment* traf, TrackFragment* traf,
EncryptionKeySource* encryption_key_source, KeySource* encryption_key_source,
EncryptionKeySource::TrackType track_type, KeySource::TrackType track_type,
int64 crypto_period_duration, int64 crypto_period_duration,
int64 clear_time, int64 clear_time,
uint8 nalu_length_size); uint8 nalu_length_size);
@ -50,8 +50,8 @@ class KeyRotationFragmenter : public EncryptingFragmenter {
private: private:
MovieFragment* moof_; MovieFragment* moof_;
EncryptionKeySource* encryption_key_source_; KeySource* encryption_key_source_;
EncryptionKeySource::TrackType track_type_; KeySource::TrackType track_type_;
const int64 crypto_period_duration_; const int64 crypto_period_duration_;
size_t prev_crypto_period_index_; size_t prev_crypto_period_index_;

View File

@ -10,7 +10,7 @@
#include "base/time/time.h" #include "base/time/time.h"
#include "media/base/aes_encryptor.h" #include "media/base/aes_encryptor.h"
#include "media/base/audio_stream_info.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_sample.h"
#include "media/base/media_stream.h" #include "media/base/media_stream.h"
#include "media/base/video_stream_info.h" #include "media/base/video_stream_info.h"

View File

@ -10,7 +10,7 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "media/base/buffer_writer.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_sample.h"
#include "media/base/media_stream.h" #include "media/base/media_stream.h"
#include "media/base/muxer_options.h" #include "media/base/muxer_options.h"
@ -94,17 +94,17 @@ uint8 GetNaluLengthSize(const StreamInfo& stream_info) {
return video_stream_info.nalu_length_size(); return video_stream_info.nalu_length_size();
} }
EncryptionKeySource::TrackType GetTrackTypeForEncryption( KeySource::TrackType GetTrackTypeForEncryption(
const StreamInfo& stream_info, uint32 max_sd_pixels) { const StreamInfo& stream_info, uint32 max_sd_pixels) {
if (stream_info.stream_type() == kStreamAudio) if (stream_info.stream_type() == kStreamAudio)
return EncryptionKeySource::TRACK_TYPE_AUDIO; return KeySource::TRACK_TYPE_AUDIO;
DCHECK_EQ(kStreamVideo, stream_info.stream_type()); DCHECK_EQ(kStreamVideo, stream_info.stream_type());
const VideoStreamInfo& video_stream_info = const VideoStreamInfo& video_stream_info =
static_cast<const VideoStreamInfo&>(stream_info); static_cast<const VideoStreamInfo&>(stream_info);
uint32 pixels = video_stream_info.width() * video_stream_info.height(); uint32 pixels = video_stream_info.width() * video_stream_info.height();
return (pixels > max_sd_pixels) ? EncryptionKeySource::TRACK_TYPE_HD return (pixels > max_sd_pixels) ? KeySource::TRACK_TYPE_HD
: EncryptionKeySource::TRACK_TYPE_SD; : KeySource::TRACK_TYPE_SD;
} }
} // namespace } // namespace
@ -126,7 +126,7 @@ Segmenter::~Segmenter() { STLDeleteElements(&fragmenters_); }
Status Segmenter::Initialize(const std::vector<MediaStream*>& streams, Status Segmenter::Initialize(const std::vector<MediaStream*>& streams,
event::MuxerListener* muxer_listener, event::MuxerListener* muxer_listener,
EncryptionKeySource* encryption_key_source, KeySource* encryption_key_source,
uint32 max_sd_pixels, uint32 max_sd_pixels,
double clear_lead_in_seconds, double clear_lead_in_seconds,
double crypto_period_duration_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()); uint8 nalu_length_size = GetNaluLengthSize(*streams[i]->info());
EncryptionKeySource::TrackType track_type = KeySource::TrackType track_type =
GetTrackTypeForEncryption(*streams[i]->info(), max_sd_pixels); GetTrackTypeForEncryption(*streams[i]->info(), max_sd_pixels);
SampleDescription& description = SampleDescription& description =
moov_->tracks[i].media.information.sample_table.description; moov_->tracks[i].media.information.sample_table.description;

View File

@ -19,7 +19,7 @@ namespace media {
struct MuxerOptions; struct MuxerOptions;
class BufferWriter; class BufferWriter;
class EncryptionKeySource; class KeySource;
class MediaSample; class MediaSample;
class MediaStream; class MediaStream;
@ -64,7 +64,7 @@ class Segmenter {
/// @return OK on success, an error status otherwise. /// @return OK on success, an error status otherwise.
Status Initialize(const std::vector<MediaStream*>& streams, Status Initialize(const std::vector<MediaStream*>& streams,
event::MuxerListener* muxer_listener, event::MuxerListener* muxer_listener,
EncryptionKeySource* encryption_key_source, KeySource* encryption_key_source,
uint32 max_sd_pixels, uint32 max_sd_pixels,
double clear_lead_in_seconds, double clear_lead_in_seconds,
double crypto_period_duration_in_seconds); double crypto_period_duration_in_seconds);

View File

@ -11,7 +11,7 @@
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/time/clock.h" #include "base/time/clock.h"
#include "media/base/demuxer.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/media_stream.h"
#include "media/base/muxer.h" #include "media/base/muxer.h"
#include "media/base/status_test_util.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_); Demuxer demuxer(GetFullPath(input), decryptor_source_);
ASSERT_OK(demuxer.Initialize()); ASSERT_OK(demuxer.Initialize());
scoped_ptr<EncryptionKeySource> encryption_key_source( scoped_ptr<KeySource> encryption_key_source(
EncryptionKeySource::CreateFromHexStrings( KeySource::CreateFromHexStrings(
kKeyIdHex, kKeyHex, kPsshHex, "")); kKeyIdHex, kKeyHex, kPsshHex, ""));
DCHECK(encryption_key_source); DCHECK(encryption_key_source);
@ -165,8 +165,8 @@ void PackagerTestBasic::Remux(const std::string& input,
muxer_video->AddStream(FindFirstVideoStream(demuxer.streams())); muxer_video->AddStream(FindFirstVideoStream(demuxer.streams()));
if (enable_encryption) { if (enable_encryption) {
muxer_video->SetEncryptionKeySource(encryption_key_source.get(), muxer_video->SetKeySource(encryption_key_source.get(),
EncryptionKeySource::TRACK_TYPE_SD, KeySource::TRACK_TYPE_SD,
kClearLeadInSeconds, kClearLeadInSeconds,
kCryptoDurationInSeconds); kCryptoDurationInSeconds);
} }
@ -181,8 +181,8 @@ void PackagerTestBasic::Remux(const std::string& input,
muxer_audio->AddStream(FindFirstAudioStream(demuxer.streams())); muxer_audio->AddStream(FindFirstAudioStream(demuxer.streams()));
if (enable_encryption) { if (enable_encryption) {
muxer_audio->SetEncryptionKeySource(encryption_key_source.get(), muxer_audio->SetKeySource(encryption_key_source.get(),
EncryptionKeySource::TRACK_TYPE_SD, KeySource::TRACK_TYPE_SD,
kClearLeadInSeconds, kClearLeadInSeconds,
kCryptoDurationInSeconds); kCryptoDurationInSeconds);
} }