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

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: 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
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 StopOnWorkerThread(base::Thread* render_thread,
112 const base::Closure& callback) {
113 if (render_thread) {
Alpha Left Google 2014/01/09 01:37:07 DCHECK that render_thread is not NULL instead of d
imcheng 2014/01/09 23:31:09 Done.
114 render_thread->Stop();
115
116 // After thread join call the callback on UI thread.
117 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, callback);
118 }
119 }
120
121 void DeleteOnWorkerThread(scoped_ptr<base::Thread> render_thread) {
122 if (render_thread) {
Alpha Left Google 2014/01/09 01:37:07 Don't need this. Just call reset.
imcheng 2014/01/09 23:31:09 Done.
123 render_thread.reset();
124 }
125 }
126
111 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible 127 // FrameSubscriber is a proxy to the ThreadSafeCaptureOracle that's compatible
112 // with RenderWidgetHostViewFrameSubscriber. We create one per event type. 128 // with RenderWidgetHostViewFrameSubscriber. We create one per event type.
113 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber { 129 class FrameSubscriber : public RenderWidgetHostViewFrameSubscriber {
114 public: 130 public:
115 FrameSubscriber(VideoCaptureOracle::Event event_type, 131 FrameSubscriber(VideoCaptureOracle::Event event_type,
116 const scoped_refptr<ThreadSafeCaptureOracle>& oracle) 132 const scoped_refptr<ThreadSafeCaptureOracle>& oracle)
117 : event_type_(event_type), 133 : event_type_(event_type),
118 oracle_proxy_(oracle) {} 134 oracle_proxy_(oracle) {}
119 135
120 virtual bool ShouldCaptureFrame( 136 virtual bool ShouldCaptureFrame(
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
204 : public VideoCaptureMachine, 220 : public VideoCaptureMachine,
205 public WebContentsObserver, 221 public WebContentsObserver,
206 public base::SupportsWeakPtr<WebContentsCaptureMachine> { 222 public base::SupportsWeakPtr<WebContentsCaptureMachine> {
207 public: 223 public:
208 WebContentsCaptureMachine(int render_process_id, int render_view_id); 224 WebContentsCaptureMachine(int render_process_id, int render_view_id);
209 virtual ~WebContentsCaptureMachine(); 225 virtual ~WebContentsCaptureMachine();
210 226
211 // VideoCaptureMachine overrides. 227 // VideoCaptureMachine overrides.
212 virtual bool Start( 228 virtual bool Start(
213 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) OVERRIDE; 229 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) OVERRIDE;
214 virtual void Stop() OVERRIDE; 230 virtual void Stop(const base::Closure& callback) OVERRIDE;
215 231
216 // Starts a copy from the backing store or the composited surface. Must be run 232 // 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 233 // on the UI BrowserThread. |deliver_frame_cb| will be run when the operation
218 // completes. The copy will occur to |target|. 234 // completes. The copy will occur to |target|.
219 // 235 //
220 // This may be used as a ContentCaptureSubscription::CaptureCallback. 236 // This may be used as a ContentCaptureSubscription::CaptureCallback.
221 void Capture(const base::TimeTicks& start_time, 237 void Capture(const base::TimeTicks& start_time,
222 const scoped_refptr<media::VideoFrame>& target, 238 const scoped_refptr<media::VideoFrame>& target,
223 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 239 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
224 deliver_frame_cb); 240 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 294 // after any change to the WebContents that affects the RenderWidgetHost or
279 // attached views. 295 // attached views.
280 void RenewFrameSubscription(); 296 void RenewFrameSubscription();
281 297
282 // Parameters saved in constructor. 298 // Parameters saved in constructor.
283 const int initial_render_process_id_; 299 const int initial_render_process_id_;
284 const int initial_render_view_id_; 300 const int initial_render_view_id_;
285 301
286 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will 302 // A dedicated worker thread on which SkBitmap->VideoFrame conversion will
287 // occur. Only used when this activity cannot be done on the GPU. 303 // occur. Only used when this activity cannot be done on the GPU.
288 base::Thread render_thread_; 304 scoped_ptr<base::Thread> render_thread_;
Alpha Left Google 2014/01/09 01:37:07 There's no need to change this.
imcheng 2014/01/09 23:31:09 See comment below
289 305
290 // Makes all the decisions about which frames to copy, and how. 306 // Makes all the decisions about which frames to copy, and how.
291 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_; 307 scoped_refptr<ThreadSafeCaptureOracle> oracle_proxy_;
292 308
293 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE 309 // Routing ID of any active fullscreen render widget or MSG_ROUTING_NONE
294 // otherwise. 310 // otherwise.
295 int fullscreen_widget_id_; 311 int fullscreen_widget_id_;
296 312
297 // Last known RenderView size. 313 // Last known RenderView size.
298 gfx::Size last_view_size_; 314 gfx::Size last_view_size_;
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 count_frames_rendered_ = 0; 560 count_frames_rendered_ = 0;
545 last_frame_number_ = frame_number; 561 last_frame_number_ = frame_number;
546 } 562 }
547 } 563 }
548 } 564 }
549 565
550 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id, 566 WebContentsCaptureMachine::WebContentsCaptureMachine(int render_process_id,
551 int render_view_id) 567 int render_view_id)
552 : initial_render_process_id_(render_process_id), 568 : initial_render_process_id_(render_process_id),
553 initial_render_view_id_(render_view_id), 569 initial_render_view_id_(render_view_id),
554 render_thread_("WebContentsVideo_RenderThread"), 570 render_thread_(new base::Thread("WebContentsVideo_RenderThread")),
555 fullscreen_widget_id_(MSG_ROUTING_NONE) {} 571 fullscreen_widget_id_(MSG_ROUTING_NONE) {}
556 572
557 WebContentsCaptureMachine::~WebContentsCaptureMachine() {} 573 WebContentsCaptureMachine::~WebContentsCaptureMachine() {
574 BrowserThread::GetBlockingPool()->PostTask(FROM_HERE,
Alpha Left Google 2014/01/09 01:37:07 This shouldn't be necessary. The thread has alread
imcheng 2014/01/09 23:31:09 See comment below
575 base::Bind(&DeleteOnWorkerThread, base::Passed(&render_thread_)));
576 }
558 577
559 bool WebContentsCaptureMachine::Start( 578 bool WebContentsCaptureMachine::Start(
560 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) { 579 const scoped_refptr<ThreadSafeCaptureOracle>& oracle_proxy) {
561 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
562 DCHECK(!started_); 581 DCHECK(!started_);
563 582
564 DCHECK(oracle_proxy.get()); 583 DCHECK(oracle_proxy.get());
565 oracle_proxy_ = oracle_proxy; 584 oracle_proxy_ = oracle_proxy;
566 585
567 if (!render_thread_.Start()) { 586 if (!render_thread_->Start()) {
568 DVLOG(1) << "Failed to spawn render thread."; 587 DVLOG(1) << "Failed to spawn render thread.";
569 return false; 588 return false;
570 } 589 }
571 590
572 if (!StartObservingWebContents()) 591 if (!StartObservingWebContents())
573 return false; 592 return false;
574 593
575 started_ = true; 594 started_ = true;
576 return true; 595 return true;
577 } 596 }
578 597
579 void WebContentsCaptureMachine::Stop() { 598 void WebContentsCaptureMachine::Stop(const base::Closure& callback) {
580 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 599 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
581 subscription_.reset(); 600 subscription_.reset();
582 if (web_contents()) { 601 if (web_contents()) {
583 web_contents()->DecrementCapturerCount(); 602 web_contents()->DecrementCapturerCount();
584 Observe(NULL); 603 Observe(NULL);
585 } 604 }
586 render_thread_.Stop(); 605
606 // TODO(imcheng): why is it needed?
607 // This shuts down the message loop but thread is not complete dead yet.
608 render_thread_->StopSoon();
imcheng 2014/01/09 01:15:17 Not sure if needed? Seems the general advice is to
Alpha Left Google 2014/01/09 01:37:07 That's fine if we don't call this.
imcheng 2014/01/09 23:31:09 ACK, removed.
609
610 // The render thread cannot be stopped on the UI thread, so post a message
611 // to the thread pool used for blocking operations.
612 BrowserThread::GetBlockingPool()->PostTask(FROM_HERE,
613 base::Bind(&StopOnWorkerThread, render_thread_.get(), callback));
Alpha Left Google 2014/01/09 01:37:07 Just use &render_thread_ instead of render_thread_
imcheng 2014/01/09 23:31:09 I am a bit concerned about render_thread_ being in
614
587 started_ = false; 615 started_ = false;
588 } 616 }
589 617
590 void WebContentsCaptureMachine::Capture( 618 void WebContentsCaptureMachine::Capture(
591 const base::TimeTicks& start_time, 619 const base::TimeTicks& start_time,
592 const scoped_refptr<media::VideoFrame>& target, 620 const scoped_refptr<media::VideoFrame>& target,
593 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback& 621 const RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback&
594 deliver_frame_cb) { 622 deliver_frame_cb) {
595 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 623 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
596 624
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
703 deliver_frame_cb, 731 deliver_frame_cb,
704 bool success, 732 bool success,
705 const SkBitmap& bitmap) { 733 const SkBitmap& bitmap) {
706 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 734 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
707 735
708 base::TimeTicks now = base::TimeTicks::Now(); 736 base::TimeTicks now = base::TimeTicks::Now();
709 if (success) { 737 if (success) {
710 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time); 738 UMA_HISTOGRAM_TIMES("TabCapture.CopyTimeBitmap", now - start_time);
711 TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(), 739 TRACE_EVENT_ASYNC_STEP_INTO0("mirroring", "Capture", target.get(),
712 "Render"); 740 "Render");
713 render_thread_.message_loop_proxy()->PostTask(FROM_HERE, base::Bind( 741 render_thread_->message_loop_proxy()->PostTask(FROM_HERE, base::Bind(
714 &RenderVideoFrame, bitmap, target, 742 &RenderVideoFrame, bitmap, target,
715 base::Bind(deliver_frame_cb, start_time))); 743 base::Bind(deliver_frame_cb, start_time)));
716 } else { 744 } else {
717 // Capture can fail due to transient issues, so just skip this frame. 745 // Capture can fail due to transient issues, so just skip this frame.
718 DVLOG(1) << "CopyFromBackingStore failed; skipping frame."; 746 DVLOG(1) << "CopyFromBackingStore failed; skipping frame.";
719 deliver_frame_cb.Run(start_time, false); 747 deliver_frame_cb.Run(start_time, false);
720 } 748 }
721 } 749 }
722 750
723 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame( 751 void WebContentsCaptureMachine::DidCopyFromCompositingSurfaceToVideoFrame(
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
781 scoped_ptr<Client> client) { 809 scoped_ptr<Client> client) {
782 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString(); 810 DVLOG(1) << "Allocating " << params.requested_format.frame_size.ToString();
783 impl_->AllocateAndStart(params, client.Pass()); 811 impl_->AllocateAndStart(params, client.Pass());
784 } 812 }
785 813
786 void WebContentsVideoCaptureDevice::StopAndDeAllocate() { 814 void WebContentsVideoCaptureDevice::StopAndDeAllocate() {
787 impl_->StopAndDeAllocate(); 815 impl_->StopAndDeAllocate();
788 } 816 }
789 817
790 } // namespace content 818 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698