Merge "Add Max-Res Decode Engine to CDM Core" into lmp-mr1-dev

This commit is contained in:
Jeff Tinker
2014-11-06 02:35:56 +00:00
committed by Android (Google) Code Review
14 changed files with 748 additions and 99 deletions

View File

@@ -26,7 +26,8 @@ namespace wvcdm {
typedef std::set<WvCdmEventListener*>::iterator CdmEventListenerIter;
CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set) {
Create(new CdmLicense(), new CryptoSession(), new PolicyEngine(),
CryptoSession* crypto_session = new CryptoSession();
Create(new CdmLicense(), crypto_session, new PolicyEngine(crypto_session),
new DeviceFiles(), cdm_client_property_set);
}
@@ -177,7 +178,6 @@ CdmResponseType CdmSession::RestoreOfflineSession(
CdmResponseType CdmSession::RestoreUsageSession(
const CdmKeyMessage& key_request,
const CdmKeyResponse& key_response) {
key_request_ = key_request;
key_response_ = key_response;
@@ -346,7 +346,7 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
if (crypto_session_.get() == NULL || !crypto_session_->IsOpen())
return UNKNOWN_ERROR;
if (params.is_encrypted && !policy_engine_->can_decrypt()) {
if (params.is_encrypted && !policy_engine_->CanDecrypt(*params.key_id)) {
return policy_engine_->IsLicenseForFuture() ? KEY_ERROR : NEED_KEY;
}

View File

@@ -0,0 +1,182 @@
// Copyright 2014 Google Inc. All Rights Reserved.
#include "max_res_engine.h"
#include "clock.h"
#include "log.h"
namespace {
typedef std::map<wvcdm::KeyId, wvcdm::MaxResEngine::KeyStatus*>::const_iterator
KeyIterator;
const int64_t kHdcpCheckInterval = 10;
const uint32_t kNoResolution = 0;
} // namespace
namespace wvcdm {
MaxResEngine::MaxResEngine(CryptoSession* crypto_session) : status_lock_() {
Init(crypto_session, new Clock());
}
MaxResEngine::MaxResEngine(CryptoSession* crypto_session, Clock* clock)
: status_lock_() {
Init(crypto_session, clock);
}
MaxResEngine::~MaxResEngine() {
AutoLock lock(status_lock_);
DeleteAllKeys();
}
bool MaxResEngine::CanDecrypt(const KeyId& key_id) {
AutoLock lock(status_lock_);
if (keys_.count(key_id) > 0) {
return keys_[key_id]->can_decrypt();
} else {
// If a Key ID is unknown to us, we don't know of any constraints for it,
// so never block decryption.
return true;
}
}
void MaxResEngine::Init(CryptoSession* crypto_session, Clock* clock) {
AutoLock lock(status_lock_);
current_resolution_ = kNoResolution;
clock_.reset(clock);
next_check_time_ = clock_->GetCurrentTime();
crypto_session_ = crypto_session;
}
void MaxResEngine::SetLicense(
const video_widevine_server::sdk::License& license) {
AutoLock lock(status_lock_);
DeleteAllKeys();
for (int32_t key_iter = 0; key_iter < license.key_size(); ++key_iter) {
const KeyContainer& key = license.key(key_iter);
if (key.type() == KeyContainer::CONTENT && key.has_id() &&
key.video_resolution_constraints_size() > 0) {
const ConstraintList& constraints = key.video_resolution_constraints();
const KeyId& key_id = key.id();
if (key.has_required_protection()) {
keys_[key_id] =
new KeyStatus(constraints, key.required_protection().hdcp());
} else {
keys_[key_id] = new KeyStatus(constraints);
}
}
}
}
void MaxResEngine::SetResolution(uint32_t width, uint32_t height) {
AutoLock lock(status_lock_);
current_resolution_ = width * height;
}
void MaxResEngine::OnTimerEvent() {
AutoLock lock(status_lock_);
int64_t current_time = clock_->GetCurrentTime();
if (!keys_.empty() && current_resolution_ != kNoResolution &&
current_time >= next_check_time_) {
CryptoSession::OemCryptoHdcpVersion current_hdcp_level;
CryptoSession::OemCryptoHdcpVersion ignored;
if (!crypto_session_->GetHdcpCapabilities(&current_hdcp_level, &ignored)) {
current_hdcp_level = CryptoSession::kOemCryptoHdcpNotSupported;
}
for (KeyIterator i = keys_.begin(); i != keys_.end(); ++i) {
i->second->Update(current_resolution_, current_hdcp_level);
}
next_check_time_ = current_time + kHdcpCheckInterval;
}
}
void MaxResEngine::DeleteAllKeys() {
// This helper method assumes that status_lock_ is already held.
for (KeyIterator i = keys_.begin(); i != keys_.end(); ++i) delete i->second;
keys_.clear();
}
MaxResEngine::KeyStatus::KeyStatus(const ConstraintList& constraints)
: default_hdcp_level_(NULL) {
Init(constraints);
}
MaxResEngine::KeyStatus::KeyStatus(
const ConstraintList& constraints,
const OutputProtection::HDCP& default_hdcp_level) {
default_hdcp_level_.reset(new CryptoSession::OemCryptoHdcpVersion(
ProtobufHdcpToOemCryptoHdcp(default_hdcp_level)));
Init(constraints);
}
void MaxResEngine::KeyStatus::Init(const ConstraintList& constraints) {
constraints_.Clear();
constraints_.MergeFrom(constraints);
can_decrypt_ = true;
}
void MaxResEngine::KeyStatus::Update(
uint32_t res, CryptoSession::OemCryptoHdcpVersion current_hdcp_level) {
VideoResolutionConstraint* current_constraint = GetConstraintForRes(res);
if (current_constraint == NULL) {
can_decrypt_ = false;
return;
}
CryptoSession::OemCryptoHdcpVersion desired_hdcp_level;
if (current_constraint->has_required_protection()) {
desired_hdcp_level = ProtobufHdcpToOemCryptoHdcp(
current_constraint->required_protection().hdcp());
} else if (default_hdcp_level_.get() != NULL) {
desired_hdcp_level = *default_hdcp_level_;
} else {
// No constraint value and no default means there's nothing to enforce.
can_decrypt_ = true;
return;
}
can_decrypt_ = (current_hdcp_level >= desired_hdcp_level);
}
MaxResEngine::VideoResolutionConstraint*
MaxResEngine::KeyStatus::GetConstraintForRes(uint32_t res) {
typedef ConstraintList::pointer_iterator Iterator;
for (Iterator i = constraints_.pointer_begin();
i != constraints_.pointer_end(); ++i) {
VideoResolutionConstraint* constraint = *i;
if (constraint->has_min_resolution_pixels() &&
constraint->has_max_resolution_pixels() &&
res >= constraint->min_resolution_pixels() &&
res <= constraint->max_resolution_pixels()) {
return constraint;
}
}
return NULL;
}
CryptoSession::OemCryptoHdcpVersion
MaxResEngine::KeyStatus::ProtobufHdcpToOemCryptoHdcp(
const OutputProtection::HDCP& input) {
switch (input) {
case OutputProtection::HDCP_NONE:
return CryptoSession::kOemCryptoHdcpNotSupported;
case OutputProtection::HDCP_V1:
return CryptoSession::kOemCryptoHdcpVersion1;
case OutputProtection::HDCP_V2:
return CryptoSession::kOemCryptoHdcpVersion2;
case OutputProtection::HDCP_V2_1:
return CryptoSession::kOemCryptoHdcpVersion2_1;
case OutputProtection::HDCP_V2_2:
return CryptoSession::kOemCryptoHdcpVersion2_2;
default:
LOGE(
"MaxResEngine::KeyStatus::ProtobufHdcpToOemCryptoHdcp: "
"Unknown HDCP Level");
return CryptoSession::kOemCryptoNoHdcpDeviceAttached;
}
}
} // wvcdm

View File

@@ -16,11 +16,13 @@
namespace wvcdm {
PolicyEngine::PolicyEngine() {
PolicyEngine::PolicyEngine(CryptoSession* crypto_session)
: max_res_engine_(crypto_session) {
Init(new Clock());
}
PolicyEngine::PolicyEngine(Clock* clock) {
PolicyEngine::PolicyEngine(CryptoSession* crypto_session, Clock* clock)
: max_res_engine_(crypto_session) {
Init(clock);
}
@@ -40,6 +42,10 @@ void PolicyEngine::Init(Clock* clock) {
clock_ = clock;
}
bool PolicyEngine::CanDecrypt(const KeyId& key_id) {
return can_decrypt_ && max_res_engine_.CanDecrypt(key_id);
}
void PolicyEngine::OnTimerEvent(bool* event_occurred, CdmEventType* event) {
*event_occurred = false;
int64_t current_time = clock_->GetCurrentTime();
@@ -101,6 +107,8 @@ void PolicyEngine::OnTimerEvent(bool* event_occurred, CdmEventType* event) {
*event = LICENSE_RENEWAL_NEEDED_EVENT;
*event_occurred = true;
}
max_res_engine_.OnTimerEvent();
}
void PolicyEngine::SetLicense(
@@ -109,6 +117,7 @@ void PolicyEngine::SetLicense(
license_id_.CopyFrom(license.id());
policy_.Clear();
UpdateLicense(license);
max_res_engine_.SetLicense(license);
}
void PolicyEngine::UpdateLicense(