1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "services/video_capture/video_capture_service_impl.h"
6 
7 #include <utility>
8 
9 #include "base/bind.h"
10 #include "base/feature_list.h"
11 #include "base/task/post_task.h"
12 #include "base/task/thread_pool.h"
13 #include "build/build_config.h"
14 #include "build/chromeos_buildflags.h"
15 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
16 #include "media/capture/video/create_video_capture_device_factory.h"
17 #include "media/capture/video/fake_video_capture_device_factory.h"
18 #include "media/capture/video/video_capture_buffer_pool.h"
19 #include "media/capture/video/video_capture_buffer_tracker.h"
20 #include "media/capture/video/video_capture_system_impl.h"
21 #include "mojo/public/cpp/bindings/pending_receiver.h"
22 #include "mojo/public/cpp/bindings/pending_remote.h"
23 #include "mojo/public/cpp/bindings/remote.h"
24 #include "mojo/public/cpp/bindings/self_owned_receiver.h"
25 #include "services/video_capture/device_factory_media_to_mojo_adapter.h"
26 #include "services/video_capture/testing_controls_impl.h"
27 #include "services/video_capture/video_source_provider_impl.h"
28 #include "services/video_capture/virtual_device_enabled_device_factory.h"
29 #include "services/viz/public/cpp/gpu/gpu.h"
30 
31 #if defined(OS_MAC)
32 #include "media/capture/video/mac/video_capture_device_factory_mac.h"
33 #endif
34 
35 namespace video_capture {
36 
37 // Intended usage of this class is to instantiate on any sequence, and then
38 // operate and release the instance on the task runner exposed via
39 // GetTaskRunner() via WeakPtrs provided via GetWeakPtr(). To this end,
40 // GetTaskRunner() and GetWeakPtr() can be called from any sequence, typically
41 // the same as the one calling the constructor.
42 class VideoCaptureServiceImpl::GpuDependenciesContext {
43  public:
GpuDependenciesContext()44   GpuDependenciesContext() {
45     gpu_io_task_runner_ = base::ThreadPool::CreateSequencedTaskRunner(
46         {base::TaskPriority::USER_BLOCKING, base::MayBlock()});
47   }
48 
~GpuDependenciesContext()49   ~GpuDependenciesContext() {
50     DCHECK(gpu_io_task_runner_->RunsTasksInCurrentSequence());
51   }
52 
GetWeakPtr()53   base::WeakPtr<GpuDependenciesContext> GetWeakPtr() {
54     return weak_factory_for_gpu_io_thread_.GetWeakPtr();
55   }
56 
GetTaskRunner()57   scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() {
58     return gpu_io_task_runner_;
59   }
60 
61 #if BUILDFLAG(IS_ASH)
InjectGpuDependencies(mojo::PendingRemote<mojom::AcceleratorFactory> accelerator_factory_info)62   void InjectGpuDependencies(
63       mojo::PendingRemote<mojom::AcceleratorFactory> accelerator_factory_info) {
64     DCHECK(gpu_io_task_runner_->RunsTasksInCurrentSequence());
65     accelerator_factory_.reset();
66     accelerator_factory_.Bind(std::move(accelerator_factory_info));
67   }
68 
CreateJpegDecodeAccelerator(mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator> receiver)69   void CreateJpegDecodeAccelerator(
70       mojo::PendingReceiver<chromeos_camera::mojom::MjpegDecodeAccelerator>
71           receiver) {
72     DCHECK(gpu_io_task_runner_->RunsTasksInCurrentSequence());
73     if (!accelerator_factory_)
74       return;
75     accelerator_factory_->CreateJpegDecodeAccelerator(std::move(receiver));
76   }
77 #endif  // BUILDFLAG(IS_ASH)
78 
79  private:
80   // Task runner for operating |accelerator_factory_| and
81   // |gpu_memory_buffer_manager_| on. This must be a different thread from the
82   // main service thread in order to avoid a deadlock during shutdown where
83   // the main service thread joins a video capture device thread that, in turn,
84   // will try to post the release of the jpeg decoder to the thread it is
85   // operated on.
86   scoped_refptr<base::SequencedTaskRunner> gpu_io_task_runner_;
87 
88 #if BUILDFLAG(IS_ASH)
89   mojo::Remote<mojom::AcceleratorFactory> accelerator_factory_;
90 #endif  // BUILDFLAG(IS_ASH)
91 
92   base::WeakPtrFactory<GpuDependenciesContext> weak_factory_for_gpu_io_thread_{
93       this};
94 };
95 
VideoCaptureServiceImpl(mojo::PendingReceiver<mojom::VideoCaptureService> receiver,scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)96 VideoCaptureServiceImpl::VideoCaptureServiceImpl(
97     mojo::PendingReceiver<mojom::VideoCaptureService> receiver,
98     scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner)
99     : receiver_(this, std::move(receiver)),
100       ui_task_runner_(std::move(ui_task_runner)) {}
101 
~VideoCaptureServiceImpl()102 VideoCaptureServiceImpl::~VideoCaptureServiceImpl() {
103   factory_receivers_.Clear();
104   device_factory_.reset();
105 
106 #if BUILDFLAG(IS_ASH)
107   camera_app_device_bridge_.reset();
108 #endif  // defined (OS_CHROMEOS)
109 
110   if (gpu_dependencies_context_) {
111     gpu_dependencies_context_->GetTaskRunner()->DeleteSoon(
112         FROM_HERE, std::move(gpu_dependencies_context_));
113   }
114 }
115 
116 #if BUILDFLAG(IS_ASH)
InjectGpuDependencies(mojo::PendingRemote<mojom::AcceleratorFactory> accelerator_factory)117 void VideoCaptureServiceImpl::InjectGpuDependencies(
118     mojo::PendingRemote<mojom::AcceleratorFactory> accelerator_factory) {
119   LazyInitializeGpuDependenciesContext();
120   gpu_dependencies_context_->GetTaskRunner()->PostTask(
121       FROM_HERE, base::BindOnce(&GpuDependenciesContext::InjectGpuDependencies,
122                                 gpu_dependencies_context_->GetWeakPtr(),
123                                 std::move(accelerator_factory)));
124 }
125 
ConnectToCameraAppDeviceBridge(mojo::PendingReceiver<cros::mojom::CameraAppDeviceBridge> receiver)126 void VideoCaptureServiceImpl::ConnectToCameraAppDeviceBridge(
127     mojo::PendingReceiver<cros::mojom::CameraAppDeviceBridge> receiver) {
128   DCHECK(camera_app_device_bridge_);
129   camera_app_device_bridge_->BindReceiver(std::move(receiver));
130 }
131 #endif  // BUILDFLAG(IS_ASH)
132 
ConnectToDeviceFactory(mojo::PendingReceiver<mojom::DeviceFactory> receiver)133 void VideoCaptureServiceImpl::ConnectToDeviceFactory(
134     mojo::PendingReceiver<mojom::DeviceFactory> receiver) {
135   LazyInitializeDeviceFactory();
136   factory_receivers_.Add(device_factory_.get(), std::move(receiver));
137 }
138 
ConnectToVideoSourceProvider(mojo::PendingReceiver<mojom::VideoSourceProvider> receiver)139 void VideoCaptureServiceImpl::ConnectToVideoSourceProvider(
140     mojo::PendingReceiver<mojom::VideoSourceProvider> receiver) {
141   LazyInitializeVideoSourceProvider();
142   video_source_provider_->AddClient(std::move(receiver));
143 }
144 
SetRetryCount(int32_t count)145 void VideoCaptureServiceImpl::SetRetryCount(int32_t count) {
146 #if defined(OS_MAC)
147   media::VideoCaptureDeviceFactoryMac::SetGetDevicesInfoRetryCount(count);
148 #endif
149 }
150 
BindControlsForTesting(mojo::PendingReceiver<mojom::TestingControls> receiver)151 void VideoCaptureServiceImpl::BindControlsForTesting(
152     mojo::PendingReceiver<mojom::TestingControls> receiver) {
153   mojo::MakeSelfOwnedReceiver(std::make_unique<TestingControlsImpl>(),
154                               std::move(receiver));
155 }
156 
LazyInitializeGpuDependenciesContext()157 void VideoCaptureServiceImpl::LazyInitializeGpuDependenciesContext() {
158   if (!gpu_dependencies_context_)
159     gpu_dependencies_context_ = std::make_unique<GpuDependenciesContext>();
160 }
161 
LazyInitializeDeviceFactory()162 void VideoCaptureServiceImpl::LazyInitializeDeviceFactory() {
163   if (device_factory_)
164     return;
165 
166   LazyInitializeGpuDependenciesContext();
167 
168   // Create the platform-specific device factory.
169   // The task runner passed to CreateFactory is used for things that need to
170   // happen on a "UI thread equivalent", e.g. obtaining screen rotation on
171   // Chrome OS.
172 #if BUILDFLAG(IS_ASH)
173   camera_app_device_bridge_ =
174       std::make_unique<media::CameraAppDeviceBridgeImpl>();
175   std::unique_ptr<media::VideoCaptureDeviceFactory> media_device_factory =
176       media::CreateVideoCaptureDeviceFactory(ui_task_runner_,
177                                              camera_app_device_bridge_.get());
178   camera_app_device_bridge_->SetIsSupported(
179       media_device_factory->IsSupportedCameraAppDeviceBridge());
180 #else
181   std::unique_ptr<media::VideoCaptureDeviceFactory> media_device_factory =
182       media::CreateVideoCaptureDeviceFactory(ui_task_runner_);
183 #endif  // BUILDFLAG(IS_ASH)
184 
185   auto video_capture_system = std::make_unique<media::VideoCaptureSystemImpl>(
186       std::move(media_device_factory));
187 
188 #if BUILDFLAG(IS_ASH)
189   device_factory_ = std::make_unique<VirtualDeviceEnabledDeviceFactory>(
190       std::make_unique<DeviceFactoryMediaToMojoAdapter>(
191           std::move(video_capture_system),
192           base::BindRepeating(
193               &GpuDependenciesContext::CreateJpegDecodeAccelerator,
194               gpu_dependencies_context_->GetWeakPtr()),
195           gpu_dependencies_context_->GetTaskRunner()));
196 #else
197   device_factory_ = std::make_unique<VirtualDeviceEnabledDeviceFactory>(
198       std::make_unique<DeviceFactoryMediaToMojoAdapter>(
199           std::move(video_capture_system)));
200 #endif  // BUILDFLAG(IS_ASH)
201 }
202 
LazyInitializeVideoSourceProvider()203 void VideoCaptureServiceImpl::LazyInitializeVideoSourceProvider() {
204   if (video_source_provider_)
205     return;
206   LazyInitializeDeviceFactory();
207   video_source_provider_ = std::make_unique<VideoSourceProviderImpl>(
208       device_factory_.get(),
209       // Unretained(this) is safe, because |this| owns |video_source_provider_|.
210       base::BindRepeating(
211           &VideoCaptureServiceImpl::OnLastSourceProviderClientDisconnected,
212           base::Unretained(this)));
213 }
214 
OnLastSourceProviderClientDisconnected()215 void VideoCaptureServiceImpl::OnLastSourceProviderClientDisconnected() {
216   video_source_provider_.reset();
217 }
218 
219 }  // namespace video_capture
220