| // 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/stable_video_decoder_factory.h" |
| |
| #include "base/containers/queue.h" |
| #include "build/chromeos_buildflags.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/stable/stable_video_decoder.mojom.h" |
| #include "mojo/public/cpp/bindings/remote_set.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| #include "chromeos/lacros/lacros_service.h" |
| #endif |
| |
| namespace content { |
| |
| #if BUILDFLAG(ALLOW_HOSTING_OOP_VIDEO_DECODER) |
| |
| namespace { |
| |
| // StableVideoDecoderFactoryProcessLauncher is a helper singleton class that |
| // launches utility processes to host a |
| // media::stable::mojom::StableVideoDecoderFactory once the gpu::GpuFeatureInfo |
| // is known. |
| class StableVideoDecoderFactoryProcessLauncher final |
| : public GpuDataManagerObserver { |
| public: |
| static StableVideoDecoderFactoryProcessLauncher& Instance() { |
| static base::NoDestructor<StableVideoDecoderFactoryProcessLauncher> |
| instance; |
| return *instance; |
| } |
| |
| StableVideoDecoderFactoryProcessLauncher( |
| const StableVideoDecoderFactoryProcessLauncher&) = delete; |
| StableVideoDecoderFactoryProcessLauncher& operator=( |
| const StableVideoDecoderFactoryProcessLauncher&) = delete; |
| |
| void LaunchWhenGpuFeatureInfoIsKnown( |
| mojo::PendingReceiver<media::stable::mojom::StableVideoDecoderFactory> |
| 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(&StableVideoDecoderFactoryProcessLauncher:: |
| LaunchWhenGpuFeatureInfoIsKnownOnUIThread, |
| base::Unretained(this), std::move(receiver))); |
| } |
| |
| private: |
| friend class base::NoDestructor<StableVideoDecoderFactoryProcessLauncher>; |
| |
| StableVideoDecoderFactoryProcessLauncher() |
| : ui_thread_task_runner_(GetUIThreadTaskRunner({})), |
| gpu_preferences_(content::GetGpuPreferencesFromCommandLine()) {} |
| ~StableVideoDecoderFactoryProcessLauncher() 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(&StableVideoDecoderFactoryProcessLauncher:: |
| 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::stable::mojom::StableVideoDecoderFactory> |
| 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::stable::mojom::StableVideoDecoderFactory> |
| receiver) { |
| DCHECK_CALLED_ON_VALID_SEQUENCE(ui_sequence_checker_); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| const bool enable_direct_video_decoder = |
| gpu_preferences_.enable_chromeos_direct_video_decoder; |
| #else |
| const bool enable_direct_video_decoder = true; |
| #endif |
| |
| mojo::Remote<media::stable::mojom::StableVideoDecoderFactoryProcess> |
| process; |
| ServiceProcessHost::Launch( |
| process.BindNewPipeAndPassReceiver(), |
| ServiceProcessHost::Options().WithDisplayName("Video Decoder").Pass()); |
| process->InitializeStableVideoDecoderFactory( |
| *gpu_feature_info_, enable_direct_video_decoder, 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 a |
| // StableVideoDecoderFactoryProcess implementation which is used to broker a |
| // StableVideoDecoderFactory connection. The process stays alive until either |
| // a) the StableVideoDecoderFactoryProcess connection is lost, or b) it |
| // crashes. Case (a) will typically happen when the client that uses the |
| // StableVideoDecoderFactory connection closes its endpoint (e.g., a renderer |
| // process dies). In that situation, the utility process should detect that |
| // the StableVideoDecoderFactory connection got lost and subsequently close |
| // the StableVideoDecoderFactoryProcess connection which should cause the |
| // termination of the process. We need to keep the |
| // StableVideoDecoderFactoryProcess connection endpoint in a RemoteSet to keep |
| // the process alive until the StableVideoDecoderFactory connection is lost. |
| mojo::RemoteSet<media::stable::mojom::StableVideoDecoderFactoryProcess> |
| processes_ GUARDED_BY_CONTEXT(ui_sequence_checker_); |
| |
| absl::optional<gpu::GpuFeatureInfo> gpu_feature_info_ |
| GUARDED_BY_CONTEXT(ui_sequence_checker_); |
| |
| // This member holds onto any requests for a StableVideoDecoderFactory until |
| // the gpu::GpuFeatureInfo is known. |
| base::queue< |
| mojo::PendingReceiver<media::stable::mojom::StableVideoDecoderFactory>> |
| pending_factory_receivers_ GUARDED_BY_CONTEXT(ui_sequence_checker_); |
| }; |
| |
| } // namespace |
| |
| #endif // BUILDFLAG(ALLOW_HOSTING_OOP_VIDEO_DECODER) |
| |
| void LaunchStableVideoDecoderFactory( |
| mojo::PendingReceiver<media::stable::mojom::StableVideoDecoderFactory> |
| receiver) { |
| #if BUILDFLAG(ALLOW_HOSTING_OOP_VIDEO_DECODER) |
| StableVideoDecoderFactoryProcessLauncher::Instance() |
| .LaunchWhenGpuFeatureInfoIsKnown(std::move(receiver)); |
| #elif BUILDFLAG(IS_CHROMEOS_LACROS) |
| // For LaCrOS, we need to use crosapi to establish a |
| // StableVideoDecoderFactory connection to ash-chrome. |
| auto* lacros_service = chromeos::LacrosService::Get(); |
| if (lacros_service && lacros_service->IsStableVideoDecoderFactoryAvailable()) |
| lacros_service->BindStableVideoDecoderFactory(std::move(receiver)); |
| #endif |
| } |
| |
| } // namespace content |