OLD | NEW |
(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 base::ResetAndReturn(&done_cb).Run(); |
| 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 callbacks->OnDeviceStartFailed(controller); |
| 117 base::ResetAndReturn(&done_cb).Run(); |
| 118 return; |
| 119 } |
| 120 controller->OnLog(base::StringPrintf( |
| 121 "Starting device: id: %s, name: %s, api: %s", |
| 122 descriptor->device_id.c_str(), descriptor->GetNameAndModel().c_str(), |
| 123 descriptor->GetCaptureApiTypeString())); |
| 124 |
| 125 callbacks->WillStartDevice(descriptor->facing); |
| 126 |
| 127 // Use of Unretained() is safe, because |done_cb| guarantees that |this| |
| 128 // stays alive. |
| 129 ReceiveDeviceCallback after_start_capture_callback = |
| 130 media::BindToCurrentLoop( |
| 131 base::Bind(&InProcessBuildableVideoCaptureDevice::OnDeviceStarted, |
| 132 base::Unretained(this), controller, callbacks, |
| 133 base::Passed(&done_cb))); |
| 134 start_capture_closure = |
| 135 base::Bind(&InProcessBuildableVideoCaptureDevice:: |
| 136 DoStartDeviceCaptureOnDeviceThread, |
| 137 base::Unretained(this), *descriptor, params, |
| 138 base::Passed(std::move(device_client)), |
| 139 std::move(after_start_capture_callback)); |
| 140 break; |
| 141 } |
| 142 case MEDIA_TAB_VIDEO_CAPTURE: { |
| 143 // Use of Unretained() is safe, because |done_cb| guarantees that |this| |
| 144 // stays alive. |
| 145 ReceiveDeviceCallback after_start_capture_callback = |
| 146 media::BindToCurrentLoop( |
| 147 base::Bind(&InProcessBuildableVideoCaptureDevice::OnDeviceStarted, |
| 148 base::Unretained(this), controller, callbacks, |
| 149 base::Passed(&done_cb))); |
| 150 start_capture_closure = |
| 151 base::Bind(&InProcessBuildableVideoCaptureDevice:: |
| 152 DoStartTabCaptureOnDeviceThread, |
| 153 base::Unretained(this), controller->device_id(), params, |
| 154 base::Passed(std::move(device_client)), |
| 155 std::move(after_start_capture_callback)); |
| 156 break; |
| 157 } |
| 158 case MEDIA_DESKTOP_VIDEO_CAPTURE: { |
| 159 // Use of Unretained() is safe, because |done_cb| guarantees that |this| |
| 160 // stays alive. |
| 161 ReceiveDeviceCallback after_start_capture_callback = |
| 162 media::BindToCurrentLoop( |
| 163 base::Bind(&InProcessBuildableVideoCaptureDevice::OnDeviceStarted, |
| 164 base::Unretained(this), controller, callbacks, |
| 165 base::Passed(&done_cb))); |
| 166 start_capture_closure = |
| 167 base::Bind(&InProcessBuildableVideoCaptureDevice:: |
| 168 DoStartDesktopCaptureOnDeviceThread, |
| 169 base::Unretained(this), controller->device_id(), params, |
| 170 base::Passed(std::move(device_client)), |
| 171 std::move(after_start_capture_callback)); |
| 172 break; |
| 173 } |
| 174 default: { |
| 175 NOTIMPLEMENTED(); |
| 176 return; |
| 177 } |
| 178 } |
| 179 |
| 180 device_task_runner_->PostTask(FROM_HERE, start_capture_closure); |
| 181 } |
| 182 |
| 183 void InProcessBuildableVideoCaptureDevice::ReleaseDeviceAsync( |
| 184 VideoCaptureController* controller, |
| 185 base::OnceClosure done_cb) { |
| 186 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 187 controller->SetConsumerFeedbackObserver(nullptr); |
| 188 if (!device_) |
| 189 return; |
| 190 media::VideoCaptureDevice* device_ptr = device_.release(); |
| 191 |
| 192 bool posting_task_succeeded = device_task_runner_->PostTask( |
| 193 FROM_HERE, |
| 194 base::Bind(&StopAndReleaseDeviceOnDeviceThread, device_ptr, |
| 195 base::Bind([](scoped_refptr<base::SingleThreadTaskRunner>) {}, |
| 196 device_task_runner_))); |
| 197 if (posting_task_succeeded == false) { |
| 198 // Since posting to the task runner has failed, we attempt doing it on |
| 199 // the calling thread instead. |
| 200 StopAndReleaseDeviceOnDeviceThread(device_ptr, base::Bind([]() {})); |
| 201 } |
| 202 base::ResetAndReturn(&done_cb).Run(); |
| 203 } |
| 204 |
| 205 bool InProcessBuildableVideoCaptureDevice::IsDeviceAlive() const { |
| 206 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 207 return device_ != nullptr; |
| 208 } |
| 209 |
| 210 void InProcessBuildableVideoCaptureDevice::GetPhotoCapabilities( |
| 211 media::VideoCaptureDevice::GetPhotoCapabilitiesCallback callback) const { |
| 212 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 213 // Unretained() is safe to use here because |device| would be null if it |
| 214 // was scheduled for shutdown and destruction, and because this task is |
| 215 // guaranteed to run before the task that destroys the |device|. |
| 216 device_task_runner_->PostTask( |
| 217 FROM_HERE, |
| 218 base::Bind(&media::VideoCaptureDevice::GetPhotoCapabilities, |
| 219 base::Unretained(device_.get()), base::Passed(&callback))); |
| 220 } |
| 221 |
| 222 void InProcessBuildableVideoCaptureDevice::SetPhotoOptions( |
| 223 media::mojom::PhotoSettingsPtr settings, |
| 224 media::VideoCaptureDevice::SetPhotoOptionsCallback callback) { |
| 225 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 226 // Unretained() is safe to use here because |device| would be null if it |
| 227 // was scheduled for shutdown and destruction, and because this task is |
| 228 // guaranteed to run before the task that destroys the |device|. |
| 229 device_task_runner_->PostTask( |
| 230 FROM_HERE, base::Bind(&media::VideoCaptureDevice::SetPhotoOptions, |
| 231 base::Unretained(device_.get()), |
| 232 base::Passed(&settings), base::Passed(&callback))); |
| 233 } |
| 234 |
| 235 void InProcessBuildableVideoCaptureDevice::TakePhoto( |
| 236 media::VideoCaptureDevice::TakePhotoCallback callback) { |
| 237 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 238 // Unretained() is safe to use here because |device| would be null if it |
| 239 // was scheduled for shutdown and destruction, and because this task is |
| 240 // guaranteed to run before the task that destroys the |device|. |
| 241 device_task_runner_->PostTask( |
| 242 FROM_HERE, |
| 243 base::Bind(&media::VideoCaptureDevice::TakePhoto, |
| 244 base::Unretained(device_.get()), base::Passed(&callback))); |
| 245 } |
| 246 |
| 247 void InProcessBuildableVideoCaptureDevice::MaybeSuspendDevice() { |
| 248 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 249 // Unretained() is safe to use here because |device| would be null if it |
| 250 // was scheduled for shutdown and destruction, and because this task is |
| 251 // guaranteed to run before the task that destroys the |device|. |
| 252 device_task_runner_->PostTask( |
| 253 FROM_HERE, base::Bind(&media::VideoCaptureDevice::MaybeSuspend, |
| 254 base::Unretained(device_.get()))); |
| 255 } |
| 256 |
| 257 void InProcessBuildableVideoCaptureDevice::ResumeDevice() { |
| 258 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 259 // Unretained() is safe to use here because |device| would be null if it |
| 260 // was scheduled for shutdown and destruction, and because this task is |
| 261 // guaranteed to run before the task that destroys the |device|. |
| 262 device_task_runner_->PostTask(FROM_HERE, |
| 263 base::Bind(&media::VideoCaptureDevice::Resume, |
| 264 base::Unretained(device_.get()))); |
| 265 } |
| 266 |
| 267 void InProcessBuildableVideoCaptureDevice::RequestRefreshFrame() { |
| 268 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 269 // Unretained() is safe to use here because |device| would be null if it |
| 270 // was scheduled for shutdown and destruction, and because this task is |
| 271 // guaranteed to run before the task that destroys the |device|. |
| 272 device_task_runner_->PostTask( |
| 273 FROM_HERE, base::Bind(&media::VideoCaptureDevice::RequestRefreshFrame, |
| 274 base::Unretained(device_.get()))); |
| 275 } |
| 276 |
| 277 void InProcessBuildableVideoCaptureDevice::SetDesktopCaptureWindowIdAsync( |
| 278 gfx::NativeViewId window_id, |
| 279 base::OnceClosure done_cb) { |
| 280 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 281 // Post |device_| to the the |device_task_runner_|. This is safe since the |
| 282 // device is destroyed on the |device_task_runner_| and |done_cb| guarantees |
| 283 // that |this| stays alive. |
| 284 device_task_runner_->PostTask( |
| 285 FROM_HERE, base::Bind(&InProcessBuildableVideoCaptureDevice:: |
| 286 SetDesktopCaptureWindowIdOnDeviceThread, |
| 287 base::Unretained(this), device_.get(), window_id, |
| 288 base::Passed(&done_cb))); |
| 289 } |
| 290 |
| 291 std::unique_ptr<media::VideoCaptureDeviceClient> |
| 292 InProcessBuildableVideoCaptureDevice::CreateDeviceClient( |
| 293 int buffer_pool_max_buffer_count, |
| 294 base::WeakPtr<media::VideoFrameReceiver> receiver) { |
| 295 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 296 |
| 297 scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_ = |
| 298 new media::VideoCaptureBufferPoolImpl( |
| 299 base::MakeUnique<media::VideoCaptureBufferTrackerFactoryImpl>(), |
| 300 buffer_pool_max_buffer_count); |
| 301 |
| 302 return base::MakeUnique<media::VideoCaptureDeviceClient>( |
| 303 base::MakeUnique<VideoFrameReceiverOnIOThread>(receiver), buffer_pool_, |
| 304 base::Bind(&CreateGpuJpegDecoder, |
| 305 base::Bind(&media::VideoFrameReceiver::OnFrameReadyInBuffer, |
| 306 receiver))); |
| 307 } |
| 308 |
| 309 void InProcessBuildableVideoCaptureDevice::OnDeviceStarted( |
| 310 VideoCaptureController* controller, |
| 311 Callbacks* callbacks, |
| 312 base::OnceClosure done_cb, |
| 313 std::unique_ptr<media::VideoCaptureDevice> device) { |
| 314 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
| 315 if (!device) { |
| 316 callbacks->OnDeviceStartFailed(controller); |
| 317 base::ResetAndReturn(&done_cb).Run(); |
| 318 return; |
| 319 } |
| 320 // Passing raw pointer |device.get()| to the controller is safe, |
| 321 // because we take ownership of |device| and we call |
| 322 // controller->SetConsumerFeedbackObserver(nullptr) before releasing |device|. |
| 323 controller->SetConsumerFeedbackObserver( |
| 324 base::MakeUnique<VideoFrameConsumerFeedbackObserverOnTaskRunner>( |
| 325 device.get(), device_task_runner_)); |
| 326 device_ = std::move(device); |
| 327 callbacks->DidStartDevice(controller); |
| 328 base::ResetAndReturn(&done_cb).Run(); |
| 329 } |
| 330 |
| 331 void InProcessBuildableVideoCaptureDevice::DoStartDeviceCaptureOnDeviceThread( |
| 332 const media::VideoCaptureDeviceDescriptor& descriptor, |
| 333 const media::VideoCaptureParams& params, |
| 334 std::unique_ptr<media::VideoCaptureDeviceClient> device_client, |
| 335 ReceiveDeviceCallback result_callback) { |
| 336 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); |
| 337 DCHECK(device_task_runner_->BelongsToCurrentThread()); |
| 338 |
| 339 std::unique_ptr<media::VideoCaptureDevice> video_capture_device = |
| 340 device_factory_->CreateDevice(descriptor); |
| 341 |
| 342 if (!video_capture_device) { |
| 343 result_callback.Run(nullptr); |
| 344 return; |
| 345 } |
| 346 |
| 347 video_capture_device->AllocateAndStart(params, std::move(device_client)); |
| 348 result_callback.Run(std::move(video_capture_device)); |
| 349 } |
| 350 |
| 351 void InProcessBuildableVideoCaptureDevice::DoStartTabCaptureOnDeviceThread( |
| 352 const std::string& id, |
| 353 const media::VideoCaptureParams& params, |
| 354 std::unique_ptr<media::VideoCaptureDeviceClient> device_client, |
| 355 ReceiveDeviceCallback result_callback) { |
| 356 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); |
| 357 DCHECK(device_task_runner_->BelongsToCurrentThread()); |
| 358 |
| 359 std::unique_ptr<media::VideoCaptureDevice> video_capture_device; |
| 360 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) |
| 361 video_capture_device = WebContentsVideoCaptureDevice::Create(id); |
| 362 #endif |
| 363 |
| 364 if (!video_capture_device) { |
| 365 result_callback.Run(nullptr); |
| 366 return; |
| 367 } |
| 368 |
| 369 video_capture_device->AllocateAndStart(params, std::move(device_client)); |
| 370 result_callback.Run(std::move(video_capture_device)); |
| 371 } |
| 372 |
| 373 void InProcessBuildableVideoCaptureDevice::DoStartDesktopCaptureOnDeviceThread( |
| 374 const std::string& id, |
| 375 const media::VideoCaptureParams& params, |
| 376 std::unique_ptr<media::VideoCaptureDeviceClient> device_client, |
| 377 ReceiveDeviceCallback result_callback) { |
| 378 SCOPED_UMA_HISTOGRAM_TIMER("Media.VideoCaptureManager.StartDeviceTime"); |
| 379 DCHECK(device_task_runner_->BelongsToCurrentThread()); |
| 380 |
| 381 std::unique_ptr<media::VideoCaptureDevice> video_capture_device; |
| 382 #if defined(ENABLE_SCREEN_CAPTURE) |
| 383 DesktopMediaID desktop_id = DesktopMediaID::Parse(id); |
| 384 if (desktop_id.is_null()) { |
| 385 DLOG(ERROR) << "Desktop media ID is null"; |
| 386 result_callback.Run(nullptr); |
| 387 return; |
| 388 } |
| 389 |
| 390 if (desktop_id.type == DesktopMediaID::TYPE_WEB_CONTENTS) { |
| 391 #if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN) |
| 392 video_capture_device = WebContentsVideoCaptureDevice::Create(id); |
| 393 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED); |
| 394 if (desktop_id.audio_share) |
| 395 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED_WITH_AUDIO); |
| 396 else |
| 397 IncrementDesktopCaptureCounter(TAB_VIDEO_CAPTURER_CREATED_WITHOUT_AUDIO); |
| 398 #endif |
| 399 } else { |
| 400 #if defined(OS_ANDROID) |
| 401 video_capture_device = base::MakeUnique<ScreenCaptureDeviceAndroid>(); |
| 402 #else |
| 403 #if defined(USE_AURA) |
| 404 video_capture_device = DesktopCaptureDeviceAura::Create(desktop_id); |
| 405 #endif // defined(USE_AURA) |
| 406 #if BUILDFLAG(ENABLE_WEBRTC) |
| 407 if (!video_capture_device) |
| 408 video_capture_device = DesktopCaptureDevice::Create(desktop_id); |
| 409 #endif // BUILDFLAG(ENABLE_WEBRTC) |
| 410 #endif // defined (OS_ANDROID) |
| 411 } |
| 412 #endif // defined(ENABLE_SCREEN_CAPTURE) |
| 413 |
| 414 if (!video_capture_device) { |
| 415 result_callback.Run(nullptr); |
| 416 return; |
| 417 } |
| 418 |
| 419 video_capture_device->AllocateAndStart(params, std::move(device_client)); |
| 420 result_callback.Run(std::move(video_capture_device)); |
| 421 } |
| 422 |
| 423 void InProcessBuildableVideoCaptureDevice:: |
| 424 SetDesktopCaptureWindowIdOnDeviceThread(media::VideoCaptureDevice* device, |
| 425 gfx::NativeViewId window_id, |
| 426 base::OnceClosure done_cb) { |
| 427 DCHECK(device_task_runner_->BelongsToCurrentThread()); |
| 428 #if defined(ENABLE_SCREEN_CAPTURE) && BUILDFLAG(ENABLE_WEBRTC) && \ |
| 429 !defined(OS_ANDROID) |
| 430 DesktopCaptureDevice* desktop_device = |
| 431 static_cast<DesktopCaptureDevice*>(device); |
| 432 desktop_device->SetNotificationWindowId(window_id); |
| 433 VLOG(2) << "Screen capture notification window passed on device thread."; |
| 434 #endif |
| 435 base::ResetAndReturn(&done_cb).Run(); |
| 436 } |
| 437 |
| 438 } // namespace content |
OLD | NEW |