OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/media/capture/desktop_capture_device_aura.h" | 5 #include "content/browser/media/capture/desktop_capture_device_aura.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/metrics/histogram.h" |
8 #include "base/timer/timer.h" | 9 #include "base/timer/timer.h" |
9 #include "cc/output/copy_output_request.h" | 10 #include "cc/output/copy_output_request.h" |
10 #include "cc/output/copy_output_result.h" | 11 #include "cc/output/copy_output_result.h" |
11 #include "content/browser/compositor/image_transport_factory.h" | 12 #include "content/browser/compositor/image_transport_factory.h" |
12 #include "content/browser/media/capture/content_video_capture_device_core.h" | 13 #include "content/browser/media/capture/content_video_capture_device_core.h" |
| 14 #include "content/browser/media/capture/desktop_capture_device_uma_types.h" |
13 #include "content/common/gpu/client/gl_helper.h" | 15 #include "content/common/gpu/client/gl_helper.h" |
14 #include "content/public/browser/browser_thread.h" | 16 #include "content/public/browser/browser_thread.h" |
15 #include "media/base/video_util.h" | 17 #include "media/base/video_util.h" |
16 #include "media/video/capture/video_capture_types.h" | 18 #include "media/video/capture/video_capture_types.h" |
17 #include "skia/ext/image_operations.h" | 19 #include "skia/ext/image_operations.h" |
18 #include "third_party/skia/include/core/SkBitmap.h" | 20 #include "third_party/skia/include/core/SkBitmap.h" |
19 #include "ui/aura/env.h" | 21 #include "ui/aura/env.h" |
20 #include "ui/aura/window.h" | 22 #include "ui/aura/window.h" |
21 #include "ui/aura/window_observer.h" | 23 #include "ui/aura/window_observer.h" |
22 #include "ui/aura/window_tree_host.h" | 24 #include "ui/aura/window_tree_host.h" |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 // Update capture size. Must be called on the UI thread. | 124 // Update capture size. Must be called on the UI thread. |
123 void UpdateCaptureSize(); | 125 void UpdateCaptureSize(); |
124 | 126 |
125 // Response callback for cc::Layer::RequestCopyOfOutput(). | 127 // Response callback for cc::Layer::RequestCopyOfOutput(). |
126 void DidCopyOutput( | 128 void DidCopyOutput( |
127 scoped_refptr<media::VideoFrame> video_frame, | 129 scoped_refptr<media::VideoFrame> video_frame, |
128 base::TimeTicks start_time, | 130 base::TimeTicks start_time, |
129 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, | 131 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, |
130 scoped_ptr<cc::CopyOutputResult> result); | 132 scoped_ptr<cc::CopyOutputResult> result); |
131 | 133 |
| 134 // A helper which does the real work for DidCopyOutput. Returns true if |
| 135 // succeeded. |
| 136 bool ProcessCopyOutputResponse( |
| 137 scoped_refptr<media::VideoFrame> video_frame, |
| 138 base::TimeTicks start_time, |
| 139 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, |
| 140 scoped_ptr<cc::CopyOutputResult> result); |
| 141 |
132 // Helper function to update cursor state. | 142 // Helper function to update cursor state. |
133 // |region_in_frame| defines the desktop bound in the captured frame. | 143 // |region_in_frame| defines the desktop bound in the captured frame. |
134 // Returns the current cursor position in captured frame. | 144 // Returns the current cursor position in captured frame. |
135 gfx::Point UpdateCursorState(const gfx::Rect& region_in_frame); | 145 gfx::Point UpdateCursorState(const gfx::Rect& region_in_frame); |
136 | 146 |
137 // Clears cursor state. | 147 // Clears cursor state. |
138 void ClearCursorState(); | 148 void ClearCursorState(); |
139 | 149 |
140 // The window associated with the desktop. | 150 // The window associated with the desktop. |
141 aura::Window* desktop_window_; | 151 aura::Window* desktop_window_; |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
285 RenderCursorOnVideoFrame(target, cursor_bitmap, cursor_position); | 295 RenderCursorOnVideoFrame(target, cursor_bitmap, cursor_position); |
286 release_callback->Run(0, false); | 296 release_callback->Run(0, false); |
287 capture_frame_cb.Run(start_time, result); | 297 capture_frame_cb.Run(start_time, result); |
288 } | 298 } |
289 | 299 |
290 void DesktopVideoCaptureMachine::DidCopyOutput( | 300 void DesktopVideoCaptureMachine::DidCopyOutput( |
291 scoped_refptr<media::VideoFrame> video_frame, | 301 scoped_refptr<media::VideoFrame> video_frame, |
292 base::TimeTicks start_time, | 302 base::TimeTicks start_time, |
293 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, | 303 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, |
294 scoped_ptr<cc::CopyOutputResult> result) { | 304 scoped_ptr<cc::CopyOutputResult> result) { |
| 305 static bool first_call = true; |
| 306 |
| 307 bool succeeded = ProcessCopyOutputResponse( |
| 308 video_frame, start_time, capture_frame_cb, result.Pass()); |
| 309 |
| 310 base::TimeDelta capture_time = base::TimeTicks::Now() - start_time; |
| 311 UMA_HISTOGRAM_TIMES( |
| 312 window_id_.type == DesktopMediaID::TYPE_SCREEN ? kUmaScreenCaptureTime |
| 313 : kUmaWindowCaptureTime, |
| 314 capture_time); |
| 315 |
| 316 if (first_call) { |
| 317 first_call = false; |
| 318 if (window_id_.type == DesktopMediaID::TYPE_SCREEN) { |
| 319 IncrementDesktopCaptureCounter(succeeded ? FIRST_SCREEN_CAPTURE_SUCCEEDED |
| 320 : FIRST_SCREEN_CAPTURE_FAILED); |
| 321 } else { |
| 322 IncrementDesktopCaptureCounter(succeeded |
| 323 ? FIRST_WINDOW_CAPTURE_SUCCEEDED |
| 324 : FIRST_WINDOW_CAPTURE_SUCCEEDED); |
| 325 } |
| 326 } |
| 327 } |
| 328 |
| 329 bool DesktopVideoCaptureMachine::ProcessCopyOutputResponse( |
| 330 scoped_refptr<media::VideoFrame> video_frame, |
| 331 base::TimeTicks start_time, |
| 332 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, |
| 333 scoped_ptr<cc::CopyOutputResult> result) { |
295 if (result->IsEmpty() || result->size().IsEmpty() || !desktop_layer_) | 334 if (result->IsEmpty() || result->size().IsEmpty() || !desktop_layer_) |
296 return; | 335 return false; |
297 | 336 |
298 // Compute the dest size we want after the letterboxing resize. Make the | 337 // Compute the dest size we want after the letterboxing resize. Make the |
299 // coordinates and sizes even because we letterbox in YUV space | 338 // coordinates and sizes even because we letterbox in YUV space |
300 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to | 339 // (see CopyRGBToVideoFrame). They need to be even for the UV samples to |
301 // line up correctly. | 340 // line up correctly. |
302 // The video frame's coded_size() and the result's size() are both physical | 341 // The video frame's coded_size() and the result's size() are both physical |
303 // pixels. | 342 // pixels. |
304 gfx::Rect region_in_frame = | 343 gfx::Rect region_in_frame = |
305 media::ComputeLetterboxRegion(gfx::Rect(video_frame->coded_size()), | 344 media::ComputeLetterboxRegion(gfx::Rect(video_frame->coded_size()), |
306 result->size()); | 345 result->size()); |
307 region_in_frame = gfx::Rect(region_in_frame.x() & ~1, | 346 region_in_frame = gfx::Rect(region_in_frame.x() & ~1, |
308 region_in_frame.y() & ~1, | 347 region_in_frame.y() & ~1, |
309 region_in_frame.width() & ~1, | 348 region_in_frame.width() & ~1, |
310 region_in_frame.height() & ~1); | 349 region_in_frame.height() & ~1); |
311 if (region_in_frame.IsEmpty()) | 350 if (region_in_frame.IsEmpty()) |
312 return; | 351 return false; |
313 | 352 |
314 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); | 353 ImageTransportFactory* factory = ImageTransportFactory::GetInstance(); |
315 GLHelper* gl_helper = factory->GetGLHelper(); | 354 GLHelper* gl_helper = factory->GetGLHelper(); |
316 if (!gl_helper) | 355 if (!gl_helper) |
317 return; | 356 return false; |
318 | 357 |
319 cc::TextureMailbox texture_mailbox; | 358 cc::TextureMailbox texture_mailbox; |
320 scoped_ptr<cc::SingleReleaseCallback> release_callback; | 359 scoped_ptr<cc::SingleReleaseCallback> release_callback; |
321 result->TakeTexture(&texture_mailbox, &release_callback); | 360 result->TakeTexture(&texture_mailbox, &release_callback); |
322 DCHECK(texture_mailbox.IsTexture()); | 361 DCHECK(texture_mailbox.IsTexture()); |
323 if (!texture_mailbox.IsTexture()) | 362 if (!texture_mailbox.IsTexture()) |
324 return; | 363 return false; |
325 | 364 |
326 gfx::Rect result_rect(result->size()); | 365 gfx::Rect result_rect(result->size()); |
327 if (!yuv_readback_pipeline_ || | 366 if (!yuv_readback_pipeline_ || |
328 yuv_readback_pipeline_->scaler()->SrcSize() != result_rect.size() || | 367 yuv_readback_pipeline_->scaler()->SrcSize() != result_rect.size() || |
329 yuv_readback_pipeline_->scaler()->SrcSubrect() != result_rect || | 368 yuv_readback_pipeline_->scaler()->SrcSubrect() != result_rect || |
330 yuv_readback_pipeline_->scaler()->DstSize() != region_in_frame.size()) { | 369 yuv_readback_pipeline_->scaler()->DstSize() != region_in_frame.size()) { |
331 yuv_readback_pipeline_.reset( | 370 yuv_readback_pipeline_.reset( |
332 gl_helper->CreateReadbackPipelineYUV(GLHelper::SCALER_QUALITY_FAST, | 371 gl_helper->CreateReadbackPipelineYUV(GLHelper::SCALER_QUALITY_FAST, |
333 result_rect.size(), | 372 result_rect.size(), |
334 result_rect, | 373 result_rect, |
335 video_frame->coded_size(), | 374 video_frame->coded_size(), |
336 region_in_frame, | 375 region_in_frame, |
337 true, | 376 true, |
338 true)); | 377 true)); |
339 } | 378 } |
340 | 379 |
341 gfx::Point cursor_position_in_frame = UpdateCursorState(region_in_frame); | 380 gfx::Point cursor_position_in_frame = UpdateCursorState(region_in_frame); |
342 yuv_readback_pipeline_->ReadbackYUV( | 381 yuv_readback_pipeline_->ReadbackYUV( |
343 texture_mailbox.mailbox(), | 382 texture_mailbox.mailbox(), |
344 texture_mailbox.sync_point(), | 383 texture_mailbox.sync_point(), |
345 video_frame.get(), | 384 video_frame.get(), |
346 base::Bind(&CopyOutputFinishedForVideo, | 385 base::Bind(&CopyOutputFinishedForVideo, |
347 start_time, | 386 start_time, |
348 capture_frame_cb, | 387 capture_frame_cb, |
349 video_frame, | 388 video_frame, |
350 scaled_cursor_bitmap_, | 389 scaled_cursor_bitmap_, |
351 cursor_position_in_frame, | 390 cursor_position_in_frame, |
352 base::Passed(&release_callback))); | 391 base::Passed(&release_callback))); |
| 392 return true; |
353 } | 393 } |
354 | 394 |
355 gfx::Point DesktopVideoCaptureMachine::UpdateCursorState( | 395 gfx::Point DesktopVideoCaptureMachine::UpdateCursorState( |
356 const gfx::Rect& region_in_frame) { | 396 const gfx::Rect& region_in_frame) { |
357 const gfx::Rect desktop_bounds = desktop_layer_->bounds(); | 397 const gfx::Rect desktop_bounds = desktop_layer_->bounds(); |
358 gfx::NativeCursor cursor = | 398 gfx::NativeCursor cursor = |
359 desktop_window_->GetHost()->last_cursor(); | 399 desktop_window_->GetHost()->last_cursor(); |
360 if (last_cursor_ != cursor) { | 400 if (last_cursor_ != cursor) { |
361 SkBitmap cursor_bitmap; | 401 SkBitmap cursor_bitmap; |
362 if (ui::GetCursorBitmap(cursor, &cursor_bitmap, &cursor_hot_point_)) { | 402 if (ui::GetCursorBitmap(cursor, &cursor_bitmap, &cursor_hot_point_)) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 : core_(new ContentVideoCaptureDeviceCore(scoped_ptr<VideoCaptureMachine>( | 465 : core_(new ContentVideoCaptureDeviceCore(scoped_ptr<VideoCaptureMachine>( |
426 new DesktopVideoCaptureMachine(source)))) {} | 466 new DesktopVideoCaptureMachine(source)))) {} |
427 | 467 |
428 DesktopCaptureDeviceAura::~DesktopCaptureDeviceAura() { | 468 DesktopCaptureDeviceAura::~DesktopCaptureDeviceAura() { |
429 DVLOG(2) << "DesktopCaptureDeviceAura@" << this << " destroying."; | 469 DVLOG(2) << "DesktopCaptureDeviceAura@" << this << " destroying."; |
430 } | 470 } |
431 | 471 |
432 // static | 472 // static |
433 media::VideoCaptureDevice* DesktopCaptureDeviceAura::Create( | 473 media::VideoCaptureDevice* DesktopCaptureDeviceAura::Create( |
434 const DesktopMediaID& source) { | 474 const DesktopMediaID& source) { |
| 475 IncrementDesktopCaptureCounter(source.type == DesktopMediaID::TYPE_SCREEN |
| 476 ? SCREEN_CAPTURER_CREATED |
| 477 : WINDOW_CATPTURER_CREATED); |
435 return new DesktopCaptureDeviceAura(source); | 478 return new DesktopCaptureDeviceAura(source); |
436 } | 479 } |
437 | 480 |
438 void DesktopCaptureDeviceAura::AllocateAndStart( | 481 void DesktopCaptureDeviceAura::AllocateAndStart( |
439 const media::VideoCaptureParams& params, | 482 const media::VideoCaptureParams& params, |
440 scoped_ptr<Client> client) { | 483 scoped_ptr<Client> client) { |
441 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); | 484 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); |
442 core_->AllocateAndStart(params, client.Pass()); | 485 core_->AllocateAndStart(params, client.Pass()); |
443 } | 486 } |
444 | 487 |
445 void DesktopCaptureDeviceAura::StopAndDeAllocate() { | 488 void DesktopCaptureDeviceAura::StopAndDeAllocate() { |
446 core_->StopAndDeAllocate(); | 489 core_->StopAndDeAllocate(); |
447 } | 490 } |
448 | 491 |
449 } // namespace content | 492 } // namespace content |
OLD | NEW |