1 // Copyright 2021 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/mojo/services/stable_video_decoder_factory_service.h"
7 #include "base/task/single_thread_task_runner.h"
8 #include "base/task/thread_pool.h"
9 #include "components/viz/common/switches.h"
10 #include "gpu/config/gpu_driver_bug_workarounds.h"
11 #include "gpu/config/gpu_preferences.h"
12 #include "media/base/media_log.h"
13 #include "media/base/media_util.h"
14 #include "media/gpu/buildflags.h"
15 #include "media/gpu/chromeos/platform_video_frame_pool.h"
16 #include "media/gpu/chromeos/video_decoder_pipeline.h"
17 #include "media/gpu/gpu_video_accelerator_util.h"
18 #include "media/gpu/gpu_video_decode_accelerator_factory.h"
19 #include "media/gpu/gpu_video_decode_accelerator_helpers.h"
20 #include "media/gpu/ipc/service/vda_video_decoder.h"
21 #include "media/mojo/services/mojo_media_client.h"
22 #include "media/mojo/services/mojo_video_decoder_service.h"
23 #include "media/mojo/services/stable_video_decoder_service.h"
24 #include "media/video/video_decode_accelerator.h"
25 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
31 // This is a lighter alternative to using a GpuMojoMediaClient. While we could
32 // use a GpuMojoMediaClient, that would be abusing the abstraction a bit since
33 // that class is too semantically coupled with the GPU process through things
34 // like its |gpu_task_runner_| and |media_gpu_channel_manager_| members.
35 class MojoMediaClientImpl : public MojoMediaClient {
37 MojoMediaClientImpl(const gpu::GpuFeatureInfo& gpu_feature_info,
38 bool enable_direct_video_decoder)
39 : gpu_driver_bug_workarounds_(
40 gpu_feature_info.enabled_gpu_driver_bug_workarounds),
41 enable_direct_video_decoder_(enable_direct_video_decoder) {}
42 MojoMediaClientImpl(const MojoMediaClientImpl&) = delete;
43 MojoMediaClientImpl& operator=(const MojoMediaClientImpl&) = delete;
44 ~MojoMediaClientImpl() override = default;
46 // MojoMediaClient implementation.
47 std::vector<SupportedVideoDecoderConfig> GetSupportedVideoDecoderConfigs()
49 absl::optional<std::vector<SupportedVideoDecoderConfig>> configs;
50 switch (GetDecoderImplementationType()) {
51 case VideoDecoderType::kVaapi:
52 case VideoDecoderType::kV4L2:
53 configs = VideoDecoderPipeline::GetSupportedConfigs(
54 GetDecoderImplementationType(), gpu_driver_bug_workarounds_);
56 case VideoDecoderType::kVda: {
57 // Note that we pass a default-constructed gpu::GpuPreferences.
58 // GpuVideoDecodeAcceleratorFactory::GetDecoderCapabilities() uses the
59 // preferences only to check if accelerated video decoding is disabled.
60 // However, if we're here, we know that accelerated video decoding is
61 // enabled since the browser process checks for this.
62 VideoDecodeAccelerator::Capabilities capabilities =
63 GpuVideoAcceleratorUtil::ConvertGpuToMediaDecodeCapabilities(
64 GpuVideoDecodeAcceleratorFactory::GetDecoderCapabilities(
65 gpu::GpuPreferences(), gpu_driver_bug_workarounds_));
66 configs = ConvertFromSupportedProfiles(
67 capabilities.supported_profiles,
68 capabilities.flags & VideoDecodeAccelerator::Capabilities::
69 SUPPORTS_ENCRYPTED_STREAMS);
75 return configs.value_or(std::vector<SupportedVideoDecoderConfig>{});
77 VideoDecoderType GetDecoderImplementationType() final {
78 if (!enable_direct_video_decoder_) {
79 return VideoDecoderType::kVda;
82 // TODO(b/195769334): how can we keep this in sync with
83 // VideoDecoderPipeline::GetDecoderType()?
84 #if BUILDFLAG(USE_VAAPI)
85 return VideoDecoderType::kVaapi;
86 #elif BUILDFLAG(USE_V4L2_CODEC)
87 return VideoDecoderType::kV4L2;
89 #error StableVideoDecoderFactoryService should only be built on platforms that
90 #error support video decode acceleration through either VA-API or V4L2.
93 std::unique_ptr<VideoDecoder> CreateVideoDecoder(
94 scoped_refptr<base::SequencedTaskRunner> task_runner,
96 mojom::CommandBufferIdPtr command_buffer_id,
97 RequestOverlayInfoCB request_overlay_info_cb,
98 const gfx::ColorSpace& target_color_space,
99 mojo::PendingRemote<stable::mojom::StableVideoDecoder> oop_video_decoder)
101 // For out-of-process video decoding, |command_buffer_id| is not used and
102 // should not be supplied.
103 DCHECK(!command_buffer_id);
105 DCHECK(!oop_video_decoder);
107 std::unique_ptr<MediaLog> log =
108 media_log ? media_log->Clone()
109 : std::make_unique<media::NullMediaLog>();
111 if (GetDecoderImplementationType() == VideoDecoderType::kVda) {
112 if (!gpu_task_runner_) {
113 gpu_task_runner_ = base::ThreadPool::CreateSingleThreadTaskRunner(
114 {base::WithBaseSyncPrimitives(), base::MayBlock()},
115 base::SingleThreadTaskRunnerThreadMode::DEDICATED);
117 // Note that we pass a default-constructed gpu::GpuPreferences.
118 // VdaVideoDecoder::Create() uses the preferences only to check if
119 // accelerated video decoding is disabled. However, if we're here, we know
120 // that accelerated video decoding is enabled since the browser process
122 return VdaVideoDecoder::Create(
123 /*parent_task_runner=*/std::move(task_runner), gpu_task_runner_,
124 std::move(log), target_color_space, gpu::GpuPreferences(),
125 gpu_driver_bug_workarounds_,
126 /*get_stub_cb=*/base::NullCallback(),
127 VideoDecodeAccelerator::Config::OutputMode::kImport);
129 return VideoDecoderPipeline::Create(
130 gpu_driver_bug_workarounds_,
131 /*client_task_runner=*/std::move(task_runner),
132 std::make_unique<PlatformVideoFramePool>(),
133 /*frame_converter=*/nullptr,
134 VideoDecoderPipeline::DefaultPreferredRenderableFourccs(),
136 /*oop_video_decoder=*/{});
141 // A "GPU" thread. With traditional hardware video decoding that runs in the
142 // GPU process, this would be the thread needed to access specific GPU
143 // functionality. For out-of-process video decoding, this isn't really the
144 // "GPU" thread, but we use the terminology of the VdaVideoDecoder::Create()
145 // (as such this member is only used when using the VdaVideoDecoder).
147 // TODO(b/195769334): could we get rid of this and just use the same task
148 // runner for the |parent_task_runner| and |gpu_task_runner| parameters of
149 // VdaVideoDecoder::Create(). For now, we've made it a dedicated thread in
150 // case the VdaVideoDecoder or any of the underlying components rely on a
151 // separate GPU thread.
152 scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
153 const gpu::GpuDriverBugWorkarounds gpu_driver_bug_workarounds_;
154 const bool enable_direct_video_decoder_;
159 StableVideoDecoderFactoryService::StableVideoDecoderFactoryService(
160 const gpu::GpuFeatureInfo& gpu_feature_info,
161 bool enable_direct_video_decoder)
164 std::make_unique<MojoMediaClientImpl>(gpu_feature_info,
165 enable_direct_video_decoder)) {
166 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
167 mojo_media_client_->Initialize();
170 StableVideoDecoderFactoryService::~StableVideoDecoderFactoryService() {
171 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
174 void StableVideoDecoderFactoryService::BindReceiver(
175 mojo::PendingReceiver<stable::mojom::StableVideoDecoderFactory> receiver,
176 base::OnceClosure disconnect_cb) {
177 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
178 // The browser process should guarantee that BindReceiver() is only called
180 DCHECK(!receiver_.is_bound());
181 receiver_.Bind(std::move(receiver));
182 receiver_.set_disconnect_handler(std::move(disconnect_cb));
185 void StableVideoDecoderFactoryService::CreateStableVideoDecoder(
186 mojo::PendingReceiver<stable::mojom::StableVideoDecoder> receiver,
187 mojo::PendingRemote<stable::mojom::StableVideoDecoderTracker> tracker) {
188 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
190 std::unique_ptr<mojom::VideoDecoder> dst_video_decoder;
191 if (video_decoder_creation_cb_for_testing_) {
192 dst_video_decoder = video_decoder_creation_cb_for_testing_.Run(
193 mojo_media_client_.get(), &cdm_service_context_);
195 dst_video_decoder = std::make_unique<MojoVideoDecoderService>(
196 mojo_media_client_.get(), &cdm_service_context_,
197 mojo::PendingRemote<stable::mojom::StableVideoDecoder>());
199 video_decoders_.Add(std::make_unique<StableVideoDecoderService>(
200 std::move(tracker), std::move(dst_video_decoder),
201 &cdm_service_context_),
202 std::move(receiver));