blob: 615b95a2b9676f31ba5fb044f81bd22a77bcf9ed [file] [log] [blame]
// Copyright 2018 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 "fuchsia/engine/renderer/web_engine_content_renderer_client.h"
#include "base/feature_list.h"
#include "base/macros.h"
#include "components/cdm/renderer/widevine_key_system_properties.h"
#include "content/public/renderer/render_frame.h"
#include "fuchsia/engine/renderer/on_load_script_injector.h"
#include "fuchsia/engine/renderer/web_engine_url_loader_throttle_provider.h"
#include "fuchsia/engine/switches.h"
#include "media/base/eme_constants.h"
#include "media/base/video_codecs.h"
#include "services/network/public/cpp/features.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h"
namespace {
// Returns true if the specified video format can be decoded on hardware.
bool IsSupportedHardwareVideoCodec(const media::VideoType& type) {
// TODO(crbug.com/1013412): Replace these hardcoded checks with a query to the
// fuchsia.mediacodec FIDL service when fxb/36000 is resolved.
if (type.codec == media::kCodecH264 && type.level <= 41)
return true;
if (type.codec == media::kCodecVP9 && type.level <= 40)
return true;
return false;
}
class PlayreadyKeySystemProperties : public ::media::KeySystemProperties {
public:
PlayreadyKeySystemProperties(const std::string& key_system_name,
media::SupportedCodecs supported_codecs,
bool persistent_license_support)
: key_system_name_(key_system_name),
supported_codecs_(supported_codecs),
persistent_license_support_(persistent_license_support) {}
std::string GetKeySystemName() const override { return key_system_name_; }
bool IsSupportedInitDataType(
media::EmeInitDataType init_data_type) const override {
return init_data_type == media::EmeInitDataType::CENC;
}
media::SupportedCodecs GetSupportedCodecs() const override {
return supported_codecs_;
}
media::SupportedCodecs GetSupportedHwSecureCodecs() const override {
return supported_codecs_;
}
media::EmeConfigRule GetRobustnessConfigRule(
media::EmeMediaType media_type,
const std::string& requested_robustness) const override {
// Only empty robustness string is currently supported.
if (requested_robustness.empty()) {
return media::EmeConfigRule::HW_SECURE_CODECS_REQUIRED;
}
return media::EmeConfigRule::NOT_SUPPORTED;
}
media::EmeSessionTypeSupport GetPersistentLicenseSessionSupport()
const override {
return persistent_license_support_
? media::EmeSessionTypeSupport::SUPPORTED
: media::EmeSessionTypeSupport::NOT_SUPPORTED;
}
media::EmeSessionTypeSupport GetPersistentUsageRecordSessionSupport()
const override {
return media::EmeSessionTypeSupport::NOT_SUPPORTED;
}
media::EmeFeatureSupport GetPersistentStateSupport() const override {
return media::EmeFeatureSupport::ALWAYS_ENABLED;
}
media::EmeFeatureSupport GetDistinctiveIdentifierSupport() const override {
return media::EmeFeatureSupport::ALWAYS_ENABLED;
}
media::EmeConfigRule GetEncryptionSchemeConfigRule(
media::EncryptionScheme encryption_mode) const override {
if (encryption_mode == ::media::EncryptionScheme::kCenc) {
return media::EmeConfigRule::SUPPORTED;
}
return media::EmeConfigRule::NOT_SUPPORTED;
}
private:
const std::string key_system_name_;
const media::SupportedCodecs supported_codecs_;
const bool persistent_license_support_;
};
} // namespace
WebEngineContentRendererClient::WebEngineContentRendererClient() = default;
WebEngineContentRendererClient::~WebEngineContentRendererClient() = default;
UrlRequestRulesReceiver*
WebEngineContentRendererClient::GetUrlRequestRulesReceiverForRenderFrameId(
int render_frame_id) const {
auto iter = url_request_receivers_by_id_.find(render_frame_id);
DCHECK(iter != url_request_receivers_by_id_.end());
return iter->second.get();
}
void WebEngineContentRendererClient::OnRenderFrameDeleted(int render_frame_id) {
size_t count = url_request_receivers_by_id_.erase(render_frame_id);
DCHECK_EQ(count, 1u);
}
void WebEngineContentRendererClient::RenderFrameCreated(
content::RenderFrame* render_frame) {
// Add WebEngine services to the new RenderFrame.
// The objects' lifetimes are bound to the RenderFrame's lifetime.
new OnLoadScriptInjector(render_frame);
int render_frame_id = render_frame->GetRoutingID();
auto rules_receiver = std::make_unique<UrlRequestRulesReceiver>(
content::RenderFrame::FromRoutingID(render_frame_id),
base::BindOnce(&WebEngineContentRendererClient::OnRenderFrameDeleted,
base::Unretained(this)));
auto iter = url_request_receivers_by_id_.emplace(render_frame_id,
std::move(rules_receiver));
DCHECK(iter.second);
}
std::unique_ptr<content::URLLoaderThrottleProvider>
WebEngineContentRendererClient::CreateURLLoaderThrottleProvider(
content::URLLoaderThrottleProviderType type) {
DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
// TODO(crbug.com/976975): Add support for service workers.
if (type == content::URLLoaderThrottleProviderType::kWorker)
return nullptr;
return std::make_unique<WebEngineURLLoaderThrottleProvider>(this);
}
void WebEngineContentRendererClient::AddSupportedKeySystems(
std::vector<std::unique_ptr<media::KeySystemProperties>>* key_systems) {
media::SupportedCodecs supported_video_codecs = 0;
constexpr uint8_t kUnknownCodecLevel = 0;
if (IsSupportedHardwareVideoCodec(media::VideoType{
media::kCodecVP9, media::VP9PROFILE_PROFILE0, kUnknownCodecLevel,
media::VideoColorSpace::REC709()})) {
supported_video_codecs |= media::EME_CODEC_VP9_PROFILE0;
}
if (IsSupportedHardwareVideoCodec(media::VideoType{
media::kCodecVP9, media::VP9PROFILE_PROFILE2, kUnknownCodecLevel,
media::VideoColorSpace::REC709()})) {
supported_video_codecs |= media::EME_CODEC_VP9_PROFILE2;
}
if (IsSupportedHardwareVideoCodec(media::VideoType{
media::kCodecH264, media::H264PROFILE_MAIN, kUnknownCodecLevel,
media::VideoColorSpace::REC709()})) {
supported_video_codecs |= media::EME_CODEC_AVC1;
}
media::SupportedCodecs supported_audio_codecs = media::EME_CODEC_AUDIO_ALL;
media::SupportedCodecs supported_codecs =
supported_video_codecs | supported_audio_codecs;
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableWidevine)) {
base::flat_set<media::EncryptionScheme> encryption_schemes{
media::EncryptionScheme::kCenc, media::EncryptionScheme::kCbcs};
// Fuchsia always decrypts audio into clear buffers and return them back to
// Chromium. Hardware secured decoders are only available for supported
// video codecs.
key_systems->emplace_back(new cdm::WidevineKeySystemProperties(
supported_codecs, // codecs
encryption_schemes, // encryption schemes
supported_codecs, // hw secure codecs
encryption_schemes, // hw secure encryption schemes
cdm::WidevineKeySystemProperties::Robustness::
HW_SECURE_CRYPTO, // max audio robustness
cdm::WidevineKeySystemProperties::Robustness::
HW_SECURE_ALL, // max video robustness
media::EmeSessionTypeSupport::NOT_SUPPORTED, // persistent license
media::EmeSessionTypeSupport::NOT_SUPPORTED, // persistent usage record
media::EmeFeatureSupport::ALWAYS_ENABLED, // persistent state
media::EmeFeatureSupport::ALWAYS_ENABLED)); // distinctive identifier
}
std::string playready_key_system =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kPlayreadyKeySystem);
if (!playready_key_system.empty()) {
key_systems->emplace_back(
new PlayreadyKeySystemProperties(playready_key_system, supported_codecs,
/*persistent_license_support=*/false));
}
}
bool WebEngineContentRendererClient::IsSupportedVideoType(
const media::VideoType& type) {
// Fall back to default codec querying logic if software codecs aren't
// disabled.
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableSoftwareVideoDecoders)) {
return ContentRendererClient::IsSupportedVideoType(type);
}
return IsSupportedHardwareVideoCodec(type);
}