| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 // Implementation notes: This needs to work on a variety of hardware | 5 // Implementation notes: This needs to work on a variety of hardware |
| 6 // configurations where the speed of the CPU and GPU greatly affect overall | 6 // configurations where the speed of the CPU and GPU greatly affect overall |
| 7 // performance. Spanning several threads, the process of capturing has been | 7 // performance. Spanning several threads, the process of capturing has been |
| 8 // split up into four conceptual stages: | 8 // split up into four conceptual stages: |
| 9 // | 9 // |
| 10 // 1. Reserve Buffer: Before a frame can be captured, a slot in the client's | 10 // 1. Reserve Buffer: Before a frame can be captured, a slot in the client's |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 // system is designed so that Capture and Render may run concurrently. A timing | 37 // system is designed so that Capture and Render may run concurrently. A timing |
| 38 // diagram helps illustrate this point (@30 FPS): | 38 // diagram helps illustrate this point (@30 FPS): |
| 39 // | 39 // |
| 40 // Time: 0ms 33ms 66ms 99ms | 40 // Time: 0ms 33ms 66ms 99ms |
| 41 // thread1: |-Capture-f1------v |-Capture-f2------v |-Capture-f3----v |-Capt | 41 // thread1: |-Capture-f1------v |-Capture-f2------v |-Capture-f3----v |-Capt |
| 42 // thread2: |-Render-f1-----v |-Render-f2-----v |-Render-f3 | 42 // thread2: |-Render-f1-----v |-Render-f2-----v |-Render-f3 |
| 43 // | 43 // |
| 44 // In the above example, both capturing and rendering *each* take almost the | 44 // In the above example, both capturing and rendering *each* take almost the |
| 45 // full 33 ms available between frames, yet we see that the required throughput | 45 // full 33 ms available between frames, yet we see that the required throughput |
| 46 // is obtained. | 46 // is obtained. |
| 47 // | |
| 48 // Turning on verbose logging will cause the effective frame rate to be logged | |
| 49 // at 5-second intervals. | |
| 50 | 47 |
| 51 #include "content/browser/media/capture/web_contents_video_capture_device.h" | 48 #include "content/browser/media/capture/web_contents_video_capture_device.h" |
| 52 | 49 |
| 53 #include <stdint.h> | 50 #include <stdint.h> |
| 54 | 51 |
| 55 #include <algorithm> | 52 #include <algorithm> |
| 56 #include <memory> | 53 #include <memory> |
| 57 #include <utility> | 54 #include <utility> |
| 58 | 55 |
| 59 #include "base/bind.h" | 56 #include "base/bind.h" |
| 60 #include "base/callback_helpers.h" | 57 #include "base/callback_helpers.h" |
| 61 #include "base/location.h" | 58 #include "base/location.h" |
| 62 #include "base/logging.h" | 59 #include "base/logging.h" |
| 63 #include "base/macros.h" | 60 #include "base/macros.h" |
| 64 #include "base/memory/ptr_util.h" | 61 #include "base/memory/ptr_util.h" |
| 65 #include "base/memory/weak_ptr.h" | 62 #include "base/memory/weak_ptr.h" |
| 66 #include "base/metrics/histogram_macros.h" | |
| 67 #include "base/sequenced_task_runner.h" | 63 #include "base/sequenced_task_runner.h" |
| 68 #include "base/single_thread_task_runner.h" | 64 #include "base/single_thread_task_runner.h" |
| 69 #include "base/threading/thread.h" | 65 #include "base/threading/thread.h" |
| 70 #include "base/threading/thread_checker.h" | 66 #include "base/threading/thread_checker.h" |
| 71 #include "base/time/time.h" | 67 #include "base/time/time.h" |
| 72 #include "build/build_config.h" | 68 #include "build/build_config.h" |
| 73 #include "content/browser/media/capture/cursor_renderer.h" | 69 #include "content/browser/media/capture/cursor_renderer.h" |
| 74 #include "content/browser/media/capture/web_contents_tracker.h" | 70 #include "content/browser/media/capture/web_contents_tracker.h" |
| 75 #include "content/browser/media/capture/window_activity_tracker.h" | 71 #include "content/browser/media/capture/window_activity_tracker.h" |
| 76 #include "content/browser/renderer_host/render_widget_host_impl.h" | 72 #include "content/browser/renderer_host/render_widget_host_impl.h" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 108 }; | 104 }; |
| 109 | 105 |
| 110 void DeleteOnWorkerThread(std::unique_ptr<base::Thread> render_thread, | 106 void DeleteOnWorkerThread(std::unique_ptr<base::Thread> render_thread, |
| 111 const base::Closure& callback) { | 107 const base::Closure& callback) { |
| 112 render_thread.reset(); | 108 render_thread.reset(); |
| 113 | 109 |
| 114 // After thread join call the callback on UI thread. | 110 // After thread join call the callback on UI thread. |
| 115 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | 111 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); |
| 116 } | 112 } |
| 117 | 113 |
| 118 // Responsible for logging the effective frame rate. | |
| 119 class VideoFrameDeliveryLog { | |
| 120 public: | |
| 121 VideoFrameDeliveryLog(); | |
| 122 | |
| 123 // Report that the frame posted with |frame_time| has been delivered. | |
| 124 void ChronicleFrameDelivery(base::TimeTicks frame_time); | |
| 125 | |
| 126 private: | |
| 127 // The following keep track of and log the effective frame rate whenever | |
| 128 // verbose logging is turned on. | |
| 129 base::TimeTicks last_frame_rate_log_time_; | |
| 130 int count_frames_rendered_; | |
| 131 | |
| 132 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog); | |
| 133 }; | |
| 134 | |
| 135 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible | 114 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible |
| 136 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. | 115 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. |
| 137 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { | 116 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { |
| 138 public: | 117 public: |
| 139 FrameSubscriber(media::VideoCaptureOracle::Event event_type, | 118 FrameSubscriber(media::VideoCaptureOracle::Event event_type, |
| 140 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle, | 119 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle, |
| 141 VideoFrameDeliveryLog* delivery_log, | |
| 142 base::WeakPtr<content::CursorRenderer> cursor_renderer, | 120 base::WeakPtr<content::CursorRenderer> cursor_renderer, |
| 143 base::WeakPtr<content::WindowActivityTracker> tracker) | 121 base::WeakPtr<content::WindowActivityTracker> tracker) |
| 144 : event_type_(event_type), | 122 : event_type_(event_type), |
| 145 oracle_proxy_(oracle), | 123 oracle_proxy_(oracle), |
| 146 delivery_log_(delivery_log), | |
| 147 cursor_renderer_(cursor_renderer), | 124 cursor_renderer_(cursor_renderer), |
| 148 window_activity_tracker_(tracker), | 125 window_activity_tracker_(tracker), |
| 149 weak_ptr_factory_(this) {} | 126 weak_ptr_factory_(this) {} |
| 150 | 127 |
| 151 bool ShouldCaptureFrame( | 128 bool ShouldCaptureFrame( |
| 152 const gfx::Rect& damage_rect, | 129 const gfx::Rect& damage_rect, |
| 153 base::TimeTicks present_time, | 130 base::TimeTicks present_time, |
| 154 scoped_refptr<media::VideoFrame>* storage, | 131 scoped_refptr<media::VideoFrame>* storage, |
| 155 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* | 132 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* |
| 156 deliver_frame_cb) override; | 133 deliver_frame_cb) override; |
| 157 | 134 |
| 158 static void DidCaptureFrame( | 135 static void DidCaptureFrame( |
| 159 base::WeakPtr<FrameSubscriber> frame_subscriber_, | 136 base::WeakPtr<FrameSubscriber> frame_subscriber_, |
| 160 const media::ThreadSafeCaptureOracle::CaptureFrameCallback& | 137 const media::ThreadSafeCaptureOracle::CaptureFrameCallback& |
| 161 capture_frame_cb, | 138 capture_frame_cb, |
| 162 const scoped_refptr<media::VideoFrame>& frame, | 139 const scoped_refptr<media::VideoFrame>& frame, |
| 163 base::TimeTicks timestamp, | 140 base::TimeTicks timestamp, |
| 164 const gfx::Rect& region_in_frame, | 141 const gfx::Rect& region_in_frame, |
| 165 bool success); | 142 bool success); |
| 166 | 143 |
| 167 bool IsUserInteractingWithContent(); | 144 bool IsUserInteractingWithContent(); |
| 168 | 145 |
| 169 private: | 146 private: |
| 170 const media::VideoCaptureOracle::Event event_type_; | 147 const media::VideoCaptureOracle::Event event_type_; |
| 171 scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_; | 148 scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_; |
| 172 VideoFrameDeliveryLog* const delivery_log_; | |
| 173 // We need a weak pointer since FrameSubscriber is owned externally and | 149 // We need a weak pointer since FrameSubscriber is owned externally and |
| 174 // may outlive the cursor renderer. | 150 // may outlive the cursor renderer. |
| 175 base::WeakPtr<CursorRenderer> cursor_renderer_; | 151 base::WeakPtr<CursorRenderer> cursor_renderer_; |
| 176 // We need a weak pointer since FrameSubscriber is owned externally and | 152 // We need a weak pointer since FrameSubscriber is owned externally and |
| 177 // may outlive the ui activity tracker. | 153 // may outlive the ui activity tracker. |
| 178 base::WeakPtr<WindowActivityTracker> window_activity_tracker_; | 154 base::WeakPtr<WindowActivityTracker> window_activity_tracker_; |
| 179 base::WeakPtrFactory<FrameSubscriber> weak_ptr_factory_; | 155 base::WeakPtrFactory<FrameSubscriber> weak_ptr_factory_; |
| 180 }; | 156 }; |
| 181 | 157 |
| 182 // ContentCaptureSubscription is the relationship between a RenderWidgetHost | 158 // ContentCaptureSubscription is the relationship between a RenderWidgetHost |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 214 private: | 190 private: |
| 215 // Called for active frame refresh requests, or mouse activity events. | 191 // Called for active frame refresh requests, or mouse activity events. |
| 216 void OnEvent(FrameSubscriber* subscriber); | 192 void OnEvent(FrameSubscriber* subscriber); |
| 217 | 193 |
| 218 // Maintain a weak reference to the RenderWidgetHost (via its routing ID), | 194 // Maintain a weak reference to the RenderWidgetHost (via its routing ID), |
| 219 // since the instance could be destroyed externally during the lifetime of | 195 // since the instance could be destroyed externally during the lifetime of |
| 220 // |this|. | 196 // |this|. |
| 221 const int render_process_id_; | 197 const int render_process_id_; |
| 222 const int render_widget_id_; | 198 const int render_widget_id_; |
| 223 | 199 |
| 224 VideoFrameDeliveryLog delivery_log_; | |
| 225 std::unique_ptr<FrameSubscriber> refresh_subscriber_; | 200 std::unique_ptr<FrameSubscriber> refresh_subscriber_; |
| 226 std::unique_ptr<FrameSubscriber> mouse_activity_subscriber_; | 201 std::unique_ptr<FrameSubscriber> mouse_activity_subscriber_; |
| 227 CaptureCallback capture_callback_; | 202 CaptureCallback capture_callback_; |
| 228 | 203 |
| 229 // Responsible for tracking the cursor state and input events to make | 204 // Responsible for tracking the cursor state and input events to make |
| 230 // decisions and then render the mouse cursor on the video frame after | 205 // decisions and then render the mouse cursor on the video frame after |
| 231 // capture is completed. | 206 // capture is completed. |
| 232 std::unique_ptr<content::CursorRenderer> cursor_renderer_; | 207 std::unique_ptr<content::CursorRenderer> cursor_renderer_; |
| 233 | 208 |
| 234 // Responsible for tracking the UI events and making a decision on whether | 209 // Responsible for tracking the UI events and making a decision on whether |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will | 311 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will |
| 337 // occur. Only used when this activity cannot be done on the GPU. | 312 // occur. Only used when this activity cannot be done on the GPU. |
| 338 std::unique_ptr<base::Thread> render_thread_; | 313 std::unique_ptr<base::Thread> render_thread_; |
| 339 | 314 |
| 340 // Makes all the decisions about which frames to copy, and how. | 315 // Makes all the decisions about which frames to copy, and how. |
| 341 scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_; | 316 scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_; |
| 342 | 317 |
| 343 // Video capture parameters that this machine is started with. | 318 // Video capture parameters that this machine is started with. |
| 344 media::VideoCaptureParams capture_params_; | 319 media::VideoCaptureParams capture_params_; |
| 345 | 320 |
| 346 // Last known RenderView size. | |
| 347 gfx::Size last_view_size_; | |
| 348 | |
| 349 // Responsible for forwarding events from the active RenderWidgetHost to the | 321 // Responsible for forwarding events from the active RenderWidgetHost to the |
| 350 // oracle, and initiating captures accordingly. | 322 // oracle, and initiating captures accordingly. |
| 351 std::unique_ptr<ContentCaptureSubscription> subscription_; | 323 std::unique_ptr<ContentCaptureSubscription> subscription_; |
| 352 | 324 |
| 353 // False while frame capture has been suspended. This prevents subscriptions | 325 // False while frame capture has been suspended. This prevents subscriptions |
| 354 // from being created by RenewFrameSubscription() until frame capture is | 326 // from being created by RenewFrameSubscription() until frame capture is |
| 355 // resumed. | 327 // resumed. |
| 356 bool frame_capture_active_; | 328 bool frame_capture_active_; |
| 357 | 329 |
| 358 // Weak pointer factory used to invalidate callbacks. | 330 // Weak pointer factory used to invalidate callbacks. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 372 | 344 |
| 373 media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; | 345 media::ThreadSafeCaptureOracle::CaptureFrameCallback capture_frame_cb; |
| 374 | 346 |
| 375 bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture( | 347 bool oracle_decision = oracle_proxy_->ObserveEventAndDecideCapture( |
| 376 event_type_, damage_rect, present_time, storage, &capture_frame_cb); | 348 event_type_, damage_rect, present_time, storage, &capture_frame_cb); |
| 377 | 349 |
| 378 if (!capture_frame_cb.is_null()) | 350 if (!capture_frame_cb.is_null()) |
| 379 *deliver_frame_cb = | 351 *deliver_frame_cb = |
| 380 base::Bind(&FrameSubscriber::DidCaptureFrame, | 352 base::Bind(&FrameSubscriber::DidCaptureFrame, |
| 381 weak_ptr_factory_.GetWeakPtr(), capture_frame_cb, *storage); | 353 weak_ptr_factory_.GetWeakPtr(), capture_frame_cb, *storage); |
| 382 if (oracle_decision) | |
| 383 delivery_log_->ChronicleFrameDelivery(present_time); | |
| 384 return oracle_decision; | 354 return oracle_decision; |
| 385 } | 355 } |
| 386 | 356 |
| 387 void FrameSubscriber::DidCaptureFrame( | 357 void FrameSubscriber::DidCaptureFrame( |
| 388 base::WeakPtr<FrameSubscriber> frame_subscriber_, | 358 base::WeakPtr<FrameSubscriber> frame_subscriber_, |
| 389 const media::ThreadSafeCaptureOracle::CaptureFrameCallback& | 359 const media::ThreadSafeCaptureOracle::CaptureFrameCallback& |
| 390 capture_frame_cb, | 360 capture_frame_cb, |
| 391 const scoped_refptr<media::VideoFrame>& frame, | 361 const scoped_refptr<media::VideoFrame>& frame, |
| 392 base::TimeTicks timestamp, | 362 base::TimeTicks timestamp, |
| 393 const gfx::Rect& region_in_frame, | 363 const gfx::Rect& region_in_frame, |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 432 } | 402 } |
| 433 return interactive_mode; | 403 return interactive_mode; |
| 434 } | 404 } |
| 435 | 405 |
| 436 ContentCaptureSubscription::ContentCaptureSubscription( | 406 ContentCaptureSubscription::ContentCaptureSubscription( |
| 437 const RenderWidgetHost& source, | 407 const RenderWidgetHost& source, |
| 438 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, | 408 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, |
| 439 const CaptureCallback& capture_callback) | 409 const CaptureCallback& capture_callback) |
| 440 : render_process_id_(source.GetProcess()->GetID()), | 410 : render_process_id_(source.GetProcess()->GetID()), |
| 441 render_widget_id_(source.GetRoutingID()), | 411 render_widget_id_(source.GetRoutingID()), |
| 442 delivery_log_(), | |
| 443 capture_callback_(capture_callback) { | 412 capture_callback_(capture_callback) { |
| 444 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 413 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 445 | 414 |
| 446 RenderWidgetHostView* const view = source.GetView(); | 415 RenderWidgetHostView* const view = source.GetView(); |
| 447 #if defined(USE_AURA) || defined(OS_MACOSX) | 416 #if defined(USE_AURA) || defined(OS_MACOSX) |
| 448 if (view) { | 417 if (view) { |
| 449 cursor_renderer_ = CursorRenderer::Create(view->GetNativeView()); | 418 cursor_renderer_ = CursorRenderer::Create(view->GetNativeView()); |
| 450 window_activity_tracker_ = | 419 window_activity_tracker_ = |
| 451 WindowActivityTracker::Create(view->GetNativeView()); | 420 WindowActivityTracker::Create(view->GetNativeView()); |
| 452 } | 421 } |
| 453 #endif | 422 #endif |
| 454 refresh_subscriber_.reset(new FrameSubscriber( | 423 refresh_subscriber_.reset(new FrameSubscriber( |
| 455 media::VideoCaptureOracle::kActiveRefreshRequest, oracle_proxy, | 424 media::VideoCaptureOracle::kActiveRefreshRequest, oracle_proxy, |
| 456 &delivery_log_, | |
| 457 cursor_renderer_ ? cursor_renderer_->GetWeakPtr() | 425 cursor_renderer_ ? cursor_renderer_->GetWeakPtr() |
| 458 : base::WeakPtr<CursorRenderer>(), | 426 : base::WeakPtr<CursorRenderer>(), |
| 459 window_activity_tracker_ ? window_activity_tracker_->GetWeakPtr() | 427 window_activity_tracker_ ? window_activity_tracker_->GetWeakPtr() |
| 460 : base::WeakPtr<WindowActivityTracker>())); | 428 : base::WeakPtr<WindowActivityTracker>())); |
| 461 mouse_activity_subscriber_.reset(new FrameSubscriber( | 429 mouse_activity_subscriber_.reset(new FrameSubscriber( |
| 462 media::VideoCaptureOracle::kMouseCursorUpdate, oracle_proxy, | 430 media::VideoCaptureOracle::kMouseCursorUpdate, oracle_proxy, |
| 463 &delivery_log_, cursor_renderer_ ? cursor_renderer_->GetWeakPtr() | 431 cursor_renderer_ ? cursor_renderer_->GetWeakPtr() |
| 464 : base::WeakPtr<CursorRenderer>(), | 432 : base::WeakPtr<CursorRenderer>(), |
| 465 window_activity_tracker_ ? window_activity_tracker_->GetWeakPtr() | 433 window_activity_tracker_ ? window_activity_tracker_->GetWeakPtr() |
| 466 : base::WeakPtr<WindowActivityTracker>())); | 434 : base::WeakPtr<WindowActivityTracker>())); |
| 467 | 435 |
| 468 // Subscribe to compositor updates. These will be serviced directly by the | 436 // Subscribe to compositor updates. These will be serviced directly by the |
| 469 // oracle. | 437 // oracle. |
| 470 if (view) { | 438 if (view) { |
| 471 std::unique_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( | 439 std::unique_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( |
| 472 new FrameSubscriber( | 440 new FrameSubscriber( |
| 473 media::VideoCaptureOracle::kCompositorUpdate, oracle_proxy, | 441 media::VideoCaptureOracle::kCompositorUpdate, oracle_proxy, |
| 474 &delivery_log_, cursor_renderer_ ? cursor_renderer_->GetWeakPtr() | 442 cursor_renderer_ ? cursor_renderer_->GetWeakPtr() |
| 475 : base::WeakPtr<CursorRenderer>(), | 443 : base::WeakPtr<CursorRenderer>(), |
| 476 window_activity_tracker_ ? window_activity_tracker_->GetWeakPtr() | 444 window_activity_tracker_ ? window_activity_tracker_->GetWeakPtr() |
| 477 : base::WeakPtr<WindowActivityTracker>())); | 445 : base::WeakPtr<WindowActivityTracker>())); |
| 478 view->BeginFrameSubscription(std::move(subscriber)); | 446 view->BeginFrameSubscription(std::move(subscriber)); |
| 479 } | 447 } |
| 480 | 448 |
| 481 // Subscribe to mouse movement and mouse cursor update events. | 449 // Subscribe to mouse movement and mouse cursor update events. |
| 482 if (window_activity_tracker_) { | 450 if (window_activity_tracker_) { |
| 483 window_activity_tracker_->RegisterMouseInteractionObserver( | 451 window_activity_tracker_->RegisterMouseInteractionObserver( |
| 484 base::Bind(&ContentCaptureSubscription::OnEvent, base::Unretained(this), | 452 base::Bind(&ContentCaptureSubscription::OnEvent, base::Unretained(this), |
| 485 mouse_activity_subscriber_.get())); | 453 mouse_activity_subscriber_.get())); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 588 media::CopyRGBToVideoFrame( | 556 media::CopyRGBToVideoFrame( |
| 589 reinterpret_cast<uint8_t*>(scaled_bitmap.getPixels()), | 557 reinterpret_cast<uint8_t*>(scaled_bitmap.getPixels()), |
| 590 scaled_bitmap.rowBytes(), region_in_yv12_frame, output.get()); | 558 scaled_bitmap.rowBytes(), region_in_yv12_frame, output.get()); |
| 591 } | 559 } |
| 592 | 560 |
| 593 // The result is now ready. | 561 // The result is now ready. |
| 594 ignore_result(failure_handler.Release()); | 562 ignore_result(failure_handler.Release()); |
| 595 done_cb.Run(region_in_frame, true); | 563 done_cb.Run(region_in_frame, true); |
| 596 } | 564 } |
| 597 | 565 |
| 598 VideoFrameDeliveryLog::VideoFrameDeliveryLog() | |
| 599 : last_frame_rate_log_time_(), count_frames_rendered_(0) {} | |
| 600 | |
| 601 void VideoFrameDeliveryLog::ChronicleFrameDelivery(base::TimeTicks frame_time) { | |
| 602 // Log frame rate, if verbose logging is turned on. | |
| 603 static const base::TimeDelta kFrameRateLogInterval = | |
| 604 base::TimeDelta::FromSeconds(10); | |
| 605 if (last_frame_rate_log_time_.is_null()) { | |
| 606 last_frame_rate_log_time_ = frame_time; | |
| 607 count_frames_rendered_ = 0; | |
| 608 } else { | |
| 609 ++count_frames_rendered_; | |
| 610 const base::TimeDelta elapsed = frame_time - last_frame_rate_log_time_; | |
| 611 if (elapsed >= kFrameRateLogInterval) { | |
| 612 const double measured_fps = count_frames_rendered_ / elapsed.InSecondsF(); | |
| 613 UMA_HISTOGRAM_COUNTS("TabCapture.FrameRate", | |
| 614 static_cast<int>(measured_fps)); | |
| 615 VLOG(1) << "Current measured frame rate for " | |
| 616 << "WebContentsVideoCaptureDevice is " << measured_fps << " FPS."; | |
| 617 last_frame_rate_log_time_ = frame_time; | |
| 618 count_frames_rendered_ = 0; | |
| 619 } | |
| 620 } | |
| 621 } | |
| 622 | |
| 623 WebContentsCaptureMachine::WebContentsCaptureMachine( | 566 WebContentsCaptureMachine::WebContentsCaptureMachine( |
| 624 int render_process_id, | 567 int render_process_id, |
| 625 int main_render_frame_id, | 568 int main_render_frame_id, |
| 626 bool enable_auto_throttling) | 569 bool enable_auto_throttling) |
| 627 : initial_render_process_id_(render_process_id), | 570 : initial_render_process_id_(render_process_id), |
| 628 initial_main_render_frame_id_(main_render_frame_id), | 571 initial_main_render_frame_id_(main_render_frame_id), |
| 629 tracker_(new WebContentsTracker(true)), | 572 tracker_(new WebContentsTracker(true)), |
| 630 auto_throttling_enabled_(enable_auto_throttling), | 573 auto_throttling_enabled_(enable_auto_throttling), |
| 631 frame_capture_active_(true), | 574 frame_capture_active_(true), |
| 632 weak_ptr_factory_(this) { | 575 weak_ptr_factory_(this) { |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 772 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 715 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 773 | 716 |
| 774 RenderWidgetHost* rwh = tracker_->GetTargetRenderWidgetHost(); | 717 RenderWidgetHost* rwh = tracker_->GetTargetRenderWidgetHost(); |
| 775 RenderWidgetHostViewBase* view = | 718 RenderWidgetHostViewBase* view = |
| 776 rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL; | 719 rwh ? static_cast<RenderWidgetHostViewBase*>(rwh->GetView()) : NULL; |
| 777 if (!view) { | 720 if (!view) { |
| 778 deliver_frame_cb.Run(base::TimeTicks(), gfx::Rect(), false); | 721 deliver_frame_cb.Run(base::TimeTicks(), gfx::Rect(), false); |
| 779 return; | 722 return; |
| 780 } | 723 } |
| 781 | 724 |
| 782 gfx::Size view_size = view->GetViewBounds().size(); | 725 const gfx::Size view_size = view->GetViewBounds().size(); |
| 783 if (view_size != last_view_size_) { | |
| 784 last_view_size_ = view_size; | |
| 785 | |
| 786 // Measure the number of kilopixels. | |
| 787 UMA_HISTOGRAM_COUNTS_10000("TabCapture.ViewChangeKiloPixels", | |
| 788 view_size.width() * view_size.height() / 1024); | |
| 789 } | |
| 790 | |
| 791 if (view->CanCopyToVideoFrame()) { | 726 if (view->CanCopyToVideoFrame()) { |
| 792 view->CopyFromCompositingSurfaceToVideoFrame( | 727 view->CopyFromCompositingSurfaceToVideoFrame( |
| 793 gfx::Rect(view_size), target, | 728 gfx::Rect(view_size), target, |
| 794 base::Bind(&WebContentsCaptureMachine:: | 729 base::Bind(&WebContentsCaptureMachine:: |
| 795 DidCopyFromCompositingSurfaceToVideoFrame, | 730 DidCopyFromCompositingSurfaceToVideoFrame, |
| 796 weak_ptr_factory_.GetWeakPtr(), start_time, | 731 weak_ptr_factory_.GetWeakPtr(), start_time, |
| 797 deliver_frame_cb)); | 732 deliver_frame_cb)); |
| 798 } else { | 733 } else { |
| 799 const gfx::Size fitted_size = | 734 const gfx::Size fitted_size = |
| 800 view_size.IsEmpty() | 735 view_size.IsEmpty() |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 879 | 814 |
| 880 void WebContentsCaptureMachine::DidCopyFromBackingStore( | 815 void WebContentsCaptureMachine::DidCopyFromBackingStore( |
| 881 const base::TimeTicks& start_time, | 816 const base::TimeTicks& start_time, |
| 882 const scoped_refptr<media::VideoFrame>& target, | 817 const scoped_refptr<media::VideoFrame>& target, |
| 883 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& | 818 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
| 884 deliver_frame_cb, | 819 deliver_frame_cb, |
| 885 const SkBitmap& bitmap, | 820 const SkBitmap& bitmap, |
| 886 ReadbackResponse response) { | 821 ReadbackResponse response) { |
| 887 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 822 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 888 | 823 |
| 889 base::TimeTicks now = base::TimeTicks::Now(); | |
| 890 DCHECK(render_thread_); | 824 DCHECK(render_thread_); |
| 891 if (response == READBACK_SUCCESS) { | 825 if (response == READBACK_SUCCESS) { |
| 892 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); | |
| 893 TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", target.get(), | 826 TRACE_EVENT_ASYNC_STEP_INTO0("gpu.capture", "Capture", target.get(), |
| 894 "Render"); | 827 "Render"); |
| 895 render_thread_->task_runner()->PostTask( | 828 render_thread_->task_runner()->PostTask( |
| 896 FROM_HERE, media::BindToCurrentLoop( | 829 FROM_HERE, media::BindToCurrentLoop( |
| 897 base::Bind(&RenderVideoFrame, bitmap, target, | 830 base::Bind(&RenderVideoFrame, bitmap, target, |
| 898 base::Bind(deliver_frame_cb, start_time)))); | 831 base::Bind(deliver_frame_cb, start_time)))); |
| 899 } else { | 832 } else { |
| 900 // Capture can fail due to transient issues, so just skip this frame. | 833 // Capture can fail due to transient issues, so just skip this frame. |
| 901 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; | 834 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; |
| 902 deliver_frame_cb.Run(start_time, gfx::Rect(), false); | 835 deliver_frame_cb.Run(start_time, gfx::Rect(), false); |
| 903 } | 836 } |
| 904 } | 837 } |
| 905 | 838 |
| 906 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( | 839 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( |
| 907 const base::TimeTicks& start_time, | 840 const base::TimeTicks& start_time, |
| 908 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& | 841 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& |
| 909 deliver_frame_cb, | 842 deliver_frame_cb, |
| 910 const gfx::Rect& region_in_frame, | 843 const gfx::Rect& region_in_frame, |
| 911 bool success) { | 844 bool success) { |
| 912 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 845 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 913 base::TimeTicks now = base::TimeTicks::Now(); | |
| 914 | 846 |
| 915 if (success) { | 847 // Capture can fail due to transient issues, so just skip this frame. |
| 916 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeVideoFrame", now - start_time); | 848 DVLOG_IF(1, !success) << "CopyFromCompositingSurface failed; skipping frame."; |
| 917 } else { | |
| 918 // Capture can fail due to transient issues, so just skip this frame. | |
| 919 DVLOG(1) << "CopyFromCompositingSurface failed; skipping frame."; | |
| 920 } | |
| 921 deliver_frame_cb.Run(start_time, region_in_frame, success); | 849 deliver_frame_cb.Run(start_time, region_in_frame, success); |
| 922 } | 850 } |
| 923 | 851 |
| 924 void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) { | 852 void WebContentsCaptureMachine::RenewFrameSubscription(bool had_target) { |
| 925 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 853 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 926 | 854 |
| 927 RenderWidgetHost* const rwh = | 855 RenderWidgetHost* const rwh = |
| 928 had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr; | 856 had_target ? tracker_->GetTargetRenderWidgetHost() : nullptr; |
| 929 | 857 |
| 930 // Always destroy the old subscription before creating a new one. | 858 // Always destroy the old subscription before creating a new one. |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1023 | 951 |
| 1024 void WebContentsVideoCaptureDevice::Resume() { | 952 void WebContentsVideoCaptureDevice::Resume() { |
| 1025 core_->Resume(); | 953 core_->Resume(); |
| 1026 } | 954 } |
| 1027 | 955 |
| 1028 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { | 956 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { |
| 1029 core_->StopAndDeAllocate(); | 957 core_->StopAndDeAllocate(); |
| 1030 } | 958 } |
| 1031 | 959 |
| 1032 } // namespace content | 960 } // namespace content |
| OLD | NEW |