Skip to content

Commit

Permalink
media: Check hardware secure decryption capabilities on Windows
Browse files Browse the repository at this point in the history
- Update KeySystemSupportImpl to check kDisableAcceleratedVideoDecode
  and kMojoVideoDecoder.
- Update KeySystemSupportImpl to call ContentBrowserClient to query
  hardware secure decryption capabilities.
- Add ContentBrowserClient::GetHardwareSecureDecryptionCaps().
- Implement
  ChromeContentBrowserClient::GetHardwareSecureDecryptionCaps().
- Add GetWidevineHardwareCaps() to check Widevine-specific caps on
  Windows.
- Rename kEnableHardwareSecureCodecsForTesting to
  kOverrideHardwareSecureCodecsForTesting to better reflect that fact
  that real platform hardware secure codecs check will be skipped.

Bug: 848532
Test: Added unit test.
Change-Id: Ia931fc945e5eb2fd406793cf87e334f3f9e00256
Reviewed-on: https://chromium-review.googlesource.com/1106960
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
Reviewed-by: John Rummell <jrummell@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Xiaohan Wang <xhwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#570475}
  • Loading branch information
xhwang-chromium authored and Commit Bot committed Jun 26, 2018
1 parent 52e14d9 commit a4e4184
Show file tree
Hide file tree
Showing 16 changed files with 341 additions and 55 deletions.
13 changes: 12 additions & 1 deletion chrome/browser/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -3805,6 +3805,17 @@ jumbo_split_static_library("browser") {
"media/output_protection_impl.cc",
"media/output_protection_impl.h",
]
deps += [ "//media/mojo/interfaces" ]

if (is_win) {
sources += [
"media/widevine_hardware_caps_win.cc",
"media/widevine_hardware_caps_win.h",
]
deps += [ "//third_party/widevine/cdm:headers" ]
libs += [ "d3d11.lib" ]
}

if (enable_cdm_storage_id) {
sources += [
"media/cdm_storage_id.cc",
Expand All @@ -3816,7 +3827,7 @@ jumbo_split_static_library("browser") {
sources += [ "internal/google_chrome_cdm_storage_id_key.h" ]
}
}
deps += [ "//media/mojo/interfaces" ]

if (mojo_media_host == "browser") {
deps += [
"//media/mojo/interfaces:constants",
Expand Down
1 change: 1 addition & 0 deletions chrome/browser/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ include_rules = [
"+third_party/cros_system_api",
"+third_party/libaom/av1_buildflags.h",
"+third_party/metrics_proto",
"+third_party/widevine/cdm/widevine_cdm_common.h",

# Code under //ash runs out-of-process in mash so it must be accessed via mojo
# interfaces in //ash/public/interfaces. See //ash/README.md.
Expand Down
25 changes: 22 additions & 3 deletions chrome/browser/chrome_content_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@
#include "chrome/browser/font_family_cache.h"
#include "chrome/browser/language/chrome_language_detection_tab_helper.h"
#include "chrome/browser/lifetime/browser_shutdown.h"
#include "chrome/browser/media/platform_verification_impl.h"
#include "chrome/browser/media/router/media_router_feature.h"
#include "chrome/browser/media/router/presentation/presentation_service_delegate_impl.h"
#include "chrome/browser/media/router/presentation/receiver_presentation_service_delegate_impl.h"
Expand Down Expand Up @@ -466,12 +465,18 @@
#include "chrome/services/printing/public/mojom/constants.mojom.h"
#endif

#if BUILDFLAG(ENABLE_MOJO_MEDIA)
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
#include "chrome/browser/media/output_protection_impl.h"
#include "chrome/browser/media/platform_verification_impl.h"
#if defined(OS_WIN) && defined(WIDEVINE_CDM_AVAILABLE)
#include "chrome/browser/media/widevine_hardware_caps_win.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h"
#endif
#endif

#if BUILDFLAG(ENABLE_MOJO_CDM) && defined(OS_ANDROID)
#include "chrome/browser/media/android/cdm/media_drm_storage_factory.h"
#endif
#endif

#if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
#include "media/mojo/interfaces/constants.mojom.h" // nogncheck
Expand Down Expand Up @@ -3921,6 +3926,20 @@ ChromeContentBrowserClient::GetNavigationUIData(
return std::make_unique<ChromeNavigationUIData>(navigation_handle);
}

void ChromeContentBrowserClient::GetHardwareSecureDecryptionCaps(
const std::string& key_system,
const base::flat_set<media::CdmProxy::Protocol>& cdm_proxy_protocols,
base::flat_set<media::VideoCodec>* video_codecs,
base::flat_set<media::EncryptionMode>* encryption_schemes) {
#if defined(OS_WIN) && BUILDFLAG(ENABLE_LIBRARY_CDMS) && \
defined(WIDEVINE_CDM_AVAILABLE)
if (key_system == kWidevineKeySystem) {
GetWidevineHardwareCaps(cdm_proxy_protocols, video_codecs,
encryption_schemes);
}
#endif
}

content::DevToolsManagerDelegate*
ChromeContentBrowserClient::GetDevToolsManagerDelegate() {
#if defined(OS_ANDROID)
Expand Down
5 changes: 5 additions & 0 deletions chrome/browser/chrome_content_browser_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,11 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
CreateThrottlesForNavigation(content::NavigationHandle* handle) override;
std::unique_ptr<content::NavigationUIData> GetNavigationUIData(
content::NavigationHandle* navigation_handle) override;
void GetHardwareSecureDecryptionCaps(
const std::string& key_system,
const base::flat_set<media::CdmProxy::Protocol>& cdm_proxy_protocols,
base::flat_set<media::VideoCodec>* video_codecs,
base::flat_set<media::EncryptionMode>* encryption_schemes) override;
std::unique_ptr<content::MemoryCoordinatorDelegate>
GetMemoryCoordinatorDelegate() override;
::rappor::RapporService* GetRapporService() override;
Expand Down
1 change: 1 addition & 0 deletions chrome/browser/media/DEPS
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ include_rules = [
"+media/audio",
"+media/base",
"+media/cast",
"+media/cdm/cdm_proxy.h",
"+media/cdm/supported_cdm_versions.h",
"+media/media_buildflags.h",
"+media/mojo/interfaces",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ class EncryptedMediaSupportedTypesWidevineHwSecureTest
// Pretend that we support hardware secure decryption for vp8 and vp9, but
// not for avc1.
command_line->AppendSwitchASCII(
switches::kEnableHardwareSecureCodecsForTesting, "vp8,vp9");
switches::kOverrideHardwareSecureCodecsForTesting, "vp8,vp9");
}

private:
Expand Down Expand Up @@ -1119,7 +1119,7 @@ IN_PROC_BROWSER_TEST_F(EncryptedMediaSupportedTypesWidevineTest,
// Widevine with hardware secure decryption support. Note that for the test
// suite EncryptedMediaSupportedTypesWidevineHwSecureTest, feature
// media::kHardwareSecureDecryption is enabled, and command line switch
// kEnableHardwareSecureCodecsForTesting is used to always enable vp8 and vp9,
// kOverrideHardwareSecureCodecsForTesting is used to always enable vp8 and vp9,
// and disable avc1. With the switch, real hardware capabilities are not checked
// for the stability of tests.

Expand Down
127 changes: 127 additions & 0 deletions chrome/browser/media/widevine_hardware_caps_win.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/media/widevine_hardware_caps_win.h"

#include <comdef.h>
#include <d3d11_1.h>
#include <initguid.h>
#include <stdint.h>
#include <wrl/client.h>
#include <bitset>

#include "base/macros.h"
#include "base/stl_util.h"
#include "media/base/decrypt_config.h"

namespace {

// Alias for printing HRESULT.
const auto PrintHr = logging::SystemErrorCodeToString;

// TODO(xhwang): Deduplicate this file and widevine_cdm_proxy_factory.cc.
// clang-format off
DEFINE_GUID(kD3DCryptoTypeIntelWidevine,
0x586e681, 0x4e14, 0x4133, 0x85, 0xe5, 0xa1, 0x4, 0x1f, 0x59, 0x9e, 0x26);
// clang-format on

// Bit indices for Intel Widevine hardware secure decryption capabilities.
//
// Encryption schemes are defined in ISO/IEC 23001-7, "Common encryption in ISO
// base media file format files". Version 1 refers to ISO/IEC 23001-7:2012.
// Version 3 refers to ISO/IEC 23001-7:2016. The difference that matters in this
// context is as follows:
// - In Version 1, section 9.5, "In full sample encryption, the entire sample is
// encrypted".
// - In Version 3, section 9.4.1, "Full sample encryption MAY be used for all
// encrypted media types other than NAL Structured video, which SHALL use
// Subsample encryption."
// Therefore with kCencVersion1, it is possible that an entire sample of NAL
// Structured video is encrypted. This is not allowed with kCencVersion3.
enum IntelWidevineCaps {
kSupported = 0,
kAesCtr = 8,
kAesCbc = 9,
kCencVersion1 = 10,
kCencVersion3 = 11,
kCbcs = 17,
};

} // namespace

void GetWidevineHardwareCaps(
const base::flat_set<media::CdmProxy::Protocol>& cdm_proxy_protocols,
base::flat_set<media::VideoCodec>* video_codecs,
base::flat_set<media::EncryptionMode>* encryption_schemes) {
DCHECK(!cdm_proxy_protocols.empty());
DCHECK(video_codecs->empty());
DCHECK(encryption_schemes->empty());

// We only support kD3DCryptoTypeIntelWidevine.
if (!cdm_proxy_protocols.count(media::CdmProxy::Protocol::kIntel)) {
DVLOG(1) << "CDM supported CdmProxy protocol not supported by the system";
return;
}

Microsoft::WRL::ComPtr<ID3D11Device> device;
Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device;

// D3D11CdmProxy requires D3D_FEATURE_LEVEL_11_1.
const D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_1};

// Create device and pupulate |device|.
HRESULT hresult = D3D11CreateDevice(
nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, 0, feature_levels,
base::size(feature_levels), D3D11_SDK_VERSION, device.GetAddressOf(),
nullptr, nullptr);

if (FAILED(hresult)) {
DVLOG(1) << "Failed to create the D3D11Device: " << PrintHr(hresult);
return;
}

hresult = device.CopyTo(video_device.GetAddressOf());
if (FAILED(hresult)) {
DVLOG(1) << "Failed to get ID3D11VideoDevice: " << PrintHr(hresult);
return;
}

D3D11_VIDEO_CONTENT_PROTECTION_CAPS caps = {};

// Check whether kD3DCryptoTypeIntelWidevine is supported with H264 codec.
// TODO(xhwang): Support query for VP9.
hresult = video_device->GetContentProtectionCaps(
&kD3DCryptoTypeIntelWidevine, &D3D11_DECODER_PROFILE_H264_VLD_NOFGT,
&caps);
if (FAILED(hresult)) {
DVLOG(1) << "Failed to GetContentProtectionCaps: " << PrintHr(hresult);
return;
}

// For kD3DCryptoTypeIntelWidevine, this is a bitmask of IntelWidevineCaps.
auto capability = std::bitset<64>(caps.ProtectedMemorySize);
DVLOG(1) << "Content protection caps: " << capability;

if (!capability.test(IntelWidevineCaps::kSupported)) {
DVLOG(1) << "Hardware secure decryption not supported";
return;
}

// TODO(xhwang): Support query for CBCS.
if (!capability.test(IntelWidevineCaps::kAesCtr)) {
DVLOG(1) << "AES-CTR decryption not supported";
return;
}

// There are contents encrypted with kCencVersion1 out there. Therefore we
// require kCencVersion1 to declare "cenc" support.
if (!capability.test(IntelWidevineCaps::kCencVersion1)) {
DVLOG(1) << "CENC version 1 not supported";
return;
}

DVLOG(1) << "Widevine hardware secure H264/CENC decryption supported";
video_codecs->insert(media::VideoCodec::kCodecH264);
encryption_schemes->insert(media::EncryptionMode::kCenc);
}
23 changes: 23 additions & 0 deletions chrome/browser/media/widevine_hardware_caps_win.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_MEDIA_WIDEVINE_HARDWARE_CAPS_WIN_H_
#define CHROME_BROWSER_MEDIA_WIDEVINE_HARDWARE_CAPS_WIN_H_

#include "base/containers/flat_set.h"
#include "media/base/video_codecs.h"
#include "media/cdm/cdm_proxy.h"

namespace media {
enum class EncryptionMode;
}

// Get supported Widevine hardware capabilities, including supported
// |video_codecs| and |encryption_schemes|.
void GetWidevineHardwareCaps(
const base::flat_set<media::CdmProxy::Protocol>& cdm_proxy_protocols,
base::flat_set<media::VideoCodec>* video_codecs,
base::flat_set<media::EncryptionMode>* encryption_schemes);

#endif // CHROME_BROWSER_MEDIA_WIDEVINE_HARDWARE_CAPS_WIN_H_
18 changes: 18 additions & 0 deletions chrome/browser/media/widevine_hardware_caps_win_unittest.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/media/widevine_hardware_caps_win.h"

#include "testing/gtest/include/gtest/gtest.h"

TEST(WidevineHardwareCapsTest, GetWidevineHardwareCaps) {
base::flat_set<media::CdmProxy::Protocol> cdm_proxy_protocols = {
media::CdmProxy::Protocol::kIntel};
base::flat_set<media::VideoCodec> video_codecs;
base::flat_set<media::EncryptionMode> encryption_schemes;

// Not checking the results since it's hardware dependent.
GetWidevineHardwareCaps(cdm_proxy_protocols, &video_codecs,
&encryption_schemes);
}
28 changes: 8 additions & 20 deletions chrome/gpu/widevine_cdm_proxy_factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,18 @@
#include <comdef.h>
#include <initguid.h>

#include <iomanip>

#include "base/logging.h"
#include "build/build_config.h"
#include "media/cdm/cdm_proxy.h"
#include "media/gpu/windows/d3d11_cdm_proxy.h"

namespace {

// Helpers for printing HRESULTs.
struct PrintHr {
explicit PrintHr(HRESULT hr) : hr(hr) {}
HRESULT hr;
};

std::ostream& operator<<(std::ostream& os, const PrintHr& phr) {
std::ios_base::fmtflags ff = os.flags();
os << _com_error(phr.hr).ErrorMessage() << " (" << std::showbase << std::hex
<< std::uppercase << std::setfill('0') << std::setw(8) << phr.hr << ")";
os.flags(ff);
return os;
}
// Alias for printing HRESULT.
const auto PrintHr = logging::SystemErrorCodeToString;

// clang-format off
DEFINE_GUID(kD3D11ConfigWidevineStreamId,
DEFINE_GUID(kD3DCryptoTypeIntelWidevine,
0x586e681, 0x4e14, 0x4133, 0x85, 0xe5, 0xa1, 0x4, 0x1f, 0x59, 0x9e, 0x26);
// clang-format on

Expand Down Expand Up @@ -62,10 +50,10 @@ std::unique_ptr<media::CdmProxy> CreateWidevineCdmProxy() {

D3D11_VIDEO_CONTENT_PROTECTION_CAPS caps = {};

// Check whether kD3D11ConfigWidevineStreamId is supported.
// Check whether kD3DCryptoTypeIntelWidevine is supported.
// We do not care about decoder support so just use a null decoder profile.
hresult = video_device->GetContentProtectionCaps(
&kD3D11ConfigWidevineStreamId, nullptr, &caps);
hresult = video_device->GetContentProtectionCaps(&kD3DCryptoTypeIntelWidevine,
nullptr, &caps);
if (FAILED(hresult)) {
DLOG(ERROR) << "Failed to GetContentProtectionCaps: " << PrintHr(hresult);
return nullptr;
Expand All @@ -76,6 +64,6 @@ std::unique_ptr<media::CdmProxy> CreateWidevineCdmProxy() {
0x90000001}};

return std::make_unique<media::D3D11CdmProxy>(
kD3D11ConfigWidevineStreamId, media::CdmProxy::Protocol::kIntel,
kD3DCryptoTypeIntelWidevine, media::CdmProxy::Protocol::kIntel,
std::move(function_id_map));
}
1 change: 1 addition & 0 deletions chrome/test/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -2718,6 +2718,7 @@ test("unit_tests") {
if (is_win) {
assert(toolkit_views)
sources += [
"../browser/media/widevine_hardware_caps_win_unittest.cc",
"../browser/notifications/win/mock_notification_image_retainer.cc",
"../browser/notifications/win/mock_notification_image_retainer.h",
"../browser/ui/views/try_chrome_dialog_win/button_layout_unittest.cc",
Expand Down
Loading

0 comments on commit a4e4184

Please sign in to comment.