| // Copyright 2017 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 "content/browser/media/key_system_support_impl.h" |
| |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/containers/flat_set.h" |
| #include "base/feature_list.h" |
| #include "base/logging.h" |
| #include "base/metrics/histogram_functions.h" |
| #include "base/strings/string_split.h" |
| #include "content/public/browser/cdm_registry.h" |
| #include "content/public/browser/content_browser_client.h" |
| #include "content/public/common/cdm_info.h" |
| #include "content/public/common/content_client.h" |
| #include "content/public/common/content_switches.h" |
| #include "media/base/key_system_names.h" |
| #include "media/base/key_systems.h" |
| #include "media/base/media_switches.h" |
| #include "media/mojo/buildflags.h" |
| #include "mojo/public/cpp/bindings/strong_binding.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| void SendCdmAvailableUMA(const std::string& key_system, bool available) { |
| base::UmaHistogramBoolean("Media.EME." + |
| media::GetKeySystemNameForUMA(key_system) + |
| ".LibraryCdmAvailable", |
| available); |
| } |
| |
| template <typename T> |
| std::vector<T> SetToVector(const base::flat_set<T>& s) { |
| return std::vector<T>(s.begin(), s.end()); |
| } |
| |
| // Returns whether hardware secure codecs are enabled from command line. If |
| // true, |video_codecs| are filled with codecs specified on command line, which |
| // could be empty if no codecs are specified. If false, |video_codecs| will not |
| // be modified. |
| bool IsHardwareSecureCodecsOverriddenFromCommandLine( |
| std::vector<media::VideoCodec>* video_codecs, |
| std::vector<media::EncryptionMode>* encryption_schemes) { |
| DCHECK(video_codecs->empty()); |
| DCHECK(encryption_schemes->empty()); |
| |
| auto* command_line = base::CommandLine::ForCurrentProcess(); |
| if (!command_line || !command_line->HasSwitch( |
| switches::kOverrideHardwareSecureCodecsForTesting)) { |
| return false; |
| } |
| |
| auto codecs_string = command_line->GetSwitchValueASCII( |
| switches::kOverrideHardwareSecureCodecsForTesting); |
| const auto supported_codecs = base::SplitStringPiece( |
| codecs_string, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| |
| for (const auto& codec : supported_codecs) { |
| if (codec == "vp8") |
| video_codecs->push_back(media::VideoCodec::kCodecVP8); |
| else if (codec == "vp9") |
| video_codecs->push_back(media::VideoCodec::kCodecVP9); |
| else if (codec == "avc1") |
| video_codecs->push_back(media::VideoCodec::kCodecH264); |
| else |
| DVLOG(1) << "Unsupported codec specified on command line: " << codec; |
| } |
| |
| // Codecs enabled from command line assumes CENC support. |
| if (!video_codecs->empty()) |
| encryption_schemes->push_back(media::EncryptionMode::kCenc); |
| |
| return true; |
| } |
| |
| void GetHardwareSecureDecryptionCaps( |
| const std::string& key_system, |
| const base::flat_set<media::CdmProxy::Protocol>& cdm_proxy_protocols, |
| std::vector<media::VideoCodec>* video_codecs, |
| std::vector<media::EncryptionMode>* encryption_schemes) { |
| DCHECK(video_codecs->empty()); |
| DCHECK(encryption_schemes->empty()); |
| |
| if (!base::FeatureList::IsEnabled(media::kHardwareSecureDecryption)) { |
| DVLOG(1) << "Hardware secure decryption disabled"; |
| return; |
| } |
| |
| // Secure codecs override takes precedence over other checks. |
| if (IsHardwareSecureCodecsOverriddenFromCommandLine(video_codecs, |
| encryption_schemes)) { |
| DVLOG(1) << "Hardware secure codecs overridden from command line"; |
| return; |
| } |
| |
| if (cdm_proxy_protocols.empty()) { |
| DVLOG(1) << "CDM does not support any CdmProxy protocols"; |
| return; |
| } |
| |
| // Hardware secure video codecs need hardware video decoder support. |
| // TODO(xhwang): Make sure this check is as close as possible to the check |
| // in the render process. For example, also check check GPU features like |
| // GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE. |
| auto* command_line = base::CommandLine::ForCurrentProcess(); |
| if (command_line && |
| command_line->HasSwitch(switches::kDisableAcceleratedVideoDecode)) { |
| DVLOG(1) << "Hardware secure codecs not supported because accelerated " |
| "video decode disabled"; |
| return; |
| } |
| |
| #if BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER) |
| if (!base::FeatureList::IsEnabled(media::kMojoVideoDecoder)) { |
| DVLOG(1) << "Hardware secure codecs not supported because mojo video " |
| "decode was disabled at runtime"; |
| return; |
| } |
| #else |
| DVLOG(1) << "Hardware secure codecs not supported because mojo video " |
| "decode was disabled at buildtime"; |
| return; |
| #endif |
| |
| base::flat_set<media::VideoCodec> video_codec_set; |
| base::flat_set<media::EncryptionMode> encryption_scheme_set; |
| |
| GetContentClient()->browser()->GetHardwareSecureDecryptionCaps( |
| key_system, cdm_proxy_protocols, &video_codec_set, |
| &encryption_scheme_set); |
| |
| *video_codecs = SetToVector(video_codec_set); |
| *encryption_schemes = SetToVector(encryption_scheme_set); |
| } |
| |
| } // namespace |
| |
| // static |
| void KeySystemSupportImpl::Create( |
| media::mojom::KeySystemSupportRequest request) { |
| DVLOG(3) << __func__; |
| // The created object is bound to (and owned by) |request|. |
| mojo::MakeStrongBinding(std::make_unique<KeySystemSupportImpl>(), |
| std::move(request)); |
| } |
| |
| // static |
| std::unique_ptr<CdmInfo> KeySystemSupportImpl::GetCdmInfoForKeySystem( |
| const std::string& key_system) { |
| DVLOG(2) << __func__ << ": key_system = " << key_system; |
| for (const auto& cdm : CdmRegistry::GetInstance()->GetAllRegisteredCdms()) { |
| if (cdm.supported_key_system == key_system || |
| (cdm.supports_sub_key_systems && |
| media::IsChildKeySystemOf(key_system, cdm.supported_key_system))) { |
| return std::make_unique<CdmInfo>(cdm); |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| KeySystemSupportImpl::KeySystemSupportImpl() = default; |
| |
| KeySystemSupportImpl::~KeySystemSupportImpl() = default; |
| |
| void KeySystemSupportImpl::IsKeySystemSupported( |
| const std::string& key_system, |
| IsKeySystemSupportedCallback callback) { |
| 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, nullptr); |
| return; |
| } |
| |
| SendCdmAvailableUMA(key_system, true); |
| |
| // Supported codecs and encryption schemes. |
| auto capability = media::mojom::KeySystemCapability::New(); |
| capability->video_codecs = cdm_info->capability.video_codecs; |
| capability->supports_vp9_profile2 = |
| cdm_info->capability.supports_vp9_profile2; |
| capability->encryption_schemes = |
| SetToVector(cdm_info->capability.encryption_schemes); |
| |
| GetHardwareSecureDecryptionCaps(key_system, |
| cdm_info->capability.cdm_proxy_protocols, |
| &capability->hw_secure_video_codecs, |
| &capability->hw_secure_encryption_schemes); |
| |
| capability->session_types = SetToVector(cdm_info->capability.session_types); |
| |
| std::move(callback).Run(true, std::move(capability)); |
| } |
| |
| } // namespace content |