blob: 35ed9c8db68250a256a55e2655c019e926ff31de [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/mojo/services/gpu_mojo_media_client.h"
#include <utility>
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "gpu/ipc/service/gpu_channel.h"
#include "media/base/audio_decoder.h"
#include "media/base/audio_encoder.h"
#include "media/base/cdm_factory.h"
#include "media/base/media_switches.h"
#include "media/base/media_util.h"
#include "media/base/video_decoder.h"
#include "media/gpu/gpu_video_accelerator_util.h"
#include "media/gpu/gpu_video_decode_accelerator_factory.h"
#include "media/gpu/gpu_video_decode_accelerator_helpers.h"
#include "media/gpu/ipc/service/media_gpu_channel_manager.h"
#include "media/gpu/ipc/service/vda_video_decoder.h"
#include "media/mojo/mojom/video_decoder.mojom.h"
#include "media/video/video_decode_accelerator.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
namespace media {
namespace {
gpu::CommandBufferStub* GetCommandBufferStub(
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
base::UnguessableToken channel_token,
int32_t route_id) {
DCHECK(gpu_task_runner->BelongsToCurrentThread());
if (!media_gpu_channel_manager)
return nullptr;
gpu::GpuChannel* channel =
media_gpu_channel_manager->LookupChannel(channel_token);
if (!channel)
return nullptr;
gpu::CommandBufferStub* stub = channel->LookupCommandBuffer(route_id);
if (!stub)
return nullptr;
// Only allow stubs that have a ContextGroup, that is, the GLES2 ones. Later
// code assumes the ContextGroup is valid.
if (!stub->decoder_context()->GetContextGroup())
return nullptr;
return stub;
}
SupportedVideoDecoderConfigs GetVDAVideoDecoderConfigs(
const gpu::GpuPreferences& gpu_preferences,
const gpu::GpuDriverBugWorkarounds& gpu_workarounds) {
VideoDecodeAccelerator::Capabilities capabilities =
GpuVideoAcceleratorUtil::ConvertGpuToMediaDecodeCapabilities(
GpuVideoDecodeAcceleratorFactory::GetDecoderCapabilities(
gpu_preferences, gpu_workarounds));
return ConvertFromSupportedProfiles(
capabilities.supported_profiles,
capabilities.flags &
VideoDecodeAccelerator::Capabilities::SUPPORTS_ENCRYPTED_STREAMS);
}
} // namespace
VideoDecoderTraits::~VideoDecoderTraits() = default;
VideoDecoderTraits::VideoDecoderTraits(
scoped_refptr<base::SequencedTaskRunner> task_runner,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
std::unique_ptr<MediaLog> media_log,
RequestOverlayInfoCB request_overlay_info_cb,
const gfx::ColorSpace* target_color_space,
gpu::GpuPreferences gpu_preferences,
gpu::GpuFeatureInfo gpu_feature_info,
gpu::GPUInfo gpu_info,
const gpu::GpuDriverBugWorkarounds* gpu_workarounds,
gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
GetConfigCacheCB get_cached_configs_cb,
GetCommandBufferStubCB get_command_buffer_stub_cb,
AndroidOverlayMojoFactoryCB android_overlay_factory_cb,
mojo::PendingRemote<stable::mojom::StableVideoDecoder> oop_video_decoder)
: task_runner(std::move(task_runner)),
gpu_task_runner(std::move(gpu_task_runner)),
media_log(std::move(media_log)),
request_overlay_info_cb(request_overlay_info_cb),
target_color_space(target_color_space),
gpu_preferences(gpu_preferences),
gpu_feature_info(gpu_feature_info),
gpu_info(gpu_info),
gpu_workarounds(gpu_workarounds),
gpu_memory_buffer_factory(gpu_memory_buffer_factory),
get_cached_configs_cb(std::move(get_cached_configs_cb)),
get_command_buffer_stub_cb(std::move(get_command_buffer_stub_cb)),
android_overlay_factory_cb(std::move(android_overlay_factory_cb)),
oop_video_decoder(std::move(oop_video_decoder)) {}
GpuMojoMediaClient::GpuMojoMediaClient(
const gpu::GpuPreferences& gpu_preferences,
const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
const gpu::GpuFeatureInfo& gpu_feature_info,
const gpu::GPUInfo& gpu_info,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
gpu::GpuMemoryBufferFactory* gpu_memory_buffer_factory,
AndroidOverlayMojoFactoryCB android_overlay_factory_cb)
: gpu_preferences_(gpu_preferences),
gpu_workarounds_(gpu_workarounds),
gpu_feature_info_(gpu_feature_info),
gpu_info_(gpu_info),
gpu_task_runner_(std::move(gpu_task_runner)),
media_gpu_channel_manager_(std::move(media_gpu_channel_manager)),
android_overlay_factory_cb_(std::move(android_overlay_factory_cb)),
gpu_memory_buffer_factory_(gpu_memory_buffer_factory) {
base::UmaHistogramEnumeration("Media.GPU.VideoDecoderType",
GetDecoderImplementationType());
}
GpuMojoMediaClient::~GpuMojoMediaClient() = default;
std::unique_ptr<AudioDecoder> GpuMojoMediaClient::CreateAudioDecoder(
scoped_refptr<base::SequencedTaskRunner> task_runner,
std::unique_ptr<MediaLog> media_log) {
return CreatePlatformAudioDecoder(std::move(task_runner),
std::move(media_log));
}
std::unique_ptr<AudioEncoder> GpuMojoMediaClient::CreateAudioEncoder(
scoped_refptr<base::SequencedTaskRunner> task_runner) {
return base::FeatureList::IsEnabled(kPlatformAudioEncoder)
? CreatePlatformAudioEncoder(std::move(task_runner))
: nullptr;
}
VideoDecoderType GpuMojoMediaClient::GetDecoderImplementationType() {
return GetPlatformDecoderImplementationType(gpu_workarounds_,
gpu_preferences_, gpu_info_);
}
SupportedVideoDecoderConfigs
GpuMojoMediaClient::GetSupportedVideoDecoderConfigs() {
if (!supported_config_cache_) {
supported_config_cache_ = GetSupportedVideoDecoderConfigsStatic(
gpu_preferences_, gpu_workarounds_, gpu_info_);
// Once per GPU process record accelerator information. Profile support is
// often just manufactured and not tested, so just record the base codec.
bool has_accelerated_h264 = false;
bool has_accelerated_h265 = false;
bool has_accelerated_vp9 = false;
bool has_accelerated_av1 = false;
if (supported_config_cache_) {
for (const auto& config : *supported_config_cache_) {
if (config.profile_min >= H264PROFILE_MIN &&
config.profile_max <= H264PROFILE_MAX) {
has_accelerated_h264 = true;
} else if (config.profile_min >= VP9PROFILE_MIN &&
config.profile_max <= VP9PROFILE_MAX) {
has_accelerated_vp9 = true;
} else if (config.profile_min >= AV1PROFILE_MIN &&
config.profile_max <= AV1PROFILE_MAX) {
has_accelerated_av1 = true;
} else if ((config.profile_min >= HEVCPROFILE_MIN &&
config.profile_max <= HEVCPROFILE_MAX) ||
(config.profile_min >= HEVCPROFILE_EXT_MIN &&
config.profile_max <= HEVCPROFILE_EXT_MAX)) {
has_accelerated_h265 = true;
}
}
}
base::UmaHistogramBoolean("Media.HasAcceleratedVideoDecode.H264",
has_accelerated_h264);
base::UmaHistogramBoolean("Media.HasAcceleratedVideoDecode.H265",
has_accelerated_h265);
base::UmaHistogramBoolean("Media.HasAcceleratedVideoDecode.VP9",
has_accelerated_vp9);
base::UmaHistogramBoolean("Media.HasAcceleratedVideoDecode.AV1",
has_accelerated_av1);
}
return supported_config_cache_.value_or(SupportedVideoDecoderConfigs{});
}
absl::optional<SupportedVideoDecoderConfigs>
GpuMojoMediaClient::GetSupportedVideoDecoderConfigsStatic(
const gpu::GpuPreferences& gpu_preferences,
const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
const gpu::GPUInfo& gpu_info) {
return GetPlatformSupportedVideoDecoderConfigs(
gpu_workarounds, gpu_preferences, gpu_info,
base::BindOnce(&GetVDAVideoDecoderConfigs, gpu_preferences,
gpu_workarounds));
}
#if BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
void GpuMojoMediaClient::NotifyDecoderSupportKnown(
mojo::PendingRemote<stable::mojom::StableVideoDecoder> oop_video_decoder,
base::OnceCallback<
void(mojo::PendingRemote<stable::mojom::StableVideoDecoder>)> cb) {
#if BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
// TODO(b/195769334): this call should ideally be guarded only by
// BUILDFLAG(ALLOW_OOP_VIDEO_DECODER) because eventually, the GPU process
// should not need to know what video acceleration API is used. Until then, we
// must guard this with (USE_VAAPI || USE_V4L2_CODEC) to be able to compile
// Linux/CrOS builds that don't use either API (e.g., linux-x64-castos).
NotifyPlatformDecoderSupport(gpu_preferences_, gpu_info_,
std::move(oop_video_decoder), std::move(cb));
#else
DCHECK(!oop_video_decoder);
std::move(cb).Run(std::move(oop_video_decoder));
#endif // BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC)
}
#endif // BUILDFLAG(ALLOW_OOP_VIDEO_DECODER)
std::unique_ptr<VideoDecoder> GpuMojoMediaClient::CreateVideoDecoder(
scoped_refptr<base::SequencedTaskRunner> task_runner,
MediaLog* media_log,
mojom::CommandBufferIdPtr command_buffer_id,
RequestOverlayInfoCB request_overlay_info_cb,
const gfx::ColorSpace& target_color_space,
mojo::PendingRemote<stable::mojom::StableVideoDecoder> oop_video_decoder) {
// All implementations require a command buffer.
if (!command_buffer_id)
return nullptr;
std::unique_ptr<MediaLog> log =
media_log ? media_log->Clone() : std::make_unique<media::NullMediaLog>();
VideoDecoderTraits traits(
task_runner, gpu_task_runner_, std::move(log),
std::move(request_overlay_info_cb), &target_color_space, gpu_preferences_,
gpu_feature_info_, gpu_info_, &gpu_workarounds_,
gpu_memory_buffer_factory_,
// CreatePlatformVideoDecoder does not keep a reference to |traits|
// so this bound method will not outlive |this|
base::BindRepeating(&GpuMojoMediaClient::GetSupportedVideoDecoderConfigs,
base::Unretained(this)),
base::BindRepeating(
&GetCommandBufferStub, gpu_task_runner_, media_gpu_channel_manager_,
command_buffer_id->channel_token, command_buffer_id->route_id),
android_overlay_factory_cb_, std::move(oop_video_decoder));
return CreatePlatformVideoDecoder(traits);
}
std::unique_ptr<CdmFactory> GpuMojoMediaClient::CreateCdmFactory(
mojom::FrameInterfaceFactory* frame_interfaces) {
return CreatePlatformCdmFactory(frame_interfaces);
}
} // namespace media