Refactor KeySource::FetchKeys to use EME init data types

Change-Id: I517ea992a8868d7382988a8837f4f05df9f974d7
This commit is contained in:
Kongqun Yang 2017-04-04 12:43:41 -07:00 committed by KongQun Yang
parent 9d101f85e3
commit fb0790e1d5
14 changed files with 151 additions and 158 deletions

View File

@ -15,18 +15,8 @@ namespace media {
FixedKeySource::~FixedKeySource() {} FixedKeySource::~FixedKeySource() {}
Status FixedKeySource::FetchKeys(const std::vector<uint8_t>& pssh_box) { Status FixedKeySource::FetchKeys(EmeInitDataType init_data_type,
// Do nothing for fixed key encryption/decryption. const std::vector<uint8_t>& init_data) {
return Status::OK;
}
Status FixedKeySource::FetchKeys(
const std::vector<std::vector<uint8_t>>& key_ids) {
// Do nothing for fixed key encryption/decryption.
return Status::OK;
}
Status FixedKeySource::FetchKeys(uint32_t asset_id) {
// Do nothing for fixed key encryption/decryption. // Do nothing for fixed key encryption/decryption.
return Status::OK; return Status::OK;
} }

View File

@ -30,10 +30,8 @@ class FixedKeySource : public KeySource {
/// @name KeySource implementation overrides. /// @name KeySource implementation overrides.
/// @{ /// @{
Status FetchKeys(const std::vector<uint8_t>& pssh_box) override; Status FetchKeys(EmeInitDataType init_data_type,
Status FetchKeys(const std::vector<std::vector<uint8_t>>& key_ids) override; const std::vector<uint8_t>& init_data) override;
Status FetchKeys(uint32_t asset_id) override;
Status GetKey(TrackType track_type, EncryptionKey* key) override; Status GetKey(TrackType track_type, EncryptionKey* key) override;
Status GetKey(const std::vector<uint8_t>& key_id, Status GetKey(const std::vector<uint8_t>& key_id,
EncryptionKey* key) override; EncryptionKey* key) override;

View File

@ -16,6 +16,21 @@
namespace shaka { namespace shaka {
namespace media { namespace media {
/// Encrypted media init data types. It is extended from:
/// https://www.w3.org/TR/eme-initdata-registry/#registry.
enum class EmeInitDataType {
UNKNOWN,
/// One or multiple PSSH boxes.
CENC,
/// WebM init data is basically KeyId.
WEBM,
/// JSON formatted key ids.
KEYIDS,
/// Widevine classic asset id.
WIDEVINE_CLASSIC,
MAX = WIDEVINE_CLASSIC
};
struct EncryptionKey { struct EncryptionKey {
EncryptionKey(); EncryptionKey();
~EncryptionKey(); ~EncryptionKey();
@ -43,22 +58,12 @@ class KeySource {
KeySource(); KeySource();
virtual ~KeySource(); virtual ~KeySource();
/// Fetch keys for CENC from the key server. /// Fetch keys based on the specified encrypted media init data.
/// @param pssh_box The entire PSSH box for the content to be decrypted /// @param init_data_type specifies the encrypted media init data type.
/// @param init_data contains the init data.
/// @return OK on success, an error status otherwise. /// @return OK on success, an error status otherwise.
virtual Status FetchKeys(const std::vector<uint8_t>& pssh_box) = 0; virtual Status FetchKeys(EmeInitDataType init_data_type,
const std::vector<uint8_t>& init_data) = 0;
/// Fetch keys for CENC from the key server.
/// @param key_ids the key IDs for the keys to fetch from the server.
/// @return OK on success, an error status otherwise.
virtual Status FetchKeys(
const std::vector<std::vector<uint8_t>>& key_ids) = 0;
/// Fetch keys for WVM decryption from the key server.
/// @param asset_id is the Widevine Classic asset ID for the content to be
/// decrypted.
/// @return OK on success, an error status otherwise.
virtual Status FetchKeys(uint32_t asset_id) = 0;
/// 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 track_type is the type of track for which retrieving the key.

View File

@ -310,19 +310,9 @@ Status PlayReadyKeySource::FetchKeysWithProgramIdentifier(
return Status::OK; return Status::OK;
} }
Status PlayReadyKeySource::FetchKeys(const std::vector<uint8_t>& pssh_box) { Status PlayReadyKeySource::FetchKeys(EmeInitDataType init_data_type,
// Does nothing for playready encryption/decryption. const std::vector<uint8_t>& init_data) {
return Status::OK; // Do nothing for playready encryption/decryption.
}
Status PlayReadyKeySource::FetchKeys(
const std::vector<std::vector<uint8_t>>& key_ids) {
// Does nothing for playready encryption/decryption.
return Status::OK;
}
Status PlayReadyKeySource::FetchKeys(uint32_t asset_id) {
// Does nothing for playready encryption/decryption.
return Status::OK; return Status::OK;
} }

View File

@ -40,10 +40,8 @@ class PlayReadyKeySource : public KeySource {
/// @name KeySource implementation overrides. /// @name KeySource implementation overrides.
/// @{ /// @{
Status FetchKeys(const std::vector<uint8_t>& pssh_box) override; Status FetchKeys(EmeInitDataType init_data_type,
Status FetchKeys(const std::vector<std::vector<uint8_t>>& key_ids) override; const std::vector<uint8_t>& init_data) override;
Status FetchKeys(uint32_t asset_id) override;
Status GetKey(TrackType track_type, EncryptionKey* key) override; Status GetKey(TrackType track_type, EncryptionKey* key) override;
Status GetKey(const std::vector<uint8_t>& key_id, Status GetKey(const std::vector<uint8_t>& key_id,
EncryptionKey* key) override; EncryptionKey* key) override;

View File

@ -14,6 +14,7 @@
#include "packager/base/json/json_writer.h" #include "packager/base/json/json_writer.h"
#include "packager/media/base/fixed_key_source.h" #include "packager/media/base/fixed_key_source.h"
#include "packager/media/base/http_key_fetcher.h" #include "packager/media/base/http_key_fetcher.h"
#include "packager/media/base/network_util.h"
#include "packager/media/base/producer_consumer_queue.h" #include "packager/media/base/producer_consumer_queue.h"
#include "packager/media/base/protection_system_specific_info.h" #include "packager/media/base/protection_system_specific_info.h"
#include "packager/media/base/rcheck.h" #include "packager/media/base/rcheck.h"
@ -41,6 +42,18 @@ const int kDefaultCryptoPeriodCount = 10;
const int kGetKeyTimeoutInSeconds = 5 * 60; // 5 minutes. const int kGetKeyTimeoutInSeconds = 5 * 60; // 5 minutes.
const int kKeyFetchTimeoutInSeconds = 60; // 1 minute. const int kKeyFetchTimeoutInSeconds = 60; // 1 minute.
std::vector<uint8_t> StringToBytes(const std::string& string) {
return std::vector<uint8_t>(string.begin(), string.end());
}
std::vector<uint8_t> WidevinePsshFromKeyId(
const std::vector<std::vector<uint8_t>>& key_ids) {
media::WidevinePsshData widevine_pssh_data;
for (const std::vector<uint8_t>& key_id : key_ids)
widevine_pssh_data.add_key_id(key_id.data(), key_id.size());
return StringToBytes(widevine_pssh_data.SerializeAsString());
}
bool Base64StringToBytes(const std::string& base64_string, bool Base64StringToBytes(const std::string& base64_string,
std::vector<uint8_t>* bytes) { std::vector<uint8_t>* bytes) {
DCHECK(bytes); DCHECK(bytes);
@ -147,61 +160,63 @@ Status WidevineKeySource::FetchKeys(const std::vector<uint8_t>& content_id,
return FetchKeysInternal(!kEnableKeyRotation, 0, false); return FetchKeysInternal(!kEnableKeyRotation, 0, false);
} }
Status WidevineKeySource::FetchKeys(const std::vector<uint8_t>& pssh_box) { Status WidevineKeySource::FetchKeys(EmeInitDataType init_data_type,
const std::vector<uint8_t> widevine_system_id( const std::vector<uint8_t>& init_data) {
kWidevineSystemId, kWidevineSystemId + arraysize(kWidevineSystemId)); std::vector<uint8_t> pssh_data;
uint32_t asset_id = 0;
ProtectionSystemSpecificInfo info; switch (init_data_type) {
if (!info.Parse(pssh_box.data(), pssh_box.size())) case EmeInitDataType::CENC: {
return Status(error::PARSER_FAILURE, "Error parsing the PSSH box."); const std::vector<uint8_t> widevine_system_id(
kWidevineSystemId, kWidevineSystemId + arraysize(kWidevineSystemId));
if (info.system_id() == widevine_system_id) { std::vector<ProtectionSystemSpecificInfo> protection_systems_info;
base::AutoLock scoped_lock(lock_); if (!ProtectionSystemSpecificInfo::ParseBoxes(
request_dict_.Clear(); init_data.data(), init_data.size(), &protection_systems_info)) {
std::string pssh_data_base64_string; return Status(error::PARSER_FAILURE, "Error parsing the PSSH boxes.");
}
BytesToBase64String(info.pssh_data(), &pssh_data_base64_string); for (const auto& info: protection_systems_info) {
request_dict_.SetString("pssh_data", pssh_data_base64_string); // Use Widevine PSSH if available otherwise construct a Widevine PSSH
return FetchKeysInternal(!kEnableKeyRotation, 0, false); // from the first available key ids.
} else if (!info.key_ids().empty()) { if (info.system_id() == widevine_system_id) {
// This is not a Widevine PSSH box. Try making the request for the key-IDs. pssh_data = info.pssh_data();
// Even if this is a different key-system, it should still work. Either break;
// the server will not recognize it and return an error, or it will } else if (pssh_data.empty() && !info.key_ids().empty()) {
// recognize it and the key must be correct (or the content is bad). pssh_data = WidevinePsshFromKeyId(info.key_ids());
return FetchKeys(info.key_ids()); // Continue to see if there is any Widevine PSSH. The KeyId generated
// PSSH is only used if a Widevine PSSH could not be found.
continue;
}
}
if (pssh_data.empty())
return Status(error::INVALID_ARGUMENT, "No supported PSSHs found.");
break;
}
case EmeInitDataType::WEBM:
pssh_data = WidevinePsshFromKeyId({init_data});
break;
case EmeInitDataType::WIDEVINE_CLASSIC:
if (init_data.size() < sizeof(asset_id))
return Status(error::INVALID_ARGUMENT, "Invalid asset id.");
asset_id = ntohlFromBuffer(init_data.data());
break;
default:
LOG(ERROR) << "Init data type " << static_cast<int>(init_data_type)
<< " not supported.";
return Status(error::INVALID_ARGUMENT, "Unsupported init data type.");
}
const bool widevine_classic =
init_data_type == EmeInitDataType::WIDEVINE_CLASSIC;
base::AutoLock scoped_lock(lock_);
request_dict_.Clear();
if (widevine_classic) {
// Javascript/JSON does not support int64_t or unsigned numbers. Use double
// instead as 32-bit integer can be lossless represented using double.
request_dict_.SetDouble("asset_id", asset_id);
} else { } else {
return Status(error::NOT_FOUND, "No key IDs given in PSSH box."); std::string pssh_data_base64_string;
BytesToBase64String(pssh_data, &pssh_data_base64_string);
request_dict_.SetString("pssh_data", pssh_data_base64_string);
} }
} return FetchKeysInternal(!kEnableKeyRotation, 0, widevine_classic);
Status WidevineKeySource::FetchKeys(
const std::vector<std::vector<uint8_t>>& key_ids) {
base::AutoLock scoped_lock(lock_);
request_dict_.Clear();
std::string pssh_data_base64_string;
// Generate Widevine PSSH data from the key-IDs.
WidevinePsshData widevine_pssh_data;
for (size_t i = 0; i < key_ids.size(); i++) {
widevine_pssh_data.add_key_id(key_ids[i].data(), key_ids[i].size());
}
const std::string serialized_string = widevine_pssh_data.SerializeAsString();
std::vector<uint8_t> pssh_data(serialized_string.begin(),
serialized_string.end());
BytesToBase64String(pssh_data, &pssh_data_base64_string);
request_dict_.SetString("pssh_data", pssh_data_base64_string);
return FetchKeysInternal(!kEnableKeyRotation, 0, false);
}
Status WidevineKeySource::FetchKeys(uint32_t asset_id) {
base::AutoLock scoped_lock(lock_);
request_dict_.Clear();
// Javascript/JSON does not support int64_t or unsigned numbers. Use double
// instead as 32-bit integer can be lossless represented using double.
request_dict_.SetDouble("asset_id", asset_id);
return FetchKeysInternal(!kEnableKeyRotation, 0, true);
} }
Status WidevineKeySource::GetKey(TrackType track_type, EncryptionKey* key) { Status WidevineKeySource::GetKey(TrackType track_type, EncryptionKey* key) {
@ -566,7 +581,9 @@ bool WidevineKeySource::ExtractEncryptionKey(
DCHECK(!encryption_key_map.empty()); DCHECK(!encryption_key_map.empty());
if (!enable_key_rotation) { if (!enable_key_rotation) {
encryption_key_map_.swap(encryption_key_map); // Merge with previously requested keys.
for (auto& pair : encryption_key_map)
encryption_key_map_[pair.first] = std::move(pair.second);
return true; return true;
} }
return PushToKeyPool(&encryption_key_map); return PushToKeyPool(&encryption_key_map);

View File

@ -36,10 +36,8 @@ class WidevineKeySource : public KeySource {
/// @name KeySource implementation overrides. /// @name KeySource implementation overrides.
/// @{ /// @{
Status FetchKeys(const std::vector<uint8_t>& pssh_box) override; Status FetchKeys(EmeInitDataType init_data_type,
Status FetchKeys(const std::vector<std::vector<uint8_t>>& key_ids) override; const std::vector<uint8_t>& init_data) override;
Status FetchKeys(uint32_t asset_id) override;
Status GetKey(TrackType track_type, EncryptionKey* key) override; Status GetKey(TrackType track_type, EncryptionKey* key) override;
Status GetKey(const std::vector<uint8_t>& key_id, Status GetKey(const std::vector<uint8_t>& key_id,
EncryptionKey* key) override; EncryptionKey* key) override;

View File

@ -75,6 +75,7 @@ const uint8_t kRequestKeyId[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05};
// 32-bit with leading bit set, to verify that big uint32_t can be handled // 32-bit with leading bit set, to verify that big uint32_t can be handled
// correctly. // correctly.
const uint32_t kClassicAssetId = 0x80038cd9; const uint32_t kClassicAssetId = 0x80038cd9;
const uint8_t kClassicAssetIdBytes[] = {0x80, 0x03, 0x8c, 0xd9};
std::string Base64Encode(const std::string& input) { std::string Base64Encode(const std::string& input) {
std::string output; std::string output;
@ -319,11 +320,11 @@ TEST_P(WidevineKeySourceTest, LicenseStatusCencWithPsshBoxOK) {
widevine_key_source_->set_signer(std::move(mock_request_signer_)); widevine_key_source_->set_signer(std::move(mock_request_signer_));
std::vector<uint8_t> pssh_box(kRequestPsshBox, std::vector<uint8_t> pssh_box(kRequestPsshBox,
kRequestPsshBox + arraysize(kRequestPsshBox)); kRequestPsshBox + arraysize(kRequestPsshBox));
ASSERT_OK(widevine_key_source_->FetchKeys(pssh_box)); ASSERT_OK(widevine_key_source_->FetchKeys(EmeInitDataType::CENC, pssh_box));
VerifyKeys(false); VerifyKeys(false);
} }
TEST_P(WidevineKeySourceTest, LicenseStatusCencWithKeyIdsOK) { TEST_P(WidevineKeySourceTest, LicenseStatusCencWithKeyIdOK) {
std::string expected_pssh_data( std::string expected_pssh_data(
kRequestPsshDataFromKeyIds, kRequestPsshDataFromKeyIds,
kRequestPsshDataFromKeyIds + arraysize(kRequestPsshDataFromKeyIds)); kRequestPsshDataFromKeyIds + arraysize(kRequestPsshDataFromKeyIds));
@ -341,10 +342,9 @@ TEST_P(WidevineKeySourceTest, LicenseStatusCencWithKeyIdsOK) {
CreateWidevineKeySource(); CreateWidevineKeySource();
widevine_key_source_->set_signer(std::move(mock_request_signer_)); widevine_key_source_->set_signer(std::move(mock_request_signer_));
std::vector<std::vector<uint8_t>> key_ids; std::vector<uint8_t> key_id(kRequestKeyId,
key_ids.push_back(std::vector<uint8_t>( kRequestKeyId + arraysize(kRequestKeyId));
kRequestKeyId, kRequestKeyId + arraysize(kRequestKeyId))); ASSERT_OK(widevine_key_source_->FetchKeys(EmeInitDataType::WEBM, key_id));
ASSERT_OK(widevine_key_source_->FetchKeys(key_ids));
VerifyKeys(false); VerifyKeys(false);
} }
@ -363,7 +363,10 @@ TEST_P(WidevineKeySourceTest, LicenseStatusClassicOK) {
CreateWidevineKeySource(); CreateWidevineKeySource();
widevine_key_source_->set_signer(std::move(mock_request_signer_)); widevine_key_source_->set_signer(std::move(mock_request_signer_));
ASSERT_OK(widevine_key_source_->FetchKeys(kClassicAssetId)); ASSERT_OK(widevine_key_source_->FetchKeys(
EmeInitDataType::WIDEVINE_CLASSIC,
std::vector<uint8_t>(std::begin(kClassicAssetIdBytes),
std::end(kClassicAssetIdBytes))));
VerifyKeys(true); VerifyKeys(true);
} }

View File

@ -640,27 +640,18 @@ bool MP4MediaParser::FetchKeysIfNecessary(
if (!decryption_key_source_) if (!decryption_key_source_)
return true; return true;
Status status; std::vector<uint8_t> pssh_raw_data;
for (std::vector<ProtectionSystemSpecificHeader>::const_iterator iter = for (const auto& header : headers) {
headers.begin(); iter != headers.end(); ++iter) { pssh_raw_data.insert(pssh_raw_data.end(), header.raw_box.begin(),
status = decryption_key_source_->FetchKeys(iter->raw_box); header.raw_box.end());
if (!status.ok()) {
// If there is an error, try using the next PSSH box and report if none
// work.
VLOG(1) << "Unable to fetch decryption keys: " << status
<< ", trying the next PSSH box";
continue;
}
return true;
} }
Status status =
decryption_key_source_->FetchKeys(EmeInitDataType::CENC, pssh_raw_data);
if (!status.ok()) { if (!status.ok()) {
LOG(ERROR) << "Error fetching decryption keys: " << status; LOG(ERROR) << "Error fetching decryption keys: " << status;
return false; return false;
} }
return true;
LOG(ERROR) << "No viable 'pssh' box found for content decryption.";
return false;
} }
bool MP4MediaParser::EnqueueSample(bool* err) { bool MP4MediaParser::EnqueueSample(bool* err) {

View File

@ -31,7 +31,9 @@ const char kKeyId[] = "0123456789012345";
class MockKeySource : public FixedKeySource { class MockKeySource : public FixedKeySource {
public: public:
MOCK_METHOD1(FetchKeys, Status(const std::vector<uint8_t>& pssh_data)); MOCK_METHOD2(FetchKeys,
Status(EmeInitDataType init_data_type,
const std::vector<uint8_t>& init_data));
MOCK_METHOD2(GetKey, MOCK_METHOD2(GetKey,
Status(const std::vector<uint8_t>& key_id, EncryptionKey* key)); Status(const std::vector<uint8_t>& key_id, EncryptionKey* key));
}; };
@ -247,7 +249,7 @@ TEST_F(MP4MediaParserTest, CencInitWithoutDecryptionSource) {
TEST_F(MP4MediaParserTest, CencWithDecryptionSourceAndAuxInMdat) { TEST_F(MP4MediaParserTest, CencWithDecryptionSourceAndAuxInMdat) {
MockKeySource mock_key_source; MockKeySource mock_key_source;
EXPECT_CALL(mock_key_source, FetchKeys(_)).WillOnce(Return(Status::OK)); EXPECT_CALL(mock_key_source, FetchKeys(_, _)).WillOnce(Return(Status::OK));
EncryptionKey encryption_key; EncryptionKey encryption_key;
encryption_key.key.assign(kKey, kKey + strlen(kKey)); encryption_key.key.assign(kKey, kKey + strlen(kKey));
@ -266,7 +268,7 @@ TEST_F(MP4MediaParserTest, CencWithDecryptionSourceAndAuxInMdat) {
TEST_F(MP4MediaParserTest, CencWithDecryptionSourceAndSenc) { TEST_F(MP4MediaParserTest, CencWithDecryptionSourceAndSenc) {
MockKeySource mock_key_source; MockKeySource mock_key_source;
EXPECT_CALL(mock_key_source, FetchKeys(_)).WillOnce(Return(Status::OK)); EXPECT_CALL(mock_key_source, FetchKeys(_, _)).WillOnce(Return(Status::OK));
EncryptionKey encryption_key; EncryptionKey encryption_key;
encryption_key.key.assign(kKey, kKey + strlen(kKey)); encryption_key.key.assign(kKey, kKey + strlen(kKey));

View File

@ -242,17 +242,19 @@ bool WebMMediaParser::FetchKeysIfNecessary(
if (!decryption_key_source_) if (!decryption_key_source_)
return true; return true;
std::vector<std::vector<uint8_t>> key_ids; Status status;
if (!audio_encryption_key_id.empty()) { if (!audio_encryption_key_id.empty()) {
key_ids.push_back(std::vector<uint8_t>(audio_encryption_key_id.begin(), status.Update(decryption_key_source_->FetchKeys(
audio_encryption_key_id.end())); EmeInitDataType::WEBM,
std::vector<uint8_t>(audio_encryption_key_id.begin(),
audio_encryption_key_id.end())));
} }
if (!video_encryption_key_id.empty()) { if (!video_encryption_key_id.empty()) {
key_ids.push_back(std::vector<uint8_t>(video_encryption_key_id.begin(), status.Update(decryption_key_source_->FetchKeys(
video_encryption_key_id.end())); EmeInitDataType::WEBM,
std::vector<uint8_t>(video_encryption_key_id.begin(),
video_encryption_key_id.end())));
} }
Status status = decryption_key_source_->FetchKeys(key_ids);
if (!status.ok()) { if (!status.ok()) {
LOG(ERROR) << "Error fetching decryption keys: " << status; LOG(ERROR) << "Error fetching decryption keys: " << status;
return false; return false;

View File

@ -1058,21 +1058,23 @@ bool WvmMediaParser::EmitSample(uint32_t parsed_audio_or_video_stream_id,
return true; return true;
} }
bool WvmMediaParser::GetAssetKey(const uint32_t asset_id, bool WvmMediaParser::GetAssetKey(const uint8_t* asset_id,
EncryptionKey* encryption_key) { EncryptionKey* encryption_key) {
DCHECK(decryption_key_source_); DCHECK(decryption_key_source_);
Status status = decryption_key_source_->FetchKeys(asset_id); Status status = decryption_key_source_->FetchKeys(
EmeInitDataType::WIDEVINE_CLASSIC,
std::vector<uint8_t>(asset_id, asset_id + sizeof(uint32_t)));
if (!status.ok()) { if (!status.ok()) {
LOG(ERROR) << "Fetch Key(s) failed for AssetID = " << asset_id LOG(ERROR) << "Fetch Key(s) failed for AssetID = "
<< ", error = " << status; << ntohlFromBuffer(asset_id) << ", error = " << status;
return false; return false;
} }
status = decryption_key_source_->GetKey(KeySource::TRACK_TYPE_HD, status = decryption_key_source_->GetKey(KeySource::TRACK_TYPE_HD,
encryption_key); encryption_key);
if (!status.ok()) { if (!status.ok()) {
LOG(ERROR) << "Fetch Key(s) failed for AssetID = " << asset_id LOG(ERROR) << "Fetch Key(s) failed for AssetID = "
<< ", error = " << status; << ntohlFromBuffer(asset_id) << ", error = " << status;
return false; return false;
} }
@ -1097,22 +1099,17 @@ bool WvmMediaParser::ProcessEcm() {
ecm_data += sizeof(uint32_t); // old version field - skip. ecm_data += sizeof(uint32_t); // old version field - skip.
ecm_data += sizeof(uint32_t); // clear lead - skip. ecm_data += sizeof(uint32_t); // clear lead - skip.
ecm_data += sizeof(uint32_t); // system id(includes ECM version) - skip. ecm_data += sizeof(uint32_t); // system id(includes ECM version) - skip.
uint32_t asset_id = ntohlFromBuffer(ecm_data);
if (asset_id == 0) {
LOG(ERROR) << "AssetID in ECM is not valid.";
return false;
}
ecm_data += sizeof(uint32_t); // asset_id.
EncryptionKey encryption_key; EncryptionKey encryption_key;
if (!GetAssetKey(asset_id, &encryption_key)) { if (!GetAssetKey(ecm_data, &encryption_key)) {
return false; return false;
} }
if (encryption_key.key.size() < kAssetKeySizeBytes) { if (encryption_key.key.size() < kAssetKeySizeBytes) {
LOG(ERROR) << "Asset Key size of " << encryption_key.key.size() LOG(ERROR) << "Asset Key size of " << encryption_key.key.size()
<< " for AssetID = " << asset_id << " for AssetID = " << ntohlFromBuffer(ecm_data)
<< " is less than minimum asset key size."; << " is less than minimum asset key size.";
return false; return false;
} }
ecm_data += sizeof(uint32_t); // asset_id.
// Legacy WVM content may have asset keys > 16 bytes. // Legacy WVM content may have asset keys > 16 bytes.
// Use only the first 16 bytes of the asset key to get // Use only the first 16 bytes of the asset key to get
// the content key. // the content key.

View File

@ -200,7 +200,7 @@ class WvmMediaParser : public MediaParser {
// to ouput media sample as encrypted. // to ouput media sample as encrypted.
bool Output(bool must_process_encrypted); bool Output(bool must_process_encrypted);
bool GetAssetKey(const uint32_t asset_id, EncryptionKey* encryption_key); bool GetAssetKey(const uint8_t* asset_id, EncryptionKey* encryption_key);
// Callback invoked by the ES media parser // Callback invoked by the ES media parser
// to emit a new audio/video access unit. // to emit a new audio/video access unit.

View File

@ -52,7 +52,9 @@ class MockKeySource : public FixedKeySource {
MockKeySource() {} MockKeySource() {}
~MockKeySource() override {} ~MockKeySource() override {}
MOCK_METHOD1(FetchKeys, Status(uint32_t asset_id)); MOCK_METHOD2(FetchKeys,
Status(EmeInitDataType init_data_type,
const std::vector<uint8_t>& init_data));
MOCK_METHOD2(GetKey, Status(TrackType track_type, MOCK_METHOD2(GetKey, Status(TrackType track_type,
EncryptionKey* key)); EncryptionKey* key));
@ -185,7 +187,7 @@ TEST_F(WvmMediaParserTest, ParseWvmInitWithoutKeySource) {
} }
TEST_F(WvmMediaParserTest, ParseWvm) { TEST_F(WvmMediaParserTest, ParseWvm) {
EXPECT_CALL(*key_source_, FetchKeys(_)).WillOnce(Return(Status::OK)); EXPECT_CALL(*key_source_, FetchKeys(_, _)).WillOnce(Return(Status::OK));
EXPECT_CALL(*key_source_, GetKey(_, _)) EXPECT_CALL(*key_source_, GetKey(_, _))
.WillOnce(DoAll(SetArgPointee<1>(encryption_key_), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<1>(encryption_key_), Return(Status::OK)));
Parse(kWvmFile); Parse(kWvmFile);
@ -196,7 +198,7 @@ TEST_F(WvmMediaParserTest, ParseWvm) {
} }
TEST_F(WvmMediaParserTest, ParseWvmWith64ByteAssetKey) { TEST_F(WvmMediaParserTest, ParseWvmWith64ByteAssetKey) {
EXPECT_CALL(*key_source_, FetchKeys(_)).WillOnce(Return(Status::OK)); EXPECT_CALL(*key_source_, FetchKeys(_, _)).WillOnce(Return(Status::OK));
// WVM uses only the first 16 bytes of the asset key. // WVM uses only the first 16 bytes of the asset key.
encryption_key_.key.resize(64); encryption_key_.key.resize(64);
encryption_key_.key.assign(k64ByteAssetKey, k64ByteAssetKey + 64); encryption_key_.key.assign(k64ByteAssetKey, k64ByteAssetKey + 64);
@ -209,7 +211,7 @@ TEST_F(WvmMediaParserTest, ParseWvmWith64ByteAssetKey) {
} }
TEST_F(WvmMediaParserTest, ParseMultiConfigWvm) { TEST_F(WvmMediaParserTest, ParseMultiConfigWvm) {
EXPECT_CALL(*key_source_, FetchKeys(_)).WillOnce(Return(Status::OK)); EXPECT_CALL(*key_source_, FetchKeys(_, _)).WillOnce(Return(Status::OK));
EXPECT_CALL(*key_source_, GetKey(_, _)) EXPECT_CALL(*key_source_, GetKey(_, _))
.WillOnce(DoAll(SetArgPointee<1>(encryption_key_), Return(Status::OK))); .WillOnce(DoAll(SetArgPointee<1>(encryption_key_), Return(Status::OK)));
Parse(kMultiConfigWvmFile); Parse(kMultiConfigWvmFile);