0

Handle key types in D3D11CdmProxy to handle the keyblobs correctly

- CdmProxy::SetKey takes a key type. This should be used to manage
  possibly different key blobs for different key types.
- Calling CdmProxyContext::GetD3D11DecryptContext requires passing in
  a key type as well, to specify which key type it's requesting for.
- Moved CdmProxyContext from media/base to media/cdm because 1) it
  doesn't need to be in media/base and 2) it depends on cdm_proxy.h
  now, to access CdmProxy::KeyType.

Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I4064e9426bc8efac3fe667806a9f3713881b31ac
Reviewed-on: https://chromium-review.googlesource.com/1234332
Commit-Queue: Rintaro Kuroiwa <rkuroiwa@chromium.org>
Reviewed-by: Xiaohan Wang <xhwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#593222}
This commit is contained in:
Rintaro Kuroiwa
2018-09-21 16:44:09 +00:00
committed by Commit Bot
parent 9bdc415d08
commit a6ed7ce80a
11 changed files with 79 additions and 34 deletions

@@ -98,8 +98,6 @@ jumbo_source_set("base") {
"cdm_promise.h",
"cdm_promise_adapter.cc",
"cdm_promise_adapter.h",
"cdm_proxy_context.cc",
"cdm_proxy_context.h",
"cdm_session_tracker.cc",
"cdm_session_tracker.h",
"channel_mixer.cc",

@@ -41,6 +41,8 @@ source_set("cdm") {
# when EnabledIf attribute is supported in mojom.
"cdm_proxy.cc",
"cdm_proxy.h",
"cdm_proxy_context.cc",
"cdm_proxy_context.h",
"cenc_utils.cc",
"cenc_utils.h",
"default_cdm_factory.cc",

@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/base/cdm_proxy_context.h"
#include "media/cdm/cdm_proxy_context.h"
#include "build/build_config.h"
@@ -13,7 +13,8 @@ CdmProxyContext::~CdmProxyContext() {}
#if defined(OS_WIN)
base::Optional<CdmProxyContext::D3D11DecryptContext>
CdmProxyContext::GetD3D11DecryptContext(const std::string& key_id) {
CdmProxyContext::GetD3D11DecryptContext(CdmProxy::KeyType key_type,
const std::string& key_id) {
return base::nullopt;
}
#endif

@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef MEDIA_BASE_CDM_PROXY_CONTEXT_H_
#define MEDIA_BASE_CDM_PROXY_CONTEXT_H_
#ifndef MEDIA_CDM_CDM_PROXY_CONTEXT_H_
#define MEDIA_CDM_CDM_PROXY_CONTEXT_H_
#include <stdint.h>
@@ -14,6 +14,7 @@
#include "base/optional.h"
#include "build/build_config.h"
#include "media/base/media_export.h"
#include "media/cdm/cdm_proxy.h"
#if defined(OS_WIN)
#include <d3d11.h>
@@ -45,8 +46,10 @@ class MEDIA_EXPORT CdmProxyContext {
// Returns D3D11DecryptContext on success. Returns nullopt otherwise. The
// D3D11DecryptContext instance is only guaranteed to be valid before the
// caller returns.
// |key_type| is the requesting key type.
// |key_id| is the key ID of the media to decrypt.
virtual base::Optional<D3D11DecryptContext> GetD3D11DecryptContext(
CdmProxy::KeyType key_type,
const std::string& key_id) WARN_UNUSED_RESULT;
#endif // defined(OS_WIN)
@@ -61,4 +64,4 @@ class MEDIA_EXPORT CdmProxyContext {
} // namespace media
#endif // MEDIA_BASE_CDM_PROXY_CONTEXT_H_
#endif // MEDIA_CDM_CDM_PROXY_CONTEXT_H_

@@ -15,7 +15,7 @@
#include "base/win/object_watcher.h"
#include "media/base/callback_registry.h"
#include "media/base/cdm_context.h"
#include "media/base/cdm_proxy_context.h"
#include "media/cdm/cdm_proxy_context.h"
#include "media/gpu/windows/d3d11_decryptor.h"
namespace media {
@@ -62,20 +62,21 @@ class D3D11CdmProxyContext : public CdmProxyContext {
~D3D11CdmProxyContext() override = default;
// The pointers are owned by the caller.
// TODO(rkuroiwa): Handle |key_type|.
void SetKey(ID3D11CryptoSession* crypto_session,
const std::vector<uint8_t>& key_id,
CdmProxy::KeyType /* key_type */,
CdmProxy::KeyType key_type,
const std::vector<uint8_t>& key_blob) {
std::string key_id_str(key_id.begin(), key_id.end());
KeyInfo key_info(crypto_session, key_blob);
// Note that this would overwrite an entry but it is completely valid, e.g.
// updating the keyblob due to a configuration change.
key_info_map_[key_id_str] = std::move(key_info);
key_info_map_[key_id_str][key_type] = std::move(key_info);
}
void RemoveKey(ID3D11CryptoSession* crypto_session,
const std::vector<uint8_t>& key_id) {
// There's no need for a keytype for Remove() at the moment, because it's
// used for completely removing keys associated to |key_id|.
std::string key_id_str(key_id.begin(), key_id.end());
key_info_map_.erase(key_id_str);
}
@@ -85,12 +86,18 @@ class D3D11CdmProxyContext : public CdmProxyContext {
// CdmProxyContext implementation.
base::Optional<D3D11DecryptContext> GetD3D11DecryptContext(
CdmProxy::KeyType key_type,
const std::string& key_id) override {
auto key_info_it = key_info_map_.find(key_id);
if (key_info_it == key_info_map_.end())
auto key_id_find_it = key_info_map_.find(key_id);
if (key_id_find_it == key_info_map_.end())
return base::nullopt;
auto& key_info = key_info_it->second;
auto& key_type_to_key_info = key_id_find_it->second;
auto key_type_find_it = key_type_to_key_info.find(key_type);
if (key_type_find_it == key_type_to_key_info.end())
return base::nullopt;
auto& key_info = key_type_find_it->second;
D3D11DecryptContext context = {};
context.crypto_session = key_info.crypto_session;
context.key_blob = key_info.key_blob.data();
@@ -113,13 +120,13 @@ class D3D11CdmProxyContext : public CdmProxyContext {
std::vector<uint8_t> key_blob;
};
// Maps key ID to KeyInfo.
// Maps key ID -> key type -> KeyInfo.
// The key ID's type is string, which is converted from |key_id| in
// SetKey(). It's better to use string here rather than convert
// vector<uint8_t> to string every time in GetD3D11DecryptContext() because
// in most cases it would be called more often than SetKey() and RemoveKey()
// combined.
std::map<std::string, KeyInfo> key_info_map_;
std::map<std::string, std::map<CdmProxy::KeyType, KeyInfo>> key_info_map_;
const GUID key_info_guid_;

@@ -13,7 +13,7 @@
#include "base/power_monitor/power_monitor_source.h"
#include "base/run_loop.h"
#include "base/test/scoped_task_environment.h"
#include "media/base/cdm_proxy_context.h"
#include "media/cdm/cdm_proxy_context.h"
#include "media/gpu/windows/d3d11_mocks.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -678,12 +678,39 @@ TEST_F(D3D11CdmProxyTest, GetCdmProxyContext) {
ASSERT_TRUE(context->GetCdmProxyContext());
}
// No keys are set.
TEST_F(D3D11CdmProxyTest, GetD3D11DecryptContextNoKey) {
base::WeakPtr<CdmContext> context = proxy_->GetCdmContext();
ASSERT_TRUE(context);
CdmProxyContext* proxy_context = context->GetCdmProxyContext();
// The key ID doesn't matter.
auto decrypt_context = proxy_context->GetD3D11DecryptContext("");
auto decrypt_context =
proxy_context->GetD3D11DecryptContext(kTestKeyType, "");
EXPECT_FALSE(decrypt_context);
}
// A key is set but no keys for the key type requested.
TEST_F(D3D11CdmProxyTest, GetD3D11DecryptContextNoKeyForKeyType) {
uint32_t crypto_session_id_from_initialize = 0;
EXPECT_CALL(callback_mock_,
InitializeCallback(CdmProxy::Status::kOk, kTestProtocol, _))
.WillOnce(SaveArg<2>(&crypto_session_id_from_initialize));
ASSERT_NO_FATAL_FAILURE(
Initialize(nullptr, base::BindOnce(&CallbackMock::InitializeCallback,
base::Unretained(&callback_mock_))));
::testing::Mock::VerifyAndClearExpectations(&callback_mock_);
const std::vector<uint8_t> kAnyBlob = {
0x01, 0x4f, 0x83,
};
proxy_->SetKey(crypto_session_id_from_initialize, kAnyBlob,
CdmProxy::KeyType::kDecryptAndDecode, kAnyBlob);
base::WeakPtr<CdmContext> context = proxy_->GetCdmContext();
CdmProxyContext* proxy_context = context->GetCdmProxyContext();
auto decrypt_context = proxy_context->GetD3D11DecryptContext(
CdmProxy::KeyType::kDecryptOnly,
std::string(kAnyBlob.begin(), kAnyBlob.end()));
EXPECT_FALSE(decrypt_context);
}
@@ -714,7 +741,8 @@ TEST_F(D3D11CdmProxyTest, SetKeyAndGetDecryptContext) {
kKeyBlob);
std::string key_id_str(kKeyId.begin(), kKeyId.end());
auto decrypt_context = proxy_context->GetD3D11DecryptContext(key_id_str);
auto decrypt_context =
proxy_context->GetD3D11DecryptContext(kTestKeyType, key_id_str);
ASSERT_TRUE(decrypt_context);
EXPECT_TRUE(decrypt_context->crypto_session)
@@ -763,7 +791,8 @@ TEST_F(D3D11CdmProxyTest, ClearKeysAfterHardwareContentProtectionTeardown) {
run_loop.Run();
std::string key_id_str(kKeyId.begin(), kKeyId.end());
auto decrypt_context = proxy_context->GetD3D11DecryptContext(key_id_str);
auto decrypt_context =
proxy_context->GetD3D11DecryptContext(kTestKeyType, key_id_str);
ASSERT_FALSE(decrypt_context);
}
@@ -795,7 +824,8 @@ TEST_F(D3D11CdmProxyTest, RemoveKey) {
proxy_->RemoveKey(crypto_session_id_from_initialize, kKeyId);
std::string keyblob_str(kKeyId.begin(), kKeyId.end());
auto decrypt_context = proxy_context->GetD3D11DecryptContext(keyblob_str);
auto decrypt_context =
proxy_context->GetD3D11DecryptContext(kTestKeyType, keyblob_str);
EXPECT_FALSE(decrypt_context);
}

@@ -168,8 +168,8 @@ void D3D11Decryptor::Decrypt(StreamType stream_type,
return;
}
auto context =
cdm_proxy_context_->GetD3D11DecryptContext(decrypt_config->key_id());
auto context = cdm_proxy_context_->GetD3D11DecryptContext(
CdmProxy::KeyType::kDecryptOnly, decrypt_config->key_id());
if (!context) {
decrypt_cb.Run(kNoKey, nullptr);
return;

@@ -10,8 +10,8 @@
#include "base/containers/span.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "media/base/cdm_proxy_context.h"
#include "media/base/decryptor.h"
#include "media/cdm/cdm_proxy_context.h"
#include "media/gpu/media_gpu_export.h"
#include "media/gpu/windows/d3d11_create_device_cb.h"

@@ -11,9 +11,9 @@
#include "base/bind.h"
#include "base/containers/span.h"
#include "base/stl_util.h"
#include "media/base/cdm_proxy_context.h"
#include "media/base/decoder_buffer.h"
#include "media/base/subsample_entry.h"
#include "media/cdm/cdm_proxy_context.h"
#include "media/gpu/windows/d3d11_mocks.h"
using ::testing::_;
@@ -87,8 +87,9 @@ class CallbackMock {
class CdmProxyContextMock : public CdmProxyContext {
public:
MOCK_METHOD1(GetD3D11DecryptContext,
base::Optional<D3D11DecryptContext>(const std::string& key_id));
MOCK_METHOD2(GetD3D11DecryptContext,
base::Optional<D3D11DecryptContext>(CdmProxy::KeyType key_type,
const std::string& key_id));
};
// Checks that BUFFER_DESC has these fields match.
@@ -181,7 +182,8 @@ class D3D11DecryptorTest : public ::testing::Test {
DoAll(AddRefAndSetArgPointee<1>(video_context_mock_.Get()),
Return(S_OK)));
EXPECT_CALL(mock_proxy_, GetD3D11DecryptContext(kKeyId))
EXPECT_CALL(mock_proxy_,
GetD3D11DecryptContext(CdmProxy::KeyType::kDecryptOnly, kKeyId))
.WillOnce(Return(*decrypt_context));
// These return big enough size.
@@ -469,7 +471,8 @@ TEST_F(D3D11DecryptorTest, NoDecryptContext) {
scoped_refptr<DecoderBuffer> encrypted_buffer = TestDecoderBuffer(
kAnyInput, base::size(kAnyInput), kKeyId, kIv, {kAnyInputSubsample});
EXPECT_CALL(mock_proxy_, GetD3D11DecryptContext(kKeyId))
EXPECT_CALL(mock_proxy_,
GetD3D11DecryptContext(CdmProxy::KeyType::kDecryptOnly, kKeyId))
.WillOnce(Return(base::nullopt));
CallbackMock callbacks;
@@ -504,7 +507,8 @@ TEST_F(D3D11DecryptorTest, ReuseBuffers) {
EXPECT_CALL(*crypto_session_mock.Get(), GetDevice(_))
.Times(AtLeast(1))
.WillRepeatedly(AddRefAndSetArgPointee<0>(device_mock_.Get()));
EXPECT_CALL(mock_proxy_, GetD3D11DecryptContext(kKeyId))
EXPECT_CALL(mock_proxy_,
GetD3D11DecryptContext(CdmProxy::KeyType::kDecryptOnly, kKeyId))
.WillOnce(Return(decrypt_context));
// Buffers should not be (re)initialized on the next call to decrypt because

@@ -8,8 +8,8 @@
#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "media/base/cdm_proxy_context.h"
#include "media/base/media_log.h"
#include "media/cdm/cdm_proxy_context.h"
#include "media/gpu/h264_decoder.h"
#include "media/gpu/h264_dpb.h"
#include "media/gpu/windows/d3d11_picture_buffer.h"
@@ -105,7 +105,7 @@ Status D3D11H264Accelerator::SubmitFrameMetadata(
base::Optional<CdmProxyContext::D3D11DecryptContext> decrypt_context;
if (is_encrypted) {
decrypt_context = cdm_proxy_context_->GetD3D11DecryptContext(
pic->decrypt_config()->key_id());
CdmProxy::KeyType::kDecryptAndDecode, pic->decrypt_config()->key_id());
if (!decrypt_context) {
RecordFailure("Cannot find decrypt context for the frame.");
return Status::kTryAgain;

@@ -11,9 +11,9 @@
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/test/test_message_loop.h"
#include "media/base/cdm_proxy_context.h"
#include "media/base/gmock_callback_support.h"
#include "media/base/mock_filters.h"
#include "media/cdm/cdm_proxy_context.h"
#include "media/mojo/interfaces/cdm_proxy.mojom.h"
#include "media/mojo/services/mojo_cdm_proxy.h"
#include "media/mojo/services/mojo_cdm_proxy_service.h"