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

Side by Side Diff: content/browser/media/capture/web_contents_video_capture_device.cc

Issue 1484403002: cast: Support for low-latency interactive mode (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix cast streaming API tests Created 5 years 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
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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
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/web_contents_capture_util.h" 69 #include "content/browser/media/capture/web_contents_capture_util.h"
70 #include "content/browser/media/capture/web_contents_tracker.h" 70 #include "content/browser/media/capture/web_contents_tracker.h"
71 #include "content/browser/media/capture/window_activity_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/window_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
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::WindowActivityTracker> 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 window_activity_tracker_(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 IsUserInteractingWithContent();
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<WindowActivityTracker> window_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
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::WindowActivityTracker> window_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
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_CONTENT,
396 frame_subscriber_->IsUserInteractingWithContent());
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::IsUserInteractingWithContent() {
403 bool interactive_mode = false;
404 bool ui_activity = false;
405 if (window_activity_tracker_.get()) {
406 ui_activity = window_activity_tracker_->IsUiInteractionActive();
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 window_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 window_activity_tracker_.reset(
miu 2015/12/08 00:16:16 This looks like it'll work for all Aura platforms,
Irfan 2015/12/08 01:30:18 Done.
441 new content::WindowActivityTrackerAura(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 window_activity_tracker_ ? window_activity_tracker_->GetWeakPtr()
449 : base::WeakPtr<WindowActivityTracker>()));
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 window_activity_tracker_ ? window_activity_tracker_->GetWeakPtr()
460 : base::WeakPtr<WindowActivityTracker>()));
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698