OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 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 "media/capture/service/video_capture_handler_impl.h" |
| 6 |
| 7 #include <string> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/guid.h" |
| 11 #include "base/logging.h" |
| 12 #include "base/thread_task_runner_handle.h" |
| 13 #include "base/trace_event/trace_event.h" |
| 14 #include "media/base/video_capture_types.h" |
| 15 #include "media/capture/service/video_capture_device_client_impl.h" |
| 16 #include "media/capture/service/video_capture_stream_impl.h" |
| 17 #include "media/capture/video/video_capture_device_factory.h" |
| 18 #include "mojo/converters/geometry/geometry_type_converters.h" |
| 19 |
| 20 namespace media { |
| 21 |
| 22 VideoCaptureHandlerImpl::VideoCaptureHandlerImpl(mojo::ApplicationImpl* app) |
| 23 : app_(app), |
| 24 video_capture_device_factory_( |
| 25 media::VideoCaptureDeviceFactory::CreateFactory( |
| 26 base::ThreadTaskRunnerHandle::Get())), |
| 27 weak_factory_(this) { |
| 28 // Enumerating devices is something that takes a while (up to hundred of ms in |
| 29 // certain OSs). |
| 30 // TODO(mcasas): Add a UMA like in VideoCaptureManager::EnumerateDevices(). |
| 31 TRACE_EVENT_ASYNC_BEGIN0("video_capture", "EnumerateDeviceNames", |
| 32 this /* id */); |
| 33 video_capture_device_factory_->EnumerateDeviceNames( |
| 34 base::Bind(&VideoCaptureHandlerImpl::OnVideoCaptureDevicesEnumerated, |
| 35 weak_factory_.GetWeakPtr())); |
| 36 |
| 37 // Sadly this SystemMonitor does not do much for Video devices unless someone |
| 38 // notifies of changes. |
| 39 // TODO(mcasas): launch the SysteMonitor from here if there isn't one. |
| 40 base::SystemMonitor::Get()->AddDevicesChangedObserver(this); |
| 41 } |
| 42 |
| 43 VideoCaptureHandlerImpl::~VideoCaptureHandlerImpl() { |
| 44 DCHECK(thread_checker_.CalledOnValidThread()); |
| 45 for (const auto& id_and_device_and_stream : device_and_streams_) |
| 46 id_and_device_and_stream.second.first->StopAndDeAllocate(); |
| 47 |
| 48 base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this); |
| 49 } |
| 50 |
| 51 void VideoCaptureHandlerImpl::EnumerateDevices( |
| 52 const EnumerateDevicesCallback& callback) { |
| 53 DVLOG(1) << __FUNCTION__; |
| 54 DCHECK(thread_checker_.CalledOnValidThread()); |
| 55 |
| 56 mojo::Array<mojom::VideoCaptureDeviceInfoPtr> reply; |
| 57 if (!device_names_->empty()) { |
| 58 for (const auto& device_name : *device_names_) { |
| 59 mojom::VideoCaptureDeviceInfoPtr video_capture_device_info = |
| 60 mojom::VideoCaptureDeviceInfo::New(); |
| 61 |
| 62 // Send a GUID of the Video Capture id to hide sensitive information. |
| 63 const std::string guid = base::GenerateGUID(); |
| 64 public_to_private_id_map_[guid] = device_name.id(); |
| 65 video_capture_device_info->device_id = guid; |
| 66 video_capture_device_info->name = device_name.GetNameAndModel(); |
| 67 |
| 68 reply.push_back(std::move(video_capture_device_info)); |
| 69 } |
| 70 } |
| 71 callback.Run(std::move(reply)); |
| 72 } |
| 73 |
| 74 void VideoCaptureHandlerImpl::RequestVideoCaptureStream( |
| 75 mojom::VideoCaptureOptionsPtr options, |
| 76 const RequestVideoCaptureStreamCallback& callback) { |
| 77 DVLOG(1) << __FUNCTION__ << " device guid: " << options->device_id; |
| 78 DCHECK(thread_checker_.CalledOnValidThread()); |
| 79 |
| 80 const std::string& guid = options->device_id; |
| 81 if (!ContainsKey(public_to_private_id_map_, guid)) { |
| 82 DLOG(ERROR) << "Device identified as " << guid << " not found!"; |
| 83 return; |
| 84 } |
| 85 |
| 86 // Try to find |options->id| in the list of devices. If not found -> return. |
| 87 const std::string& id = public_to_private_id_map_[guid]; |
| 88 auto name = std::find_if(device_names_->begin(), device_names_->end(), |
| 89 [id](const media::VideoCaptureDevice::Name& name) { |
| 90 return name.id() == id; |
| 91 }); |
| 92 if (name == device_names_->end()) { |
| 93 DLOG(ERROR) << "device " << options->device_id << " not found."; |
| 94 callback.Run(nullptr); |
| 95 return; |
| 96 } |
| 97 |
| 98 // TODO(mcasas): Add support for more than one client per device. |
| 99 DCHECK(!ContainsKey(device_and_streams_, public_to_private_id_map_[guid])); |
| 100 |
| 101 media::VideoCaptureParams params; |
| 102 params.requested_format.frame_size = options->capture_size.To<gfx::Size>(); |
| 103 params.requested_format.frame_rate = options->frame_rate; |
| 104 params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; |
| 105 |
| 106 mojom::VideoCaptureStreamPtr stream_ptr; |
| 107 scoped_ptr<VideoCaptureStreamImpl> stream = |
| 108 make_scoped_ptr(new VideoCaptureStreamImpl( |
| 109 mojo::GetProxy(&stream_ptr), |
| 110 base::Bind(&VideoCaptureHandlerImpl::OnStopOrError, |
| 111 weak_factory_.GetWeakPtr(), id), |
| 112 base::Bind(&VideoCaptureHandlerImpl::OnStopOrError, |
| 113 weak_factory_.GetWeakPtr(), id))); |
| 114 |
| 115 // Create the found device and Start() with the chosen VideoCaptureParameters. |
| 116 scoped_ptr<media::VideoCaptureDevice> video_capture_device = |
| 117 video_capture_device_factory_->Create(*name); |
| 118 if (!video_capture_device) { |
| 119 DLOG(ERROR) << "device " << id << " could not be created."; |
| 120 callback.Run(nullptr); |
| 121 return; |
| 122 } |
| 123 |
| 124 // Create a VideoCaptureDeviceClientImpl using |stream_| as Delegate. |
| 125 scoped_ptr<media::VideoCaptureDevice::Client> device_client( |
| 126 new VideoCaptureDeviceClientImpl(stream.get())); |
| 127 video_capture_device->AllocateAndStart(params, std::move(device_client)); |
| 128 |
| 129 device_and_streams_.insert(make_pair( |
| 130 id, make_pair(std::move(video_capture_device), std::move(stream)))); |
| 131 |
| 132 callback.Run(std::move(stream_ptr)); |
| 133 } |
| 134 |
| 135 void VideoCaptureHandlerImpl::OnDevicesChanged( |
| 136 base::SystemMonitor::DeviceType device_type) { |
| 137 DVLOG(1) << __FUNCTION__; |
| 138 DCHECK(thread_checker_.CalledOnValidThread()); |
| 139 |
| 140 // NOTE: This method is only called in response to physical audio/video device |
| 141 // changes (from the operating system). |
| 142 |
| 143 if (device_type != base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) |
| 144 return; // Uninteresting device change. |
| 145 |
| 146 TRACE_EVENT_ASYNC_BEGIN0("video_capture", "EnumerateDeviceNames", |
| 147 this /* id */); |
| 148 // Always do enumeration even though some enumeration is in progress, because |
| 149 // those enumeration commands could be sent before these devices change. |
| 150 video_capture_device_factory_->EnumerateDeviceNames( |
| 151 base::Bind(&VideoCaptureHandlerImpl::OnVideoCaptureDevicesEnumerated, |
| 152 weak_factory_.GetWeakPtr())); |
| 153 } |
| 154 |
| 155 void VideoCaptureHandlerImpl::OnVideoCaptureDevicesEnumerated( |
| 156 scoped_ptr<media::VideoCaptureDevice::Names> device_names) { |
| 157 DCHECK(thread_checker_.CalledOnValidThread()); |
| 158 TRACE_EVENT_ASYNC_END0("video_capture", "EnumerateDeviceNames", this); |
| 159 device_names_ = std::move(device_names); |
| 160 |
| 161 #if !defined(NDEBUG) |
| 162 for (const auto& device_name : *device_names_) { |
| 163 DVLOG(1) << "device: id: " << device_name.id() |
| 164 << ", name: " << device_name.GetNameAndModel() |
| 165 << ", api: " << device_name.GetCaptureApiTypeString(); |
| 166 } |
| 167 #endif |
| 168 } |
| 169 |
| 170 void VideoCaptureHandlerImpl::OnStopOrError(const std::string& id) { |
| 171 DCHECK(thread_checker_.CalledOnValidThread()); |
| 172 const auto& entry = device_and_streams_.find(id); |
| 173 if (entry == device_and_streams_.end()) { |
| 174 DLOG(ERROR) << "Device id " << id << " not found!"; |
| 175 return; |
| 176 } |
| 177 entry->second.first->StopAndDeAllocate(); |
| 178 device_and_streams_.erase(entry); |
| 179 } |
| 180 |
| 181 } // namespace media |
OLD | NEW |