Index: media/capture/service/video_capture_handler_impl.cc |
diff --git a/media/capture/service/video_capture_handler_impl.cc b/media/capture/service/video_capture_handler_impl.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..2d0587701b85c4ac7155025a720106925c3c65dd |
--- /dev/null |
+++ b/media/capture/service/video_capture_handler_impl.cc |
@@ -0,0 +1,189 @@ |
+// Copyright 2016 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 "media/capture/service/video_capture_handler_impl.h" |
+ |
+#include <string> |
+ |
+#include "base/bind.h" |
+#include "base/guid.h" |
+#include "base/logging.h" |
+#include "base/thread_task_runner_handle.h" |
+#include "base/trace_event/trace_event.h" |
+#include "media/base/video_capture_types.h" |
+#include "media/capture/service/stream_impl.h" |
+#include "media/capture/service/video_capture_device_client_impl.h" |
+#include "media/capture/video/video_capture_device_factory.h" |
+#include "mojo/converters/geometry/geometry_type_converters.h" |
+ |
+namespace media { |
+ |
+VideoCaptureHandlerImpl::VideoCaptureHandlerImpl(mojo::ApplicationImpl* app) |
+ : app_(app), |
+ video_capture_device_factory_( |
+ media::VideoCaptureDeviceFactory::CreateFactory( |
+ base::ThreadTaskRunnerHandle::Get())), |
+ weak_factory_(this) { |
+ // Enumerating devices is something that takes a while (up to hundred of ms in |
+ // certain OSs). |
+ // TODO(mcasas): Add a UMA like in VideoCaptureManager::EnumerateDevices(). |
+ TRACE_EVENT_ASYNC_BEGIN0("video_capture", "EnumerateDeviceNames", |
+ this /* id */); |
+ video_capture_device_factory_->EnumerateDeviceNames( |
+ base::Bind(&VideoCaptureHandlerImpl::OnVideoCaptureDevicesEnumerated, |
+ weak_factory_.GetWeakPtr())); |
+ |
+ // Sadly this SystemMonitor does not do much for Video devices unless someone |
+ // notifies of changes. |
+ // TODO(mcasas): monitor http://crbug.com/584817 and perhaps launch the |
+ // appropriate DeviceMonitor from here. |
+ base::SystemMonitor::Get()->AddDevicesChangedObserver(this); |
+} |
+ |
+VideoCaptureHandlerImpl::~VideoCaptureHandlerImpl() { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ for (const auto& id_and_device_and_stream : device_and_streams_) |
+ id_and_device_and_stream.second.first->StopAndDeAllocate(); |
+ |
+ base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this); |
+} |
+ |
+void VideoCaptureHandlerImpl::EnumerateDevices( |
+ const EnumerateDevicesCallback& callback) { |
+ DVLOG(1) << __FUNCTION__; |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ mojo::Array<mojom::VideoCaptureDeviceInfoPtr> reply; |
+ if (!device_names_->empty()) { |
+ for (const auto& device_name : *device_names_) { |
+ mojom::VideoCaptureDeviceInfoPtr video_capture_device_info = |
+ mojom::VideoCaptureDeviceInfo::New(); |
+ |
+ // Send a GUID of the Video Capture id to hide sensitive information. |
+ const std::string guid = base::GenerateGUID(); |
+ public_to_private_id_map_[guid] = device_name.id(); |
+ video_capture_device_info->device_id = guid; |
+ video_capture_device_info->name = device_name.GetNameAndModel(); |
+ |
+ reply.push_back(std::move(video_capture_device_info)); |
+ } |
+ } |
+ callback.Run(std::move(reply)); |
+} |
+ |
+void VideoCaptureHandlerImpl::RequestVideoCaptureStream( |
+ mojom::VideoCaptureOptionsPtr options, |
+ const RequestVideoCaptureStreamCallback& callback) { |
+ DVLOG(1) << __FUNCTION__ << " device guid: " << options->device_id; |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ const std::string& guid = options->device_id; |
+ if (!ContainsKey(public_to_private_id_map_, guid)) { |
+ DLOG(ERROR) << "Device identified as " << guid << " not found!"; |
+ return; |
+ } |
+ |
+ // Try to find |options->id| in the list of devices. If not found -> return. |
+ const std::string& id = public_to_private_id_map_[guid]; |
+ auto name = std::find_if(device_names_->begin(), device_names_->end(), |
+ [id](const media::VideoCaptureDevice::Name& name) { |
+ return name.id() == id; |
+ }); |
+ if (name == device_names_->end()) { |
+ DLOG(ERROR) << "device " << options->device_id << " not found."; |
+ callback.Run(nullptr); |
+ return; |
+ } |
+ |
+ // TODO(mcasas): At this point we need to ask the user for permission to use |
+ // this device if it hasn't been granted before or elsewhere. Soldier on for |
+ // the time being and revisit this part later on. |
+ |
+ media::VideoCaptureParams params; |
+ params.requested_format.frame_size = options->capture_size.To<gfx::Size>(); |
+ params.requested_format.frame_rate = options->frame_rate; |
+ params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; |
+ |
+ mojom::VideoCaptureStreamPtr stream_ptr; |
+ scoped_ptr<StreamImpl> stream = make_scoped_ptr(new StreamImpl( |
+ mojo::GetProxy(&stream_ptr), base::Bind(&VideoCaptureHandlerImpl::OnStart, |
+ weak_factory_.GetWeakPtr(), id), |
+ base::Bind(&VideoCaptureHandlerImpl::OnStopOrError, |
+ weak_factory_.GetWeakPtr(), id), |
+ base::Bind(&VideoCaptureHandlerImpl::OnStopOrError, |
+ weak_factory_.GetWeakPtr(), id))); |
+ |
+ // Create the found device and Start() with the chosen VideoCaptureParameters. |
+ scoped_ptr<media::VideoCaptureDevice> video_capture_device = |
+ video_capture_device_factory_->Create(*name); |
+ if (!video_capture_device) { |
+ DLOG(ERROR) << "device " << id << " could not be created."; |
+ callback.Run(nullptr); |
+ return; |
+ } |
+ |
+ // Create a VideoCaptureDeviceClientImpl using |stream_| as Delegate. |
+ scoped_ptr<media::VideoCaptureDevice::Client> device_client( |
+ new VideoCaptureDeviceClientImpl(stream.get())); |
+ video_capture_device->AllocateAndStart(params, std::move(device_client)); |
+ |
+ device_and_streams_.insert(make_pair( |
+ id, make_pair(std::move(video_capture_device), std::move(stream)))); |
+ |
+ callback.Run(std::move(stream_ptr)); |
+} |
+ |
+void VideoCaptureHandlerImpl::OnDevicesChanged( |
+ base::SystemMonitor::DeviceType device_type) { |
+ DVLOG(1) << __FUNCTION__; |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ |
+ // NOTE: This method is only called in response to physical audio/video device |
+ // changes (from the operating system). |
+ |
+ if (device_type != base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) |
+ return; // Uninteresting device change. |
+ |
+ TRACE_EVENT_ASYNC_BEGIN0("video_capture", "EnumerateDeviceNames", |
+ this /* id */); |
+ // Always do enumeration even though some enumeration is in progress, because |
+ // those enumeration commands could be sent before these devices change. |
+ video_capture_device_factory_->EnumerateDeviceNames( |
+ base::Bind(&VideoCaptureHandlerImpl::OnVideoCaptureDevicesEnumerated, |
+ weak_factory_.GetWeakPtr())); |
+} |
+ |
+void VideoCaptureHandlerImpl::OnVideoCaptureDevicesEnumerated( |
+ scoped_ptr<media::VideoCaptureDevice::Names> device_names) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ TRACE_EVENT_ASYNC_END0("video_capture", "EnumerateDeviceNames", this); |
+ device_names_ = std::move(device_names); |
+ |
+#if !defined(NDEBUG) |
+ for (const auto& device_name : *device_names_) { |
+ DVLOG(1) << "device: id: " << device_name.id() |
+ << ", name: " << device_name.GetNameAndModel() |
+ << ", api: " << device_name.GetCaptureApiTypeString(); |
+ } |
+#endif |
+} |
+ |
+void VideoCaptureHandlerImpl::OnStart(const std::string& id) { |
+ DVLOG(1) << __FUNCTION__ << " " << id; |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ // TODO(mcasas): update some tracking saying that |id| is started ? |
+} |
+ |
+void VideoCaptureHandlerImpl::OnStopOrError(const std::string& id) { |
+ DCHECK(thread_checker_.CalledOnValidThread()); |
+ const auto& entry = device_and_streams_.find(id); |
+ DLOG_IF(ERROR, entry == device_and_streams_.end()) << "Device id " << id |
+ << " not found!"; |
+ if (entry == device_and_streams_.end()) |
+ return; |
+ entry->second.first->StopAndDeAllocate(); |
+ device_and_streams_.erase(entry); |
+} |
+ |
+} // namespace media |