| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "services/video_capture/device_factory_provider_impl.h" |
| |
| #include <utility> |
| |
| #include "base/bind.h" |
| #include "base/task/post_task.h" |
| #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h" |
| #include "media/capture/video/create_video_capture_device_factory.h" |
| #include "media/capture/video/fake_video_capture_device_factory.h" |
| #include "media/capture/video/video_capture_buffer_pool.h" |
| #include "media/capture/video/video_capture_buffer_tracker.h" |
| #include "media/capture/video/video_capture_system_impl.h" |
| #include "services/video_capture/device_factory_media_to_mojo_adapter.h" |
| #include "services/video_capture/video_source_provider_impl.h" |
| #include "services/video_capture/virtual_device_enabled_device_factory.h" |
| #include "services/ws/public/cpp/gpu/gpu.h" |
| |
| namespace video_capture { |
| |
| // Intended usage of this class is to instantiate on any sequence, and then |
| // operate and release the instance on the task runner exposed via |
| // GetTaskRunner() via WeakPtrs provided via GetWeakPtr(). To this end, |
| // GetTaskRunner() and GetWeakPtr() can be called from any sequence, typically |
| // the same as the one calling the constructor. |
| class DeviceFactoryProviderImpl::GpuDependenciesContext { |
| public: |
| GpuDependenciesContext() : weak_factory_for_gpu_io_thread_(this) { |
| gpu_io_task_runner_ = base::CreateSequencedTaskRunnerWithTraits( |
| {base::TaskPriority::BEST_EFFORT, base::MayBlock()}); |
| } |
| |
| ~GpuDependenciesContext() { |
| DCHECK(gpu_io_task_runner_->RunsTasksInCurrentSequence()); |
| } |
| |
| base::WeakPtr<GpuDependenciesContext> GetWeakPtr() { |
| return weak_factory_for_gpu_io_thread_.GetWeakPtr(); |
| } |
| |
| scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() { |
| return gpu_io_task_runner_; |
| } |
| |
| void InjectGpuDependencies( |
| mojom::AcceleratorFactoryPtrInfo accelerator_factory_info) { |
| DCHECK(gpu_io_task_runner_->RunsTasksInCurrentSequence()); |
| accelerator_factory_.Bind(std::move(accelerator_factory_info)); |
| } |
| |
| void CreateJpegDecodeAccelerator( |
| media::mojom::JpegDecodeAcceleratorRequest request) { |
| DCHECK(gpu_io_task_runner_->RunsTasksInCurrentSequence()); |
| if (!accelerator_factory_) |
| return; |
| accelerator_factory_->CreateJpegDecodeAccelerator(std::move(request)); |
| } |
| |
| private: |
| // Task runner for operating |accelerator_factory_| and |
| // |gpu_memory_buffer_manager_| on. This must be a different thread from the |
| // main service thread in order to avoid a deadlock during shutdown where |
| // the main service thread joins a video capture device thread that, in turn, |
| // will try to post the release of the jpeg decoder to the thread it is |
| // operated on. |
| scoped_refptr<base::SequencedTaskRunner> gpu_io_task_runner_; |
| mojom::AcceleratorFactoryPtr accelerator_factory_; |
| base::WeakPtrFactory<GpuDependenciesContext> weak_factory_for_gpu_io_thread_; |
| }; |
| |
| DeviceFactoryProviderImpl::DeviceFactoryProviderImpl( |
| scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner, |
| base::OnceClosure request_service_quit_asap_cb) |
| : ui_task_runner_(std::move(ui_task_runner)), |
| request_service_quit_asap_cb_(std::move(request_service_quit_asap_cb)) { |
| // Unretained |this| is safe because |factory_bindings_| is owned by |
| // |this|. |
| factory_bindings_.set_connection_error_handler(base::BindRepeating( |
| &DeviceFactoryProviderImpl::OnFactoryClientDisconnected, |
| base::Unretained(this))); |
| } |
| |
| DeviceFactoryProviderImpl::~DeviceFactoryProviderImpl() { |
| factory_bindings_.CloseAllBindings(); |
| device_factory_.reset(); |
| if (gpu_dependencies_context_) { |
| gpu_dependencies_context_->GetTaskRunner()->DeleteSoon( |
| FROM_HERE, std::move(gpu_dependencies_context_)); |
| } |
| } |
| |
| void DeviceFactoryProviderImpl::SetServiceRef( |
| std::unique_ptr<service_manager::ServiceContextRef> service_ref) { |
| service_ref_ = std::move(service_ref); |
| } |
| |
| void DeviceFactoryProviderImpl::InjectGpuDependencies( |
| mojom::AcceleratorFactoryPtr accelerator_factory) { |
| LazyInitializeGpuDependenciesContext(); |
| gpu_dependencies_context_->GetTaskRunner()->PostTask( |
| FROM_HERE, base::BindOnce(&GpuDependenciesContext::InjectGpuDependencies, |
| gpu_dependencies_context_->GetWeakPtr(), |
| accelerator_factory.PassInterface())); |
| } |
| |
| void DeviceFactoryProviderImpl::ConnectToDeviceFactory( |
| mojom::DeviceFactoryRequest request) { |
| DCHECK(service_ref_); |
| LazyInitializeDeviceFactory(); |
| factory_bindings_.AddBinding(device_factory_.get(), std::move(request)); |
| } |
| |
| void DeviceFactoryProviderImpl::ConnectToVideoSourceProvider( |
| mojom::VideoSourceProviderRequest request) { |
| LazyInitializeVideoSourceProvider(); |
| video_source_provider_bindings_.AddBinding(video_source_provider_.get(), |
| std::move(request)); |
| } |
| |
| void DeviceFactoryProviderImpl::ShutdownServiceAsap() { |
| if (request_service_quit_asap_cb_) |
| std::move(request_service_quit_asap_cb_).Run(); |
| } |
| |
| void DeviceFactoryProviderImpl::LazyInitializeGpuDependenciesContext() { |
| if (!gpu_dependencies_context_) |
| gpu_dependencies_context_ = std::make_unique<GpuDependenciesContext>(); |
| } |
| |
| void DeviceFactoryProviderImpl::LazyInitializeDeviceFactory() { |
| if (device_factory_) |
| return; |
| |
| LazyInitializeGpuDependenciesContext(); |
| |
| // Create the platform-specific device factory. |
| // The task runner passed to CreateFactory is used for things that need to |
| // happen on a "UI thread equivalent", e.g. obtaining screen rotation on |
| // Chrome OS. |
| std::unique_ptr<media::VideoCaptureDeviceFactory> media_device_factory = |
| media::CreateVideoCaptureDeviceFactory(ui_task_runner_); |
| DCHECK(media_device_factory); |
| |
| auto video_capture_system = std::make_unique<media::VideoCaptureSystemImpl>( |
| std::move(media_device_factory)); |
| |
| device_factory_ = std::make_unique<VirtualDeviceEnabledDeviceFactory>( |
| std::make_unique<DeviceFactoryMediaToMojoAdapter>( |
| std::move(video_capture_system), |
| base::BindRepeating( |
| &GpuDependenciesContext::CreateJpegDecodeAccelerator, |
| gpu_dependencies_context_->GetWeakPtr()), |
| gpu_dependencies_context_->GetTaskRunner())); |
| device_factory_->SetServiceRef(service_ref_->Clone()); |
| } |
| |
| void DeviceFactoryProviderImpl::LazyInitializeVideoSourceProvider() { |
| if (video_source_provider_) |
| return; |
| |
| LazyInitializeDeviceFactory(); |
| |
| video_source_provider_ = |
| std::make_unique<VideoSourceProviderImpl>(device_factory_.get()); |
| } |
| |
| void DeviceFactoryProviderImpl::OnFactoryClientDisconnected() { |
| // If last client has disconnected, release service ref so that service |
| // shutdown timeout starts if no other references are still alive. |
| // We keep the |device_factory_| instance alive in order to avoid |
| // losing state that would be expensive to reinitialize, e.g. having |
| // already enumerated the available devices. |
| if (factory_bindings_.empty()) |
| device_factory_->SetServiceRef(nullptr); |
| } |
| |
| #if defined(OS_CHROMEOS) |
| void DeviceFactoryProviderImpl::BindCrosImageCaptureRequest( |
| cros::mojom::CrosImageCaptureRequest request) { |
| CHECK(device_factory_); |
| |
| device_factory_->BindCrosImageCaptureRequest(std::move(request)); |
| } |
| #endif // defined(OS_CHROMEOS) |
| |
| } // namespace video_capture |