blob: fecedaa7b886e996774a296d69d138cf92ade328 [file] [log] [blame]
// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/renderer/media/render_media_client.h"
#include <utility>
#include "base/command_line.h"
#include "base/time/default_tick_clock.h"
#include "content/public/common/content_client.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/renderer/render_thread_impl.h"
#include "media/base/audio_parameters.h"
#include "media/base/media_switches.h"
#include "media/base/supported_types.h"
#include "media/base/video_color_space.h"
#include "media/mojo/buildflags.h"
#include "media/video/video_encode_accelerator.h"
#include "ui/display/display_switches.h"
namespace {
#if BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT)
void UpdateDecoderVideoProfilesInternal(
const media::SupportedVideoDecoderConfigs& supported_configs) {
base::flat_set<media::VideoCodecProfile> media_profiles;
for (const auto& config : supported_configs) {
for (int profile = config.profile_min; profile <= config.profile_max;
profile++) {
media_profiles.insert(static_cast<media::VideoCodecProfile>(profile));
}
}
media::UpdateDefaultDecoderSupportedVideoProfiles(media_profiles);
}
#endif // BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT)
#if BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
void UpdateDecoderAudioTypesInternal(
const media::SupportedAudioDecoderConfigs& supported_configs) {
base::flat_set<media::AudioType> supported_types;
for (const auto& config : supported_configs) {
media::AudioType type{config.codec, config.profile, false};
supported_types.insert(type);
}
media::UpdateDefaultDecoderSupportedAudioTypes(supported_types);
}
#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
#if BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_ENCODE_SUPPORT)
void UpdateEncoderVideoProfilesInternal(
const media::VideoEncodeAccelerator::SupportedProfiles& supported_configs) {
base::flat_set<media::VideoCodecProfile> media_profiles;
for (const auto& config : supported_configs) {
media_profiles.insert(
static_cast<media::VideoCodecProfile>(config.profile));
}
media::UpdateDefaultEncoderSupportedVideoProfiles(media_profiles);
}
#endif // BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_ENCODE_SUPPORT)
} // namespace
namespace content {
void RenderMediaClient::Initialize() {
static RenderMediaClient* client = new RenderMediaClient();
media::SetMediaClient(client);
}
RenderMediaClient::RenderMediaClient()
: main_task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
#if BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT) || \
BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
RenderThreadImpl::current()->BindHostReceiver(
interface_factory_for_supported_profiles_.BindNewPipeAndPassReceiver());
interface_factory_for_supported_profiles_.set_disconnect_handler(
base::BindOnce(&RenderMediaClient::OnInterfaceFactoryDisconnected,
// base::Unretained(this) is safe because the
// RenderMediaClient is never destructed.
base::Unretained(this)));
#endif // BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT) ||
// BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
#if BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT)
// We'll first try to query the supported video decoder configurations
// asynchronously. If IsDecoderSupportedVideoType() is called before we get a
// response, that method will block if its not on the main thread or fall
// back to querying the video decoder configurations synchronously otherwise.
mojo::SharedRemote<media::mojom::VideoDecoder> video_decoder_remote;
interface_factory_for_supported_profiles_->CreateVideoDecoder(
video_decoder_remote.BindNewPipeAndPassReceiver(),
/*dst_video_decoder=*/{});
video_decoder_remote.set_disconnect_handler(
base::BindOnce(&RenderMediaClient::OnVideoDecoderDisconnected,
// base::Unretained(this) is safe because the
// RenderMediaClient is never destructed.
base::Unretained(this)),
main_task_runner_);
video_decoder_remote->GetSupportedConfigs(
base::BindOnce(&RenderMediaClient::OnGetSupportedVideoDecoderConfigs,
// base::Unretained(this) is safe because the
// RenderMediaClient is never destructed.
base::Unretained(this)));
video_decoder_for_supported_profiles_ = std::move(video_decoder_remote);
#endif // BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT)
#if BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
interface_factory_for_supported_profiles_->CreateAudioDecoder(
audio_decoder_for_supported_configs_.BindNewPipeAndPassReceiver());
audio_decoder_for_supported_configs_.set_disconnect_handler(
base::BindOnce(&RenderMediaClient::OnAudioDecoderDisconnected,
base::Unretained(this)),
main_task_runner_);
audio_decoder_for_supported_configs_->GetSupportedConfigs(
base::BindOnce(&RenderMediaClient::OnGetSupportedAudioDecoderConfigs,
base::Unretained(this)));
#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
}
RenderMediaClient::~RenderMediaClient() {
// The RenderMediaClient should never get destroyed and we have usages of
// base::Unretained(this) here that rely on that behaviour.
NOTREACHED();
}
bool RenderMediaClient::IsDecoderSupportedAudioType(
const media::AudioType& type) {
#if BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
if (!did_audio_decoder_update_.IsSignaled()) {
// The asynchronous request didn't complete in time, so we must now block
// or retrieve the information synchronously.
if (main_task_runner_->BelongsToCurrentThread()) {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
media::SupportedAudioDecoderConfigs configs;
if (!audio_decoder_for_supported_configs_->GetSupportedConfigs(
&configs)) {
configs.clear();
}
OnGetSupportedAudioDecoderConfigs(configs);
DCHECK(did_audio_decoder_update_.IsSignaled());
} else {
// There's already an asynchronous request on the main thread, so wait...
did_audio_decoder_update_.Wait();
}
}
#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
return GetContentClient()->renderer()->IsDecoderSupportedAudioType(type);
}
bool RenderMediaClient::IsDecoderSupportedVideoType(
const media::VideoType& type) {
#if BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT)
if (!did_video_decoder_update_.IsSignaled()) {
// The asynchronous request didn't complete in time, so we must now block
// or retrieve the information synchronously.
if (main_task_runner_->BelongsToCurrentThread()) {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
media::SupportedVideoDecoderConfigs configs;
media::VideoDecoderType video_decoder_type;
if (!video_decoder_for_supported_profiles_->GetSupportedConfigs(
&configs, &video_decoder_type)) {
configs.clear();
}
OnGetSupportedVideoDecoderConfigs(configs, video_decoder_type);
DCHECK(did_video_decoder_update_.IsSignaled());
} else {
// There's already an asynchronous request on the main thread, so wait...
did_video_decoder_update_.Wait();
}
}
#endif // BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT)
return GetContentClient()->renderer()->IsDecoderSupportedVideoType(type);
}
bool RenderMediaClient::IsEncoderSupportedVideoType(
const media::VideoType& type) {
#if BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_ENCODE_SUPPORT)
if (media::IsEncoderOptionalVideoType(type) && !did_video_encoder_update_) {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
// Currently only MediaRecorder will call this, which only support main
// thread. On main thread, we need to block and retrieve the supported
// profiles synchronously.
GetSupportedVideoEncoderConfigs();
DCHECK(did_video_encoder_update_);
}
#endif // BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_ENCODE_SUPPORT)
return GetContentClient()->renderer()->IsEncoderSupportedVideoType(type);
}
bool RenderMediaClient::IsSupportedBitstreamAudioCodec(
media::AudioCodec codec) {
return GetContentClient()->renderer()->IsSupportedBitstreamAudioCodec(codec);
}
bool RenderMediaClient::ShouldSuppressAudioTracks() {
return GetContentClient()->renderer()->ShouldSuppressAudioTracks();
}
std::optional<::media::AudioRendererAlgorithmParameters>
RenderMediaClient::GetAudioRendererAlgorithmParameters(
media::AudioParameters audio_parameters) {
return GetContentClient()->renderer()->GetAudioRendererAlgorithmParameters(
audio_parameters);
}
void RenderMediaClient::GetSupportedVideoEncoderConfigs() {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
#if BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_ENCODE_SUPPORT)
DCHECK(!did_video_encoder_update_);
RenderThreadImpl::current()->BindHostReceiver(
gpu_for_supported_profiles_.BindNewPipeAndPassReceiver());
gpu_for_supported_profiles_.set_disconnect_handler(
base::BindOnce(&RenderMediaClient::OnGpuDisconnected,
// base::Unretained(this) is safe because the
// RenderMediaClient is never destructed.
base::Unretained(this)));
gpu_for_supported_profiles_->CreateVideoEncodeAcceleratorProvider(
video_encoder_for_supported_profiles_.BindNewPipeAndPassReceiver());
gpu_for_supported_profiles_.reset();
video_encoder_for_supported_profiles_.set_disconnect_handler(
base::BindOnce(&RenderMediaClient::OnVideoEncoderDisconnected,
// base::Unretained(this) is safe because the
// RenderMediaClient is never destructed.
base::Unretained(this)),
main_task_runner_);
media::VideoEncodeAccelerator::SupportedProfiles configs;
if (!video_encoder_for_supported_profiles_
->GetVideoEncodeAcceleratorSupportedProfiles(&configs)) {
configs.clear();
}
OnGetSupportedVideoEncoderConfigs(configs);
#endif // BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_ENCODE_SUPPORT)
}
void RenderMediaClient::OnInterfaceFactoryDisconnected() {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
OnAudioDecoderDisconnected();
OnVideoDecoderDisconnected();
}
void RenderMediaClient::OnGpuDisconnected() {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
OnVideoEncoderDisconnected();
}
void RenderMediaClient::OnAudioDecoderDisconnected() {
#if BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
OnGetSupportedAudioDecoderConfigs(media::SupportedAudioDecoderConfigs());
#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
}
void RenderMediaClient::OnVideoDecoderDisconnected() {
#if BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT)
OnGetSupportedVideoDecoderConfigs(media::SupportedVideoDecoderConfigs(),
media::VideoDecoderType::kUnknown);
#endif // BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT)
}
void RenderMediaClient::OnVideoEncoderDisconnected() {
#if BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_ENCODE_SUPPORT)
OnGetSupportedVideoEncoderConfigs(
media::VideoEncodeAccelerator::SupportedProfiles());
#endif // BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_ENCODE_SUPPORT)
}
void RenderMediaClient::OnGetSupportedVideoDecoderConfigs(
const media::SupportedVideoDecoderConfigs& configs,
media::VideoDecoderType type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
#if BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT)
if (did_video_decoder_update_.IsSignaled()) {
return;
}
UpdateDecoderVideoProfilesInternal(configs);
did_video_decoder_update_.Signal();
video_decoder_for_supported_profiles_.reset();
#if BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
if (did_audio_decoder_update_.IsSignaled()) {
interface_factory_for_supported_profiles_.reset();
}
#else
interface_factory_for_supported_profiles_.reset();
#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
#endif // BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT)
}
void RenderMediaClient::OnGetSupportedAudioDecoderConfigs(
const media::SupportedAudioDecoderConfigs& configs) {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
#if BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
if (did_audio_decoder_update_.IsSignaled()) {
return;
}
UpdateDecoderAudioTypesInternal(configs);
did_audio_decoder_update_.Signal();
audio_decoder_for_supported_configs_.reset();
#if BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT)
if (did_video_decoder_update_.IsSignaled()) {
interface_factory_for_supported_profiles_.reset();
}
#else
interface_factory_for_supported_profiles_.reset();
#endif // BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_DECODE_SUPPORT)
#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
}
void RenderMediaClient::OnGetSupportedVideoEncoderConfigs(
const media::VideoEncodeAccelerator::SupportedProfiles& configs) {
DCHECK_CALLED_ON_VALID_SEQUENCE(main_thread_sequence_checker_);
#if BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_ENCODE_SUPPORT)
if (did_video_encoder_update_) {
return;
}
UpdateEncoderVideoProfilesInternal(configs);
did_video_encoder_update_ = true;
video_encoder_for_supported_profiles_.reset();
#endif // BUILDFLAG(PLATFORM_HAS_OPTIONAL_HEVC_ENCODE_SUPPORT)
}
media::ExternalMemoryAllocator* RenderMediaClient::GetMediaAllocator() {
return GetContentClient()->renderer()->GetMediaAllocator();
}
} // namespace content