| 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 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 #include "base/threading/thread.h" | 62 #include "base/threading/thread.h" |
| 63 #include "base/threading/thread_checker.h" | 63 #include "base/threading/thread_checker.h" |
| 64 #include "base/time/time.h" | 64 #include "base/time/time.h" |
| 65 #include "content/browser/media/capture/content_video_capture_device_core.h" | 65 #include "content/browser/media/capture/content_video_capture_device_core.h" |
| 66 #include "content/browser/media/capture/video_capture_oracle.h" | 66 #include "content/browser/media/capture/video_capture_oracle.h" |
| 67 #include "content/browser/media/capture/web_contents_capture_util.h" | 67 #include "content/browser/media/capture/web_contents_capture_util.h" |
| 68 #include "content/browser/media/capture/web_contents_tracker.h" | 68 #include "content/browser/media/capture/web_contents_tracker.h" |
| 69 #include "content/browser/renderer_host/render_widget_host_impl.h" | 69 #include "content/browser/renderer_host/render_widget_host_impl.h" |
| 70 #include "content/browser/renderer_host/render_widget_host_view_base.h" | 70 #include "content/browser/renderer_host/render_widget_host_view_base.h" |
| 71 #include "content/public/browser/browser_thread.h" | 71 #include "content/public/browser/browser_thread.h" |
| 72 #include "content/public/browser/notification_observer.h" | |
| 73 #include "content/public/browser/notification_registrar.h" | |
| 74 #include "content/public/browser/notification_source.h" | |
| 75 #include "content/public/browser/notification_types.h" | |
| 76 #include "content/public/browser/render_process_host.h" | 72 #include "content/public/browser/render_process_host.h" |
| 77 #include "content/public/browser/render_widget_host_view.h" | 73 #include "content/public/browser/render_widget_host_view.h" |
| 78 #include "content/public/browser/render_widget_host_view_frame_subscriber.h" | 74 #include "content/public/browser/render_widget_host_view_frame_subscriber.h" |
| 79 #include "content/public/browser/web_contents.h" | 75 #include "content/public/browser/web_contents.h" |
| 80 #include "media/base/video_capture_types.h" | 76 #include "media/base/video_capture_types.h" |
| 81 #include "media/base/video_util.h" | 77 #include "media/base/video_util.h" |
| 82 #include "skia/ext/image_operations.h" | 78 #include "skia/ext/image_operations.h" |
| 83 #include "third_party/skia/include/core/SkBitmap.h" | 79 #include "third_party/skia/include/core/SkBitmap.h" |
| 84 #include "third_party/skia/include/core/SkColor.h" | 80 #include "third_party/skia/include/core/SkColor.h" |
| 85 #include "ui/gfx/display.h" | 81 #include "ui/gfx/display.h" |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 153 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; | 149 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; |
| 154 VideoFrameDeliveryLog* const delivery_log_; | 150 VideoFrameDeliveryLog* const delivery_log_; |
| 155 }; | 151 }; |
| 156 | 152 |
| 157 // ContentCaptureSubscription is the relationship between a RenderWidgetHost | 153 // ContentCaptureSubscription is the relationship between a RenderWidgetHost |
| 158 // whose content is updating, a subscriber that is deciding which of these | 154 // whose content is updating, a subscriber that is deciding which of these |
| 159 // updates to capture (and where to deliver them to), and a callback that | 155 // updates to capture (and where to deliver them to), and a callback that |
| 160 // knows how to do the capture and prepare the result for delivery. | 156 // knows how to do the capture and prepare the result for delivery. |
| 161 // | 157 // |
| 162 // In practice, this means (a) installing a RenderWidgetHostFrameSubscriber in | 158 // In practice, this means (a) installing a RenderWidgetHostFrameSubscriber in |
| 163 // the RenderWidgetHostView, to process updates that occur via accelerated | 159 // the RenderWidgetHostView, to process compositor updates, and (b) running a |
| 164 // compositing, (b) installing itself as an observer of updates to the | 160 // timer to possibly initiate forced, non-event-driven captures needed by |
| 165 // RenderWidgetHost's backing store, to hook updates that occur via software | 161 // downstream consumers that require frame repeats of unchanged content. |
| 166 // rendering, and (c) running a timer to possibly initiate non-event-driven | |
| 167 // captures that the subscriber might request. | |
| 168 // | 162 // |
| 169 // All of this happens on the UI thread, although the | 163 // All of this happens on the UI thread, although the |
| 170 // RenderWidgetHostViewFrameSubscriber we install may be dispatching updates | 164 // RenderWidgetHostViewFrameSubscriber we install may be dispatching updates |
| 171 // autonomously on some other thread. | 165 // autonomously on some other thread. |
| 172 class ContentCaptureSubscription : public content::NotificationObserver { | 166 class ContentCaptureSubscription { |
| 173 public: | 167 public: |
| 174 typedef base::Callback< | 168 typedef base::Callback< |
| 175 void(const base::TimeTicks&, | 169 void(const base::TimeTicks&, |
| 176 const scoped_refptr<media::VideoFrame>&, | 170 const scoped_refptr<media::VideoFrame>&, |
| 177 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&)> | 171 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&)> |
| 178 CaptureCallback; | 172 CaptureCallback; |
| 179 | 173 |
| 180 // Create a subscription. Whenever a manual capture is required, the | 174 // Create a subscription. Whenever a manual capture is required, the |
| 181 // subscription will invoke |capture_callback| on the UI thread to do the | 175 // subscription will invoke |capture_callback| on the UI thread to do the |
| 182 // work. | 176 // work. |
| 183 ContentCaptureSubscription( | 177 ContentCaptureSubscription( |
| 184 const RenderWidgetHost& source, | 178 const RenderWidgetHost& source, |
| 185 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, | 179 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, |
| 186 const CaptureCallback& capture_callback); | 180 const CaptureCallback& capture_callback); |
| 187 ~ContentCaptureSubscription() override; | 181 ~ContentCaptureSubscription(); |
| 188 | |
| 189 // content::NotificationObserver implementation. | |
| 190 void Observe(int type, | |
| 191 const content::NotificationSource& source, | |
| 192 const content::NotificationDetails& details) override; | |
| 193 | 182 |
| 194 private: | 183 private: |
| 195 void OnTimer(); | 184 void OnTimer(); |
| 196 | 185 |
| 197 // Maintain a weak reference to the RenderWidgetHost (via its routing ID), | 186 // Maintain a weak reference to the RenderWidgetHost (via its routing ID), |
| 198 // since the instance could be destroyed externally during the lifetime of | 187 // since the instance could be destroyed externally during the lifetime of |
| 199 // |this|. | 188 // |this|. |
| 200 const int render_process_id_; | 189 const int render_process_id_; |
| 201 const int render_widget_id_; | 190 const int render_widget_id_; |
| 202 | 191 |
| 203 VideoFrameDeliveryLog delivery_log_; | 192 VideoFrameDeliveryLog delivery_log_; |
| 204 FrameSubscriber paint_subscriber_; | |
| 205 FrameSubscriber timer_subscriber_; | 193 FrameSubscriber timer_subscriber_; |
| 206 content::NotificationRegistrar registrar_; | |
| 207 CaptureCallback capture_callback_; | 194 CaptureCallback capture_callback_; |
| 208 base::Timer timer_; | 195 base::Timer timer_; |
| 209 | 196 |
| 210 DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription); | 197 DISALLOW_COPY_AND_ASSIGN(ContentCaptureSubscription); |
| 211 }; | 198 }; |
| 212 | 199 |
| 213 // Render the SkBitmap |input| into the given VideoFrame buffer |output|, then | 200 // Render the SkBitmap |input| into the given VideoFrame buffer |output|, then |
| 214 // invoke |done_cb| to indicate success or failure. |input| is expected to be | 201 // invoke |done_cb| to indicate success or failure. |input| is expected to be |
| 215 // ARGB. |output| must be YV12 or I420. Colorspace conversion is always done. | 202 // ARGB. |output| must be YV12 or I420. Colorspace conversion is always done. |
| 216 // Scaling and letterboxing will be done as needed. | 203 // Scaling and letterboxing will be done as needed. |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 321 return oracle_decision; | 308 return oracle_decision; |
| 322 } | 309 } |
| 323 | 310 |
| 324 ContentCaptureSubscription::ContentCaptureSubscription( | 311 ContentCaptureSubscription::ContentCaptureSubscription( |
| 325 const RenderWidgetHost& source, | 312 const RenderWidgetHost& source, |
| 326 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, | 313 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy, |
| 327 const CaptureCallback& capture_callback) | 314 const CaptureCallback& capture_callback) |
| 328 : render_process_id_(source.GetProcess()->GetID()), | 315 : render_process_id_(source.GetProcess()->GetID()), |
| 329 render_widget_id_(source.GetRoutingID()), | 316 render_widget_id_(source.GetRoutingID()), |
| 330 delivery_log_(), | 317 delivery_log_(), |
| 331 paint_subscriber_(VideoCaptureOracle::kSoftwarePaint, oracle_proxy, | |
| 332 &delivery_log_), | |
| 333 timer_subscriber_(VideoCaptureOracle::kTimerPoll, oracle_proxy, | 318 timer_subscriber_(VideoCaptureOracle::kTimerPoll, oracle_proxy, |
| 334 &delivery_log_), | 319 &delivery_log_), |
| 335 capture_callback_(capture_callback), | 320 capture_callback_(capture_callback), |
| 336 timer_(true, true) { | 321 timer_(true, true) { |
| 337 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 322 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 338 | 323 |
| 339 RenderWidgetHostView* const view = source.GetView(); | 324 RenderWidgetHostView* const view = source.GetView(); |
| 340 | 325 |
| 341 // Subscribe to accelerated presents. These will be serviced directly by the | 326 // Subscribe to compositor updates. These will be serviced directly by the |
| 342 // oracle. | 327 // oracle. |
| 343 if (view) { | 328 if (view) { |
| 344 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( | 329 scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber( |
| 345 new FrameSubscriber(VideoCaptureOracle::kCompositorUpdate, | 330 new FrameSubscriber(VideoCaptureOracle::kCompositorUpdate, |
| 346 oracle_proxy, &delivery_log_)); | 331 oracle_proxy, &delivery_log_)); |
| 347 view->BeginFrameSubscription(subscriber.Pass()); | 332 view->BeginFrameSubscription(subscriber.Pass()); |
| 348 } | 333 } |
| 349 | 334 |
| 350 // Subscribe to software paint events. This instance will service these by | |
| 351 // reflecting them back to the WebContentsCaptureMachine via | |
| 352 // |capture_callback|. | |
| 353 registrar_.Add( | |
| 354 this, content::NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, | |
| 355 Source<RenderWidgetHost>(&source)); | |
| 356 | |
| 357 // Subscribe to timer events. This instance will service these as well. | 335 // Subscribe to timer events. This instance will service these as well. |
| 358 timer_.Start(FROM_HERE, oracle_proxy->min_capture_period(), | 336 timer_.Start(FROM_HERE, oracle_proxy->min_capture_period(), |
| 359 base::Bind(&ContentCaptureSubscription::OnTimer, | 337 base::Bind(&ContentCaptureSubscription::OnTimer, |
| 360 base::Unretained(this))); | 338 base::Unretained(this))); |
| 361 } | 339 } |
| 362 | 340 |
| 363 ContentCaptureSubscription::~ContentCaptureSubscription() { | 341 ContentCaptureSubscription::~ContentCaptureSubscription() { |
| 364 // If the BrowserThreads have been torn down, then the browser is in the final | 342 // If the BrowserThreads have been torn down, then the browser is in the final |
| 365 // stages of exiting and it is dangerous to take any further action. We must | 343 // stages of exiting and it is dangerous to take any further action. We must |
| 366 // return early. http://crbug.com/396413 | 344 // return early. http://crbug.com/396413 |
| 367 if (!BrowserThread::IsMessageLoopValid(BrowserThread::UI)) | 345 if (!BrowserThread::IsMessageLoopValid(BrowserThread::UI)) |
| 368 return; | 346 return; |
| 369 | 347 |
| 370 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 348 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 371 RenderWidgetHost* const source = | 349 RenderWidgetHost* const source = |
| 372 RenderWidgetHost::FromID(render_process_id_, render_widget_id_); | 350 RenderWidgetHost::FromID(render_process_id_, render_widget_id_); |
| 373 RenderWidgetHostView* const view = source ? source->GetView() : NULL; | 351 RenderWidgetHostView* const view = source ? source->GetView() : NULL; |
| 374 if (view) | 352 if (view) |
| 375 view->EndFrameSubscription(); | 353 view->EndFrameSubscription(); |
| 376 } | 354 } |
| 377 | 355 |
| 378 void ContentCaptureSubscription::Observe( | |
| 379 int type, | |
| 380 const content::NotificationSource& source, | |
| 381 const content::NotificationDetails& details) { | |
| 382 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
| 383 DCHECK_EQ(NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, type); | |
| 384 | |
| 385 RenderWidgetHostImpl* rwh = | |
| 386 RenderWidgetHostImpl::From(Source<RenderWidgetHost>(source).ptr()); | |
| 387 | |
| 388 // This message occurs on window resizes and visibility changes even when | |
| 389 // accelerated compositing is active, so we need to filter out these cases. | |
| 390 if (!rwh || !rwh->GetView()) | |
| 391 return; | |
| 392 // Mac sends DID_UPDATE_BACKING_STORE messages to inform the capture system | |
| 393 // of new software compositor frames, so always treat these messages as | |
| 394 // signals of a new frame on Mac. | |
| 395 // http://crbug.com/333986 | |
| 396 #if !defined(OS_MACOSX) | |
| 397 if (rwh->GetView()->IsSurfaceAvailableForCopy()) | |
| 398 return; | |
| 399 #endif | |
| 400 | |
| 401 TRACE_EVENT1("mirroring", "ContentCaptureSubscription::Observe", | |
| 402 "instance", this); | |
| 403 | |
| 404 base::Closure copy_done_callback; | |
| 405 scoped_refptr<media::VideoFrame> frame; | |
| 406 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb; | |
| 407 const base::TimeTicks start_time = base::TimeTicks::Now(); | |
| 408 if (paint_subscriber_.ShouldCaptureFrame(gfx::Rect(), | |
| 409 start_time, | |
| 410 &frame, | |
| 411 &deliver_frame_cb)) { | |
| 412 // This message happens just before paint. If we post a task to do the copy, | |
| 413 // it should run soon after the paint. | |
| 414 BrowserThread::PostTask( | |
| 415 BrowserThread::UI, FROM_HERE, | |
| 416 base::Bind(capture_callback_, start_time, frame, deliver_frame_cb)); | |
| 417 } | |
| 418 } | |
| 419 | |
| 420 void ContentCaptureSubscription::OnTimer() { | 356 void ContentCaptureSubscription::OnTimer() { |
| 421 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 357 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 422 TRACE_EVENT0("mirroring", "ContentCaptureSubscription::OnTimer"); | 358 TRACE_EVENT0("mirroring", "ContentCaptureSubscription::OnTimer"); |
| 423 | 359 |
| 424 scoped_refptr<media::VideoFrame> frame; | 360 scoped_refptr<media::VideoFrame> frame; |
| 425 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb; | 361 RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback deliver_frame_cb; |
| 426 | 362 |
| 427 const base::TimeTicks start_time = base::TimeTicks::Now(); | 363 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 428 if (timer_subscriber_.ShouldCaptureFrame(gfx::Rect(), | 364 if (timer_subscriber_.ShouldCaptureFrame(gfx::Rect(), |
| 429 start_time, | 365 start_time, |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 783 scoped_ptr<Client> client) { | 719 scoped_ptr<Client> client) { |
| 784 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); | 720 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); |
| 785 core_->AllocateAndStart(params, client.Pass()); | 721 core_->AllocateAndStart(params, client.Pass()); |
| 786 } | 722 } |
| 787 | 723 |
| 788 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { | 724 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { |
| 789 core_->StopAndDeAllocate(); | 725 core_->StopAndDeAllocate(); |
| 790 } | 726 } |
| 791 | 727 |
| 792 } // namespace content | 728 } // namespace content |
| OLD | NEW |