Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(296)

Side by Side Diff: content/browser/renderer_host/media/in_process_buildable_video_capture_device.cc

Issue 2738763002: [Mojo Video Capture] Introduce abstraction BuildableVideoCaptureDevice (Closed)
Patch Set: Incorporated mcasas@'s suggestions from PatchSet 7 and Similarity 50 Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "content/browser/renderer_host/media/in_process_buildable_video_capture _device.h"
6
7 #include "base/metrics/histogram_macros.h"
8 #include "base/strings/stringprintf.h"
9 #include "content/browser/media/capture/desktop_capture_device_uma_types.h"
10 #include "content/browser/media/capture/web_contents_video_capture_device.h"
11 #include "content/browser/renderer_host/media/video_capture_controller.h"
12 #include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h"
13 #include "content/browser/renderer_host/media/video_frame_receiver_on_io_thread. h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/desktop_media_id.h"
16 #include "content/public/common/media_stream_request.h"
17 #include "media/base/bind_to_current_loop.h"
18 #include "media/capture/video/video_capture_buffer_pool_impl.h"
19 #include "media/capture/video/video_capture_buffer_tracker_factory_impl.h"
20 #include "media/capture/video/video_capture_device_client.h"
21 #include "media/capture/video/video_frame_receiver.h"
22
23 #if defined(ENABLE_SCREEN_CAPTURE) && !defined(OS_ANDROID)
24 #include "content/browser/media/capture/desktop_capture_device.h"
25 #if defined(USE_AURA)
26 #include "content/browser/media/capture/desktop_capture_device_aura.h"
27 #endif
28 #endif
29
30 #if defined(ENABLE_SCREEN_CAPTURE) && defined(OS_ANDROID)
31 #include "content/browser/media/capture/screen_capture_device_android.h"
32 #endif
33
34 namespace {
35
36 class VideoFrameConsumerFeedbackObserverOnTaskRunner
37 : public media::VideoFrameConsumerFeedbackObserver {
38 public:
39 VideoFrameConsumerFeedbackObserverOnTaskRunner(
40 media::VideoFrameConsumerFeedbackObserver* observer,
41 scoped_refptr<base::SingleThreadTaskRunner> task_runner)
42 : observer_(observer), task_runner_(std::move(task_runner)) {}
43
44 void OnUtilizationReport(int frame_feedback_id, double utilization) override {
45 task_runner_->PostTask(
46 FROM_HERE,
47 base::Bind(
48 &media::VideoFrameConsumerFeedbackObserver::OnUtilizationReport,
49 base::Unretained(observer_), frame_feedback_id, utilization));
50 }
51
52 private:
53 media::VideoFrameConsumerFeedbackObserver* const observer_;
54 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
55 };
56
57 std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder(
58 const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) {
59 return base::MakeUnique<content::VideoCaptureGpuJpegDecoder>(decode_done_cb);
60 }
61
62 void StopAndReleaseDeviceOnDeviceThread(media::VideoCaptureDevice* device,
63 base::OnceClosure done_cb) {
64 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StopDeviceTime");
65 device->StopAndDeAllocate();
66 DVLOG(3) << "StopAndReleaseDeviceOnDeviceThread";
67 delete device;
68 std::move(done_cb).Run();
miu 2017/03/22 22:09:50 Oh, I mentioned this in the other CL, but here is
chfremer 2017/03/22 23:20:38 Yes. The OnceCallback must be moved in order to in
69 }
70
71 // The maximum number of video frame buffers in-flight at any one time. This
72 // value should be based on the logical capacity of the capture pipeline, and
73 // not on hardware performance. For example, tab capture requires more buffers
74 // than webcam capture because the pipeline is longer (it includes read-backs
75 // pending in the GPU pipeline).
76 const int kMaxNumberOfBuffers = 3;
77 // TODO(miu): The value for tab capture should be determined programmatically.
78 // http://crbug.com/460318
79 const int kMaxNumberOfBuffersForTabCapture = 10;
80
81 } // anonymous namespace
82
83 namespace content {
84
85 InProcessBuildableVideoCaptureDevice::InProcessBuildableVideoCaptureDevice(
86 scoped_refptr<base::SingleThreadTaskRunner> device_task_runner,
87 media::VideoCaptureDeviceFactory* device_factory)
88 : device_task_runner_(std::move(device_task_runner)),
89 device_factory_(device_factory) {}
90
91 InProcessBuildableVideoCaptureDevice::~InProcessBuildableVideoCaptureDevice() {
92 DCHECK_CURRENTLY_ON(BrowserThread::IO);
93 DCHECK(!device_);
94 }
95
96 void InProcessBuildableVideoCaptureDevice::CreateAndStartDeviceAsync(
97 VideoCaptureController* controller,
98 const media::VideoCaptureParams& params,
99 Callbacks* callbacks,
100 base::OnceClosure done_cb) {
101 DCHECK_CURRENTLY_ON(BrowserThread::IO);
102
103 const int max_buffers = (controller->stream_type() == MEDIA_TAB_VIDEO_CAPTURE
104 ? kMaxNumberOfBuffersForTabCapture
105 : kMaxNumberOfBuffers);
106
107 auto device_client =
108 CreateDeviceClient(max_buffers, controller->GetWeakPtrForIOThread());
109
110 base::Closure start_capture_closure;
111 switch (controller->stream_type()) {
112 case MEDIA_DEVICE_VIDEO_CAPTURE: {
113 const media::VideoCaptureDeviceDescriptor* descriptor =
114 callbacks->LookupDeviceDescriptor(controller->device_id());
115 if (descriptor) {
116 controller->OnLog(
117 base::StringPrintf("Starting device: id: %s, name: %s, api: %s",
118 descriptor->device_id.c_str(),
119 descriptor->GetNameAndModel().c_str(),
120 descriptor->GetCaptureApiTypeString()));
121
122 callbacks->WillStartDevice(descriptor->facing);
123
124 // Use of Unretained() is safe, because |context_reference| guarantees
mcasas 2017/03/22 22:43:16 Seems like |context_reference| doesn't exist aroun
chfremer 2017/03/22 23:20:38 Done.
125 // that |this| stays alive.
126 ReceiveDeviceCallback after_start_capture_callback =
127 media::BindToCurrentLoop(base::Bind(
128 &InProcessBuildableVideoCaptureDevice::OnDeviceStarted,
129 base::Unretained(this), controller, callbacks,
130 base::Passed(&done_cb)));
131 start_capture_closure =
132 base::Bind(&InProcessBuildableVideoCaptureDevice::
133 DoStartDeviceCaptureOnDeviceThread,
134 base::Unretained(this), *descriptor, params,
135 base::Passed(std::move(device_client)),
136 std::move(after_start_capture_callback));
137 } else {
138 callbacks->OnDeviceStartFailed(controller);
139 std::move(done_cb).Run();
140 return;
141 }
mcasas 2017/03/22 22:43:16 This probably predatesthis CL, but I suggest we mo
chfremer 2017/03/22 23:20:38 Done.
142 break;
143 }
144 case MEDIA_TAB_VIDEO_CAPTURE: {
145 // Use of Unretained() is safe, because |context_reference| guarantees
miu 2017/03/22 22:16:51 s/context_reference/done_cb/ ...and elsewhere...
chfremer 2017/03/22 23:20:38 Done.
146 // that |this| stays alive.
147 ReceiveDeviceCallback after_start_capture_callback =
148 media::BindToCurrentLoop(
149 base::Bind(&InProcessBuildableVideoCaptureDevice::OnDeviceStarted,
150 base::Unretained(this), controller, callbacks,
151 base::Passed(&done_cb)));
152 start_capture_closure =
153 base::Bind(&InProcessBuildableVideoCaptureDevice::
154 DoStartTabCaptureOnDeviceThread,
155 base::Unretained(this), controller->device_id(), params,
156 base::Passed(std::move(device_client)),
157 std::move(after_start_capture_callback));
158 break;
159 }
160 case MEDIA_DESKTOP_VIDEO_CAPTURE: {
161 // Use of Unretained() is safe, because |context_reference| guarantees
162 // that |this| stays alive.
163 ReceiveDeviceCallback after_start_capture_callback =
164 media::BindToCurrentLoop(
165 base::Bind(&InProcessBuildableVideoCaptureDevice::OnDeviceStarted,
166 base::Unretained(this), controller, callbacks,
167 base::Passed(&done_cb)));
168 start_capture_closure =
169 base::Bind(&InProcessBuildableVideoCaptureDevice::
170 DoStartDesktopCaptureOnDeviceThread,
171 base::Unretained(this), controller->device_id(), params,
172 base::Passed(std::move(device_client)),
173 std::move(after_start_capture_callback));
174 break;
175 }
176 default: {
177 NOTIMPLEMENTED();
178 return;
179 }
180 }
181
182 device_task_runner_->PostTask(FROM_HERE, start_capture_closure);
183 }
184
185 void InProcessBuildableVideoCaptureDevice::ReleaseDeviceAsync(
186 VideoCaptureController* controller,
187 base::OnceClosure done_cb) {
188 DCHECK_CURRENTLY_ON(BrowserThread::IO);
189 controller->SetConsumerFeedbackObserver(nullptr);
190 if (!device_)
191 return;
192 media::VideoCaptureDevice* device_ptr = device_.release();
193
194 bool posting_task_succeeded = device_task_runner_->PostTask(
195 FROM_HERE,
196 base::Bind(&StopAndReleaseDeviceOnDeviceThread, device_ptr,
197 base::Bind([](scoped_refptr<base::SingleThreadTaskRunner>) {},
198 device_task_runner_)));
199 if (posting_task_succeeded == false) {
200 // Since posting to the task runner has failed, we attempt doing it on
201 // the calling thread instead.
202 StopAndReleaseDeviceOnDeviceThread(device_ptr, base::Bind([]() {}));
203 }
204 std::move(done_cb).Run();
mcasas 2017/03/22 22:43:16 Same as in l.139, I'd say here base::ResetAndRet
chfremer 2017/03/22 23:20:38 Thanks. I didn't know that base::ResetAndReturn()
205 }
206
207 bool InProcessBuildableVideoCaptureDevice::IsDeviceAlive() const {
208 DCHECK_CURRENTLY_ON(BrowserThread::IO);
209 return device_ != nullptr;
210 }
211
212 void InProcessBuildableVideoCaptureDevice::GetPhotoCapabilities(
213 media::VideoCaptureDevice::GetPhotoCapabilitiesCallback callback) const {
214 DCHECK_CURRENTLY_ON(BrowserThread::IO);
215 // Unretained() is safe to use here because |device| would be null if it
216 // was scheduled for shutdown and destruction, and because this task is
217 // guaranteed to run before the task that destroys the |device|.
218 device_task_runner_->PostTask(
219 FROM_HERE,
220 base::Bind(&media::VideoCaptureDevice::GetPhotoCapabilities,
221 base::Unretained(device_.get()), base::Passed(&callback)));
222 }
223
224 void InProcessBuildableVideoCaptureDevice::SetPhotoOptions(
225 media::mojom::PhotoSettingsPtr settings,
226 media::VideoCaptureDevice::SetPhotoOptionsCallback callback) {
227 DCHECK_CURRENTLY_ON(BrowserThread::IO);
228 // Unretained() is safe to use here because |device| would be null if it
229 // was scheduled for shutdown and destruction, and because this task is
230 // guaranteed to run before the task that destroys the |device|.
231 device_task_runner_->PostTask(
232 FROM_HERE, base::Bind(&media::VideoCaptureDevice::SetPhotoOptions,
233 base::Unretained(device_.get()),
234 base::Passed(&settings), base::Passed(&callback)));
235 }
236
237 void InProcessBuildableVideoCaptureDevice::TakePhoto(
238 media::VideoCaptureDevice::TakePhotoCallback callback) {
239 DCHECK_CURRENTLY_ON(BrowserThread::IO);
240 // Unretained() is safe to use here because |device| would be null if it
241 // was scheduled for shutdown and destruction, and because this task is
242 // guaranteed to run before the task that destroys the |device|.
243 device_task_runner_->PostTask(
244 FROM_HERE,
245 base::Bind(&media::VideoCaptureDevice::TakePhoto,
246 base::Unretained(device_.get()), base::Passed(&callback)));
247 }
248
249 void InProcessBuildableVideoCaptureDevice::MaybeSuspendDevice() {
250 DCHECK_CURRENTLY_ON(BrowserThread::IO);
251 // Unretained() is safe to use here because |device| would be null if it
252 // was scheduled for shutdown and destruction, and because this task is
253 // guaranteed to run before the task that destroys the |device|.
254 device_task_runner_->PostTask(
255 FROM_HERE, base::Bind(&media::VideoCaptureDevice::MaybeSuspend,
256 base::Unretained(device_.get())));
257 }
258
259 void InProcessBuildableVideoCaptureDevice::ResumeDevice() {
260 DCHECK_CURRENTLY_ON(BrowserThread::IO);
261 // Unretained() is safe to use here because |device| would be null if it
262 // was scheduled for shutdown and destruction, and because this task is
263 // guaranteed to run before the task that destroys the |device|.
264 device_task_runner_->PostTask(FROM_HERE,
265 base::Bind(&media::VideoCaptureDevice::Resume,
266 base::Unretained(device_.get())));
267 }
268
269 void InProcessBuildableVideoCaptureDevice::RequestRefreshFrame() {
270 DCHECK_CURRENTLY_ON(BrowserThread::IO);
271 // Unretained() is safe to use here because |device| would be null if it
272 // was scheduled for shutdown and destruction, and because this task is
273 // guaranteed to run before the task that destroys the |device|.
274 device_task_runner_->PostTask(
275 FROM_HERE, base::Bind(&media::VideoCaptureDevice::RequestRefreshFrame,
276 base::Unretained(device_.get())));
277 }
278
279 void InProcessBuildableVideoCaptureDevice::SetDesktopCaptureWindowIdAsync(
280 gfx::NativeViewId window_id,
281 base::OnceClosure done_cb) {
282 DCHECK_CURRENTLY_ON(BrowserThread::IO);
283 // Post |device_| to the the device_task_runner_. This is safe since the
284 // device is destroyed on the device_task_runner_ and |context_reference|
mcasas 2017/03/22 22:43:16 s/device_task_runner_/|device_task_runner_|/ |con
chfremer 2017/03/22 23:20:38 Done.
285 // guarantees that |this| stays alive.
286 device_task_runner_->PostTask(
287 FROM_HERE, base::Bind(&InProcessBuildableVideoCaptureDevice::
288 SetDesktopCaptureWindowIdOnDeviceThread,
289 base::Unretained(this), device_.get(), window_id,
290 base::Passed(&done_cb)));
291 }
292
293 std::unique_ptr<media::VideoCaptureDeviceClient>
294 InProcessBuildableVideoCaptureDevice::CreateDeviceClient(
295 int buffer_pool_max_buffer_count,
296 base::WeakPtr<media::VideoFrameReceiver> receiver) {
297 DCHECK_CURRENTLY_ON(BrowserThread::IO);
298
299 scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_ =
300 new media::VideoCaptureBufferPoolImpl(
301 base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(),
302 buffer_pool_max_buffer_count);
303
304 return base::MakeUnique<media::VideoCaptureDeviceClient>(
305 base::MakeUnique<VideoFrameReceiverOnIOThread>(receiver), buffer_pool_,
306 base::Bind(&CreateGpuJpegDecoder,
307 base::Bind(&media::VideoFrameReceiver::OnFrameReadyInBuffer,
308 receiver)));
309 }
310
311 void InProcessBuildableVideoCaptureDevice::OnDeviceStarted(
312 VideoCaptureController* controller,
313 Callbacks* callbacks,
314 base::OnceClosure done_cb,
315 std::unique_ptr<media::VideoCaptureDevice> device) {
316 DCHECK_CURRENTLY_ON(BrowserThread::IO);
317 if (!device) {
318 callbacks->OnDeviceStartFailed(controller);
319 std::move(done_cb).Run();
320 return;
321 }
322 // Passing raw pointer |device.get()| to the controller is safe,
323 // because we take ownership of |device| and we call
324 // controller->SetConsumerFeedbackObserver(nullptr) before releasing |device|.
325 controller->SetConsumerFeedbackObserver(
326 base::MakeUnique<VideoFrameConsumerFeedbackObserverOnTaskRunner>(
327 device.get(), device_task_runner_));
328 device_ = std::move(device);
329 callbacks->DidStartDevice(controller);
330 std::move(done_cb).Run();
331 }
332
333 void InProcessBuildableVideoCaptureDevice::DoStartDeviceCaptureOnDeviceThread(
334 const media::VideoCaptureDeviceDescriptor& descriptor,
335 const media::VideoCaptureParams& params,
336 std::unique_ptr<media::VideoCaptureDeviceClient> device_client,
337 ReceiveDeviceCallback result_callback) {
338 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
339 DCHECK(device_task_runner_->BelongsToCurrentThread());
340
341 std::unique_ptr<media::VideoCaptureDevice> video_capture_device =
342 device_factory_->CreateDevice(descriptor);
343
344 if (!video_capture_device) {
345 result_callback.Run(nullptr);
346 return;
347 }
348
349 video_capture_device->AllocateAndStart(params, std::move(device_client));
350 result_callback.Run(std::move(video_capture_device));
351 }
352
353 void InProcessBuildableVideoCaptureDevice::DoStartTabCaptureOnDeviceThread(
354 const std::string& id,
355 const media::VideoCaptureParams& params,
356 std::unique_ptr<media::VideoCaptureDeviceClient> device_client,
357 ReceiveDeviceCallback result_callback) {
358 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
359 DCHECK(device_task_runner_->BelongsToCurrentThread());
360
361 std::unique_ptr<media::VideoCaptureDevice> video_capture_device;
362 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
363 video_capture_device = WebContentsVideoCaptureDevice::Create(id);
364 #endif
365
366 if (!video_capture_device) {
367 result_callback.Run(nullptr);
368 return;
369 }
370
371 video_capture_device->AllocateAndStart(params, std::move(device_client));
372 result_callback.Run(std::move(video_capture_device));
373 }
374
375 void InProcessBuildableVideoCaptureDevice::DoStartDesktopCaptureOnDeviceThread(
376 const std::string& id,
377 const media::VideoCaptureParams& params,
378 std::unique_ptr<media::VideoCaptureDeviceClient> device_client,
379 ReceiveDeviceCallback result_callback) {
380 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime");
381 DCHECK(device_task_runner_->BelongsToCurrentThread());
382
383 std::unique_ptr<media::VideoCaptureDevice> video_capture_device;
384 #if defined(ENABLE_SCREEN_CAPTURE)
385 DesktopMediaID desktop_id = DesktopMediaID::Parse(id);
386 if (desktop_id.is_null()) {
387 DLOG(ERROR) << "Desktop media ID is null";
388 result_callback.Run(nullptr);
389 return;
390 }
391
392 if (desktop_id.type == DesktopMediaID::TYPE_WEB_CONTENTS) {
393 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
394 video_capture_device = WebContentsVideoCaptureDevice::Create(id);
395 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED);
396 if (desktop_id.audio_share) {
397 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED_WITH_AUDIO);
398 } else {
399 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED_WITHOUT_AUDIO);
400 }
mcasas 2017/03/22 22:43:16 nit: no {} for one line bodies. Probably this pre
chfremer 2017/03/22 23:20:38 Done.
401 #endif
402 } else {
403 #if defined(OS_ANDROID)
404 video_capture_device = base::MakeUnique<ScreenCaptureDeviceAndroid>();
405 #else
406 #if defined(USE_AURA)
407 video_capture_device = DesktopCaptureDeviceAura::Create(desktop_id);
408 #endif // defined(USE_AURA)
409 #if BUILDFLAG(ENABLE_WEBRTC)
410 if (!video_capture_device)
411 video_capture_device = DesktopCaptureDevice::Create(desktop_id);
412 #endif // BUILDFLAG(ENABLE_WEBRTC)
413 #endif // defined (OS_ANDROID)
414 }
415 #endif // defined(ENABLE_SCREEN_CAPTURE)
416
417 if (!video_capture_device) {
418 result_callback.Run(nullptr);
419 return;
420 }
421
422 video_capture_device->AllocateAndStart(params, std::move(device_client));
423 result_callback.Run(std::move(video_capture_device));
424 }
425
426 void InProcessBuildableVideoCaptureDevice::
427 SetDesktopCaptureWindowIdOnDeviceThread(media::VideoCaptureDevice* device,
428 gfx::NativeViewId window_id,
429 base::OnceClosure done_cb) {
430 DCHECK(device_task_runner_->BelongsToCurrentThread());
431 #if defined(ENABLE_SCREEN_CAPTURE) && BUILDFLAG(ENABLE_WEBRTC) && \
432 !defined(OS_ANDROID)
433 DesktopCaptureDevice* desktop_device =
434 static_cast<DesktopCaptureDevice*>(device);
435 desktop_device->SetNotificationWindowId(window_id);
436 VLOG(2) << "Screen capture notification window passed on device thread.";
437 #endif
438 std::move(done_cb).Run();
439 }
440
441 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698