Commit ad51b5b1 authored by Xiaohan Wang's avatar Xiaohan Wang Committed by Commit Bot

media: Refactor KeySystemSupport

- Add hardware secure codecs and encryption_scheme support
- Use a vector for supported session types in case we need to support
  more session types in the future
- Use the mojom type directly on the client side to avoid duplicate code

Bug: 848532
Test: No functionality change.
Change-Id: Ieb61bdd223bc340593eb633b5f85e1abc3cec6f8
Reviewed-on: https://chromium-review.googlesource.com/1102836Reviewed-by: default avatarNasko Oskov <nasko@chromium.org>
Reviewed-by: default avatarJohn Rummell <jrummell@chromium.org>
Commit-Queue: Xiaohan Wang <xhwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#568237}
parent 764f6b58
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <vector> #include <vector>
#include "base/logging.h" #include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
...@@ -80,12 +81,9 @@ static void AddExternalClearKey( ...@@ -80,12 +81,9 @@ static void AddExternalClearKey(
static const char kExternalClearKeyCdmProxyKeySystem[] = static const char kExternalClearKeyCdmProxyKeySystem[] =
"org.chromium.externalclearkey.cdmproxy"; "org.chromium.externalclearkey.cdmproxy";
std::vector<media::VideoCodec> supported_video_codecs; media::mojom::KeySystemCapabilityPtr capability;
bool supports_persistent_license; if (!content::IsKeySystemSupported(kExternalClearKeyKeySystem, &capability)) {
std::vector<media::EncryptionMode> supported_encryption_schemes; DVLOG(1) << "External Clear Key not supported";
if (!content::IsKeySystemSupported(
kExternalClearKeyKeySystem, &supported_video_codecs,
&supports_persistent_license, &supported_encryption_schemes)) {
return; return;
} }
...@@ -233,30 +231,39 @@ static void AddWidevine( ...@@ -233,30 +231,39 @@ static void AddWidevine(
return; return;
#endif // defined(WIDEVINE_CDM_MIN_GLIBC_VERSION) #endif // defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
std::vector<media::VideoCodec> supported_video_codecs; media::mojom::KeySystemCapabilityPtr capability;
bool supports_persistent_license = false; if (!content::IsKeySystemSupported(kWidevineKeySystem, &capability)) {
std::vector<media::EncryptionMode> supported_encryption_schemes;
if (!content::IsKeySystemSupported(
kWidevineKeySystem, &supported_video_codecs,
&supports_persistent_license, &supported_encryption_schemes)) {
DVLOG(1) << "Widevine CDM is not currently available."; DVLOG(1) << "Widevine CDM is not currently available.";
return; return;
} }
auto supported_codecs = GetSupportedCodecs(supported_video_codecs); auto supported_codecs = GetSupportedCodecs(capability->video_codecs);
const auto& supported_encryption_schemes = capability->encryption_schemes;
// On ChromeOS, we do not have real hardware secure codecs. But this does not // On ChromeOS, we do not have real hardware secure codecs. But this does not
// affect HW_SECURE* support since the support doesn't require hardware secure // affect HW_SECURE* support since the support doesn't require hardware secure
// codecs. See WidevineKeySystemProperties::GetRobustnessConfigRule(). // codecs. See WidevineKeySystemProperties::GetRobustnessConfigRule().
// TODO(crbug.com/848532): Populate supported secure codecs if supported by auto supported_hw_secure_codecs =
// CDM and the platform. GetSupportedCodecs(capability->hw_secure_video_codecs);
auto supported_hw_secure_codecs = media::EME_CODEC_NONE;
// TODO(crbug.com/853261): Support capability->hw_secure_encryption_schemes.
bool cdm_supports_temporary_session = base::ContainsValue(
capability->session_types, media::CdmSessionType::TEMPORARY_SESSION);
if (!cdm_supports_temporary_session) {
DVLOG(1) << "Temporary session must be supported.";
return;
}
bool cdm_supports_persistent_license =
base::ContainsValue(capability->session_types,
media::CdmSessionType::PERSISTENT_LICENSE_SESSION);
auto persistent_license_support = auto persistent_license_support =
GetPersistentLicenseSupport(supports_persistent_license); GetPersistentLicenseSupport(cdm_supports_persistent_license);
using Robustness = cdm::WidevineKeySystemProperties::Robustness; using Robustness = cdm::WidevineKeySystemProperties::Robustness;
// TODO(xhwang/jrummell): Parse hw_secure_encryption_schemes.
concrete_key_systems->emplace_back(new cdm::WidevineKeySystemProperties( concrete_key_systems->emplace_back(new cdm::WidevineKeySystemProperties(
supported_encryption_schemes, supported_codecs, supported_encryption_schemes, supported_codecs,
supported_hw_secure_codecs, supported_hw_secure_codecs,
......
...@@ -59,20 +59,36 @@ KeySystemSupportImpl::~KeySystemSupportImpl() = default; ...@@ -59,20 +59,36 @@ KeySystemSupportImpl::~KeySystemSupportImpl() = default;
void KeySystemSupportImpl::IsKeySystemSupported( void KeySystemSupportImpl::IsKeySystemSupported(
const std::string& key_system, const std::string& key_system,
IsKeySystemSupportedCallback callback) { IsKeySystemSupportedCallback callback) {
DVLOG(3) << __func__; DVLOG(3) << __func__ << ": key_system = " << key_system;
std::unique_ptr<CdmInfo> cdm = GetCdmInfoForKeySystem(key_system);
if (!cdm) { auto cdm_info = GetCdmInfoForKeySystem(key_system);
if (!cdm_info) {
SendCdmAvailableUMA(key_system, false); SendCdmAvailableUMA(key_system, false);
std::move(callback).Run(false, {}, false, {}); std::move(callback).Run(false, nullptr);
return; return;
} }
const base::flat_set<media::EncryptionMode>& schemes =
cdm->supported_encryption_schemes;
SendCdmAvailableUMA(key_system, true); SendCdmAvailableUMA(key_system, true);
std::move(callback).Run(
true, cdm->supported_video_codecs, cdm->supports_persistent_license, // Supported codecs and encryption schemes.
std::vector<media::EncryptionMode>(schemes.begin(), schemes.end())); auto capability = media::mojom::KeySystemCapability::New();
const auto& schemes = cdm_info->supported_encryption_schemes;
capability->video_codecs = cdm_info->supported_video_codecs;
capability->encryption_schemes =
std::vector<media::EncryptionMode>(schemes.begin(), schemes.end());
// TODO(xhwang): Populate hw_secure* fields on Windows.
// Temporary session is always supported.
// TODO(xhwang): Populate this from CdmInfo.
capability->session_types.push_back(media::CdmSessionType::TEMPORARY_SESSION);
if (cdm_info->supports_persistent_license) {
capability->session_types.push_back(
media::CdmSessionType::PERSISTENT_LICENSE_SESSION);
}
std::move(callback).Run(true, std::move(capability));
} }
} // namespace content } // namespace content
...@@ -22,11 +22,35 @@ namespace content { ...@@ -22,11 +22,35 @@ namespace content {
namespace { namespace {
using VideoCodec = media::VideoCodec;
using EncryptionMode = media::EncryptionMode;
using CdmSessionType = media::CdmSessionType;
const char kTestCdmGuid[] = "62FE9C4B-384E-48FD-B28A-9F6F248BC8CC"; const char kTestCdmGuid[] = "62FE9C4B-384E-48FD-B28A-9F6F248BC8CC";
const char kVersion[] = "1.1.1.1"; const char kVersion[] = "1.1.1.1";
const char kTestPath[] = "/aa/bb"; const char kTestPath[] = "/aa/bb";
const char kTestFileSystemId[] = "file_system_id"; const char kTestFileSystemId[] = "file_system_id";
// Helper function to compare a STL container to an initializer_list.
template <typename Container, typename T>
bool StlEquals(const Container a, std::initializer_list<T> b) {
return a == Container(b);
}
#define EXPECT_STL_EQ(a, ...) \
do { \
EXPECT_TRUE(StlEquals(a, {__VA_ARGS__})); \
} while (false)
#define EXPECT_VIDEO_CODECS(...) \
EXPECT_STL_EQ(capability_->video_codecs, __VA_ARGS__)
#define EXPECT_ENCRYPTION_SCHEMES(...) \
EXPECT_STL_EQ(capability_->encryption_schemes, __VA_ARGS__)
#define EXPECT_SESSION_TYPES(...) \
EXPECT_STL_EQ(capability_->session_types, __VA_ARGS__)
} // namespace } // namespace
class KeySystemSupportTest : public testing::Test { class KeySystemSupportTest : public testing::Test {
...@@ -58,8 +82,7 @@ class KeySystemSupportTest : public testing::Test { ...@@ -58,8 +82,7 @@ class KeySystemSupportTest : public testing::Test {
DVLOG(1) << __func__; DVLOG(1) << __func__;
bool is_available = false; bool is_available = false;
key_system_support_->IsKeySystemSupported(key_system, &is_available, key_system_support_->IsKeySystemSupported(key_system, &is_available,
&codecs_, &persistent_, &capability_);
&encryption_schemes_);
return is_available; return is_available;
} }
...@@ -67,9 +90,7 @@ class KeySystemSupportTest : public testing::Test { ...@@ -67,9 +90,7 @@ class KeySystemSupportTest : public testing::Test {
TestBrowserThreadBundle test_browser_thread_bundle_; TestBrowserThreadBundle test_browser_thread_bundle_;
// Updated by IsSupported(). // Updated by IsSupported().
std::vector<media::VideoCodec> codecs_; media::mojom::KeySystemCapabilityPtr capability_;
bool persistent_;
std::vector<media::EncryptionMode> encryption_schemes_;
}; };
// Note that as CdmRegistry::GetInstance() is a static, it is shared between // Note that as CdmRegistry::GetInstance() is a static, it is shared between
...@@ -78,18 +99,18 @@ class KeySystemSupportTest : public testing::Test { ...@@ -78,18 +99,18 @@ class KeySystemSupportTest : public testing::Test {
TEST_F(KeySystemSupportTest, NoKeySystems) { TEST_F(KeySystemSupportTest, NoKeySystems) {
EXPECT_FALSE(IsSupported("KeySystem1")); EXPECT_FALSE(IsSupported("KeySystem1"));
EXPECT_FALSE(capability_);
} }
TEST_F(KeySystemSupportTest, OneKeySystem) { TEST_F(KeySystemSupportTest, OneKeySystem) {
Register("KeySystem2", {media::VideoCodec::kCodecVP8}, true, Register("KeySystem2", {VideoCodec::kCodecVP8}, true,
{media::EncryptionMode::kCenc, media::EncryptionMode::kCbcs}); {EncryptionMode::kCenc, EncryptionMode::kCbcs});
EXPECT_TRUE(IsSupported("KeySystem2")); EXPECT_TRUE(IsSupported("KeySystem2"));
EXPECT_EQ(1u, codecs_.size()); EXPECT_VIDEO_CODECS(VideoCodec::kCodecVP8);
EXPECT_EQ(media::VideoCodec::kCodecVP8, codecs_[0]); EXPECT_ENCRYPTION_SCHEMES(EncryptionMode::kCenc, EncryptionMode::kCbcs);
EXPECT_TRUE(persistent_); EXPECT_SESSION_TYPES(CdmSessionType::TEMPORARY_SESSION,
EXPECT_EQ(2u, encryption_schemes_.size()); CdmSessionType::PERSISTENT_LICENSE_SESSION);
EXPECT_EQ(media::EncryptionMode::kCenc, encryption_schemes_[0]);
EXPECT_EQ(media::EncryptionMode::kCbcs, encryption_schemes_[1]);
} }
TEST_F(KeySystemSupportTest, MultipleKeySystems) { TEST_F(KeySystemSupportTest, MultipleKeySystems) {
...@@ -98,25 +119,25 @@ TEST_F(KeySystemSupportTest, MultipleKeySystems) { ...@@ -98,25 +119,25 @@ TEST_F(KeySystemSupportTest, MultipleKeySystems) {
{media::EncryptionMode::kCenc}); {media::EncryptionMode::kCenc});
Register("KeySystem4", {media::VideoCodec::kCodecVP9}, false, Register("KeySystem4", {media::VideoCodec::kCodecVP9}, false,
{media::EncryptionMode::kCbcs}); {media::EncryptionMode::kCbcs});
EXPECT_TRUE(IsSupported("KeySystem3")); EXPECT_TRUE(IsSupported("KeySystem3"));
EXPECT_EQ(2u, codecs_.size()); EXPECT_VIDEO_CODECS(VideoCodec::kCodecVP8, VideoCodec::kCodecVP9);
EXPECT_EQ(media::VideoCodec::kCodecVP8, codecs_[0]); EXPECT_ENCRYPTION_SCHEMES(EncryptionMode::kCenc);
EXPECT_EQ(media::VideoCodec::kCodecVP9, codecs_[1]); EXPECT_SESSION_TYPES(CdmSessionType::TEMPORARY_SESSION,
EXPECT_TRUE(persistent_); CdmSessionType::PERSISTENT_LICENSE_SESSION);
EXPECT_EQ(1u, encryption_schemes_.size());
EXPECT_EQ(media::EncryptionMode::kCenc, encryption_schemes_[0]);
EXPECT_TRUE(IsSupported("KeySystem4")); EXPECT_TRUE(IsSupported("KeySystem4"));
EXPECT_EQ(1u, codecs_.size()); EXPECT_VIDEO_CODECS(VideoCodec::kCodecVP9);
EXPECT_EQ(media::VideoCodec::kCodecVP9, codecs_[0]); EXPECT_ENCRYPTION_SCHEMES(EncryptionMode::kCbcs);
EXPECT_FALSE(persistent_); EXPECT_SESSION_TYPES(CdmSessionType::TEMPORARY_SESSION);
EXPECT_EQ(1u, encryption_schemes_.size());
EXPECT_EQ(media::EncryptionMode::kCbcs, encryption_schemes_[0]);
} }
TEST_F(KeySystemSupportTest, MissingKeySystem) { TEST_F(KeySystemSupportTest, MissingKeySystem) {
Register("KeySystem5", {media::VideoCodec::kCodecVP8}, true, Register("KeySystem5", {media::VideoCodec::kCodecVP8}, true,
{media::EncryptionMode::kCenc}); {media::EncryptionMode::kCenc});
EXPECT_FALSE(IsSupported("KeySystem6")); EXPECT_FALSE(IsSupported("KeySystem6"));
EXPECT_FALSE(capability_);
} }
} // namespace content } // namespace content
...@@ -14,9 +14,7 @@ namespace content { ...@@ -14,9 +14,7 @@ namespace content {
bool IsKeySystemSupported( bool IsKeySystemSupported(
const std::string& key_system, const std::string& key_system,
std::vector<media::VideoCodec>* supported_video_codecs, media::mojom::KeySystemCapabilityPtr* key_system_capability) {
bool* supports_persistent_license,
std::vector<media::EncryptionMode>* supported_encryption_schemes) {
DVLOG(3) << __func__ << " key_system: " << key_system; DVLOG(3) << __func__ << " key_system: " << key_system;
bool is_supported = false; bool is_supported = false;
...@@ -24,9 +22,8 @@ bool IsKeySystemSupported( ...@@ -24,9 +22,8 @@ bool IsKeySystemSupported(
content::RenderThread::Get()->GetConnector()->BindInterface( content::RenderThread::Get()->GetConnector()->BindInterface(
mojom::kBrowserServiceName, mojo::MakeRequest(&key_system_support)); mojom::kBrowserServiceName, mojo::MakeRequest(&key_system_support));
key_system_support->IsKeySystemSupported( key_system_support->IsKeySystemSupported(key_system, &is_supported,
key_system, &is_supported, supported_video_codecs, key_system_capability);
supports_persistent_license, supported_encryption_schemes);
return is_supported; return is_supported;
} }
......
...@@ -9,20 +9,16 @@ ...@@ -9,20 +9,16 @@
#include <vector> #include <vector>
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "media/base/decrypt_config.h" #include "media/mojo/interfaces/key_system_support.mojom.h"
#include "media/base/video_codecs.h"
namespace content { namespace content {
// Determines if |key_system| is supported by calling into the browser. // Determines if |key_system| is supported by calling into the browser.
// If it is supported, return true and |supported_video_codecs|, // If it is supported, return true and |key_system_capability| is updated
// |supports_persistent_license| and |supported_encryption_schemes| are updated
// to match what |key_system| supports. If not supported, false is returned. // to match what |key_system| supports. If not supported, false is returned.
CONTENT_EXPORT bool IsKeySystemSupported( CONTENT_EXPORT bool IsKeySystemSupported(
const std::string& key_system, const std::string& key_system,
std::vector<media::VideoCodec>* supported_video_codecs, media::mojom::KeySystemCapabilityPtr* key_system_capability);
bool* supports_persistent_license,
std::vector<media::EncryptionMode>* supported_encryption_schemes);
} // namespace content } // namespace content
......
...@@ -4,21 +4,36 @@ ...@@ -4,21 +4,36 @@
module media.mojom; module media.mojom;
import "media/mojo/interfaces/content_decryption_module.mojom";
import "media/mojo/interfaces/media_types.mojom"; import "media/mojo/interfaces/media_types.mojom";
// TODO(xhwang): Use "set" instead of "array" if supported by mojom.
// TODO(crbug.com/796725) Find a way to include profiles and levels for
// supported codecs.
struct KeySystemCapability {
// Software secure codecs and encryption schemes supported by the CDM.
array<VideoCodec> video_codecs;
array<EncryptionMode> encryption_schemes;
// Hardware secure codecs and encryption schemes supported by the CDM,
// directly or indirectly through CdmProxy.
array<VideoCodec> hw_secure_video_codecs;
array<EncryptionMode> hw_secure_encryption_schemes;
// Session types supported in software secure mode if no
// |hw_secure_video_codecs| is supported, or in both modes otherwise.
array<CdmSessionType> session_types;
};
interface KeySystemSupport { interface KeySystemSupport {
// Query to determine if the browser supports the key system |key_system|. // Query to determine if the browser supports the |key_system|. If supported,
// If supported, |is_supported| = true and the remaining properties indicate // |key_system_capability| is non-null indicating supported capability.
// the codecs supported, if the key system supports persistent licenses, and // KeySystemSupport implementation is in the browser process, as it maintains
// the set of encryption schemes supported. KeySystemSupport implementation // the list of registered CDMs, and hardware secure support check also needs
// is in the browser process, as it maintains the list of installed key // to run in the browser process because the render process is sandboxed.
// systems. Clients run in the renderer process. // KeySystemSupport clients run in the renderer process.
// TODO(crbug.com/796725) Find a way to include profiles and levels for // TODO(crbug.com/853264): Make this an async call.
// |supported_video_codecs|.
[Sync] [Sync]
IsKeySystemSupported(string key_system) IsKeySystemSupported(string key_system)
=> (bool is_supported, => (bool is_supported, KeySystemCapability? key_system_capability);
array<VideoCodec> supported_video_codecs,
bool supports_persistent_license,
array<EncryptionMode> supported_encryption_schemes);
}; };
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment