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/stream_impl.h" | |
16 #include "media/capture/service/video_capture_device_client_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): monitor http://crbug.com/584817 and perhaps launch the | |
40 // appropriate DeviceMonitor from here. | |
41 base::SystemMonitor::Get()->AddDevicesChangedObserver(this); | |
42 } | |
43 | |
44 VideoCaptureHandlerImpl::~VideoCaptureHandlerImpl() { | |
45 DCHECK(thread_checker_.CalledOnValidThread()); | |
46 for (const auto& id_and_device_and_stream : device_and_streams_) | |
47 id_and_device_and_stream.second.first->StopAndDeAllocate(); | |
48 | |
49 base::SystemMonitor::Get()->RemoveDevicesChangedObserver(this); | |
50 } | |
51 | |
52 void VideoCaptureHandlerImpl::EnumerateDevices( | |
53 const EnumerateDevicesCallback& callback) { | |
54 DVLOG(1) << __FUNCTION__; | |
55 DCHECK(thread_checker_.CalledOnValidThread()); | |
56 | |
57 mojo::Array<mojom::VideoCaptureDeviceInfoPtr> reply; | |
58 if (!device_names_->empty()) { | |
perkj_chrome
2016/03/07 23:58:27
? So if this is called before video_capture_device
mcasas
2016/03/08 23:57:29
That should never happen because the Monitors
sta
| |
59 for (const auto& device_name : *device_names_) { | |
60 mojom::VideoCaptureDeviceInfoPtr video_capture_device_info = | |
61 mojom::VideoCaptureDeviceInfo::New(); | |
62 | |
63 // Send a GUID of the Video Capture id to hide sensitive information. | |
perkj_chrome
2016/03/07 23:58:27
Why would this be sensitive?
Doesnt this mean you
mcasas
2016/03/08 23:57:29
You can't send the OS-specific device ID to
rende
| |
64 const std::string guid = base::GenerateGUID(); | |
65 public_to_private_id_map_[guid] = device_name.id(); | |
66 video_capture_device_info->device_id = guid; | |
67 video_capture_device_info->name = device_name.GetNameAndModel(); | |
68 | |
69 reply.push_back(std::move(video_capture_device_info)); | |
70 } | |
71 } | |
72 callback.Run(std::move(reply)); | |
73 } | |
74 | |
75 void VideoCaptureHandlerImpl::RequestVideoCaptureStream( | |
76 mojom::VideoCaptureOptionsPtr options, | |
77 const RequestVideoCaptureStreamCallback& callback) { | |
78 DVLOG(1) << __FUNCTION__ << " device guid: " << options->device_id; | |
79 DCHECK(thread_checker_.CalledOnValidThread()); | |
80 | |
81 const std::string& guid = options->device_id; | |
82 if (!ContainsKey(public_to_private_id_map_, guid)) { | |
83 DLOG(ERROR) << "Device identified as " << guid << " not found!"; | |
84 return; | |
85 } | |
86 | |
87 // Try to find |options->id| in the list of devices. If not found -> return. | |
88 const std::string& id = public_to_private_id_map_[guid]; | |
89 auto name = std::find_if(device_names_->begin(), device_names_->end(), | |
90 [id](const media::VideoCaptureDevice::Name& name) { | |
91 return name.id() == id; | |
92 }); | |
93 if (name == device_names_->end()) { | |
94 DLOG(ERROR) << "device " << options->device_id << " not found."; | |
95 callback.Run(nullptr); | |
96 return; | |
97 } | |
98 | |
99 // TODO(mcasas): At this point we need to ask the user for permission to use | |
perkj_chrome
2016/03/07 23:58:27
This must be handled outside this mojo and is not
mcasas
2016/03/08 23:57:29
Done.
| |
100 // this device if it hasn't been granted before or elsewhere. Soldier on for | |
101 // the time being and revisit this part later on. | |
102 | |
103 media::VideoCaptureParams params; | |
104 params.requested_format.frame_size = options->capture_size.To<gfx::Size>(); | |
105 params.requested_format.frame_rate = options->frame_rate; | |
106 params.requested_format.pixel_format = media::PIXEL_FORMAT_I420; | |
107 | |
108 mojom::VideoCaptureStreamPtr stream_ptr; | |
109 scoped_ptr<StreamImpl> stream = make_scoped_ptr(new StreamImpl( | |
110 mojo::GetProxy(&stream_ptr), base::Bind(&VideoCaptureHandlerImpl::OnStart, | |
111 weak_factory_.GetWeakPtr(), id), | |
112 base::Bind(&VideoCaptureHandlerImpl::OnStopOrError, | |
113 weak_factory_.GetWeakPtr(), id), | |
114 base::Bind(&VideoCaptureHandlerImpl::OnStopOrError, | |
115 weak_factory_.GetWeakPtr(), id))); | |
116 | |
117 // Create the found device and Start() with the chosen VideoCaptureParameters. | |
118 scoped_ptr<media::VideoCaptureDevice> video_capture_device = | |
119 video_capture_device_factory_->Create(*name); | |
perkj_chrome
2016/03/07 23:58:27
So this means there can only be one VideoCaptureSt
mcasas
2016/03/08 23:57:29
This mirrors the current cardinality: every VCDevi
| |
120 if (!video_capture_device) { | |
121 DLOG(ERROR) << "device " << id << " could not be created."; | |
122 callback.Run(nullptr); | |
123 return; | |
124 } | |
125 | |
126 // Create a VideoCaptureDeviceClientImpl using |stream_| as Delegate. | |
127 scoped_ptr<media::VideoCaptureDevice::Client> device_client( | |
128 new VideoCaptureDeviceClientImpl(stream.get())); | |
129 video_capture_device->AllocateAndStart(params, std::move(device_client)); | |
130 | |
131 device_and_streams_.insert(make_pair( | |
132 id, make_pair(std::move(video_capture_device), std::move(stream)))); | |
133 | |
134 callback.Run(std::move(stream_ptr)); | |
135 } | |
136 | |
137 void VideoCaptureHandlerImpl::OnDevicesChanged( | |
138 base::SystemMonitor::DeviceType device_type) { | |
139 DVLOG(1) << __FUNCTION__; | |
140 DCHECK(thread_checker_.CalledOnValidThread()); | |
141 | |
142 // NOTE: This method is only called in response to physical audio/video device | |
143 // changes (from the operating system). | |
144 | |
145 if (device_type != base::SystemMonitor::DEVTYPE_VIDEO_CAPTURE) | |
146 return; // Uninteresting device change. | |
147 | |
148 TRACE_EVENT_ASYNC_BEGIN0("video_capture", "EnumerateDeviceNames", | |
149 this /* id */); | |
150 // Always do enumeration even though some enumeration is in progress, because | |
151 // those enumeration commands could be sent before these devices change. | |
152 video_capture_device_factory_->EnumerateDeviceNames( | |
153 base::Bind(&VideoCaptureHandlerImpl::OnVideoCaptureDevicesEnumerated, | |
154 weak_factory_.GetWeakPtr())); | |
155 } | |
156 | |
157 void VideoCaptureHandlerImpl::OnVideoCaptureDevicesEnumerated( | |
158 scoped_ptr<media::VideoCaptureDevice::Names> device_names) { | |
159 DCHECK(thread_checker_.CalledOnValidThread()); | |
160 TRACE_EVENT_ASYNC_END0("video_capture", "EnumerateDeviceNames", this); | |
161 device_names_ = std::move(device_names); | |
162 | |
163 #if !defined(NDEBUG) | |
164 for (const auto& device_name : *device_names_) { | |
165 DVLOG(1) << "device: id: " << device_name.id() | |
166 << ", name: " << device_name.GetNameAndModel() | |
167 << ", api: " << device_name.GetCaptureApiTypeString(); | |
168 } | |
169 #endif | |
170 } | |
171 | |
172 void VideoCaptureHandlerImpl::OnStart(const std::string& id) { | |
173 DVLOG(1) << __FUNCTION__ << " " << id; | |
174 DCHECK(thread_checker_.CalledOnValidThread()); | |
175 // TODO(mcasas): update some tracking saying that |id| is started ? | |
176 } | |
177 | |
178 void VideoCaptureHandlerImpl::OnStopOrError(const std::string& id) { | |
179 DCHECK(thread_checker_.CalledOnValidThread()); | |
180 const auto& entry = device_and_streams_.find(id); | |
181 DLOG_IF(ERROR, entry == device_and_streams_.end()) << "Device id " << id | |
182 << " not found!"; | |
183 if (entry == device_and_streams_.end()) | |
184 return; | |
185 entry->second.first->StopAndDeAllocate(); | |
186 device_and_streams_.erase(entry); | |
187 } | |
188 | |
189 } // namespace media | |
OLD | NEW |