blob: 1157641ae1ffe9609eb27f026821ff21378cfe11 [file] [log] [blame]
// Copyright 2022 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/public/browser/oop_video_decoder_factory.h"
#include "base/containers/queue.h"
#include "components/viz/common/switches.h"
#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/gpu_data_manager_observer.h"
#include "content/public/browser/gpu_utils.h"
#include "content/public/browser/service_process_host.h"
#include "media/mojo/mojom/interface_factory.mojom.h"
#include "media/mojo/mojom/video_decoder.mojom.h"
#include "media/mojo/mojom/video_decoder_factory_process.mojom.h"
#include "mojo/public/cpp/bindings/remote_set.h"
namespace content {
#if BUILDFLAG(ALLOW_HOSTING_OOP_VIDEO_DECODER)
namespace {
// OOPVideoDecoderFactoryProcessLauncher is a helper singleton class that
// launches utility processes to host a media::mojom::InterfaceFactory once
// the gpu::GpuFeatureInfo is known.
class OOPVideoDecoderFactoryProcessLauncher final
: public GpuDataManagerObserver {
public:
static OOPVideoDecoderFactoryProcessLauncher& Instance() {
static base::NoDestructor<OOPVideoDecoderFactoryProcessLauncher> instance;
return *instance;
}
OOPVideoDecoderFactoryProcessLauncher(
const OOPVideoDecoderFactoryProcessLauncher&) = delete;
OOPVideoDecoderFactoryProcessLauncher& operator=(
const OOPVideoDecoderFactoryProcessLauncher&) = delete;
void LaunchWhenGpuFeatureInfoIsKnown(
mojo::PendingReceiver<media::mojom::InterfaceFactory> receiver) {
if (gpu_preferences_.disable_accelerated_video_decode) {
return;
}
if (ui_thread_task_runner_->RunsTasksInCurrentSequence()) {
LaunchWhenGpuFeatureInfoIsKnownOnUIThread(std::move(receiver));
return;
}
// base::Unretained(this) is safe because *|this| is never destroyed.
ui_thread_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&OOPVideoDecoderFactoryProcessLauncher::
LaunchWhenGpuFeatureInfoIsKnownOnUIThread,
base::Unretained(this), std::move(receiver)));
}
private:
friend class base::NoDestructor<OOPVideoDecoderFactoryProcessLauncher>;
OOPVideoDecoderFactoryProcessLauncher()
: ui_thread_task_runner_(GetUIThreadTaskRunner({})),
gpu_preferences_(content::GetGpuPreferencesFromCommandLine()) {}
~OOPVideoDecoderFactoryProcessLauncher() final = default;
// GpuDataManagerObserver implementation.
void OnGpuInfoUpdate() final {
if (ui_thread_task_runner_->RunsTasksInCurrentSequence()) {
OnGpuInfoUpdateOnUIThread();
return;
}
// base::Unretained(this) is safe because *|this| is never destroyed.
ui_thread_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
&OOPVideoDecoderFactoryProcessLauncher::OnGpuInfoUpdateOnUIThread,
base::Unretained(this)));
}
void OnGpuInfoUpdateOnUIThread() {
DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
auto* manager = GpuDataManagerImpl::GetInstance();
if (!manager->IsGpuFeatureInfoAvailable()) {
return;
}
gpu_feature_info_ = manager->GetGpuFeatureInfo();
while (!pending_factory_receivers_.empty()) {
auto factory_receiver = std::move(pending_factory_receivers_.front());
pending_factory_receivers_.pop();
LaunchOnUIThread(std::move(factory_receiver));
}
}
void LaunchWhenGpuFeatureInfoIsKnownOnUIThread(
mojo::PendingReceiver<media::mojom::InterfaceFactory> receiver) {
DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
if (gpu_feature_info_) {
LaunchOnUIThread(std::move(receiver));
return;
}
pending_factory_receivers_.emplace(std::move(receiver));
GpuDataManagerImpl::GetInstance()->AddObserver(this);
OnGpuInfoUpdateOnUIThread();
}
void LaunchOnUIThread(
mojo::PendingReceiver<media::mojom::InterfaceFactory> receiver) {
DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_);
if (gpu_feature_info_
->status_values[gpu::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE] !=
gpu::kGpuFeatureStatusEnabled) {
return;
}
mojo::Remote<media::mojom::VideoDecoderFactoryProcess> process;
ServiceProcessHost::Launch(
process.BindNewPipeAndPassReceiver(),
ServiceProcessHost::Options().WithDisplayName("Video Decoder").Pass());
process->InitializeVideoDecoderFactory(*gpu_feature_info_,
std::move(receiver));
processes_.Add(std::move(process));
}
const scoped_refptr<base::SequencedTaskRunner> ui_thread_task_runner_;
const gpu::GpuPreferences gpu_preferences_;
SEQUENCE_CHECKER(ui_sequence_checker_);
// Each utility process launched by this class hosts an
// OOPVideoDecoderFactoryProcess implementation which is used to broker an
// InterfaceFactory connection. The process stays alive until either
// a) the OOPVideoDecoderFactoryProcess connection is lost, or b) it
// crashes. Case (a) will typically happen when the client that uses the
// InterfaceFactory connection closes its endpoint (e.g., a renderer
// process dies). In that situation, the utility process should detect that
// the InterfaceFactory connection got lost and subsequently close
// the OOPVideoDecoderFactoryProcess connection which should cause the
// termination of the process. We need to keep the
// OOPVideoDecoderFactoryProcess connection endpoint in a RemoteSet to keep
// the process alive until the InterfaceFactory connection is lost.
mojo::RemoteSet<media::mojom::VideoDecoderFactoryProcess> processes_
GUARDED_BY_CONTEXT(ui_sequence_checker_);
std::optional<gpu::GpuFeatureInfo> gpu_feature_info_
GUARDED_BY_CONTEXT(ui_sequence_checker_);
// This member holds onto any requests for an InterfaceFactory until
// the gpu::GpuFeatureInfo is known.
base::queue<mojo::PendingReceiver<media::mojom::InterfaceFactory>>
pending_factory_receivers_ GUARDED_BY_CONTEXT(ui_sequence_checker_);
};
} // namespace
#endif // BUILDFLAG(ALLOW_HOSTING_OOP_VIDEO_DECODER)
void LaunchOOPVideoDecoderFactory(
mojo::PendingReceiver<media::mojom::InterfaceFactory> receiver) {
#if BUILDFLAG(ALLOW_HOSTING_OOP_VIDEO_DECODER)
OOPVideoDecoderFactoryProcessLauncher::Instance()
.LaunchWhenGpuFeatureInfoIsKnown(std::move(receiver));
#endif
}
} // namespace content