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/video_frame.h" 10 #include "media/base/video_util.h" 11 12 namespace content { 13 14 RTCVideoRenderer::RTCVideoRenderer( 15 const blink::WebMediaStreamTrack& video_track, 16 const base::Closure& error_cb, 17 const RepaintCB& repaint_cb) 18 : error_cb_(error_cb), 19 repaint_cb_(repaint_cb), 20 message_loop_proxy_(base::MessageLoopProxy::current()), 21 state_(STOPPED), 22 first_frame_rendered_(false), 23 video_track_(video_track) { 24 } 25 26 RTCVideoRenderer::~RTCVideoRenderer() { 27 } 28 29 void RTCVideoRenderer::Start() { 30 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 31 DCHECK_EQ(state_, STOPPED); 32 DCHECK(!first_frame_rendered_); 33 34 AddToVideoTrack(this, video_track_); 35 state_ = STARTED; 36 37 if (video_track_.source().readyState() == 38 blink::WebMediaStreamSource::ReadyStateEnded || 39 !video_track_.isEnabled()) { 40 MaybeRenderSignalingFrame(); 41 } 42 } 43 44 void RTCVideoRenderer::Stop() { 45 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 46 DCHECK(state_ == STARTED || state_ == PAUSED); 47 RemoveFromVideoTrack(this, video_track_); 48 state_ = STOPPED; 49 first_frame_rendered_ = false; 50 } 51 52 void RTCVideoRenderer::Play() { 53 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 54 if (state_ == PAUSED) { 55 state_ = STARTED; 56 } 57 } 58 59 void RTCVideoRenderer::Pause() { 60 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 61 if (state_ == STARTED) { 62 state_ = PAUSED; 63 } 64 } 65 66 void RTCVideoRenderer::OnReadyStateChanged( 67 blink::WebMediaStreamSource::ReadyState state) { 68 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 69 if (state == blink::WebMediaStreamSource::ReadyStateEnded) 70 MaybeRenderSignalingFrame(); 71 } 72 73 void RTCVideoRenderer::OnEnabledChanged(bool enabled) { 74 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 75 if (!enabled) 76 MaybeRenderSignalingFrame(); 77 } 78 79 void RTCVideoRenderer::OnVideoFrame( 80 const scoped_refptr<media::VideoFrame>& frame) { 81 DCHECK(message_loop_proxy_->BelongsToCurrentThread()); 82 if (state_ != STARTED) { 83 return; 84 } 85 86 TRACE_EVENT_INSTANT1("rtc_video_renderer", 87 "OnVideoFrame", 88 TRACE_EVENT_SCOPE_THREAD, 89 "timestamp", 90 frame->GetTimestamp().InMilliseconds()); 91 repaint_cb_.Run(frame); 92 first_frame_rendered_ = true; 93 } 94 95 void RTCVideoRenderer::MaybeRenderSignalingFrame() { 96 // Render a small black frame if no frame has been rendered. 97 // This is necessary to make sure audio can play if the video tag src is 98 // a MediaStream video track that has been rejected, ended or disabled. 99 if (first_frame_rendered_) 100 return; 101 102 const int kMinFrameSize = 2; 103 const gfx::Size size(kMinFrameSize, kMinFrameSize); 104 scoped_refptr<media::VideoFrame> video_frame = 105 media::VideoFrame::CreateBlackFrame(size); 106 OnVideoFrame(video_frame); 107 } 108 109 } // namespace content 110