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 @@
#include <vector>
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string16.h"
#include "base/strings/string_split.h"
#include "base/strings/utf_string_conversions.h"
......@@ -80,12 +81,9 @@ static void AddExternalClearKey(
static const char kExternalClearKeyCdmProxyKeySystem[] =
"org.chromium.externalclearkey.cdmproxy";
std::vector<media::VideoCodec> supported_video_codecs;
bool supports_persistent_license;
std::vector<media::EncryptionMode> supported_encryption_schemes;
if (!content::IsKeySystemSupported(
kExternalClearKeyKeySystem, &supported_video_codecs,
&supports_persistent_license, &supported_encryption_schemes)) {
media::mojom::KeySystemCapabilityPtr capability;
if (!content::IsKeySystemSupported(kExternalClearKeyKeySystem, &capability)) {
DVLOG(1) << "External Clear Key not supported";
return;
}
......@@ -233,30 +231,39 @@ static void AddWidevine(
return;
#endif // defined(WIDEVINE_CDM_MIN_GLIBC_VERSION)
std::vector<media::VideoCodec> supported_video_codecs;
bool supports_persistent_license = false;
std::vector<media::EncryptionMode> supported_encryption_schemes;
if (!content::IsKeySystemSupported(
kWidevineKeySystem, &supported_video_codecs,
&supports_persistent_license, &supported_encryption_schemes)) {
media::mojom::KeySystemCapabilityPtr capability;
if (!content::IsKeySystemSupported(kWidevineKeySystem, &capability)) {
DVLOG(1) << "Widevine CDM is not currently available.";
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
// affect HW_SECURE* support since the support doesn't require hardware secure
// codecs. See WidevineKeySystemProperties::GetRobustnessConfigRule().
// TODO(crbug.com/848532): Populate supported secure codecs if supported by
// CDM and the platform.
auto supported_hw_secure_codecs = media::EME_CODEC_NONE;
auto supported_hw_secure_codecs =
GetSupportedCodecs(capability->hw_secure_video_codecs);
// 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 =
GetPersistentLicenseSupport(supports_persistent_license);
GetPersistentLicenseSupport(cdm_supports_persistent_license);
using Robustness = cdm::WidevineKeySystemProperties::Robustness;
// TODO(xhwang/jrummell): Parse hw_secure_encryption_schemes.
concrete_key_systems->emplace_back(new cdm::WidevineKeySystemProperties(
supported_encryption_schemes, supported_codecs,
supported_hw_secure_codecs,
......
......@@ -59,20 +59,36 @@ KeySystemSupportImpl::~KeySystemSupportImpl() = default;
void KeySystemSupportImpl::IsKeySystemSupported(
const std::string& key_system,
IsKeySystemSupportedCallback callback) {
DVLOG(3) << __func__;
std::unique_ptr<CdmInfo> cdm = GetCdmInfoForKeySystem(key_system);
if (!cdm) {
DVLOG(3) << __func__ << ": key_system = " << key_system;
auto cdm_info = GetCdmInfoForKeySystem(key_system);
if (!cdm_info) {
SendCdmAvailableUMA(key_system, false);
std::move(callback).Run(false, {}, false, {});
std::move(callback).Run(false, nullptr);
return;
}
const base::flat_set<media::EncryptionMode>& schemes =
cdm->supported_encryption_schemes;
SendCdmAvailableUMA(key_system, true);
std::move(callback).Run(
true, cdm->supported_video_codecs, cdm->supports_persistent_license,
std::vector<media::EncryptionMode>(schemes.begin(), schemes.end()));
// Supported codecs and encryption schemes.
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
......@@ -22,11 +22,35 @@ namespace content {
namespace {
using VideoCodec = media::VideoCodec;
using EncryptionMode = media::EncryptionMode;
using CdmSessionType = media::CdmSessionType;
const char kTestCdmGuid[] = "62FE9C4B-384E-48FD-B28A-9F6F248BC8CC";
const char kVersion[] = "1.1.1.1";
const char kTestPath[] = "/aa/bb";
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
class KeySystemSupportTest : public testing::Test {
......@@ -58,8 +82,7 @@ class KeySystemSupportTest : public testing::Test {
DVLOG(1) << __func__;
bool is_available = false;
key_system_support_->IsKeySystemSupported(key_system, &is_available,
&codecs_, &persistent_,
&encryption_schemes_);
&capability_);
return is_available;
}
......@@ -67,9 +90,7 @@ class KeySystemSupportTest : public testing::Test {
TestBrowserThreadBundle test_browser_thread_bundle_;
// Updated by IsSupported().
std::vector<media::VideoCodec> codecs_;
bool persistent_;
std::vector<media::EncryptionMode> encryption_schemes_;
media::mojom::KeySystemCapabilityPtr capability_;
};
// Note that as CdmRegistry::GetInstance() is a static, it is shared between
......@@ -78,18 +99,18 @@ class KeySystemSupportTest : public testing::Test {
TEST_F(KeySystemSupportTest, NoKeySystems) {
EXPECT_FALSE(IsSupported("KeySystem1"));
EXPECT_FALSE(capability_);
}
TEST_F(KeySystemSupportTest, OneKeySystem) {
Register("KeySystem2", {media::VideoCodec::kCodecVP8}, true,
{media::EncryptionMode::kCenc, media::EncryptionMode::kCbcs});
Register("KeySystem2", {VideoCodec::kCodecVP8}, true,
{EncryptionMode::kCenc, EncryptionMode::kCbcs});
EXPECT_TRUE(IsSupported("KeySystem2"));
EXPECT_EQ(1u, codecs_.size());
EXPECT_EQ(media::VideoCodec::kCodecVP8, codecs_[0]);
EXPECT_TRUE(persistent_);
EXPECT_EQ(2u, encryption_schemes_.size());
EXPECT_EQ(media::EncryptionMode::kCenc, encryption_schemes_[0]);
EXPECT_EQ(media::EncryptionMode::kCbcs, encryption_schemes_[1]);
EXPECT_VIDEO_CODECS(VideoCodec::kCodecVP8);
EXPECT_ENCRYPTION_SCHEMES(EncryptionMode::kCenc, EncryptionMode::kCbcs);
EXPECT_SESSION_TYPES(CdmSessionType::TEMPORARY_SESSION,
CdmSessionType::PERSISTENT_LICENSE_SESSION);
}
TEST_F(KeySystemSupportTest, MultipleKeySystems) {
......@@ -98,25 +119,25 @@ TEST_F(KeySystemSupportTest, MultipleKeySystems) {
{media::EncryptionMode::kCenc});
Register("KeySystem4", {media::VideoCodec::kCodecVP9}, false,
{media::EncryptionMode::kCbcs});
EXPECT_TRUE(IsSupported("KeySystem3"));
EXPECT_EQ(2u, codecs_.size());
EXPECT_EQ(media::VideoCodec::kCodecVP8, codecs_[0]);
EXPECT_EQ(media::VideoCodec::kCodecVP9, codecs_[1]);
EXPECT_TRUE(persistent_);
EXPECT_EQ(1u, encryption_schemes_.size());
EXPECT_EQ(media::EncryptionMode::kCenc, encryption_schemes_[0]);
EXPECT_VIDEO_CODECS(VideoCodec::kCodecVP8, VideoCodec::kCodecVP9);
EXPECT_ENCRYPTION_SCHEMES(EncryptionMode::kCenc);
EXPECT_SESSION_TYPES(CdmSessionType::TEMPORARY_SESSION,
CdmSessionType::PERSISTENT_LICENSE_SESSION);
EXPECT_TRUE(IsSupported("KeySystem4"));
EXPECT_EQ(1u, codecs_.size());
EXPECT_EQ(media::VideoCodec::kCodecVP9, codecs_[0]);
EXPECT_FALSE(persistent_);
EXPECT_EQ(1u, encryption_schemes_.size());
EXPECT_EQ(media::EncryptionMode::kCbcs, encryption_schemes_[0]);
EXPECT_VIDEO_CODECS(VideoCodec::kCodecVP9);
EXPECT_ENCRYPTION_SCHEMES(EncryptionMode::kCbcs);
EXPECT_SESSION_TYPES(CdmSessionType::TEMPORARY_SESSION);
}
TEST_F(KeySystemSupportTest, MissingKeySystem) {
Register("KeySystem5", {media::VideoCodec::kCodecVP8}, true,
{media::EncryptionMode::kCenc});
EXPECT_FALSE(IsSupported("KeySystem6"));
EXPECT_FALSE(capability_);
}
} // namespace content
......@@ -14,9 +14,7 @@ namespace content {
bool IsKeySystemSupported(
const std::string& key_system,
std::vector<media::VideoCodec>* supported_video_codecs,
bool* supports_persistent_license,
std::vector<media::EncryptionMode>* supported_encryption_schemes) {
media::mojom::KeySystemCapabilityPtr* key_system_capability) {
DVLOG(3) << __func__ << " key_system: " << key_system;
bool is_supported = false;
......@@ -24,9 +22,8 @@ bool IsKeySystemSupported(
content::RenderThread::Get()->GetConnector()->BindInterface(
mojom::kBrowserServiceName, mojo::MakeRequest(&key_system_support));
key_system_support->IsKeySystemSupported(
key_system, &is_supported, supported_video_codecs,
supports_persistent_license, supported_encryption_schemes);
key_system_support->IsKeySystemSupported(key_system, &is_supported,
key_system_capability);
return is_supported;
}
......
......@@ -9,20 +9,16 @@
#include <vector>
#include "content/common/content_export.h"
#include "media/base/decrypt_config.h"
#include "media/base/video_codecs.h"
#include "media/mojo/interfaces/key_system_support.mojom.h"
namespace content {
// Determines if |key_system| is supported by calling into the browser.
// If it is supported, return true and |supported_video_codecs|,
// |supports_persistent_license| and |supported_encryption_schemes| are updated
// If it is supported, return true and |key_system_capability| is updated
// to match what |key_system| supports. If not supported, false is returned.
CONTENT_EXPORT bool IsKeySystemSupported(
const std::string& key_system,
std::vector<media::VideoCodec>* supported_video_codecs,
bool* supports_persistent_license,
std::vector<media::EncryptionMode>* supported_encryption_schemes);
media::mojom::KeySystemCapabilityPtr* key_system_capability);
} // namespace content
......
......@@ -4,21 +4,36 @@
module media.mojom;
import "media/mojo/interfaces/content_decryption_module.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 {
// Query to determine if the browser supports the key system |key_system|.
// If supported, |is_supported| = true and the remaining properties indicate
// the codecs supported, if the key system supports persistent licenses, and
// the set of encryption schemes supported. KeySystemSupport implementation
// is in the browser process, as it maintains the list of installed key
// systems. Clients run in the renderer process.
// TODO(crbug.com/796725) Find a way to include profiles and levels for
// |supported_video_codecs|.
// Query to determine if the browser supports the |key_system|. If supported,
// |key_system_capability| is non-null indicating supported capability.
// KeySystemSupport implementation is in the browser process, as it maintains
// the list of registered CDMs, and hardware secure support check also needs
// to run in the browser process because the render process is sandboxed.
// KeySystemSupport clients run in the renderer process.
// TODO(crbug.com/853264): Make this an async call.
[Sync]
IsKeySystemSupported(string key_system)
=> (bool is_supported,
array<VideoCodec> supported_video_codecs,
bool supports_persistent_license,
array<EncryptionMode> supported_encryption_schemes);
=> (bool is_supported, KeySystemCapability? key_system_capability);
};
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