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

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: Create render_thread_ during Start() instead of ctor / Stop() 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 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 101
102 // Wrapper function to invoke ThreadSafeCaptureOracle::CaptureFrameCallback, is 102 // Wrapper function to invoke ThreadSafeCaptureOracle::CaptureFrameCallback, is
103 // compatible with RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback. 103 // compatible with RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback.
104 void InvokeCaptureFrameCallback( 104 void InvokeCaptureFrameCallback(
105 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb, 105 const ThreadSafeCaptureOracle::CaptureFrameCallback& capture_frame_cb,
106 base::TimeTicks timestamp, 106 base::TimeTicks timestamp,
107 bool frame_captured) { 107 bool frame_captured) {
108 capture_frame_cb.Run(timestamp, frame_captured); 108 capture_frame_cb.Run(timestamp, frame_captured);
109 } 109 }
110 110
111 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread,
112 const base::Closure& callback) {
113 render_thread.reset();
114
115 // After thread join call the callback on UI thread.
116 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
117 }
118
111 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible 119 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible
112 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. 120 // with RenderWidgetHostViewFrameSubscriber. We create one per event type.
113 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { 121 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
114 public: 122 public:
115 FrameSubscriber(VideoCaptureOracle::Event event_type, 123 FrameSubscriber(VideoCaptureOracle::Event event_type,
116 const scoped_refptr<ThreadSafeCaptureOracle>& oracle) 124 const scoped_refptr<ThreadSafeCaptureOracle>& oracle)
117 : event_type_(event_type), 125 : event_type_(event_type),
118 oracle_proxy_(oracle) {} 126 oracle_proxy_(oracle) {}
119 127
120 virtual bool ShouldCaptureFrame( 128 virtual bool ShouldCaptureFrame(
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 : public VideoCaptureMachine, 212 : public VideoCaptureMachine,
205 public WebContentsObserver, 213 public WebContentsObserver,
206 public base::SupportsWeakPtr<WebContentsCaptureMachine> { 214 public base::SupportsWeakPtr<WebContentsCaptureMachine> {
207 public: 215 public:
208 WebContentsCaptureMachine(int render_process_id, int render_view_id); 216 WebContentsCaptureMachine(int render_process_id, int render_view_id);
209 virtual ~WebContentsCaptureMachine(); 217 virtual ~WebContentsCaptureMachine();
210 218
211 // VideoCaptureMachine overrides. 219 // VideoCaptureMachine overrides.
212 virtual bool Start( 220 virtual bool Start(
213 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) OVERRIDE; 221 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) OVERRIDE;
214 virtual void Stop() OVERRIDE; 222 virtual void Stop(const base::Closure& callback) OVERRIDE;
215 223
216 // Starts a copy from the backing store or the composited surface. Must be run 224 // 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 225 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation
218 // completes. The copy will occur to |target|. 226 // completes. The copy will occur to |target|.
219 // 227 //
220 // This may be used as a ContentCaptureSubscription::CaptureCallback. 228 // This may be used as a ContentCaptureSubscription::CaptureCallback.
221 void Capture(const base::TimeTicks& start_time, 229 void Capture(const base::TimeTicks& start_time,
222 const scoped_refptr<media::VideoFrame>& target, 230 const scoped_refptr<media::VideoFrame>& target,
223 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 231 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
224 deliver_frame_cb); 232 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 286 // after any change to the WebContents that affects the RenderWidgetHost or
279 // attached views. 287 // attached views.
280 void RenewFrameSubscription(); 288 void RenewFrameSubscription();
281 289
282 // Parameters saved in constructor. 290 // Parameters saved in constructor.
283 const int initial_render_process_id_; 291 const int initial_render_process_id_;
284 const int initial_render_view_id_; 292 const int initial_render_view_id_;
285 293
286 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will 294 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will
287 // occur. Only used when this activity cannot be done on the GPU. 295 // occur. Only used when this activity cannot be done on the GPU.
288 base::Thread render_thread_; 296 scoped_ptr<base::Thread> render_thread_;
289 297
290 // Makes all the decisions about which frames to copy, and how. 298 // Makes all the decisions about which frames to copy, and how.
291 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; 299 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
292 300
293 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE 301 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE
294 // otherwise. 302 // otherwise.
295 int fullscreen_widget_id_; 303 int fullscreen_widget_id_;
296 304
297 // Last known RenderView size. 305 // Last known RenderView size.
298 gfx::Size last_view_size_; 306 gfx::Size last_view_size_;
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 count_frames_rendered_ = 0; 552 count_frames_rendered_ = 0;
545 last_frame_number_ = frame_number; 553 last_frame_number_ = frame_number;
546 } 554 }
547 } 555 }
548 } 556 }
549 557
550 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id, 558 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id,
551 int render_view_id) 559 int render_view_id)
552 : initial_render_process_id_(render_process_id), 560 : initial_render_process_id_(render_process_id),
553 initial_render_view_id_(render_view_id), 561 initial_render_view_id_(render_view_id),
554 render_thread_("WebContentsVideo_RenderThread"),
555 fullscreen_widget_id_(MSG_ROUTING_NONE) {} 562 fullscreen_widget_id_(MSG_ROUTING_NONE) {}
556 563
557 WebContentsCaptureMachine::~WebContentsCaptureMachine() {} 564 WebContentsCaptureMachine::~WebContentsCaptureMachine() {
565 BrowserThread::PostBlockingPoolTask(
566 FROM_HERE,
567 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_),
568 base::Bind(&base::DoNothing)));
569 }
558 570
559 bool WebContentsCaptureMachine::Start( 571 bool WebContentsCaptureMachine::Start(
560 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) { 572 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) {
561 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 573 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
562 DCHECK(!started_); 574 DCHECK(!started_);
563 575
564 DCHECK(oracle_proxy.get()); 576 DCHECK(oracle_proxy.get());
565 oracle_proxy_ = oracle_proxy; 577 oracle_proxy_ = oracle_proxy;
566 578
567 if (!render_thread_.Start()) { 579 render_thread_.reset(new base::Thread("WebContentsVideo_RenderThread"));
580 if (!render_thread_->Start()) {
568 DVLOG(1) << "Failed to spawn render thread."; 581 DVLOG(1) << "Failed to spawn render thread.";
569 return false; 582 return false;
miu 2014/01/13 23:25:10 Add a render_thread_.reset() here before the retur
imcheng 2014/01/14 02:06:52 Done. It seems it's also needed below in "if (!Sta
570 } 583 }
571 584
572 if (!StartObservingWebContents()) 585 if (!StartObservingWebContents())
573 return false; 586 return false;
574 587
575 started_ = true; 588 started_ = true;
576 return true; 589 return true;
577 } 590 }
578 591
579 void WebContentsCaptureMachine::Stop() { 592 void WebContentsCaptureMachine::Stop(const base::Closure& callback) {
580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 593 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
581 subscription_.reset(); 594 subscription_.reset();
582 if (web_contents()) { 595 if (web_contents()) {
583 web_contents()->DecrementCapturerCount(); 596 web_contents()->DecrementCapturerCount();
584 Observe(NULL); 597 Observe(NULL);
585 } 598 }
586 render_thread_.Stop(); 599
600 // The render thread cannot be stopped on the UI thread, so post a message
601 // to the thread pool used for blocking operations.
602 BrowserThread::PostBlockingPoolTask(
603 FROM_HERE,
604 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_),
605 callback));
606
587 started_ = false; 607 started_ = false;
588 } 608 }
589 609
590 void WebContentsCaptureMachine::Capture( 610 void WebContentsCaptureMachine::Capture(
591 const base::TimeTicks& start_time, 611 const base::TimeTicks& start_time,
592 const scoped_refptr<media::VideoFrame>& target, 612 const scoped_refptr<media::VideoFrame>& target,
593 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 613 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
594 deliver_frame_cb) { 614 deliver_frame_cb) {
595 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 615 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
596 616
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
699 void WebContentsCaptureMachine::DidCopyFromBackingStore( 719 void WebContentsCaptureMachine::DidCopyFromBackingStore(
700 const base::TimeTicks& start_time, 720 const base::TimeTicks& start_time,
701 const scoped_refptr<media::VideoFrame>& target, 721 const scoped_refptr<media::VideoFrame>& target,
702 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 722 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
703 deliver_frame_cb, 723 deliver_frame_cb,
704 bool success, 724 bool success,
705 const SkBitmap& bitmap) { 725 const SkBitmap& bitmap) {
706 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 726 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
707 727
708 base::TimeTicks now = base::TimeTicks::Now(); 728 base::TimeTicks now = base::TimeTicks::Now();
709 if (success) { 729 if (success && render_thread_ && render_thread_->message_loop_proxy()) {
miu 2014/01/13 23:22:14 nit: This should be a DCHECK(render_thread_.get())
imcheng 2014/01/14 02:06:52 Done.
710 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); 730 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
711 TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(), 731 TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(),
712 "Render"); 732 "Render");
713 render_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( 733 render_thread_->message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
714 &RenderVideoFrame, bitmap, target, 734 &RenderVideoFrame, bitmap, target,
715 base::Bind(deliver_frame_cb, start_time))); 735 base::Bind(deliver_frame_cb, start_time)));
716 } else { 736 } else {
717 // Capture can fail due to transient issues, so just skip this frame. 737 // Capture can fail due to transient issues, so just skip this frame.
718 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; 738 DVLOG(1) << "CopyFromBackingStore failed; skipping frame.";
719 deliver_frame_cb.Run(start_time, false); 739 deliver_frame_cb.Run(start_time, false);
720 } 740 }
721 } 741 }
722 742
723 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( 743 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 scoped_ptr<Client> client) { 801 scoped_ptr<Client> client) {
782 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); 802 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString();
783 impl_->AllocateAndStart(params, client.Pass()); 803 impl_->AllocateAndStart(params, client.Pass());
784 } 804 }
785 805
786 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { 806 void WebContentsVideoCaptureDevice::StopAndDeAllocate() {
787 impl_->StopAndDeAllocate(); 807 impl_->StopAndDeAllocate();
788 } 808 }
789 809
790 } // namespace content 810 } // 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