Home | History | Annotate | Download | only in media
      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