Commit e4b86646 authored by xhwang@chromium.org's avatar xhwang@chromium.org

Store SupportedCodecs in KeySystemInfo and KeySystems.

Previously we convert SupportedCodecs (a uint32 bit mask indicating which
codec is supported) to ContainerCodecMap (a map from a container type to a set
of supported codecs in that container). Then we pass ContainerCodecMap to
KeySystems and store it there for easy look up.

This results in a lot of duplicate converting code. This CL stores
SupportedCodecs in KeySystmeInfo and KeySystems so that we don't need to convert
anything. Then when IsTypeSupported() is called, we find the bit masks for
queried container and codec types and compare it with the SupportedCodecs stored
in KeySystems.

BUG=362769
TEST=All existing tests pass.

Review URL: https://codereview.chromium.org/246033002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266148 0039d316-1c4b-4281-b951-d872f2087c98
parent db6659bb
...@@ -8,18 +8,13 @@ ...@@ -8,18 +8,13 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/logging.h" #include "base/logging.h"
#include "content/public/common/eme_codec.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h" #include "third_party/widevine/cdm/widevine_cdm_common.h"
using content::KeySystemInfo; using content::KeySystemInfo;
namespace { namespace {
const char kAudioMp4[] = "audio/mp4";
const char kVideoMp4[] = "video/mp4";
const char kMp4a[] = "mp4a";
const char kAvc1[] = "avc1";
const char kAvc3[] = "avc3";
// Return |name|'s parent key system. // Return |name|'s parent key system.
std::string GetDirectParentName(const std::string& name) { std::string GetDirectParentName(const std::string& name) {
int last_period = name.find_last_of('.'); int last_period = name.find_last_of('.');
...@@ -35,10 +30,7 @@ void AddWidevineWithCodecs(const std::string& key_system_name, ...@@ -35,10 +30,7 @@ void AddWidevineWithCodecs(const std::string& key_system_name,
if (add_parent_name) if (add_parent_name)
info.parent_key_system = GetDirectParentName(key_system_name); info.parent_key_system = GetDirectParentName(key_system_name);
info.supported_types[kAudioMp4].insert(kMp4a); info.supported_codecs = content::EME_CODEC_MP4_ALL;
info.supported_types[kVideoMp4] = info.supported_types[kAudioMp4];
info.supported_types[kVideoMp4].insert(kAvc1);
info.supported_types[kVideoMp4].insert(kAvc3);
concrete_key_systems->push_back(info); concrete_key_systems->push_back(info);
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "media/base/android/media_drm_bridge.h" #include "media/base/android/media_drm_bridge.h"
using content::BrowserThread; using content::BrowserThread;
using content::SupportedCodecs;
using media::MediaCodecBridge; using media::MediaCodecBridge;
using media::MediaDrmBridge; using media::MediaDrmBridge;
...@@ -25,26 +26,26 @@ enum CodecType { ...@@ -25,26 +26,26 @@ enum CodecType {
}; };
struct CodecInfo { struct CodecInfo {
android::SupportedCodecs codec; SupportedCodecs codec;
CodecType codec_type; CodecType codec_type;
const char* codec_name; const char* codec_name;
const char* container_mime_type; const char* container_mime_type;
}; };
const CodecInfo kCodecsToQuery[] = { const CodecInfo kCodecsToQuery[] = {
{android::WEBM_VORBIS, CODEC_AUDIO, "vorbis", "video/webm"}, {content::EME_CODEC_WEBM_VORBIS, CODEC_AUDIO, "vorbis", "video/webm"},
{android::WEBM_VP8, CODEC_VIDEO, "vp8", "video/webm"}, {content::EME_CODEC_WEBM_VP8, CODEC_VIDEO, "vp8", "video/webm"},
#if defined(USE_PROPRIETARY_CODECS) #if defined(USE_PROPRIETARY_CODECS)
{android::MP4_AAC, CODEC_AUDIO, "mp4a", "video/mp4"}, {content::EME_CODEC_MP4_AAC, CODEC_AUDIO, "mp4a", "video/mp4"},
{android::MP4_AVC1, CODEC_VIDEO, "avc1", "video/mp4"} {content::EME_CODEC_MP4_AVC1, CODEC_VIDEO, "avc1", "video/mp4"}
#endif // defined(USE_PROPRIETARY_CODECS) #endif // defined(USE_PROPRIETARY_CODECS)
}; };
static android::SupportedCodecs GetSupportedCodecs( static SupportedCodecs GetSupportedCodecs(
const SupportedKeySystemRequest& request, const SupportedKeySystemRequest& request,
bool video_must_be_compositable) { bool video_must_be_compositable) {
const std::string& key_system = request.key_system; const std::string& key_system = request.key_system;
android::SupportedCodecs supported_codecs = android::NO_CODECS; SupportedCodecs supported_codecs = content::EME_CODEC_NONE;
for (size_t i = 0; i < arraysize(kCodecsToQuery); ++i) { for (size_t i = 0; i < arraysize(kCodecsToQuery); ++i) {
const CodecInfo& info = kCodecsToQuery[i]; const CodecInfo& info = kCodecsToQuery[i];
...@@ -56,8 +57,7 @@ static android::SupportedCodecs GetSupportedCodecs( ...@@ -56,8 +57,7 @@ static android::SupportedCodecs GetSupportedCodecs(
MediaDrmBridge::IsKeySystemSupportedWithType( MediaDrmBridge::IsKeySystemSupportedWithType(
key_system, info.container_mime_type) && key_system, info.container_mime_type) &&
MediaCodecBridge::CanDecode(info.codec_name, is_secure)) { MediaCodecBridge::CanDecode(info.codec_name, is_secure)) {
supported_codecs = static_cast<android::SupportedCodecs>( supported_codecs |= info.codec;
supported_codecs | info.codec);
} }
} }
...@@ -104,8 +104,7 @@ void EncryptedMediaMessageFilterAndroid::OnGetSupportedKeySystems( ...@@ -104,8 +104,7 @@ void EncryptedMediaMessageFilterAndroid::OnGetSupportedKeySystems(
if (!MediaDrmBridge::IsKeySystemSupported(request.key_system)) if (!MediaDrmBridge::IsKeySystemSupported(request.key_system))
return; return;
DCHECK_EQ(request.codecs & android::INVALID_CODECS, android::NO_CODECS) DCHECK(request.codecs & content::EME_CODEC_ALL) << "unrecognized codec";
<< "unrecognized codec";
response->key_system = request.key_system; response->key_system = request.key_system;
// TODO(qinmin): check composition is supported or not. // TODO(qinmin): check composition is supported or not.
response->compositing_codecs = GetSupportedCodecs(request, true); response->compositing_codecs = GetSupportedCodecs(request, true);
......
...@@ -7,49 +7,24 @@ ...@@ -7,49 +7,24 @@
#include <vector> #include <vector>
#include "content/public/common/eme_codec.h"
#include "ipc/ipc_message_macros.h" #include "ipc/ipc_message_macros.h"
// Singly-included section for enums and custom IPC traits.
#ifndef CHROME_COMMON_ENCRYPTED_MEDIA_MESSAGES_ANDROID_H
#define CHROME_COMMON_ENCRYPTED_MEDIA_MESSAGES_ANDROID_H
namespace android {
// Defines bitmask values used to specify supported codecs.
// Each value represents a codec within a specific container.
enum SupportedCodecs {
NO_CODECS = 0,
WEBM_VORBIS = 1 << 0,
WEBM_VP8 = 1 << 1,
WEBM_CODECS = (WEBM_VORBIS | WEBM_VP8),
MP4_AAC = 1 << 2,
MP4_AVC1 = 1 << 3,
MP4_CODECS = (MP4_AAC | MP4_AVC1),
ALL_CODECS = (WEBM_CODECS | MP4_CODECS),
INVALID_CODECS = ~ALL_CODECS
};
} // namespace android
#endif // CHROME_COMMON_ENCRYPTED_MEDIA_MESSAGES_ANDROID_H
#define IPC_MESSAGE_START EncryptedMediaMsgStart #define IPC_MESSAGE_START EncryptedMediaMsgStart
IPC_ENUM_TRAITS(android::SupportedCodecs)
IPC_STRUCT_BEGIN(SupportedKeySystemRequest) IPC_STRUCT_BEGIN(SupportedKeySystemRequest)
IPC_STRUCT_MEMBER(std::string, key_system) IPC_STRUCT_MEMBER(std::string, key_system)
IPC_STRUCT_MEMBER(android::SupportedCodecs, codecs, IPC_STRUCT_MEMBER(content::SupportedCodecs, codecs, content::EME_CODEC_NONE)
android::NO_CODECS)
IPC_STRUCT_END() IPC_STRUCT_END()
IPC_STRUCT_BEGIN(SupportedKeySystemResponse) IPC_STRUCT_BEGIN(SupportedKeySystemResponse)
IPC_STRUCT_MEMBER(std::string, key_system) IPC_STRUCT_MEMBER(std::string, key_system)
IPC_STRUCT_MEMBER(android::SupportedCodecs, compositing_codecs, IPC_STRUCT_MEMBER(content::SupportedCodecs,
android::NO_CODECS) compositing_codecs,
IPC_STRUCT_MEMBER(android::SupportedCodecs, non_compositing_codecs, content::EME_CODEC_NONE)
android::NO_CODECS) IPC_STRUCT_MEMBER(content::SupportedCodecs,
non_compositing_codecs,
content::EME_CODEC_NONE)
IPC_STRUCT_END() IPC_STRUCT_END()
// Messages sent from the renderer to the browser. // Messages sent from the renderer to the browser.
......
...@@ -28,20 +28,7 @@ ...@@ -28,20 +28,7 @@
#endif #endif
using content::KeySystemInfo; using content::KeySystemInfo;
using content::SupportedCodecs;
const char kAudioWebM[] = "audio/webm";
const char kVideoWebM[] = "video/webm";
const char kVorbis[] = "vorbis";
const char kVP8[] = "vp8";
const char kVP80[] = "vp8.0";
#if defined(USE_PROPRIETARY_CODECS)
const char kAudioMp4[] = "audio/mp4";
const char kVideoMp4[] = "video/mp4";
const char kMp4a[] = "mp4a";
const char kAvc1[] = "avc1";
const char kAvc3[] = "avc3";
#endif // defined(USE_PROPRIETARY_CODECS)
#if defined(ENABLE_PEPPER_CDMS) #if defined(ENABLE_PEPPER_CDMS)
static bool IsPepperCdmRegistered( static bool IsPepperCdmRegistered(
...@@ -85,15 +72,9 @@ static void AddExternalClearKey( ...@@ -85,15 +72,9 @@ static void AddExternalClearKey(
KeySystemInfo info(kExternalClearKeyKeySystem); KeySystemInfo info(kExternalClearKeyKeySystem);
info.supported_types[kAudioWebM].insert(kVorbis); info.supported_codecs = content::EME_CODEC_WEBM_ALL;
info.supported_types[kVideoWebM] = info.supported_types[kAudioWebM];
info.supported_types[kVideoWebM].insert(kVP8);
info.supported_types[kVideoWebM].insert(kVP80);
#if defined(USE_PROPRIETARY_CODECS) #if defined(USE_PROPRIETARY_CODECS)
info.supported_types[kAudioMp4].insert(kMp4a); info.supported_codecs |= content::EME_CODEC_MP4_ALL;
info.supported_types[kVideoMp4] = info.supported_types[kAudioMp4];
info.supported_types[kVideoMp4].insert(kAvc1);
info.supported_types[kVideoMp4].insert(kAvc3);
#endif // defined(USE_PROPRIETARY_CODECS) #endif // defined(USE_PROPRIETARY_CODECS)
info.pepper_type = kExternalClearKeyPepperType; info.pepper_type = kExternalClearKeyPepperType;
...@@ -130,42 +111,7 @@ enum WidevineCdmType { ...@@ -130,42 +111,7 @@ enum WidevineCdmType {
#endif #endif
}; };
// Defines bitmask values used to specify supported codecs. #if !defined(OS_ANDROID)
// Each value represents a codec within a specific container.
// The mask values are stored in a SupportedCodecs.
typedef uint32 SupportedCodecs;
enum SupportedCodecMasks {
NO_CODECS = 0,
WEBM_VORBIS = 1 << 0,
WEBM_VP8 = 1 << 1,
WEBM_CODECS = (WEBM_VORBIS | WEBM_VP8),
#if defined(USE_PROPRIETARY_CODECS)
MP4_AAC = 1 << 2,
MP4_AVC1 = 1 << 3,
MP4_CODECS = (MP4_AAC | MP4_AVC1),
ALL_CODECS = (WEBM_CODECS | MP4_CODECS),
#else
ALL_CODECS = WEBM_CODECS,
#endif // defined(USE_PROPRIETARY_CODECS)
INVALID_CODECS = ~ALL_CODECS
};
#if defined(OS_ANDROID)
#define COMPILE_ASSERT_MATCHING_ENUM(name) \
COMPILE_ASSERT(static_cast<int>(name) == \
static_cast<int>(android::name), \
mismatching_enums)
COMPILE_ASSERT_MATCHING_ENUM(NO_CODECS);
COMPILE_ASSERT_MATCHING_ENUM(WEBM_VORBIS);
COMPILE_ASSERT_MATCHING_ENUM(WEBM_VP8);
COMPILE_ASSERT_MATCHING_ENUM(WEBM_CODECS);
COMPILE_ASSERT_MATCHING_ENUM(MP4_AAC);
COMPILE_ASSERT_MATCHING_ENUM(MP4_AVC1);
COMPILE_ASSERT_MATCHING_ENUM(MP4_CODECS);
COMPILE_ASSERT_MATCHING_ENUM(ALL_CODECS);
COMPILE_ASSERT_MATCHING_ENUM(INVALID_CODECS);
#undef COMPILE_ASSERT_MATCHING_ENUM
#else
static bool IsWidevineHrSupported() { static bool IsWidevineHrSupported() {
// TODO(jrummell): Need to call CheckPlatformState() but it is // TODO(jrummell): Need to call CheckPlatformState() but it is
// asynchronous, and needs to be done in the browser. // asynchronous, and needs to be done in the browser.
...@@ -206,29 +152,7 @@ static void AddWidevineWithCodecs( ...@@ -206,29 +152,7 @@ static void AddWidevineWithCodecs(
// TODO(xhwang): A container or an initDataType may be supported even though // TODO(xhwang): A container or an initDataType may be supported even though
// there are no codecs supported in that container. Fix this when we support // there are no codecs supported in that container. Fix this when we support
// initDataType. // initDataType.
if (supported_codecs & WEBM_CODECS) { info.supported_codecs = supported_codecs;
if (supported_codecs & WEBM_VORBIS)
info.supported_types[kAudioWebM].insert(kVorbis);
if (supported_codecs & WEBM_VP8) {
info.supported_types[kVideoWebM] = info.supported_types[kAudioWebM];
info.supported_types[kVideoWebM].insert(kVP8);
info.supported_types[kVideoWebM].insert(kVP80);
}
}
#if defined(USE_PROPRIETARY_CODECS)
if (supported_codecs & MP4_CODECS) {
if (supported_codecs & MP4_AAC)
info.supported_types[kAudioMp4].insert(kMp4a);
if (supported_codecs & MP4_AVC1) {
info.supported_types[kVideoMp4] = info.supported_types[kAudioMp4];
info.supported_types[kVideoMp4].insert(kAvc1);
info.supported_types[kVideoMp4].insert(kAvc3);
}
}
#endif // defined(USE_PROPRIETARY_CODECS)
#if defined(ENABLE_PEPPER_CDMS) #if defined(ENABLE_PEPPER_CDMS)
info.pepper_type = kWidevineCdmPluginMimeType; info.pepper_type = kWidevineCdmPluginMimeType;
...@@ -290,17 +214,17 @@ static void AddPepperBasedWidevine( ...@@ -290,17 +214,17 @@ static void AddPepperBasedWidevine(
std::vector<std::string> codecs; std::vector<std::string> codecs;
GetSupportedCodecs(additional_param_names, additional_param_values, &codecs); GetSupportedCodecs(additional_param_names, additional_param_values, &codecs);
SupportedCodecs supported_codecs = NO_CODECS; SupportedCodecs supported_codecs = content::EME_CODEC_NONE;
for (size_t i = 0; i < codecs.size(); ++i) { for (size_t i = 0; i < codecs.size(); ++i) {
if (codecs[i] == kCdmSupportedCodecVorbis) if (codecs[i] == kCdmSupportedCodecVorbis)
supported_codecs |= WEBM_VORBIS; supported_codecs |= content::EME_CODEC_WEBM_VORBIS;
if (codecs[i] == kCdmSupportedCodecVp8) if (codecs[i] == kCdmSupportedCodecVp8)
supported_codecs |= WEBM_VP8; supported_codecs |= content::EME_CODEC_WEBM_VP8;
#if defined(USE_PROPRIETARY_CODECS) #if defined(USE_PROPRIETARY_CODECS)
if (codecs[i] == kCdmSupportedCodecAac) if (codecs[i] == kCdmSupportedCodecAac)
supported_codecs |= MP4_AAC; supported_codecs |= content::EME_CODEC_MP4_AAC;
if (codecs[i] == kCdmSupportedCodecAvc1) if (codecs[i] == kCdmSupportedCodecAvc1)
supported_codecs |= MP4_AVC1; supported_codecs |= content::EME_CODEC_MP4_AVC1;
#endif // defined(USE_PROPRIETARY_CODECS) #endif // defined(USE_PROPRIETARY_CODECS)
} }
...@@ -316,24 +240,21 @@ static void AddAndroidWidevine( ...@@ -316,24 +240,21 @@ static void AddAndroidWidevine(
SupportedKeySystemResponse response; SupportedKeySystemResponse response;
request.key_system = kWidevineKeySystem; request.key_system = kWidevineKeySystem;
request.codecs = static_cast<android::SupportedCodecs>(android::WEBM_CODECS | request.codecs = content::EME_CODEC_WEBM_ALL | content::EME_CODEC_MP4_ALL;
android::MP4_CODECS);
content::RenderThread::Get()->Send( content::RenderThread::Get()->Send(
new ChromeViewHostMsg_GetSupportedKeySystems(request, &response)); new ChromeViewHostMsg_GetSupportedKeySystems(request, &response));
DCHECK_EQ(response.compositing_codecs & android::INVALID_CODECS, DCHECK(response.compositing_codecs & content::EME_CODEC_ALL)
android::NO_CODECS)
<< "unrecognized codec"; << "unrecognized codec";
DCHECK_EQ(response.non_compositing_codecs & android::INVALID_CODECS, DCHECK(response.non_compositing_codecs & content::EME_CODEC_ALL)
android::NO_CODECS)
<< "unrecognized codec"; << "unrecognized codec";
if (response.compositing_codecs != android::NO_CODECS) { if (response.compositing_codecs != content::EME_CODEC_NONE) {
AddWidevineWithCodecs( AddWidevineWithCodecs(
WIDEVINE, WIDEVINE,
static_cast<SupportedCodecs>(response.compositing_codecs), static_cast<SupportedCodecs>(response.compositing_codecs),
concrete_key_systems); concrete_key_systems);
} }
if (response.non_compositing_codecs != android::NO_CODECS) { if (response.non_compositing_codecs != content::EME_CODEC_NONE) {
AddWidevineWithCodecs( AddWidevineWithCodecs(
WIDEVINE_HR_NON_COMPOSITING, WIDEVINE_HR_NON_COMPOSITING,
static_cast<SupportedCodecs>(response.non_compositing_codecs), static_cast<SupportedCodecs>(response.non_compositing_codecs),
......
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
'public/common/context_menu_params.h', 'public/common/context_menu_params.h',
'public/common/drop_data.cc', 'public/common/drop_data.cc',
'public/common/drop_data.h', 'public/common/drop_data.h',
'public/common/eme_codec.h',
'public/common/favicon_url.cc', 'public/common/favicon_url.cc',
'public/common/favicon_url.h', 'public/common/favicon_url.h',
'public/common/file_chooser_params.cc', 'public/common/file_chooser_params.cc',
......
// Copyright 2014 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 CONTENT_PUBLIC_COMMON_EME_CODEC_H_
#define CONTENT_PUBLIC_COMMON_EME_CODEC_H_
namespace content {
// Defines bitmask values that specify codecs used in Encrypted Media Extension
// (EME). Each value represents a codec within a specific container.
// The mask values are stored in a SupportedCodecs.
enum EmeCodec {
EME_CODEC_NONE = 0,
EME_CODEC_WEBM_VORBIS = 1 << 0,
EME_CODEC_WEBM_AUDIO_ALL = EME_CODEC_WEBM_VORBIS,
EME_CODEC_WEBM_VP8 = 1 << 1,
EME_CODEC_WEBM_VIDEO_ALL = EME_CODEC_WEBM_VP8,
EME_CODEC_WEBM_ALL = (EME_CODEC_WEBM_AUDIO_ALL | EME_CODEC_WEBM_VIDEO_ALL),
#if defined(USE_PROPRIETARY_CODECS)
EME_CODEC_MP4_AAC = 1 << 2,
EME_CODEC_MP4_AUDIO_ALL = EME_CODEC_MP4_AAC,
EME_CODEC_MP4_AVC1 = 1 << 3,
EME_CODEC_MP4_VIDEO_ALL = EME_CODEC_MP4_AVC1,
EME_CODEC_MP4_ALL = (EME_CODEC_MP4_AUDIO_ALL | EME_CODEC_MP4_VIDEO_ALL),
EME_CODEC_ALL = (EME_CODEC_WEBM_ALL | EME_CODEC_MP4_ALL),
#else
EME_CODEC_ALL = EME_CODEC_WEBM_ALL,
#endif // defined(USE_PROPRIETARY_CODECS)
};
typedef uint32 SupportedCodecs;
} // namespace content
#endif // CONTENT_PUBLIC_COMMON_EME_CODEC_H_
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/containers/hash_tables.h" #include "base/containers/hash_tables.h"
#include "content/common/content_export.h" #include "content/common/content_export.h"
#include "content/public/common/eme_codec.h"
// Definitions: // Definitions:
// * Key system // * Key system
...@@ -32,22 +33,13 @@ namespace content { ...@@ -32,22 +33,13 @@ namespace content {
// Contains information about an EME key system as well as how to instantiate // Contains information about an EME key system as well as how to instantiate
// the corresponding CDM. // the corresponding CDM.
struct CONTENT_EXPORT KeySystemInfo { struct CONTENT_EXPORT KeySystemInfo {
// Represents the set of codecs supported within a container.
typedef base::hash_set<std::string> CodecSet;
// Represents container-codec combinations. The CodecSet may contain zero
// or more codecs.
typedef std::map<std::string, CodecSet> ContainerCodecsMap;
explicit KeySystemInfo(const std::string& key_system); explicit KeySystemInfo(const std::string& key_system);
~KeySystemInfo(); ~KeySystemInfo();
std::string key_system; std::string key_system;
// Specifies container and codec combinations supported by |key_system|. // Specifies codecs supported by |key_system|.
// Multiple codecs may be listed for each container. SupportedCodecs supported_codecs;
// In all cases, the container without a codec is also always supported.
ContainerCodecsMap supported_types;
// A hierarchical parent for |key_system|. This value can be used to check // A hierarchical parent for |key_system|. This value can be used to check
// supported types but cannot be used to instantiate a MediaKeys object. // supported types but cannot be used to instantiate a MediaKeys object.
......
...@@ -4,13 +4,14 @@ ...@@ -4,13 +4,14 @@
#include "content/renderer/media/crypto/key_systems.h" #include "content/renderer/media/crypto/key_systems.h"
#include <map>
#include <string> #include <string>
#include "base/containers/hash_tables.h"
#include "base/lazy_instance.h" #include "base/lazy_instance.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "content/public/common/content_client.h" #include "content/public/common/content_client.h"
#include "content/public/common/eme_codec.h"
#include "content/public/renderer/content_renderer_client.h" #include "content/public/renderer/content_renderer_client.h"
#include "content/public/renderer/key_system_info.h" #include "content/public/renderer/key_system_info.h"
#include "content/renderer/media/crypto/key_systems_support_uma.h" #include "content/renderer/media/crypto/key_systems_support_uma.h"
...@@ -27,19 +28,34 @@ const char kClearKeyKeySystem[] = "org.w3.clearkey"; ...@@ -27,19 +28,34 @@ const char kClearKeyKeySystem[] = "org.w3.clearkey";
const char kPrefixedClearKeyKeySystem[] = "webkit-org.w3.clearkey"; const char kPrefixedClearKeyKeySystem[] = "webkit-org.w3.clearkey";
const char kUnsupportedClearKeyKeySystem[] = "unsupported-org.w3.clearkey"; const char kUnsupportedClearKeyKeySystem[] = "unsupported-org.w3.clearkey";
const char kAudioWebM[] = "audio/webm"; struct CodecMask {
const char kVideoWebM[] = "video/webm"; const char* type;
const char kVorbis[] = "vorbis"; EmeCodec mask;
const char kVP8[] = "vp8"; };
const char kVP80[] = "vp8.0";
// Mapping between container types and the masks of associated codecs.
// Only audio codec can belong to a "audio/*" container. Both audio and video
// codecs can belong to a "video/*" container.
CodecMask kContainerCodecMasks[] = {
{"audio/webm", EME_CODEC_WEBM_AUDIO_ALL},
{"video/webm", EME_CODEC_WEBM_ALL},
#if defined(USE_PROPRIETARY_CODECS)
{"audio/mp4", EME_CODEC_MP4_AUDIO_ALL},
{"video/mp4", EME_CODEC_MP4_ALL}
#endif // defined(USE_PROPRIETARY_CODECS)
};
// Mapping between codec types and their masks.
CodecMask kCodecMasks[] = {
{"vorbis", EME_CODEC_WEBM_VORBIS},
{"vp8", EME_CODEC_WEBM_VP8},
{"vp8.0", EME_CODEC_WEBM_VP8},
#if defined(USE_PROPRIETARY_CODECS) #if defined(USE_PROPRIETARY_CODECS)
const char kAudioMp4[] = "audio/mp4"; {"mp4a", EME_CODEC_MP4_AAC},
const char kVideoMp4[] = "video/mp4"; {"avc1", EME_CODEC_MP4_AVC1},
const char kMp4a[] = "mp4a"; {"avc3", EME_CODEC_MP4_AVC1}
const char kAvc1[] = "avc1";
const char kAvc3[] = "avc3";
#endif // defined(USE_PROPRIETARY_CODECS) #endif // defined(USE_PROPRIETARY_CODECS)
};
static void AddClearKey(std::vector<KeySystemInfo>* concrete_key_systems) { static void AddClearKey(std::vector<KeySystemInfo>* concrete_key_systems) {
KeySystemInfo info(kClearKeyKeySystem); KeySystemInfo info(kClearKeyKeySystem);
...@@ -48,15 +64,9 @@ static void AddClearKey(std::vector<KeySystemInfo>* concrete_key_systems) { ...@@ -48,15 +64,9 @@ static void AddClearKey(std::vector<KeySystemInfo>* concrete_key_systems) {
// implementations: // implementations:
// http://developer.android.com/guide/appendix/media-formats.html // http://developer.android.com/guide/appendix/media-formats.html
info.supported_types[kAudioWebM].insert(kVorbis); info.supported_codecs = EME_CODEC_WEBM_ALL;
info.supported_types[kVideoWebM] = info.supported_types[kAudioWebM];
info.supported_types[kVideoWebM].insert(kVP8);
info.supported_types[kVideoWebM].insert(kVP80);
#if defined(USE_PROPRIETARY_CODECS) #if defined(USE_PROPRIETARY_CODECS)
info.supported_types[kAudioMp4].insert(kMp4a); info.supported_codecs |= EME_CODEC_MP4_ALL;
info.supported_types[kVideoMp4] = info.supported_types[kAudioMp4];
info.supported_types[kVideoMp4].insert(kAvc1);
info.supported_types[kVideoMp4].insert(kAvc3);
#endif // defined(USE_PROPRIETARY_CODECS) #endif // defined(USE_PROPRIETARY_CODECS)
info.use_aes_decryptor = true; info.use_aes_decryptor = true;
...@@ -81,10 +91,10 @@ class KeySystems { ...@@ -81,10 +91,10 @@ class KeySystems {
std::string GetPepperType(const std::string& concrete_key_system); std::string GetPepperType(const std::string& concrete_key_system);
#endif #endif
private: void AddContainerMask(const std::string& container, uint32 mask);
typedef KeySystemInfo::CodecSet CodecSet; void AddCodecMask(const std::string& codec, uint32 mask);
typedef KeySystemInfo::ContainerCodecsMap ContainerCodecsMap;
private:
void AddConcreteSupportedKeySystems( void AddConcreteSupportedKeySystems(
const std::vector<KeySystemInfo>& concrete_key_systems); const std::vector<KeySystemInfo>& concrete_key_systems);
...@@ -94,7 +104,7 @@ class KeySystems { ...@@ -94,7 +104,7 @@ class KeySystems {
#if defined(ENABLE_PEPPER_CDMS) #if defined(ENABLE_PEPPER_CDMS)
const std::string& pepper_type, const std::string& pepper_type,
#endif #endif
const ContainerCodecsMap& supported_types, SupportedCodecs supported_codecs,
const std::string& parent_key_system); const std::string& parent_key_system);
friend struct base::DefaultLazyInstanceTraits<KeySystems>; friend struct base::DefaultLazyInstanceTraits<KeySystems>;
...@@ -106,19 +116,29 @@ class KeySystems { ...@@ -106,19 +116,29 @@ class KeySystems {
#if defined(ENABLE_PEPPER_CDMS) #if defined(ENABLE_PEPPER_CDMS)
std::string pepper_type; std::string pepper_type;
#endif #endif
ContainerCodecsMap supported_types; SupportedCodecs supported_codecs;
}; };
typedef std::map<std::string, KeySystemProperties> KeySystemPropertiesMap; typedef base::hash_map<std::string, KeySystemProperties>
KeySystemPropertiesMap;
typedef std::map<std::string, std::string> ParentKeySystemMap; typedef base::hash_map<std::string, std::string> ParentKeySystemMap;
typedef base::hash_map<std::string, EmeCodec> CodecMaskMap;
KeySystems(); KeySystems();
~KeySystems() {} ~KeySystems() {}
bool IsSupportedKeySystemWithContainerAndCodec(const std::string& mime_type, // Returns whether a |container| type is supported by checking
const std::string& codec, // |key_system_supported_codecs|.
const std::string& key_system); // TODO(xhwang): Update this to actually check initDataType support.
bool IsSupportedContainer(const std::string& container,
SupportedCodecs key_system_supported_codecs) const;
// Returns true if all |codecs| are supported in |container| by checking
// |key_system_supported_codecs|.
bool IsSupportedContainerAndCodecs(
const std::string& container,
const std::vector<std::string>& codecs,
SupportedCodecs key_system_supported_codecs) const;
// Map from key system string to capabilities. // Map from key system string to capabilities.
KeySystemPropertiesMap concrete_key_system_map_; KeySystemPropertiesMap concrete_key_system_map_;
...@@ -129,6 +149,9 @@ class KeySystems { ...@@ -129,6 +149,9 @@ class KeySystems {
KeySystemsSupportUMA key_systems_support_uma_; KeySystemsSupportUMA key_systems_support_uma_;
CodecMaskMap container_codec_masks_;
CodecMaskMap codec_masks_;
DISALLOW_COPY_AND_ASSIGN(KeySystems); DISALLOW_COPY_AND_ASSIGN(KeySystems);
}; };
...@@ -141,6 +164,20 @@ KeySystems& KeySystems::GetInstance() { ...@@ -141,6 +164,20 @@ KeySystems& KeySystems::GetInstance() {
// Because we use a LazyInstance, the key systems info must be populated when // Because we use a LazyInstance, the key systems info must be populated when
// the instance is lazily initiated. // the instance is lazily initiated.
KeySystems::KeySystems() { KeySystems::KeySystems() {
// Build container and codec masks for quick look up.
for (size_t i = 0; i < arraysize(kContainerCodecMasks); ++i) {
const CodecMask& container_codec_mask = kContainerCodecMasks[i];
DCHECK(container_codec_masks_.find(container_codec_mask.type) ==
container_codec_masks_.end());
container_codec_masks_[container_codec_mask.type] =
container_codec_mask.mask;
}
for (size_t i = 0; i < arraysize(kCodecMasks); ++i) {
const CodecMask& codec_mask = kCodecMasks[i];
DCHECK(codec_masks_.find(codec_mask.type) == codec_masks_.end());
codec_masks_[codec_mask.type] = codec_mask.mask;
}
std::vector<KeySystemInfo> key_systems_info; std::vector<KeySystemInfo> key_systems_info;
GetContentClient()->renderer()->AddKeySystems(&key_systems_info); GetContentClient()->renderer()->AddKeySystems(&key_systems_info);
// Clear Key is always supported. // Clear Key is always supported.
...@@ -160,7 +197,7 @@ void KeySystems::AddConcreteSupportedKeySystems( ...@@ -160,7 +197,7 @@ void KeySystems::AddConcreteSupportedKeySystems(
#if defined(ENABLE_PEPPER_CDMS) #if defined(ENABLE_PEPPER_CDMS)
key_system_info.pepper_type, key_system_info.pepper_type,
#endif #endif
key_system_info.supported_types, key_system_info.supported_codecs,
key_system_info.parent_key_system); key_system_info.parent_key_system);
} }
} }
...@@ -171,7 +208,7 @@ void KeySystems::AddConcreteSupportedKeySystem( ...@@ -171,7 +208,7 @@ void KeySystems::AddConcreteSupportedKeySystem(
#if defined(ENABLE_PEPPER_CDMS) #if defined(ENABLE_PEPPER_CDMS)
const std::string& pepper_type, const std::string& pepper_type,
#endif #endif
const ContainerCodecsMap& supported_types, SupportedCodecs supported_codecs,
const std::string& parent_key_system) { const std::string& parent_key_system) {
DCHECK(!IsConcreteSupportedKeySystem(concrete_key_system)) DCHECK(!IsConcreteSupportedKeySystem(concrete_key_system))
<< "Key system '" << concrete_key_system << "' already registered"; << "Key system '" << concrete_key_system << "' already registered";
...@@ -186,7 +223,7 @@ void KeySystems::AddConcreteSupportedKeySystem( ...@@ -186,7 +223,7 @@ void KeySystems::AddConcreteSupportedKeySystem(
properties.pepper_type = pepper_type; properties.pepper_type = pepper_type;
#endif #endif
properties.supported_types = supported_types; properties.supported_codecs = supported_codecs;
concrete_key_system_map_[concrete_key_system] = properties; concrete_key_system_map_[concrete_key_system] = properties;
...@@ -205,41 +242,59 @@ bool KeySystems::IsConcreteSupportedKeySystem(const std::string& key_system) { ...@@ -205,41 +242,59 @@ bool KeySystems::IsConcreteSupportedKeySystem(const std::string& key_system) {
concrete_key_system_map_.end(); concrete_key_system_map_.end();
} }
bool KeySystems::IsSupportedKeySystemWithContainerAndCodec( bool KeySystems::IsSupportedContainer(
const std::string& mime_type, const std::string& container,
const std::string& codec, SupportedCodecs key_system_supported_codecs) const {
const std::string& key_system) { DCHECK(!container.empty());
bool has_type = !mime_type.empty();
DCHECK(has_type || codec.empty()); // When checking container support for EME, "audio/foo" should be treated the
// same as "video/foo". Convert the |container| to achieve this.
// TODO(xhwang): Replace this with real checks against supported initDataTypes
// combined with supported demuxers.
std::string canonical_container = container;
if (container.find("audio/") == 0)
canonical_container.replace(0, 6, "video/");
CodecMaskMap::const_iterator container_iter =
container_codec_masks_.find(canonical_container);
// Unrecognized container.
if (container_iter == container_codec_masks_.end())
return false;
key_systems_support_uma_.ReportKeySystemQuery(key_system, has_type); EmeCodec container_codec_mask = container_iter->second;
// A container is supported iif at least one codec in that container is
// supported.
return (container_codec_mask & key_system_supported_codecs) != 0;
}
KeySystemPropertiesMap::const_iterator key_system_iter = bool KeySystems::IsSupportedContainerAndCodecs(
concrete_key_system_map_.find(key_system); const std::string& container,
if (key_system_iter == concrete_key_system_map_.end()) const std::vector<std::string>& codecs,
return false; SupportedCodecs key_system_supported_codecs) const {
DCHECK(!container.empty());
DCHECK(!codecs.empty());
DCHECK(IsSupportedContainer(container, key_system_supported_codecs));
key_systems_support_uma_.ReportKeySystemSupport(key_system, false); CodecMaskMap::const_iterator container_iter =
container_codec_masks_.find(container);
EmeCodec container_codec_mask = container_iter->second;
if (mime_type.empty()) for (size_t i = 0; i < codecs.size(); ++i) {
return true; const std::string& codec = codecs[i];
DCHECK(!codec.empty());
CodecMaskMap::const_iterator codec_iter = codec_masks_.find(codec);
if (codec_iter == codec_masks_.end()) // Unrecognized codec.
return false;
const ContainerCodecsMap& mime_types_map = EmeCodec codec_mask = codec_iter->second;
key_system_iter->second.supported_types; if (!(codec_mask & key_system_supported_codecs)) // Unsupported codec.
ContainerCodecsMap::const_iterator mime_iter = mime_types_map.find(mime_type); return false;
if (mime_iter == mime_types_map.end())
return false;
if (codec.empty()) { // Unsupported codec/container combination, e.g. "video/webm" and "avc1".
key_systems_support_uma_.ReportKeySystemSupport(key_system, true); if (!(codec_mask & container_codec_mask))
return true; return false;
} }
const CodecSet& codecs = mime_iter->second;
if (codecs.find(codec) == codecs.end())
return false;
key_systems_support_uma_.ReportKeySystemSupport(key_system, true);
return true; return true;
} }
...@@ -257,18 +312,36 @@ bool KeySystems::IsSupportedKeySystemWithMediaMimeType( ...@@ -257,18 +312,36 @@ bool KeySystems::IsSupportedKeySystemWithMediaMimeType(
else else
concrete_key_system = key_system; concrete_key_system = key_system;
if (codecs.empty()) { bool has_type = !mime_type.empty();
return IsSupportedKeySystemWithContainerAndCodec(
mime_type, std::string(), concrete_key_system); key_systems_support_uma_.ReportKeySystemQuery(key_system, has_type);
// Check key system support.
KeySystemPropertiesMap::const_iterator key_system_iter =
concrete_key_system_map_.find(concrete_key_system);
if (key_system_iter == concrete_key_system_map_.end())
return false;
key_systems_support_uma_.ReportKeySystemSupport(key_system, false);
if (!has_type) {
DCHECK(codecs.empty());
return true;
} }
for (size_t i = 0; i < codecs.size(); ++i) { SupportedCodecs key_system_supported_codecs =
if (!IsSupportedKeySystemWithContainerAndCodec( key_system_iter->second.supported_codecs;
mime_type, codecs[i], concrete_key_system)) {
return false; if (!IsSupportedContainer(mime_type, key_system_supported_codecs))
} return false;
if (!codecs.empty() &&
!IsSupportedContainerAndCodecs(
mime_type, codecs, key_system_supported_codecs)) {
return false;
} }
key_systems_support_uma_.ReportKeySystemSupport(key_system, true);
return true; return true;
} }
...@@ -298,6 +371,17 @@ std::string KeySystems::GetPepperType(const std::string& concrete_key_system) { ...@@ -298,6 +371,17 @@ std::string KeySystems::GetPepperType(const std::string& concrete_key_system) {
} }
#endif #endif
void KeySystems::AddContainerMask(const std::string& container, uint32 mask) {
DCHECK(container_codec_masks_.find(container) ==
container_codec_masks_.end());
container_codec_masks_[container] = static_cast<EmeCodec>(mask);
}
void KeySystems::AddCodecMask(const std::string& codec, uint32 mask) {
DCHECK(codec_masks_.find(codec) == codec_masks_.end());
codec_masks_[codec] = static_cast<EmeCodec>(mask);
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
std::string GetUnprefixedKeySystemName(const std::string& key_system) { std::string GetUnprefixedKeySystemName(const std::string& key_system) {
...@@ -351,4 +435,19 @@ std::string GetPepperType(const std::string& concrete_key_system) { ...@@ -351,4 +435,19 @@ std::string GetPepperType(const std::string& concrete_key_system) {
} }
#endif #endif
// These two functions are for testing purpose only. The declaration in the
// header file is guarded by "#if defined(UNIT_TEST)" so that they can be used
// by tests but not non-test code. However, this .cc file is compiled as part of
// "content" where "UNIT_TEST" is not defined. So we need to specify
// "CONTENT_EXPORT" here again so that they are visible to tests.
CONTENT_EXPORT void AddContainerMask(const std::string& container,
uint32 mask) {
KeySystems::GetInstance().AddContainerMask(container, mask);
}
CONTENT_EXPORT void AddCodecMask(const std::string& codec, uint32 mask) {
KeySystems::GetInstance().AddCodecMask(codec, mask);
}
} // namespace content } // namespace content
...@@ -51,6 +51,12 @@ CONTENT_EXPORT std::string GetPepperType( ...@@ -51,6 +51,12 @@ CONTENT_EXPORT std::string GetPepperType(
const std::string& concrete_key_system); const std::string& concrete_key_system);
#endif #endif
#if defined(UNIT_TEST)
// Helper functions to add container/codec types for testing purposes.
CONTENT_EXPORT void AddContainerMask(const std::string& container, uint32 mask);
CONTENT_EXPORT void AddCodecMask(const std::string& codec, uint32 mask);
#endif // defined(UNIT_TEST)
} // namespace content } // namespace content
#endif // CONTENT_RENDERER_MEDIA_CRYPTO_KEY_SYSTEMS_H_ #endif // CONTENT_RENDERER_MEDIA_CRYPTO_KEY_SYSTEMS_H_
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#endif // defined(NDEBUG) #endif // defined(NDEBUG)
#endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) #endif // defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
namespace content {
using blink::WebString; using blink::WebString;
// These are the (fake) key systems that are registered for these tests. // These are the (fake) key systems that are registered for these tests.
...@@ -49,16 +51,44 @@ const char kExternalClearKey[] = "org.chromium.externalclearkey"; ...@@ -49,16 +51,44 @@ const char kExternalClearKey[] = "org.chromium.externalclearkey";
const char kAudioWebM[] = "audio/webm"; const char kAudioWebM[] = "audio/webm";
const char kVideoWebM[] = "video/webm"; const char kVideoWebM[] = "video/webm";
const char kVorbis[] = "vorbis";
const char kVP8[] = "vp8";
const char kVP80[] = "vp8.0";
const char kAudioFoo[] = "audio/foo"; const char kAudioFoo[] = "audio/foo";
const char kVideoFoo[] = "video/foo"; const char kVideoFoo[] = "video/foo";
const char kFooAudioCodec[] = "fooaudio";
const char kFooVideoCodec[] = "foovideo";
namespace content { // Pick some arbitrary bit fields as long as they are not in conflict with the
// real ones.
enum TestCodec {
TEST_CODEC_FOO_AUDIO = 1 << 10, // An audio codec for foo container.
TEST_CODEC_FOO_AUDIO_ALL = TEST_CODEC_FOO_AUDIO,
TEST_CODEC_FOO_VIDEO = 1 << 11, // A video codec for foo container.
TEST_CODEC_FOO_VIDEO_ALL = TEST_CODEC_FOO_VIDEO,
TEST_CODEC_FOO_ALL = TEST_CODEC_FOO_AUDIO_ALL | TEST_CODEC_FOO_VIDEO_ALL
};
COMPILE_ASSERT((TEST_CODEC_FOO_ALL & EME_CODEC_ALL) == EME_CODEC_NONE,
test_codec_masks_should_only_use_invalid_codec_masks);
// Adds test container and codec masks.
// This function must be called after SetContentClient() is called.
// More details: AddXxxMask() will create KeySystems if it hasn't been created.
// During KeySystems's construction GetContentClient() will be used to add key
// systems. In test code, the content client is set by SetContentClient().
// Therefore, SetContentClient() must be called before this function to avoid
// access violation.
static void AddContainerAndCodecMasksForTest() {
// Since KeySystems is a singleton. Make sure we only add test container and
// codec masks once per process.
static bool is_test_masks_added = false;
if (is_test_masks_added)
return;
AddContainerMask("audio/foo", TEST_CODEC_FOO_AUDIO_ALL);
AddContainerMask("video/foo", TEST_CODEC_FOO_ALL);
AddCodecMask("fooaudio", TEST_CODEC_FOO_AUDIO);
AddCodecMask("foovideo", TEST_CODEC_FOO_VIDEO);
is_test_masks_added = true;
}
class TestContentRendererClient : public ContentRendererClient { class TestContentRendererClient : public ContentRendererClient {
virtual void AddKeySystems( virtual void AddKeySystems(
...@@ -68,35 +98,18 @@ class TestContentRendererClient : public ContentRendererClient { ...@@ -68,35 +98,18 @@ class TestContentRendererClient : public ContentRendererClient {
void TestContentRendererClient::AddKeySystems( void TestContentRendererClient::AddKeySystems(
std::vector<content::KeySystemInfo>* key_systems) { std::vector<content::KeySystemInfo>* key_systems) {
KeySystemInfo aes(kUsesAes); KeySystemInfo aes(kUsesAes);
aes.supported_codecs = EME_CODEC_WEBM_ALL;
aes.supported_types[kAudioWebM].insert(kVorbis); aes.supported_codecs |= TEST_CODEC_FOO_ALL;
aes.supported_types[kVideoWebM] = aes.supported_types[kAudioWebM];
aes.supported_types[kVideoWebM].insert(kVP8);
aes.supported_types[kVideoWebM].insert(kVP80);
aes.supported_types[kAudioFoo].insert(kFooAudioCodec);
aes.supported_types[kVideoFoo] = aes.supported_types[kAudioFoo];
aes.supported_types[kVideoFoo].insert(kFooVideoCodec);
aes.use_aes_decryptor = true; aes.use_aes_decryptor = true;
key_systems->push_back(aes); key_systems->push_back(aes);
KeySystemInfo ext(kExternal); KeySystemInfo ext(kExternal);
ext.supported_codecs = EME_CODEC_WEBM_ALL;
ext.supported_types[kAudioWebM].insert(kVorbis); ext.supported_codecs |= TEST_CODEC_FOO_ALL;
ext.supported_types[kVideoWebM] = ext.supported_types[kAudioWebM];
ext.supported_types[kVideoWebM].insert(kVP8);
ext.supported_types[kVideoWebM].insert(kVP80);
ext.supported_types[kAudioFoo].insert(kFooAudioCodec);
ext.supported_types[kVideoFoo] = ext.supported_types[kAudioFoo];
ext.supported_types[kVideoFoo].insert(kFooVideoCodec);
ext.parent_key_system = kExternalParent; ext.parent_key_system = kExternalParent;
#if defined(ENABLE_PEPPER_CDMS) #if defined(ENABLE_PEPPER_CDMS)
ext.pepper_type = "application/x-ppapi-external-cdm"; ext.pepper_type = "application/x-ppapi-external-cdm";
#endif // defined(ENABLE_PEPPER_CDMS) #endif // defined(ENABLE_PEPPER_CDMS)
key_systems->push_back(ext); key_systems->push_back(ext);
} }
...@@ -139,6 +152,10 @@ class KeySystemsTest : public testing::Test { ...@@ -139,6 +152,10 @@ class KeySystemsTest : public testing::Test {
SetRendererClientForTesting(&content_renderer_client_); SetRendererClientForTesting(&content_renderer_client_);
} }
virtual void SetUp() OVERRIDE {
AddContainerAndCodecMasksForTest();
}
virtual ~KeySystemsTest() { virtual ~KeySystemsTest() {
// Clear the use of content_client_, which was set in SetUp(). // Clear the use of content_client_, which was set in SetUp().
SetContentClient(NULL); SetContentClient(NULL);
......
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