Refactor KeySource::FetchKeys to use EME init data types
Change-Id: I517ea992a8868d7382988a8837f4f05df9f974d7
This commit is contained in:
parent
9d101f85e3
commit
fb0790e1d5
|
@ -15,18 +15,8 @@ namespace media {
|
|||
|
||||
FixedKeySource::~FixedKeySource() {}
|
||||
|
||||
Status FixedKeySource::FetchKeys(const std::vector<uint8_t>& pssh_box) {
|
||||
// Do nothing for fixed key encryption/decryption.
|
||||
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) {
|
||||
Status FixedKeySource::FetchKeys(EmeInitDataType init_data_type,
|
||||
const std::vector<uint8_t>& init_data) {
|
||||
// Do nothing for fixed key encryption/decryption.
|
||||
return Status::OK;
|
||||
}
|
||||
|
|
|
@ -30,10 +30,8 @@ class FixedKeySource : public KeySource {
|
|||
|
||||
/// @name KeySource implementation overrides.
|
||||
/// @{
|
||||
Status FetchKeys(const std::vector<uint8_t>& pssh_box) override;
|
||||
Status FetchKeys(const std::vector<std::vector<uint8_t>>& key_ids) override;
|
||||
Status FetchKeys(uint32_t asset_id) override;
|
||||
|
||||
Status FetchKeys(EmeInitDataType init_data_type,
|
||||
const std::vector<uint8_t>& init_data) override;
|
||||
Status GetKey(TrackType track_type, EncryptionKey* key) override;
|
||||
Status GetKey(const std::vector<uint8_t>& key_id,
|
||||
EncryptionKey* key) override;
|
||||
|
|
|
@ -16,6 +16,21 @@
|
|||
namespace shaka {
|
||||
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 {
|
||||
EncryptionKey();
|
||||
~EncryptionKey();
|
||||
|
@ -43,22 +58,12 @@ class KeySource {
|
|||
KeySource();
|
||||
virtual ~KeySource();
|
||||
|
||||
/// Fetch keys for CENC from the key server.
|
||||
/// @param pssh_box The entire PSSH box for the content to be decrypted
|
||||
/// Fetch keys based on the specified encrypted media init data.
|
||||
/// @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.
|
||||
virtual Status FetchKeys(const std::vector<uint8_t>& pssh_box) = 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;
|
||||
virtual Status FetchKeys(EmeInitDataType init_data_type,
|
||||
const std::vector<uint8_t>& init_data) = 0;
|
||||
|
||||
/// Get encryption key of the specified track type.
|
||||
/// @param track_type is the type of track for which retrieving the key.
|
||||
|
|
|
@ -310,19 +310,9 @@ Status PlayReadyKeySource::FetchKeysWithProgramIdentifier(
|
|||
return Status::OK;
|
||||
}
|
||||
|
||||
Status PlayReadyKeySource::FetchKeys(const std::vector<uint8_t>& pssh_box) {
|
||||
// Does nothing for playready encryption/decryption.
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
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.
|
||||
Status PlayReadyKeySource::FetchKeys(EmeInitDataType init_data_type,
|
||||
const std::vector<uint8_t>& init_data) {
|
||||
// Do nothing for playready encryption/decryption.
|
||||
return Status::OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,10 +40,8 @@ class PlayReadyKeySource : public KeySource {
|
|||
|
||||
/// @name KeySource implementation overrides.
|
||||
/// @{
|
||||
Status FetchKeys(const std::vector<uint8_t>& pssh_box) override;
|
||||
Status FetchKeys(const std::vector<std::vector<uint8_t>>& key_ids) override;
|
||||
Status FetchKeys(uint32_t asset_id) override;
|
||||
|
||||
Status FetchKeys(EmeInitDataType init_data_type,
|
||||
const std::vector<uint8_t>& init_data) override;
|
||||
Status GetKey(TrackType track_type, EncryptionKey* key) override;
|
||||
Status GetKey(const std::vector<uint8_t>& key_id,
|
||||
EncryptionKey* key) override;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "packager/base/json/json_writer.h"
|
||||
#include "packager/media/base/fixed_key_source.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/protection_system_specific_info.h"
|
||||
#include "packager/media/base/rcheck.h"
|
||||
|
@ -41,6 +42,18 @@ const int kDefaultCryptoPeriodCount = 10;
|
|||
const int kGetKeyTimeoutInSeconds = 5 * 60; // 5 minutes.
|
||||
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,
|
||||
std::vector<uint8_t>* bytes) {
|
||||
DCHECK(bytes);
|
||||
|
@ -147,61 +160,63 @@ Status WidevineKeySource::FetchKeys(const std::vector<uint8_t>& content_id,
|
|||
return FetchKeysInternal(!kEnableKeyRotation, 0, false);
|
||||
}
|
||||
|
||||
Status WidevineKeySource::FetchKeys(const std::vector<uint8_t>& pssh_box) {
|
||||
const std::vector<uint8_t> widevine_system_id(
|
||||
kWidevineSystemId, kWidevineSystemId + arraysize(kWidevineSystemId));
|
||||
|
||||
ProtectionSystemSpecificInfo info;
|
||||
if (!info.Parse(pssh_box.data(), pssh_box.size()))
|
||||
return Status(error::PARSER_FAILURE, "Error parsing the PSSH box.");
|
||||
|
||||
if (info.system_id() == widevine_system_id) {
|
||||
base::AutoLock scoped_lock(lock_);
|
||||
request_dict_.Clear();
|
||||
std::string pssh_data_base64_string;
|
||||
|
||||
BytesToBase64String(info.pssh_data(), &pssh_data_base64_string);
|
||||
request_dict_.SetString("pssh_data", pssh_data_base64_string);
|
||||
return FetchKeysInternal(!kEnableKeyRotation, 0, false);
|
||||
} else if (!info.key_ids().empty()) {
|
||||
// This is not a Widevine PSSH box. Try making the request for the key-IDs.
|
||||
// Even if this is a different key-system, it should still work. Either
|
||||
// the server will not recognize it and return an error, or it will
|
||||
// recognize it and the key must be correct (or the content is bad).
|
||||
return FetchKeys(info.key_ids());
|
||||
Status WidevineKeySource::FetchKeys(EmeInitDataType init_data_type,
|
||||
const std::vector<uint8_t>& init_data) {
|
||||
std::vector<uint8_t> pssh_data;
|
||||
uint32_t asset_id = 0;
|
||||
switch (init_data_type) {
|
||||
case EmeInitDataType::CENC: {
|
||||
const std::vector<uint8_t> widevine_system_id(
|
||||
kWidevineSystemId, kWidevineSystemId + arraysize(kWidevineSystemId));
|
||||
std::vector<ProtectionSystemSpecificInfo> protection_systems_info;
|
||||
if (!ProtectionSystemSpecificInfo::ParseBoxes(
|
||||
init_data.data(), init_data.size(), &protection_systems_info)) {
|
||||
return Status(error::PARSER_FAILURE, "Error parsing the PSSH boxes.");
|
||||
}
|
||||
for (const auto& info: protection_systems_info) {
|
||||
// Use Widevine PSSH if available otherwise construct a Widevine PSSH
|
||||
// from the first available key ids.
|
||||
if (info.system_id() == widevine_system_id) {
|
||||
pssh_data = info.pssh_data();
|
||||
break;
|
||||
} else if (pssh_data.empty() && !info.key_ids().empty()) {
|
||||
pssh_data = WidevinePsshFromKeyId(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 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
return FetchKeysInternal(!kEnableKeyRotation, 0, widevine_classic);
|
||||
}
|
||||
|
||||
Status WidevineKeySource::GetKey(TrackType track_type, EncryptionKey* key) {
|
||||
|
@ -566,7 +581,9 @@ bool WidevineKeySource::ExtractEncryptionKey(
|
|||
|
||||
DCHECK(!encryption_key_map.empty());
|
||||
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 PushToKeyPool(&encryption_key_map);
|
||||
|
|
|
@ -36,10 +36,8 @@ class WidevineKeySource : public KeySource {
|
|||
|
||||
/// @name KeySource implementation overrides.
|
||||
/// @{
|
||||
Status FetchKeys(const std::vector<uint8_t>& pssh_box) override;
|
||||
Status FetchKeys(const std::vector<std::vector<uint8_t>>& key_ids) override;
|
||||
Status FetchKeys(uint32_t asset_id) override;
|
||||
|
||||
Status FetchKeys(EmeInitDataType init_data_type,
|
||||
const std::vector<uint8_t>& init_data) override;
|
||||
Status GetKey(TrackType track_type, EncryptionKey* key) override;
|
||||
Status GetKey(const std::vector<uint8_t>& key_id,
|
||||
EncryptionKey* key) override;
|
||||
|
|
|
@ -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
|
||||
// correctly.
|
||||
const uint32_t kClassicAssetId = 0x80038cd9;
|
||||
const uint8_t kClassicAssetIdBytes[] = {0x80, 0x03, 0x8c, 0xd9};
|
||||
|
||||
std::string Base64Encode(const std::string& input) {
|
||||
std::string output;
|
||||
|
@ -319,11 +320,11 @@ TEST_P(WidevineKeySourceTest, LicenseStatusCencWithPsshBoxOK) {
|
|||
widevine_key_source_->set_signer(std::move(mock_request_signer_));
|
||||
std::vector<uint8_t> pssh_box(kRequestPsshBox,
|
||||
kRequestPsshBox + arraysize(kRequestPsshBox));
|
||||
ASSERT_OK(widevine_key_source_->FetchKeys(pssh_box));
|
||||
ASSERT_OK(widevine_key_source_->FetchKeys(EmeInitDataType::CENC, pssh_box));
|
||||
VerifyKeys(false);
|
||||
}
|
||||
|
||||
TEST_P(WidevineKeySourceTest, LicenseStatusCencWithKeyIdsOK) {
|
||||
TEST_P(WidevineKeySourceTest, LicenseStatusCencWithKeyIdOK) {
|
||||
std::string expected_pssh_data(
|
||||
kRequestPsshDataFromKeyIds,
|
||||
kRequestPsshDataFromKeyIds + arraysize(kRequestPsshDataFromKeyIds));
|
||||
|
@ -341,10 +342,9 @@ TEST_P(WidevineKeySourceTest, LicenseStatusCencWithKeyIdsOK) {
|
|||
|
||||
CreateWidevineKeySource();
|
||||
widevine_key_source_->set_signer(std::move(mock_request_signer_));
|
||||
std::vector<std::vector<uint8_t>> key_ids;
|
||||
key_ids.push_back(std::vector<uint8_t>(
|
||||
kRequestKeyId, kRequestKeyId + arraysize(kRequestKeyId)));
|
||||
ASSERT_OK(widevine_key_source_->FetchKeys(key_ids));
|
||||
std::vector<uint8_t> key_id(kRequestKeyId,
|
||||
kRequestKeyId + arraysize(kRequestKeyId));
|
||||
ASSERT_OK(widevine_key_source_->FetchKeys(EmeInitDataType::WEBM, key_id));
|
||||
VerifyKeys(false);
|
||||
}
|
||||
|
||||
|
@ -363,7 +363,10 @@ TEST_P(WidevineKeySourceTest, LicenseStatusClassicOK) {
|
|||
|
||||
CreateWidevineKeySource();
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -640,27 +640,18 @@ bool MP4MediaParser::FetchKeysIfNecessary(
|
|||
if (!decryption_key_source_)
|
||||
return true;
|
||||
|
||||
Status status;
|
||||
for (std::vector<ProtectionSystemSpecificHeader>::const_iterator iter =
|
||||
headers.begin(); iter != headers.end(); ++iter) {
|
||||
status = decryption_key_source_->FetchKeys(iter->raw_box);
|
||||
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;
|
||||
std::vector<uint8_t> pssh_raw_data;
|
||||
for (const auto& header : headers) {
|
||||
pssh_raw_data.insert(pssh_raw_data.end(), header.raw_box.begin(),
|
||||
header.raw_box.end());
|
||||
}
|
||||
|
||||
Status status =
|
||||
decryption_key_source_->FetchKeys(EmeInitDataType::CENC, pssh_raw_data);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Error fetching decryption keys: " << status;
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG(ERROR) << "No viable 'pssh' box found for content decryption.";
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MP4MediaParser::EnqueueSample(bool* err) {
|
||||
|
|
|
@ -31,7 +31,9 @@ const char kKeyId[] = "0123456789012345";
|
|||
|
||||
class MockKeySource : public FixedKeySource {
|
||||
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,
|
||||
Status(const std::vector<uint8_t>& key_id, EncryptionKey* key));
|
||||
};
|
||||
|
@ -247,7 +249,7 @@ TEST_F(MP4MediaParserTest, CencInitWithoutDecryptionSource) {
|
|||
|
||||
TEST_F(MP4MediaParserTest, CencWithDecryptionSourceAndAuxInMdat) {
|
||||
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;
|
||||
encryption_key.key.assign(kKey, kKey + strlen(kKey));
|
||||
|
@ -266,7 +268,7 @@ TEST_F(MP4MediaParserTest, CencWithDecryptionSourceAndAuxInMdat) {
|
|||
|
||||
TEST_F(MP4MediaParserTest, CencWithDecryptionSourceAndSenc) {
|
||||
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;
|
||||
encryption_key.key.assign(kKey, kKey + strlen(kKey));
|
||||
|
|
|
@ -242,17 +242,19 @@ bool WebMMediaParser::FetchKeysIfNecessary(
|
|||
if (!decryption_key_source_)
|
||||
return true;
|
||||
|
||||
std::vector<std::vector<uint8_t>> key_ids;
|
||||
Status status;
|
||||
if (!audio_encryption_key_id.empty()) {
|
||||
key_ids.push_back(std::vector<uint8_t>(audio_encryption_key_id.begin(),
|
||||
audio_encryption_key_id.end()));
|
||||
status.Update(decryption_key_source_->FetchKeys(
|
||||
EmeInitDataType::WEBM,
|
||||
std::vector<uint8_t>(audio_encryption_key_id.begin(),
|
||||
audio_encryption_key_id.end())));
|
||||
}
|
||||
if (!video_encryption_key_id.empty()) {
|
||||
key_ids.push_back(std::vector<uint8_t>(video_encryption_key_id.begin(),
|
||||
video_encryption_key_id.end()));
|
||||
status.Update(decryption_key_source_->FetchKeys(
|
||||
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()) {
|
||||
LOG(ERROR) << "Error fetching decryption keys: " << status;
|
||||
return false;
|
||||
|
|
|
@ -1058,21 +1058,23 @@ bool WvmMediaParser::EmitSample(uint32_t parsed_audio_or_video_stream_id,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WvmMediaParser::GetAssetKey(const uint32_t asset_id,
|
||||
bool WvmMediaParser::GetAssetKey(const uint8_t* asset_id,
|
||||
EncryptionKey* encryption_key) {
|
||||
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()) {
|
||||
LOG(ERROR) << "Fetch Key(s) failed for AssetID = " << asset_id
|
||||
<< ", error = " << status;
|
||||
LOG(ERROR) << "Fetch Key(s) failed for AssetID = "
|
||||
<< ntohlFromBuffer(asset_id) << ", error = " << status;
|
||||
return false;
|
||||
}
|
||||
|
||||
status = decryption_key_source_->GetKey(KeySource::TRACK_TYPE_HD,
|
||||
encryption_key);
|
||||
if (!status.ok()) {
|
||||
LOG(ERROR) << "Fetch Key(s) failed for AssetID = " << asset_id
|
||||
<< ", error = " << status;
|
||||
LOG(ERROR) << "Fetch Key(s) failed for AssetID = "
|
||||
<< ntohlFromBuffer(asset_id) << ", error = " << status;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1097,22 +1099,17 @@ bool WvmMediaParser::ProcessEcm() {
|
|||
ecm_data += sizeof(uint32_t); // old version field - skip.
|
||||
ecm_data += sizeof(uint32_t); // clear lead - 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;
|
||||
if (!GetAssetKey(asset_id, &encryption_key)) {
|
||||
if (!GetAssetKey(ecm_data, &encryption_key)) {
|
||||
return false;
|
||||
}
|
||||
if (encryption_key.key.size() < kAssetKeySizeBytes) {
|
||||
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.";
|
||||
return false;
|
||||
}
|
||||
ecm_data += sizeof(uint32_t); // asset_id.
|
||||
// Legacy WVM content may have asset keys > 16 bytes.
|
||||
// Use only the first 16 bytes of the asset key to get
|
||||
// the content key.
|
||||
|
|
|
@ -200,7 +200,7 @@ class WvmMediaParser : public MediaParser {
|
|||
// to ouput media sample as 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
|
||||
// to emit a new audio/video access unit.
|
||||
|
|
|
@ -52,7 +52,9 @@ class MockKeySource : public FixedKeySource {
|
|||
MockKeySource() {}
|
||||
~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,
|
||||
EncryptionKey* key));
|
||||
|
||||
|
@ -185,7 +187,7 @@ TEST_F(WvmMediaParserTest, ParseWvmInitWithoutKeySource) {
|
|||
}
|
||||
|
||||
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(_, _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(encryption_key_), Return(Status::OK)));
|
||||
Parse(kWvmFile);
|
||||
|
@ -196,7 +198,7 @@ TEST_F(WvmMediaParserTest, ParseWvm) {
|
|||
}
|
||||
|
||||
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.
|
||||
encryption_key_.key.resize(64);
|
||||
encryption_key_.key.assign(k64ByteAssetKey, k64ByteAssetKey + 64);
|
||||
|
@ -209,7 +211,7 @@ TEST_F(WvmMediaParserTest, ParseWvmWith64ByteAssetKey) {
|
|||
}
|
||||
|
||||
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(_, _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(encryption_key_), Return(Status::OK)));
|
||||
Parse(kMultiConfigWvmFile);
|
||||
|
|
Loading…
Reference in New Issue