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 3 // found in the LICENSE file. 4 5 #include "content/renderer/media/rtc_video_renderer.h" 6 7 #include "base/debug/trace_event.h" 8 #include "base/message_loop/message_loop_proxy.h" 9 #include "media/base/bind_to_current_loop.h" 10 #include "media/base/video_frame.h" 11 #include "media/base/video_util.h" 12 13 const int kMinFrameSize = 2; 14 15 namespace content { 16 17 RTCVideoRenderer::RTCVideoRenderer( 18 const blink::WebMediaStreamTrack& video_track, 19 const base::Closure& error_cb, 20 const RepaintCB& repaint_cb) 21 : error_cb_(error_cb), 22 repaint_cb_(repaint_cb), 23 message_loop_proxy_(base::MessageLoopProxy::current()), 24 state_(STOPPED), 25 frame_size_(kMinFrameSize, kMinFrameSize), 26 video_track_(video_track), 27 weak_factory_(this) { 28 } 29 30 RTCVideoRenderer::~RTCVideoRenderer() { 31 } 32 33 void RTCVideoRenderer::Start() { 34 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 35 DCHECK_EQ(state_, STOPPED); 36 37 AddToVideoTrack( 38 this, 39 media::BindToCurrentLoop( 40 base::Bind( 41 &RTCVideoRenderer::OnVideoFrame, 42 weak_factory_.GetWeakPtr())), 43 video_track_); 44 state_ = STARTED; 45 46 if (video_track_.source().readyState() == 47 blink::WebMediaStreamSource::ReadyStateEnded || 48 !video_track_.isEnabled()) { 49 RenderSignalingFrame(); 50 } 51 } 52 53 void RTCVideoRenderer::Stop() { 54 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 55 DCHECK(state_ == STARTED || state_ == PAUSED); 56 RemoveFromVideoTrack(this, video_track_); 57 weak_factory_.InvalidateWeakPtrs(); 58 state_ = STOPPED; 59 frame_size_.set_width(kMinFrameSize); 60 frame_size_.set_height(kMinFrameSize); 61 } 62 63 void RTCVideoRenderer::Play() { 64 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 65 if (state_ == PAUSED) { 66 state_ = STARTED; 67 } 68 } 69 70 void RTCVideoRenderer::Pause() { 71 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 72 if (state_ == STARTED) { 73 state_ = PAUSED; 74 } 75 } 76 77 void RTCVideoRenderer::OnReadyStateChanged( 78 blink::WebMediaStreamSource::ReadyState state) { 79 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 80 if (state == blink::WebMediaStreamSource::ReadyStateEnded) 81 RenderSignalingFrame(); 82 } 83 84 void RTCVideoRenderer::OnVideoFrame( 85 const scoped_refptr<media::VideoFrame>& frame, 86 const media::VideoCaptureFormat& format, 87 const base::TimeTicks& estimated_capture_time) { 88 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 89 if (state_ != STARTED) { 90 return; 91 } 92 93 frame_size_ = frame->natural_size(); 94 95 TRACE_EVENT_INSTANT1("rtc_video_renderer", 96 "OnVideoFrame", 97 TRACE_EVENT_SCOPE_THREAD, 98 "timestamp", 99 frame->timestamp().InMilliseconds()); 100 repaint_cb_.Run(frame); 101 } 102 103 void RTCVideoRenderer::RenderSignalingFrame() { 104 // This is necessary to make sure audio can play if the video tag src is 105 // a MediaStream video track that has been rejected or ended. 106 // It also ensure that the renderer don't hold a reference to a real video 107 // frame if no more frames are provided. This is since there might be a 108 // finite number of available buffers. E.g, video that 109 // originates from a video camera. 110 scoped_refptr<media::VideoFrame> video_frame = 111 media::VideoFrame::CreateBlackFrame(frame_size_); 112 OnVideoFrame(video_frame, media::VideoCaptureFormat(), base::TimeTicks()); 113 } 114 115 } // namespace content 116