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:

committed by
Chromium LUCI CQ

parent
348df785b3
commit
a8bef63bc7
content/renderer/media
media/mojo/mojom
@ -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);
|
||||
|
Reference in New Issue
Block a user