Chromium Code Reviews| 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 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 59 #include "base/logging.h" | 59 #include "base/logging.h" |
| 60 #include "base/memory/scoped_ptr.h" | 60 #include "base/memory/scoped_ptr.h" |
| 61 #include "base/memory/weak_ptr.h" | 61 #include "base/memory/weak_ptr.h" |
| 62 #include "base/metrics/histogram.h" | 62 #include "base/metrics/histogram.h" |
| 63 #include "base/sequenced_task_runner.h" | 63 #include "base/sequenced_task_runner.h" |
| 64 #include "base/single_thread_task_runner.h" | 64 #include "base/single_thread_task_runner.h" |
| 65 #include "base/threading/thread.h" | 65 #include "base/threading/thread.h" |
| 66 #include "base/threading/thread_checker.h" | 66 #include "base/threading/thread_checker.h" |
| 67 #include "base/time/time.h" | 67 #include "base/time/time.h" |
| 68 #include "content/browser/media/capture/cursor_renderer.h" | 68 #include "content/browser/media/capture/cursor_renderer.h" |
| 69 #include "content/browser/media/capture/ui_activity_tracker.h" | |
| 69 #include "content/browser/media/capture/web_contents_capture_util.h" | 70 #include "content/browser/media/capture/web_contents_capture_util.h" |
| 70 #include "content/browser/media/capture/web_contents_tracker.h" | 71 #include "content/browser/media/capture/web_contents_tracker.h" |
| 71 #include "content/browser/renderer_host/render_widget_host_impl.h" | 72 #include "content/browser/renderer_host/render_widget_host_impl.h" |
| 72 #include "content/browser/renderer_host/render_widget_host_view_base.h" | 73 #include "content/browser/renderer_host/render_widget_host_view_base.h" |
| 73 #include "content/public/browser/browser_thread.h" | 74 #include "content/public/browser/browser_thread.h" |
| 74 #include "content/public/browser/render_process_host.h" | 75 #include "content/public/browser/render_process_host.h" |
| 75 #include "content/public/browser/render_widget_host_view.h" | 76 #include "content/public/browser/render_widget_host_view.h" |
| 76 #include "content/public/browser/render_widget_host_view_frame_subscriber.h" | 77 #include "content/public/browser/render_widget_host_view_frame_subscriber.h" |
| 77 #include "content/public/browser/web_contents.h" | 78 #include "content/public/browser/web_contents.h" |
| 78 #include "media/base/bind_to_current_loop.h" | 79 #include "media/base/bind_to_current_loop.h" |
| 79 #include "media/base/video_capture_types.h" | 80 #include "media/base/video_capture_types.h" |
| 81 #include "media/base/video_frame_metadata.h" | |
| 80 #include "media/base/video_util.h" | 82 #include "media/base/video_util.h" |
| 81 #include "media/capture/content/screen_capture_device_core.h" | 83 #include "media/capture/content/screen_capture_device_core.h" |
| 82 #include "media/capture/content/thread_safe_capture_oracle.h" | 84 #include "media/capture/content/thread_safe_capture_oracle.h" |
| 83 #include "media/capture/content/video_capture_oracle.h" | 85 #include "media/capture/content/video_capture_oracle.h" |
| 84 #include "skia/ext/image_operations.h" | 86 #include "skia/ext/image_operations.h" |
| 85 #include "third_party/skia/include/core/SkBitmap.h" | 87 #include "third_party/skia/include/core/SkBitmap.h" |
| 86 #include "third_party/skia/include/core/SkColor.h" | 88 #include "third_party/skia/include/core/SkColor.h" |
| 87 #include "ui/base/layout.h" | 89 #include "ui/base/layout.h" |
| 88 #include "ui/gfx/geometry/dip_util.h" | 90 #include "ui/gfx/geometry/dip_util.h" |
| 89 #include "ui/gfx/geometry/size_conversions.h" | 91 #include "ui/gfx/geometry/size_conversions.h" |
| 90 | 92 |
| 91 #if defined(USE_AURA) | 93 #if defined(USE_AURA) |
| 92 #include "content/browser/media/capture/cursor_renderer_aura.h" | 94 #include "content/browser/media/capture/cursor_renderer_aura.h" |
| 95 #include "content/browser/media/capture/ui_activity_tracker_aura.h" | |
| 93 #endif | 96 #endif |
| 94 | 97 |
| 95 namespace content { | 98 namespace content { |
| 96 | 99 |
| 97 namespace { | 100 namespace { |
| 98 | 101 |
| 102 enum InteractiveModeSettings { | |
| 103 // Minimum amount of time for which there should be no animation detected | |
| 104 // to consider interactive mode being active. This is to prevent very brief | |
| 105 // periods of animated content not being detected (due to CPU fluctations for | |
| 106 // example) from causing a flip-flop on interactive mode. | |
| 107 kMinPeriodNoAnimationMillis = 3000 | |
| 108 }; | |
| 109 | |
| 99 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread, | 110 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread, |
| 100 const base::Closure& callback) { | 111 const base::Closure& callback) { |
| 101 render_thread.reset(); | 112 render_thread.reset(); |
| 102 | 113 |
| 103 // After thread join call the callback on UI thread. | 114 // After thread join call the callback on UI thread. |
| 104 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); | 115 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback); |
| 105 } | 116 } |
| 106 | 117 |
| 107 // Responsible for logging the effective frame rate. | 118 // Responsible for logging the effective frame rate. |
| 108 class VideoFrameDeliveryLog { | 119 class VideoFrameDeliveryLog { |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 121 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog); | 132 DISALLOW_COPY_AND_ASSIGN(VideoFrameDeliveryLog); |
| 122 }; | 133 }; |
| 123 | 134 |
| 124 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible | 135 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible |
| 125 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. | 136 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. |
| 126 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { | 137 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { |
| 127 public: | 138 public: |
| 128 FrameSubscriber(media::VideoCaptureOracle::Event event_type, | 139 FrameSubscriber(media::VideoCaptureOracle::Event event_type, |
| 129 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle, | 140 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle, |
| 130 VideoFrameDeliveryLog* delivery_log, | 141 VideoFrameDeliveryLog* delivery_log, |
| 131 base::WeakPtr<content::CursorRenderer> cursor_renderer) | 142 base::WeakPtr<content::CursorRenderer> cursor_renderer, |
| 143 base::WeakPtr<content::UiActivityTracker> ui_activity_tracker) | |
| 132 : event_type_(event_type), | 144 : event_type_(event_type), |
| 133 oracle_proxy_(oracle), | 145 oracle_proxy_(oracle), |
| 134 delivery_log_(delivery_log), | 146 delivery_log_(delivery_log), |
| 135 cursor_renderer_(cursor_renderer), | 147 cursor_renderer_(cursor_renderer), |
| 148 ui_activity_tracker_(ui_activity_tracker), | |
| 136 weak_ptr_factory_(this) {} | 149 weak_ptr_factory_(this) {} |
| 137 | 150 |
| 138 bool ShouldCaptureFrame( | 151 bool ShouldCaptureFrame( |
| 139 const gfx::Rect& damage_rect, | 152 const gfx::Rect& damage_rect, |
| 140 base::TimeTicks present_time, | 153 base::TimeTicks present_time, |
| 141 scoped_refptr<media::VideoFrame>* storage, | 154 scoped_refptr<media::VideoFrame>* storage, |
| 142 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* | 155 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback* |
| 143 deliver_frame_cb) override; | 156 deliver_frame_cb) override; |
| 144 | 157 |
| 145 static void DidCaptureFrame( | 158 static void DidCaptureFrame( |
| 146 base::WeakPtr<FrameSubscriber> frame_subscriber_, | 159 base::WeakPtr<FrameSubscriber> frame_subscriber_, |
| 147 const media::ThreadSafeCaptureOracle::CaptureFrameCallback& | 160 const media::ThreadSafeCaptureOracle::CaptureFrameCallback& |
| 148 capture_frame_cb, | 161 capture_frame_cb, |
| 149 const scoped_refptr<media::VideoFrame>& frame, | 162 const scoped_refptr<media::VideoFrame>& frame, |
| 150 base::TimeTicks timestamp, | 163 base::TimeTicks timestamp, |
| 151 const gfx::Rect& region_in_frame, | 164 const gfx::Rect& region_in_frame, |
| 152 bool success); | 165 bool success); |
| 153 | 166 |
| 167 bool IsInteractiveModeActive(); | |
| 168 | |
| 154 private: | 169 private: |
| 155 const media::VideoCaptureOracle::Event event_type_; | 170 const media::VideoCaptureOracle::Event event_type_; |
| 156 scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_; | 171 scoped_refptr<media::ThreadSafeCaptureOracle> oracle_proxy_; |
| 157 VideoFrameDeliveryLog* const delivery_log_; | 172 VideoFrameDeliveryLog* const delivery_log_; |
| 158 // We need a weak pointer since FrameSubscriber is owned externally and | 173 // We need a weak pointer since FrameSubscriber is owned externally and |
| 159 // may outlive the cursor renderer. | 174 // may outlive the cursor renderer. |
| 160 base::WeakPtr<CursorRenderer> cursor_renderer_; | 175 base::WeakPtr<CursorRenderer> cursor_renderer_; |
| 176 // We need a weak pointer since FrameSubscriber is owned externally and | |
| 177 // may outlive the ui activity tracker. | |
| 178 base::WeakPtr<UiActivityTracker> ui_activity_tracker_; | |
| 161 base::WeakPtrFactory<FrameSubscriber> weak_ptr_factory_; | 179 base::WeakPtrFactory<FrameSubscriber> weak_ptr_factory_; |
| 162 }; | 180 }; |
| 163 | 181 |
| 164 // ContentCaptureSubscription is the relationship between a RenderWidgetHost | 182 // ContentCaptureSubscription is the relationship between a RenderWidgetHost |
| 165 // whose content is updating, a subscriber that is deciding which of these | 183 // whose content is updating, a subscriber that is deciding which of these |
| 166 // updates to capture (and where to deliver them to), and a callback that | 184 // updates to capture (and where to deliver them to), and a callback that |
| 167 // knows how to do the capture and prepare the result for delivery. | 185 // knows how to do the capture and prepare the result for delivery. |
| 168 // | 186 // |
| 169 // In practice, this means (a) installing a RenderWidgetHostFrameSubscriber in | 187 // In practice, this means (a) installing a RenderWidgetHostFrameSubscriber in |
| 170 // the RenderWidgetHostView, to process compositor updates, and (b) running a | 188 // the RenderWidgetHostView, to process compositor updates, and (b) running a |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 203 VideoFrameDeliveryLog delivery_log_; | 221 VideoFrameDeliveryLog delivery_log_; |
| 204 scoped_ptr<FrameSubscriber> timer_subscriber_; | 222 scoped_ptr<FrameSubscriber> timer_subscriber_; |
| 205 CaptureCallback capture_callback_; | 223 CaptureCallback capture_callback_; |
| 206 base::Timer timer_; | 224 base::Timer timer_; |
| 207 | 225 |
| 208 // Responsible for tracking the cursor state and input events to make | 226 // Responsible for tracking the cursor state and input events to make |
| 209 // decisions and then render the mouse cursor on the video frame after | 227 // decisions and then render the mouse cursor on the video frame after |
| 210 // capture is completed. | 228 // capture is completed. |
| 211 scoped_ptr<content::CursorRenderer> cursor_renderer_; | 229 scoped_ptr<content::CursorRenderer> cursor_renderer_; |
| 212 | 230 |
| 231 // Responsible for tracking the UI events and making a decision on whether | |
| 232 // user is actively interacting with content. | |
| 233 scoped_ptr<content::UiActivityTracker> ui_activity_tracker_; | |
| 234 | |
| 213 DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription); | 235 DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription); |
| 214 }; | 236 }; |
| 215 | 237 |
| 216 // Render the SkBitmap |input| into the given VideoFrame buffer |output|, then | 238 // Render the SkBitmap |input| into the given VideoFrame buffer |output|, then |
| 217 // invoke |done_cb| to indicate success or failure. |input| is expected to be | 239 // invoke |done_cb| to indicate success or failure. |input| is expected to be |
| 218 // ARGB. |output| must be YV12 or I420. Colorspace conversion is always done. | 240 // ARGB. |output| must be YV12 or I420. Colorspace conversion is always done. |
| 219 // Scaling and letterboxing will be done as needed. | 241 // Scaling and letterboxing will be done as needed. |
| 220 // | 242 // |
| 221 // This software implementation should be used only when GPU acceleration of | 243 // This software implementation should be used only when GPU acceleration of |
| 222 // these activities is not possible. This operation may be expensive (tens to | 244 // these activities is not possible. This operation may be expensive (tens to |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 358 bool success) { | 380 bool success) { |
| 359 // We can get a callback in the shutdown sequence for the browser main loop | 381 // We can get a callback in the shutdown sequence for the browser main loop |
| 360 // and this can result in a DCHECK failure. Avoid this by doing DCHECK only | 382 // and this can result in a DCHECK failure. Avoid this by doing DCHECK only |
| 361 // on success. | 383 // on success. |
| 362 if (success) { | 384 if (success) { |
| 363 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 385 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 364 // TODO(isheriff): Unclear if taking a snapshot of cursor here affects user | 386 // TODO(isheriff): Unclear if taking a snapshot of cursor here affects user |
| 365 // experience in any particular scenarios. Doing it prior to capture may | 387 // experience in any particular scenarios. Doing it prior to capture may |
| 366 // require evaluating region_in_frame in this file. | 388 // require evaluating region_in_frame in this file. |
| 367 if (frame_subscriber_ && frame_subscriber_->cursor_renderer_) { | 389 if (frame_subscriber_ && frame_subscriber_->cursor_renderer_) { |
| 368 if (frame_subscriber_->cursor_renderer_->SnapshotCursorState( | 390 CursorRenderer* cursor_renderer = |
| 369 region_in_frame)) | 391 frame_subscriber_->cursor_renderer_.get(); |
| 370 frame_subscriber_->cursor_renderer_->RenderOnVideoFrame(frame); | 392 if (cursor_renderer->SnapshotCursorState(region_in_frame)) |
| 393 cursor_renderer->RenderOnVideoFrame(frame); | |
| 394 frame->metadata()->SetBoolean( | |
| 395 media::VideoFrameMetadata::INTERACTIVE_MODE, | |
| 396 frame_subscriber_->IsInteractiveModeActive()); | |
| 371 } | 397 } |
| 372 } | 398 } |
| 373 capture_frame_cb.Run(frame, timestamp, success); | 399 capture_frame_cb.Run(frame, timestamp, success); |
| 374 } | 400 } |
| 375 | 401 |
| 402 bool FrameSubscriber::IsInteractiveModeActive() { | |
|
miu
2015/12/03 21:26:23
naming nit: To aid those unfamiliar with this code
Irfan
2015/12/04 22:45:37
Done.
| |
| 403 bool interactive_mode = false; | |
| 404 bool ui_activity = false; | |
| 405 if (ui_activity_tracker_.get()) { | |
| 406 ui_activity = ui_activity_tracker_->uiInteractionActive(); | |
| 407 } | |
| 408 if (cursor_renderer_.get()) { | |
| 409 bool animation_active = | |
| 410 (base::TimeTicks::Now() - | |
| 411 oracle_proxy_->last_time_animation_was_detected()) < | |
| 412 base::TimeDelta::FromMilliseconds(kMinPeriodNoAnimationMillis); | |
| 413 if (ui_activity && !animation_active) { | |
| 414 interactive_mode = true; | |
| 415 } else if (animation_active) { | |
| 416 ui_activity_tracker_->reset(); | |
| 417 } | |
| 418 } | |
| 419 return interactive_mode; | |
| 420 } | |
| 421 | |
| 376 ContentCaptureSubscription::ContentCaptureSubscription( | 422 ContentCaptureSubscription::ContentCaptureSubscription( |
| 377 const RenderWidgetHost& source, | 423 const RenderWidgetHost& source, |
| 378 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, | 424 const scoped_refptr<media::ThreadSafeCaptureOracle>& oracle_proxy, |
| 379 const CaptureCallback& capture_callback) | 425 const CaptureCallback& capture_callback) |
| 380 : render_process_id_(source.GetProcess()->GetID()), | 426 : render_process_id_(source.GetProcess()->GetID()), |
| 381 render_widget_id_(source.GetRoutingID()), | 427 render_widget_id_(source.GetRoutingID()), |
| 382 delivery_log_(), | 428 delivery_log_(), |
| 383 capture_callback_(capture_callback), | 429 capture_callback_(capture_callback), |
| 384 timer_(true, true) { | 430 timer_(true, true) { |
| 385 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 431 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 386 | 432 |
| 387 RenderWidgetHostView* const view = source.GetView(); | 433 RenderWidgetHostView* const view = source.GetView(); |
| 388 // TODO(isheriff): Cursor resources currently only available on linux. Remove | 434 // TODO(isheriff): Cursor resources currently only available on linux. Remove |
| 389 // this once we add the necessary resources for windows. | 435 // this once we add the necessary resources for windows. |
| 390 #if defined(USE_AURA) && defined(OS_LINUX) | 436 #if defined(USE_AURA) && defined(OS_LINUX) |
| 391 if (view) | 437 if (view) { |
| 392 cursor_renderer_.reset( | 438 cursor_renderer_.reset( |
| 393 new content::CursorRendererAura(view->GetNativeView())); | 439 new content::CursorRendererAura(view->GetNativeView())); |
| 440 ui_activity_tracker_.reset( | |
| 441 new content::UiActivityTrackerAura(view->GetNativeView())); | |
| 442 } | |
| 394 #endif | 443 #endif |
| 395 timer_subscriber_.reset(new FrameSubscriber( | 444 timer_subscriber_.reset(new FrameSubscriber( |
| 396 media::VideoCaptureOracle::kTimerPoll, oracle_proxy, &delivery_log_, | 445 media::VideoCaptureOracle::kTimerPoll, oracle_proxy, &delivery_log_, |
| 397 cursor_renderer_ ? cursor_renderer_->GetWeakPtr() | 446 cursor_renderer_ ? cursor_renderer_->GetWeakPtr() |
| 398 : base::WeakPtr<CursorRenderer>())); | 447 : base::WeakPtr<CursorRenderer>(), |
| 448 ui_activity_tracker_ ? ui_activity_tracker_->GetWeakPtr() | |
| 449 : base::WeakPtr<UiActivityTracker>())); | |
| 399 | 450 |
| 400 // Subscribe to compositor updates. These will be serviced directly by the | 451 // Subscribe to compositor updates. These will be serviced directly by the |
| 401 // oracle. | 452 // oracle. |
| 402 if (view) { | 453 if (view) { |
| 403 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( | 454 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( |
| 404 new FrameSubscriber(media::VideoCaptureOracle::kCompositorUpdate, | 455 new FrameSubscriber( |
| 405 oracle_proxy, &delivery_log_, | 456 media::VideoCaptureOracle::kCompositorUpdate, oracle_proxy, |
| 406 cursor_renderer_ | 457 &delivery_log_, cursor_renderer_ ? cursor_renderer_->GetWeakPtr() |
| 407 ? cursor_renderer_->GetWeakPtr() | 458 : base::WeakPtr<CursorRenderer>(), |
| 408 : base::WeakPtr<CursorRenderer>())); | 459 ui_activity_tracker_ ? ui_activity_tracker_->GetWeakPtr() |
| 460 : base::WeakPtr<UiActivityTracker>())); | |
| 409 view->BeginFrameSubscription(subscriber.Pass()); | 461 view->BeginFrameSubscription(subscriber.Pass()); |
| 410 } | 462 } |
| 411 | 463 |
| 412 // Subscribe to timer events. This instance will service these as well. | 464 // Subscribe to timer events. This instance will service these as well. |
| 413 timer_.Start(FROM_HERE, | 465 timer_.Start(FROM_HERE, |
| 414 std::max(oracle_proxy->min_capture_period(), | 466 std::max(oracle_proxy->min_capture_period(), |
| 415 base::TimeDelta::FromMilliseconds(media | 467 base::TimeDelta::FromMilliseconds(media |
| 416 ::VideoCaptureOracle::kMinTimerPollPeriodMillis)), | 468 ::VideoCaptureOracle::kMinTimerPollPeriodMillis)), |
| 417 base::Bind(&ContentCaptureSubscription::OnTimer, | 469 base::Bind(&ContentCaptureSubscription::OnTimer, |
| 418 base::Unretained(this))); | 470 base::Unretained(this))); |
| (...skipping 490 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 909 scoped_ptr<Client> client) { | 961 scoped_ptr<Client> client) { |
| 910 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); | 962 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); |
| 911 core_->AllocateAndStart(params, client.Pass()); | 963 core_->AllocateAndStart(params, client.Pass()); |
| 912 } | 964 } |
| 913 | 965 |
| 914 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { | 966 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { |
| 915 core_->StopAndDeAllocate(); | 967 core_->StopAndDeAllocate(); |
| 916 } | 968 } |
| 917 | 969 |
| 918 } // namespace content | 970 } // namespace content |
| OLD | NEW |