• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
RTCVideoRenderer(const blink::WebMediaStreamTrack & video_track,const base::Closure & error_cb,const RepaintCB & repaint_cb)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 
~RTCVideoRenderer()26 RTCVideoRenderer::~RTCVideoRenderer() {
27 }
28 
Start()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 
Stop()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 
Play()52 void RTCVideoRenderer::Play() {
53   DCHECK(message_loop_proxy_->BelongsToCurrentThread());
54   if (state_ == PAUSED) {
55     state_ = STARTED;
56   }
57 }
58 
Pause()59 void RTCVideoRenderer::Pause() {
60   DCHECK(message_loop_proxy_->BelongsToCurrentThread());
61   if (state_ == STARTED) {
62     state_ = PAUSED;
63   }
64 }
65 
OnReadyStateChanged(blink::WebMediaStreamSource::ReadyState state)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 
OnEnabledChanged(bool enabled)73 void RTCVideoRenderer::OnEnabledChanged(bool enabled) {
74   DCHECK(message_loop_proxy_->BelongsToCurrentThread());
75   if (!enabled)
76     MaybeRenderSignalingFrame();
77 }
78 
OnVideoFrame(const scoped_refptr<media::VideoFrame> & frame)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 
MaybeRenderSignalingFrame()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