From f1f20728a18fff332af52c0e60726a8b34510ba6 Mon Sep 17 00:00:00 2001 From: ddorwin Date: Wed, 2 Mar 2016 21:06:29 -0800 Subject: EME on Android: Improve accuracy of Key System availability. Implemented per https://crbug.com/582618#c7. BUG=559236,582618 Review URL: https://codereview.chromium.org/1747073003 Cr-Commit-Position: refs/heads/master@{#378959} --- media/base/android/media_drm_bridge.cc | 67 +++++++++++++++++++++++++------ media/base/android/media_drm_bridge.h | 16 ++++++-- media/base/key_systems.cc | 11 +++++ media/base/media.cc | 6 +++ media/base/media.h | 6 +++ media/base/mime_util_internal.cc | 5 +-- media/blink/key_system_config_selector.cc | 27 ++++++++----- 7 files changed, 109 insertions(+), 29 deletions(-) diff --git a/media/base/android/media_drm_bridge.cc b/media/base/android/media_drm_bridge.cc index 0633c31..a5975f3 100644 --- a/media/base/android/media_drm_bridge.cc +++ b/media/base/android/media_drm_bridge.cc @@ -26,6 +26,7 @@ #include "base/thread_task_runner_handle.h" #include "jni/MediaDrmBridge_jni.h" #include "media/base/android/media_client_android.h" +#include "media/base/android/media_codec_util.h" #include "media/base/android/media_drm_bridge_delegate.h" #include "media/base/android/provision_fetcher.h" #include "media/base/cdm_key_information.h" @@ -174,8 +175,12 @@ base::LazyInstance::Leaky g_key_system_manager = // resolved. bool IsKeySystemSupportedWithTypeImpl(const std::string& key_system, const std::string& container_mime_type) { - if (!MediaDrmBridge::IsAvailable()) + DCHECK(MediaDrmBridge::IsAvailable()); + + if (key_system.empty()) { + NOTREACHED(); return false; + } UUID scheme_uuid = g_key_system_manager.Get().GetUUID(key_system); if (scheme_uuid.empty()) @@ -215,10 +220,7 @@ std::string GetSecurityLevelString( return ""; } -} // namespace - -// static -bool MediaDrmBridge::IsAvailable() { +bool AreMediaDrmApisAvailable() { if (base::android::BuildInfo::GetInstance()->sdk_int() < 19) return false; @@ -233,6 +235,15 @@ bool MediaDrmBridge::IsAvailable() { return true; } +} // namespace + +// MediaDrm is not generally usable without MediaCodec. Thus, both the MediaDrm +// APIs and MediaCodec APIs must be enabled and not blacklisted. +// static +bool MediaDrmBridge::IsAvailable() { + return AreMediaDrmApisAvailable() && MediaCodecUtil::IsMediaCodecAvailable(); +} + // static bool MediaDrmBridge::RegisterMediaDrmBridge(JNIEnv* env) { return RegisterNativesImpl(env); @@ -240,7 +251,9 @@ bool MediaDrmBridge::RegisterMediaDrmBridge(JNIEnv* env) { // static bool MediaDrmBridge::IsKeySystemSupported(const std::string& key_system) { - DCHECK(!key_system.empty()); + if (!MediaDrmBridge::IsAvailable()) + return false; + return IsKeySystemSupportedWithTypeImpl(key_system, ""); } @@ -248,17 +261,24 @@ bool MediaDrmBridge::IsKeySystemSupported(const std::string& key_system) { bool MediaDrmBridge::IsKeySystemSupportedWithType( const std::string& key_system, const std::string& container_mime_type) { - DCHECK(!key_system.empty() && !container_mime_type.empty()); + DCHECK(!container_mime_type.empty()) << "Call IsKeySystemSupported instead"; + + if (!MediaDrmBridge::IsAvailable()) + return false; + return IsKeySystemSupportedWithTypeImpl(key_system, container_mime_type); } // static std::vector MediaDrmBridge::GetPlatformKeySystemNames() { + if (!MediaDrmBridge::IsAvailable()) + return std::vector(); + return g_key_system_manager.Get().GetPlatformKeySystemNames(); } // static -scoped_refptr MediaDrmBridge::Create( +scoped_refptr MediaDrmBridge::CreateInternal( const std::string& key_system, SecurityLevel security_level, const CreateFetcherCB& create_fetcher_cb, @@ -267,10 +287,8 @@ scoped_refptr MediaDrmBridge::Create( const LegacySessionErrorCB& legacy_session_error_cb, const SessionKeysChangeCB& session_keys_change_cb, const SessionExpirationUpdateCB& session_expiration_update_cb) { - DVLOG(1) << __FUNCTION__; - - if (!IsAvailable()) - return nullptr; + // All paths requires the MediaDrmApis. + DCHECK(AreMediaDrmApisAvailable()); UUID scheme_uuid = g_key_system_manager.Get().GetUUID(key_system); if (scheme_uuid.empty()) @@ -288,12 +306,37 @@ scoped_refptr MediaDrmBridge::Create( } // static +scoped_refptr MediaDrmBridge::Create( + const std::string& key_system, + SecurityLevel security_level, + const CreateFetcherCB& create_fetcher_cb, + const SessionMessageCB& session_message_cb, + const SessionClosedCB& session_closed_cb, + const LegacySessionErrorCB& legacy_session_error_cb, + const SessionKeysChangeCB& session_keys_change_cb, + const SessionExpirationUpdateCB& session_expiration_update_cb) { + DVLOG(1) << __FUNCTION__; + + if (!IsAvailable()) + return nullptr; + + return CreateInternal(key_system, security_level, create_fetcher_cb, + session_message_cb, session_closed_cb, + legacy_session_error_cb, session_keys_change_cb, + session_expiration_update_cb); +} + +// static scoped_refptr MediaDrmBridge::CreateWithoutSessionSupport( const std::string& key_system, SecurityLevel security_level, const CreateFetcherCB& create_fetcher_cb) { DVLOG(1) << __FUNCTION__; + // Sessions won't be used so decoding capability is not required. + if (!AreMediaDrmApisAvailable()) + return nullptr; + return MediaDrmBridge::Create(key_system, security_level, create_fetcher_cb, SessionMessageCB(), SessionClosedCB(), LegacySessionErrorCB(), SessionKeysChangeCB(), diff --git a/media/base/android/media_drm_bridge.h b/media/base/android/media_drm_bridge.h index 04e57fc..d5408c1 100644 --- a/media/base/android/media_drm_bridge.h +++ b/media/base/android/media_drm_bridge.h @@ -55,9 +55,9 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys, public PlayerTracker { using MediaCryptoReadyCB = base::Callback; - // Checks whether MediaDRM is available. - // All other static methods check IsAvailable() internally. There's no need - // to check IsAvailable() explicitly before calling them. + // Checks whether MediaDRM is available and usable, including for decoding. + // All other static methods check IsAvailable() or equivalent internally. + // There is no need to check IsAvailable() explicitly before calling them. static bool IsAvailable(); static bool RegisterMediaDrmBridge(JNIEnv* env); @@ -243,6 +243,16 @@ class MEDIA_EXPORT MediaDrmBridge : public MediaKeys, public PlayerTracker { // For DeleteSoon() in DeleteOnCorrectThread(). friend class base::DeleteHelper; + static scoped_refptr CreateInternal( + const std::string& key_system, + SecurityLevel security_level, + const CreateFetcherCB& create_fetcher_cb, + const SessionMessageCB& session_message_cb, + const SessionClosedCB& session_closed_cb, + const LegacySessionErrorCB& legacy_session_error_cb, + const SessionKeysChangeCB& session_keys_change_cb, + const SessionExpirationUpdateCB& session_expiration_update_cb); + // Constructs a MediaDrmBridge for |scheme_uuid| and |security_level|. The // default security level will be used if |security_level| is // SECURITY_LEVEL_DEFAULT. Sessions should not be created if session callbacks diff --git a/media/base/key_systems.cc b/media/base/key_systems.cc index 914661f..8a3ae69 100644 --- a/media/base/key_systems.cc +++ b/media/base/key_systems.cc @@ -15,6 +15,7 @@ #include "base/time/time.h" #include "build/build_config.h" #include "media/base/key_system_info.h" +#include "media/base/media.h" #include "media/base/media_client.h" #include "media/cdm/key_system_names.h" #include "third_party/widevine/cdm/widevine_cdm_common.h" @@ -409,6 +410,16 @@ void KeySystemsImpl::AddSupportedKeySystems( DCHECK_EQ(key_system_map_.count(info.key_system), 0u) << "Key system '" << info.key_system << "' already registered"; + +#if defined(OS_ANDROID) + // Ensure that the renderer can access the decoders necessary to use the + // key system. + if (!info.use_aes_decryptor && !ArePlatformDecodersAvailable()) { + DLOG(WARNING) << info.key_system << " not registered"; + continue; + } +#endif // defined(OS_ANDROID) + key_system_map_[info.key_system] = info; } } diff --git a/media/base/media.cc b/media/base/media.cc index efc495b..b2e1c45 100644 --- a/media/base/media.cc +++ b/media/base/media.cc @@ -115,6 +115,12 @@ bool IsUnifiedMediaPipelineEnabledForMse() { switches::kEnableUnifiedMediaPipeline) || !MediaCodecUtil::IsMediaCodecAvailable(); } + +bool ArePlatformDecodersAvailable() { + return IsUnifiedMediaPipelineEnabled() + ? HasPlatformDecoderSupport() + : MediaCodecUtil::IsMediaCodecAvailable(); +} #endif } // namespace media diff --git a/media/base/media.h b/media/base/media.h index 65a7a69..b6cccc4 100644 --- a/media/base/media.h +++ b/media/base/media.h @@ -46,6 +46,12 @@ MEDIA_EXPORT bool IsUnifiedMediaPipelineEnabled(); // cases where existing pipeline has no support). As above, codecs requiring // platform support may not be available. MEDIA_EXPORT bool IsUnifiedMediaPipelineEnabledForMse(); + +// Returns whether the platform decoders are available for use. +// This includes decoders being available on the platform and accessible, such +// as via the GPU process. Should only be used for actual decoders +// (e.g. MediaCodec) and not full-featured players (e.g. MediaPlayer). +MEDIA_EXPORT bool ArePlatformDecodersAvailable(); #endif } // namespace media diff --git a/media/base/mime_util_internal.cc b/media/base/mime_util_internal.cc index a0ce3c4..7e7f004 100644 --- a/media/base/mime_util_internal.cc +++ b/media/base/mime_util_internal.cc @@ -274,10 +274,7 @@ MimeUtil::MimeUtil() : allow_proprietary_codecs_(false) { // When the unified media pipeline is enabled, we need support for both GPU // video decoders and MediaCodec; indicated by HasPlatformDecoderSupport(). // When the Android pipeline is used, we only need access to MediaCodec. - platform_info_.has_platform_decoders = - platform_info_.is_unified_media_pipeline_enabled - ? HasPlatformDecoderSupport() - : MediaCodecUtil::IsMediaCodecAvailable(); + platform_info_.has_platform_decoders = ArePlatformDecodersAvailable(); platform_info_.has_platform_vp8_decoder = MediaCodecUtil::IsVp8DecoderAvailable(); platform_info_.supports_opus = PlatformHasOpusSupport(); diff --git a/media/blink/key_system_config_selector.cc b/media/blink/key_system_config_selector.cc index 766feda..885049c 100644 --- a/media/blink/key_system_config_selector.cc +++ b/media/blink/key_system_config_selector.cc @@ -277,20 +277,25 @@ KeySystemConfigSelector::KeySystemConfigSelector( KeySystemConfigSelector::~KeySystemConfigSelector() { } -bool IsSupportedClearMediaFormat(const std::string& container_mime_type, - const std::string& codecs) { +bool IsSupportedMediaFormat(const std::string& container_mime_type, + const std::string& codecs, + bool use_aes_decryptor) { std::vector codec_vector; - media::ParseCodecString(codecs, &codec_vector, false); - media::SupportsType support_result = - media::IsSupportedEncryptedMediaFormat(container_mime_type, codec_vector); + ParseCodecString(codecs, &codec_vector, false); + // AesDecryptor decrypts the stream in the demuxer before it reaches the + // decoder so check whether the media format is supported when clear. + SupportsType support_result = + use_aes_decryptor + ? IsSupportedMediaFormat(container_mime_type, codec_vector) + : IsSupportedEncryptedMediaFormat(container_mime_type, codec_vector); switch (support_result) { - case media::IsSupported: + case IsSupported: return true; - case media::MayBeSupported: + case MayBeSupported: // If no codecs were specified, the best possible result is // MayBeSupported, indicating support for the container. return codec_vector.empty(); - case media::IsNotSupported: + case IsNotSupported: return false; } NOTREACHED(); @@ -309,8 +314,10 @@ bool KeySystemConfigSelector::IsSupportedContentType( // is done primarily to validate extended codecs, but it also ensures that the // CDM cannot support codecs that Chrome does not (which could complicate the // robustness algorithm). - if (!IsSupportedClearMediaFormat(container_mime_type, codecs)) + if (!IsSupportedMediaFormat(container_mime_type, codecs, + CanUseAesDecryptor(key_system))) { return false; + } // TODO(servolk): Converting |container_mime_type| to lower-case could be // moved to KeySystemsImpl::GetContentTypeConfigRule, plus we could add some @@ -321,7 +328,7 @@ bool KeySystemConfigSelector::IsSupportedContentType( // This check does not handle extended codecs, so extended codec information // is stripped (extended codec information was checked above). std::vector stripped_codec_vector; - media::ParseCodecString(codecs, &stripped_codec_vector, true); + ParseCodecString(codecs, &stripped_codec_vector, true); EmeConfigRule codecs_rule = key_systems_->GetContentTypeConfigRule( key_system, media_type, container_lower, stripped_codec_vector); if (!config_state->IsRuleSupported(codecs_rule)) -- cgit v1.1