0

RenderMediaClient: Query supported VD profiles using Mojo.

This CL changes the way RenderMediaClient gets the supported hardware
video decoder profiles. Before this CL, it established a channel to the
GPU process (if one wasn't already established). When the channel was
established, it got a list of supported video decoder profiles through
the gpu::GPUInfo. After this CL, it instead creates a
media::mojom::VideoDecoder to query the supported configurations.

The main motivation is to get further in decoupling the probing of
supported video decoder configurations from the GPU process. This would
be helpful with out-of-process video decoding where the querying for
supported profiles should happen in a utility process.

One of the main challenges was being able to start the query for
supported profiles asynchronously but fall back to blocking if
RenderMediaClient::IsSupportedVideoType() is called before the query is
complete. The solution here was to allow the
mojom::VideoDecoder::GetSupportedConfigs() method to be called either
synchronously or asynchronously. To handle the fact that
RenderMediaClient::IsSupportedVideoType() can be called from almost any
thread, we use a mojo::SharedRemote to hold the endpoint of the
connection to the mojom::VideoDecoder.

Bug: b:195769334
Test: video.PlayDRM.cencv3_hevc_ctr on volteer
Change-Id: I8c562dc682e52a8571935f4bdadd06117e0d4a95
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4172199
Reviewed-by: Ken Buchanan <kenrb@chromium.org>
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
Commit-Queue: Andres Calderon Jaramillo <andrescj@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1094624}
This commit is contained in:
Andres Calderon Jaramillo
2023-01-19 19:59:08 +00:00
committed by Chromium LUCI CQ
parent 348df785b3
commit a8bef63bc7
3 changed files with 94 additions and 35 deletions

@ -29,13 +29,14 @@ namespace {
#endif
#if NEEDS_PROFILE_UPDATER
void UpdateVideoProfilesInternal(const gpu::GPUInfo& info) {
const auto gpu_profiles = info.video_decode_accelerator_supported_profiles;
void UpdateVideoProfilesInternal(
const media::SupportedVideoDecoderConfigs& supported_configs) {
base::flat_set<media::VideoCodecProfile> media_profiles;
media_profiles.reserve(gpu_profiles.size());
for (const auto& profile : gpu_profiles) {
media_profiles.insert(
static_cast<media::VideoCodecProfile>(profile.profile));
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::UpdateDefaultSupportedVideoProfiles(media_profiles);
}
@ -50,12 +51,37 @@ void RenderMediaClient::Initialize() {
media::SetMediaClient(client);
}
RenderMediaClient::RenderMediaClient() {
RenderMediaClient::RenderMediaClient()
: main_task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {
#if NEEDS_PROFILE_UPDATER
// Unretained is safe here since the MediaClient is never destructed.
RenderThreadImpl::current()->EstablishGpuChannel(base::BindOnce(
&RenderMediaClient::OnEstablishedGpuChannel, base::Unretained(this)));
// We'll first try to query the supported video decoder configurations
// asynchronously. If IsSupportedVideoType() is called before we get a
// response, that method will fall back to querying the video decoder
// configurations synchronously.
//
// The base::Unretained()s here are safe here since the MediaClient is never
// destructed.
RenderThreadImpl::current()->BindHostReceiver(
interface_factory_for_supported_profiles_.BindNewPipeAndPassReceiver());
interface_factory_for_supported_profiles_.set_disconnect_handler(
base::BindOnce(&RenderMediaClient::OnGetSupportedVideoDecoderConfigs,
base::Unretained(this),
media::SupportedVideoDecoderConfigs(),
media::VideoDecoderType::kUnknown));
interface_factory_for_supported_profiles_->CreateVideoDecoder(
video_decoder_for_supported_profiles_.BindNewPipeAndPassReceiver(),
/*dst_video_decoder=*/{});
video_decoder_for_supported_profiles_.set_disconnect_handler(
base::BindOnce(&RenderMediaClient::OnGetSupportedVideoDecoderConfigs,
base::Unretained(this),
media::SupportedVideoDecoderConfigs(),
media::VideoDecoderType::kUnknown),
main_task_runner_);
video_decoder_for_supported_profiles_->GetSupportedConfigs(
base::BindOnce(&RenderMediaClient::OnGetSupportedVideoDecoderConfigs,
base::Unretained(this)));
#endif
}
@ -72,16 +98,20 @@ bool RenderMediaClient::IsSupportedAudioType(const media::AudioType& type) {
bool RenderMediaClient::IsSupportedVideoType(const media::VideoType& type) {
#if NEEDS_PROFILE_UPDATER
if (!did_update_.IsSignaled()) {
// The asynchronous request didn't complete in time, so we must now block
// until until the information from the GPU channel is available.
if (auto* render_thread = content::RenderThreadImpl::current()) {
if (auto gpu_host = render_thread->EstablishGpuChannelSync())
UpdateVideoProfilesInternal(gpu_host->gpu_info());
did_update_.Signal();
} else {
// There's already an asynchronous request on the main thread, so wait...
did_update_.Wait();
{
base::AutoLock lock(supported_video_decoder_profiles_lock_);
if (!supported_video_decoder_profiles_are_known_) {
// We didn't get the response for the asynchronous query in time. Let's
// fall back to a synchronous query.
media::SupportedVideoDecoderConfigs configs;
media::VideoDecoderType video_decoder_type;
if (!video_decoder_for_supported_profiles_->GetSupportedConfigs(
&configs, &video_decoder_type)) {
configs.clear();
}
UpdateVideoProfilesInternal(configs);
supported_video_decoder_profiles_are_known_ = true;
ResetConnectionForSupportedProfilesQuery();
}
}
#endif
@ -101,14 +131,33 @@ RenderMediaClient::GetAudioRendererAlgorithmParameters(
audio_parameters);
}
void RenderMediaClient::OnEstablishedGpuChannel(
scoped_refptr<gpu::GpuChannelHost> host) {
void RenderMediaClient::OnGetSupportedVideoDecoderConfigs(
const media::SupportedVideoDecoderConfigs& configs,
media::VideoDecoderType type) {
#if NEEDS_PROFILE_UPDATER
if (host && !did_update_.IsSignaled())
UpdateVideoProfilesInternal(host->gpu_info());
base::AutoLock lock(supported_video_decoder_profiles_lock_);
if (!supported_video_decoder_profiles_are_known_) {
UpdateVideoProfilesInternal(configs);
supported_video_decoder_profiles_are_known_ = true;
}
ResetConnectionForSupportedProfilesQuery();
#endif
}
// Signal even if host is nullptr, since that's the same has having no GPU.
did_update_.Signal();
void RenderMediaClient::ResetConnectionForSupportedProfilesQuery() {
#if NEEDS_PROFILE_UPDATER
if (!main_task_runner_->RunsTasksInCurrentSequence()) {
// The base::Unretained() here is safe because the MediaClient is never
// destructed.
main_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&RenderMediaClient::ResetConnectionForSupportedProfilesQuery,
base::Unretained(this)));
return;
}
interface_factory_for_supported_profiles_.reset();
video_decoder_for_supported_profiles_.reset();
#endif
}

@ -7,11 +7,13 @@
#include "base/synchronization/waitable_event.h"
#include "media/base/audio_parameters.h"
#include "media/base/decoder.h"
#include "media/base/media_client.h"
namespace gpu {
class GpuChannelHost;
}
#include "media/base/supported_video_decoder_config.h"
#include "media/mojo/mojom/interface_factory.mojom.h"
#include "media/mojo/mojom/video_decoder.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/shared_remote.h"
namespace content {
@ -39,12 +41,19 @@ class RenderMediaClient : public media::MediaClient {
RenderMediaClient();
~RenderMediaClient() override;
void OnEstablishedGpuChannel(scoped_refptr<gpu::GpuChannelHost> host);
void OnGetSupportedVideoDecoderConfigs(
const media::SupportedVideoDecoderConfigs& configs,
media::VideoDecoderType type);
// Used to indicate if optional video profile support information has been
// retrieved from the GPU channel. May be waited upon by any thread but the
// RenderThread since it's always signaled from the RenderThread.
base::WaitableEvent did_update_;
void ResetConnectionForSupportedProfilesQuery();
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
[[maybe_unused]] base::Lock supported_video_decoder_profiles_lock_;
[[maybe_unused]] bool supported_video_decoder_profiles_are_known_ = false;
[[maybe_unused]] mojo::Remote<media::mojom::InterfaceFactory>
interface_factory_for_supported_profiles_;
[[maybe_unused]] mojo::SharedRemote<media::mojom::VideoDecoder>
video_decoder_for_supported_profiles_;
};
} // namespace content

@ -66,6 +66,7 @@ interface VideoDecoder {
// that does not match an entry in this list.
//
// May be called before Construct().
[Sync]
GetSupportedConfigs() =>
(array<SupportedVideoDecoderConfig> supported_configs,
VideoDecoderType decoder_type);