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

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

Issue 130253002: Attempt to fixed crash on stop mirroring by stopping render thread on a worker thread. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix compile desktop_capture_device_aura.cc Created 6 years, 11 months 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
« no previous file with comments | « content/browser/renderer_host/media/video_capture_device_impl.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
77 #include "media/base/video_util.h" 77 #include "media/base/video_util.h"
78 #include "media/video/capture/video_capture_types.h" 78 #include "media/video/capture/video_capture_types.h"
79 #include "skia/ext/image_operations.h" 79 #include "skia/ext/image_operations.h"
80 #include "third_party/skia/include/core/SkBitmap.h" 80 #include "third_party/skia/include/core/SkBitmap.h"
81 #include "third_party/skia/include/core/SkColor.h" 81 #include "third_party/skia/include/core/SkColor.h"
82 82
83 namespace content { 83 namespace content {
84 84
85 namespace { 85 namespace {
86 86
87 const char kRenderThreadName[] = "WebContentsVideo_RenderThread";
88
87 // Compute a letterbox region, aligned to even coordinates. 89 // Compute a letterbox region, aligned to even coordinates.
88 gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size, 90 gfx::Rect ComputeYV12LetterboxRegion(const gfx::Size& frame_size,
89 const gfx::Size& content_size) { 91 const gfx::Size& content_size) {
90 92
91 gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size), 93 gfx::Rect result = media::ComputeLetterboxRegion(gfx::Rect(frame_size),
92 content_size); 94 content_size);
93 95
94 result.set_x(MakeEven(result.x())); 96 result.set_x(MakeEven(result.x()));
95 result.set_y(MakeEven(result.y())); 97 result.set_y(MakeEven(result.y()));
96 result.set_width(std::max(kMinFrameWidth, MakeEven(result.width()))); 98 result.set_width(std::max(kMinFrameWidth, MakeEven(result.width())));
97 result.set_height(std::max(kMinFrameHeight, MakeEven(result.height()))); 99 result.set_height(std::max(kMinFrameHeight, MakeEven(result.height())));
98 100
99 return result; 101 return result;
100 } 102 }
101 103
102 // Wrapper function to invoke ThreadSafeCaptureOracle::CaptureFrameCallback, is 104 // Wrapper function to invoke ThreadSafeCaptureOracle::CaptureFrameCallback, is
103 // compatible with RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback. 105 // compatible with RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback.
104 void InvokeCaptureFrameCallback( 106 void InvokeCaptureFrameCallback(
105 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, 107 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
106 base::TimeTicks timestamp, 108 base::TimeTicks timestamp,
107 bool frame_captured) { 109 bool frame_captured) {
108 capture_frame_cb.Run(timestamp, frame_captured); 110 capture_frame_cb.Run(timestamp, frame_captured);
109 } 111 }
110 112
113 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread,
114 const base::Closure& callback) {
115 render_thread.reset();
116
117 // After thread join call the callback on UI thread.
118 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
119 }
120
111 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible 121 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible
112 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. 122 // with RenderWidgetHostViewFrameSubscriber. We create one per event type.
113 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { 123 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
114 public: 124 public:
115 FrameSubscriber(VideoCaptureOracle::Event event_type, 125 FrameSubscriber(VideoCaptureOracle::Event event_type,
116 const scoped_refptr<ThreadSafeCaptureOracle>& oracle) 126 const scoped_refptr<ThreadSafeCaptureOracle>& oracle)
117 : event_type_(event_type), 127 : event_type_(event_type),
118 oracle_proxy_(oracle) {} 128 oracle_proxy_(oracle) {}
119 129
120 virtual bool ShouldCaptureFrame( 130 virtual bool ShouldCaptureFrame(
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 : public VideoCaptureMachine, 214 : public VideoCaptureMachine,
205 public WebContentsObserver, 215 public WebContentsObserver,
206 public base::SupportsWeakPtr<WebContentsCaptureMachine> { 216 public base::SupportsWeakPtr<WebContentsCaptureMachine> {
207 public: 217 public:
208 WebContentsCaptureMachine(int render_process_id, int render_view_id); 218 WebContentsCaptureMachine(int render_process_id, int render_view_id);
209 virtual ~WebContentsCaptureMachine(); 219 virtual ~WebContentsCaptureMachine();
210 220
211 // VideoCaptureMachine overrides. 221 // VideoCaptureMachine overrides.
212 virtual bool Start( 222 virtual bool Start(
213 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) OVERRIDE; 223 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) OVERRIDE;
214 virtual void Stop() OVERRIDE; 224 virtual void Stop(const base::Closure& callback) OVERRIDE;
215 225
216 // Starts a copy from the backing store or the composited surface. Must be run 226 // Starts a copy from the backing store or the composited surface. Must be run
217 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation 227 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation
218 // completes. The copy will occur to |target|. 228 // completes. The copy will occur to |target|.
219 // 229 //
220 // This may be used as a ContentCaptureSubscription::CaptureCallback. 230 // This may be used as a ContentCaptureSubscription::CaptureCallback.
221 void Capture(const base::TimeTicks& start_time, 231 void Capture(const base::TimeTicks& start_time,
222 const scoped_refptr<media::VideoFrame>& target, 232 const scoped_refptr<media::VideoFrame>& target,
223 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 233 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
224 deliver_frame_cb); 234 deliver_frame_cb);
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 // after any change to the WebContents that affects the RenderWidgetHost or 288 // after any change to the WebContents that affects the RenderWidgetHost or
279 // attached views. 289 // attached views.
280 void RenewFrameSubscription(); 290 void RenewFrameSubscription();
281 291
282 // Parameters saved in constructor. 292 // Parameters saved in constructor.
283 const int initial_render_process_id_; 293 const int initial_render_process_id_;
284 const int initial_render_view_id_; 294 const int initial_render_view_id_;
285 295
286 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will 296 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will
287 // occur. Only used when this activity cannot be done on the GPU. 297 // occur. Only used when this activity cannot be done on the GPU.
288 base::Thread render_thread_; 298 scoped_ptr<base::Thread> render_thread_;
289 299
290 // Makes all the decisions about which frames to copy, and how. 300 // Makes all the decisions about which frames to copy, and how.
291 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; 301 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
292 302
293 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE 303 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE
294 // otherwise. 304 // otherwise.
295 int fullscreen_widget_id_; 305 int fullscreen_widget_id_;
296 306
297 // Last known RenderView size. 307 // Last known RenderView size.
298 gfx::Size last_view_size_; 308 gfx::Size last_view_size_;
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 count_frames_rendered_ = 0; 554 count_frames_rendered_ = 0;
545 last_frame_number_ = frame_number; 555 last_frame_number_ = frame_number;
546 } 556 }
547 } 557 }
548 } 558 }
549 559
550 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id, 560 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id,
551 int render_view_id) 561 int render_view_id)
552 : initial_render_process_id_(render_process_id), 562 : initial_render_process_id_(render_process_id),
553 initial_render_view_id_(render_view_id), 563 initial_render_view_id_(render_view_id),
554 render_thread_("WebContentsVideo_RenderThread"), 564 render_thread_(new base::Thread("WebContentsVideo_RenderThread")),
555 fullscreen_widget_id_(MSG_ROUTING_NONE) {} 565 fullscreen_widget_id_(MSG_ROUTING_NONE) {}
556 566
557 WebContentsCaptureMachine::~WebContentsCaptureMachine() {} 567 WebContentsCaptureMachine::~WebContentsCaptureMachine() {
568 BrowserThread::PostBlockingPoolTask(
569 FROM_HERE,
570 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_),
571 base::Bind(&base::DoNothing)));
572 }
558 573
559 bool WebContentsCaptureMachine::Start( 574 bool WebContentsCaptureMachine::Start(
560 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) { 575 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) {
561 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 576 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
562 DCHECK(!started_); 577 DCHECK(!started_);
563 578
564 DCHECK(oracle_proxy.get()); 579 DCHECK(oracle_proxy.get());
565 oracle_proxy_ = oracle_proxy; 580 oracle_proxy_ = oracle_proxy;
566 581
567 if (!render_thread_.Start()) { 582 if (!render_thread_->Start()) {
568 DVLOG(1) << "Failed to spawn render thread."; 583 DVLOG(1) << "Failed to spawn render thread.";
569 return false; 584 return false;
570 } 585 }
571 586
572 if (!StartObservingWebContents()) 587 if (!StartObservingWebContents())
573 return false; 588 return false;
574 589
575 started_ = true; 590 started_ = true;
576 return true; 591 return true;
577 } 592 }
578 593
579 void WebContentsCaptureMachine::Stop() { 594 void WebContentsCaptureMachine::Stop(const base::Closure& callback) {
580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 595 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
581 subscription_.reset(); 596 subscription_.reset();
582 if (web_contents()) { 597 if (web_contents()) {
583 web_contents()->DecrementCapturerCount(); 598 web_contents()->DecrementCapturerCount();
584 Observe(NULL); 599 Observe(NULL);
585 } 600 }
586 render_thread_.Stop(); 601
602 // The render thread cannot be stopped on the UI thread, so post a message
603 // to the thread pool used for blocking operations.
604 BrowserThread::PostBlockingPoolTask(
605 FROM_HERE,
606 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_),
607 callback));
608
609 render_thread_.reset(new base::Thread(kRenderThreadName));
miu 2014/01/11 03:48:36 Seems strange to create a new thread as part of th
imcheng 2014/01/13 20:23:24 Done.
610
587 started_ = false; 611 started_ = false;
588 } 612 }
589 613
590 void WebContentsCaptureMachine::Capture( 614 void WebContentsCaptureMachine::Capture(
591 const base::TimeTicks& start_time, 615 const base::TimeTicks& start_time,
592 const scoped_refptr<media::VideoFrame>& target, 616 const scoped_refptr<media::VideoFrame>& target,
593 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 617 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
594 deliver_frame_cb) { 618 deliver_frame_cb) {
595 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 619 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
596 620
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
699 void WebContentsCaptureMachine::DidCopyFromBackingStore( 723 void WebContentsCaptureMachine::DidCopyFromBackingStore(
700 const base::TimeTicks& start_time, 724 const base::TimeTicks& start_time,
701 const scoped_refptr<media::VideoFrame>& target, 725 const scoped_refptr<media::VideoFrame>& target,
702 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 726 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
703 deliver_frame_cb, 727 deliver_frame_cb,
704 bool success, 728 bool success,
705 const SkBitmap& bitmap) { 729 const SkBitmap& bitmap) {
706 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 730 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
707 731
708 base::TimeTicks now = base::TimeTicks::Now(); 732 base::TimeTicks now = base::TimeTicks::Now();
709 if (success) { 733 if (success && render_thread_->message_loop_proxy()) {
710 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); 734 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
711 TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(), 735 TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(),
712 "Render"); 736 "Render");
713 render_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( 737 render_thread_->message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
714 &RenderVideoFrame, bitmap, target, 738 &RenderVideoFrame, bitmap, target,
715 base::Bind(deliver_frame_cb, start_time))); 739 base::Bind(deliver_frame_cb, start_time)));
716 } else { 740 } else {
717 // Capture can fail due to transient issues, so just skip this frame. 741 // Capture can fail due to transient issues, so just skip this frame.
718 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; 742 DVLOG(1) << "CopyFromBackingStore failed; skipping frame.";
719 deliver_frame_cb.Run(start_time, false); 743 deliver_frame_cb.Run(start_time, false);
720 } 744 }
721 } 745 }
722 746
723 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( 747 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 scoped_ptr<Client> client) { 805 scoped_ptr<Client> client) {
782 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); 806 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString();
783 impl_->AllocateAndStart(params, client.Pass()); 807 impl_->AllocateAndStart(params, client.Pass());
784 } 808 }
785 809
786 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { 810 void WebContentsVideoCaptureDevice::StopAndDeAllocate() {
787 impl_->StopAndDeAllocate(); 811 impl_->StopAndDeAllocate();
788 } 812 }
789 813
790 } // namespace content 814 } // namespace content
OLDNEW
« no previous file with comments | « content/browser/renderer_host/media/video_capture_device_impl.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698