Home | History | Annotate | Download | only in media
      1 // Copyright 2013 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_decoder_factory_tv.h"
      6 
      7 #include "base/callback_helpers.h"
      8 #include "content/renderer/media/rtc_video_decoder_bridge_tv.h"
      9 #include "media/base/audio_decoder_config.h"
     10 #include "media/base/bind_to_loop.h"
     11 #include "media/base/decoder_buffer.h"
     12 #include "media/base/video_decoder_config.h"
     13 #include "third_party/libjingle/source/talk/base/ratetracker.h"
     14 
     15 using media::DemuxerStream;
     16 
     17 namespace content {
     18 
     19 // RTCDemuxerStream ------------------------------------------------------------
     20 
     21 class RTCDemuxerStream : public DemuxerStream {
     22  public:
     23   explicit RTCDemuxerStream(const gfx::Size& size);
     24   virtual ~RTCDemuxerStream();
     25 
     26   // DemuxerStream implementation.
     27   virtual void Read(const ReadCB& read_cb) OVERRIDE;
     28   virtual media::AudioDecoderConfig audio_decoder_config() OVERRIDE;
     29   virtual media::VideoDecoderConfig video_decoder_config() OVERRIDE;
     30   virtual Type type() OVERRIDE;
     31   virtual void EnableBitstreamConverter() OVERRIDE;
     32 
     33   void QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer,
     34                    const gfx::Size& new_size);
     35   void Destroy();
     36 
     37  private:
     38   struct BufferEntry {
     39     BufferEntry(const scoped_refptr<media::DecoderBuffer>& decoder_buffer_param,
     40                 const gfx::Size& new_size_param)
     41         : decoder_buffer(decoder_buffer_param),
     42           new_size(new_size_param) {}
     43 
     44     scoped_refptr<media::DecoderBuffer> decoder_buffer;
     45     // When |!new_size.isEmpty()|, it means that config change with new size
     46     // |new_size| happened.
     47     gfx::Size new_size;
     48   };
     49 
     50   void RunReadCallback_Locked();
     51 
     52   base::Lock lock_;
     53   bool is_destroyed_;
     54   std::queue<BufferEntry> buffer_queue_;
     55   ReadCB read_cb_;
     56 
     57   media::AudioDecoderConfig dummy_audio_decoder_config_;
     58   media::VideoDecoderConfig video_decoder_config_;
     59   talk_base::RateTracker frame_rate_tracker_;
     60 };
     61 
     62 RTCDemuxerStream::RTCDemuxerStream(const gfx::Size& size)
     63     : is_destroyed_(false),
     64       video_decoder_config_(media::kCodecVP8,
     65                             media::VP8PROFILE_MAIN,
     66                             media::VideoFrame::NATIVE_TEXTURE,
     67                             size,
     68                             gfx::Rect(size),
     69                             size,
     70                             NULL,
     71                             0,
     72                             false) {}
     73 
     74 RTCDemuxerStream::~RTCDemuxerStream() { DCHECK(is_destroyed_); }
     75 
     76 media::AudioDecoderConfig RTCDemuxerStream::audio_decoder_config() {
     77   NOTIMPLEMENTED() << "Does not support audio.";
     78   return dummy_audio_decoder_config_;
     79 }
     80 
     81 media::VideoDecoderConfig RTCDemuxerStream::video_decoder_config() {
     82   base::AutoLock lock(lock_);
     83   return video_decoder_config_;
     84 }
     85 
     86 DemuxerStream::Type RTCDemuxerStream::type() { return DemuxerStream::VIDEO; }
     87 
     88 void RTCDemuxerStream::EnableBitstreamConverter() { NOTREACHED(); }
     89 
     90 void RTCDemuxerStream::QueueBuffer(scoped_refptr<media::DecoderBuffer> buffer,
     91                                    const gfx::Size& new_size) {
     92   base::AutoLock lock(lock_);
     93   if (is_destroyed_)
     94     return;
     95   buffer_queue_.push(BufferEntry(buffer, new_size));
     96   if (buffer)
     97     frame_rate_tracker_.Update(1);
     98   DVLOG(1) << "frame rate received : " << frame_rate_tracker_.units_second();
     99   RunReadCallback_Locked();
    100 }
    101 
    102 void RTCDemuxerStream::Read(const ReadCB& read_cb) {
    103   base::AutoLock lock(lock_);
    104   DCHECK(read_cb_.is_null());
    105   if (is_destroyed_) {
    106     media::BindToLoop(base::MessageLoopProxy::current(), read_cb)
    107         .Run(DemuxerStream::kAborted, NULL);
    108     return;
    109   }
    110   read_cb_ = media::BindToLoop(base::MessageLoopProxy::current(), read_cb);
    111   RunReadCallback_Locked();
    112 }
    113 
    114 void RTCDemuxerStream::Destroy() {
    115   base::AutoLock lock(lock_);
    116   DCHECK(!is_destroyed_);
    117   is_destroyed_ = true;
    118   if (!read_cb_.is_null())
    119     base::ResetAndReturn(&read_cb_).Run(DemuxerStream::kAborted, NULL);
    120   while (!buffer_queue_.empty())
    121     buffer_queue_.pop();
    122 }
    123 
    124 void RTCDemuxerStream::RunReadCallback_Locked() {
    125   if (read_cb_.is_null() || buffer_queue_.empty())
    126     return;
    127 
    128   BufferEntry& front = buffer_queue_.front();
    129   if (!front.new_size.IsEmpty()) {
    130     // No VideoFrame actually reaches GL renderer in Google TV case. We just
    131     // make coded_size == visible_rect == natural_size here.
    132     video_decoder_config_.Initialize(media::kCodecVP8,
    133                                      media::VP8PROFILE_MAIN,
    134                                      media::VideoFrame::NATIVE_TEXTURE,
    135                                      front.new_size,
    136                                      gfx::Rect(front.new_size),
    137                                      front.new_size,
    138                                      NULL,
    139                                      0,
    140                                      false,
    141                                      false);
    142     base::ResetAndReturn(&read_cb_).Run(DemuxerStream::kConfigChanged, NULL);
    143     front.new_size.SetSize(0, 0);
    144     return;
    145   }
    146   base::ResetAndReturn(&read_cb_).Run(DemuxerStream::kOk, front.decoder_buffer);
    147   buffer_queue_.pop();
    148 }
    149 
    150 // RTCVideoDecoderFactoryTv ----------------------------------------------------
    151 
    152 RTCVideoDecoderFactoryTv::RTCVideoDecoderFactoryTv() : is_acquired_(false) {}
    153 RTCVideoDecoderFactoryTv::~RTCVideoDecoderFactoryTv() {}
    154 
    155 webrtc::VideoDecoder* RTCVideoDecoderFactoryTv::CreateVideoDecoder(
    156     webrtc::VideoCodecType type) {
    157   base::AutoLock lock(lock_);
    158   // One decoder at a time!
    159   if (decoder_)
    160     return NULL;
    161   // Only VP8 is supported --- returning NULL will make WebRTC fall back to SW
    162   // decoder.
    163   if (type != webrtc::kVideoCodecVP8)
    164     return NULL;
    165   decoder_.reset(new RTCVideoDecoderBridgeTv(this));
    166   return decoder_.get();
    167 }
    168 
    169 void RTCVideoDecoderFactoryTv::DestroyVideoDecoder(
    170     webrtc::VideoDecoder* decoder) {
    171   base::AutoLock lock(lock_);
    172   DCHECK_EQ(decoder_.get(), decoder);
    173   decoder_.reset();
    174 }
    175 
    176 bool RTCVideoDecoderFactoryTv::AcquireDemuxer() {
    177   base::AutoLock lock(lock_);
    178   if (is_acquired_)
    179     return false;
    180   is_acquired_ = true;
    181   return true;
    182 }
    183 
    184 void RTCVideoDecoderFactoryTv::ReleaseDemuxer() {
    185   base::AutoLock lock(lock_);
    186   DCHECK(is_acquired_);
    187   is_acquired_ = false;
    188   // Clean up internal state as a demuxer.
    189   init_cb_.Reset();
    190   if (stream_) {
    191     stream_->Destroy();
    192     stream_.reset();
    193   }
    194 }
    195 
    196 void RTCVideoDecoderFactoryTv::Initialize(media::DemuxerHost* /*host*/,
    197                                           const media::PipelineStatusCB& cb,
    198                                           bool /*enable_text_tracks*/) {
    199   base::AutoLock lock(lock_);
    200   init_cb_ = media::BindToLoop(base::MessageLoopProxy::current(), cb);
    201   if (stream_)
    202     base::ResetAndReturn(&init_cb_).Run(media::PIPELINE_OK);
    203 }
    204 
    205 void RTCVideoDecoderFactoryTv::Seek(base::TimeDelta time,
    206                                     const media::PipelineStatusCB& status_cb) {
    207   DCHECK(!status_cb.is_null());
    208   status_cb.Run(media::PIPELINE_OK);
    209 }
    210 
    211 void RTCVideoDecoderFactoryTv::Stop(const base::Closure& callback) {
    212   DCHECK(!callback.is_null());
    213   callback.Run();
    214 }
    215 
    216 void RTCVideoDecoderFactoryTv::OnAudioRendererDisabled() {
    217 }
    218 
    219 DemuxerStream* RTCVideoDecoderFactoryTv::GetStream(DemuxerStream::Type type) {
    220   base::AutoLock lock(lock_);
    221   if (type == DemuxerStream::VIDEO)
    222     return stream_.get();
    223   return NULL;
    224 }
    225 
    226 base::TimeDelta RTCVideoDecoderFactoryTv::GetStartTime() const {
    227   return base::TimeDelta();
    228 }
    229 
    230 void RTCVideoDecoderFactoryTv::InitializeStream(const gfx::Size& size) {
    231   base::AutoLock lock(lock_);
    232   DCHECK(!stream_);
    233   stream_.reset(new RTCDemuxerStream(size));
    234   if (!init_cb_.is_null())
    235     base::ResetAndReturn(&init_cb_).Run(media::PIPELINE_OK);
    236 }
    237 
    238 void RTCVideoDecoderFactoryTv::QueueBuffer(
    239     scoped_refptr<media::DecoderBuffer> buffer,
    240     const gfx::Size& new_size) {
    241   base::AutoLock lock(lock_);
    242   DCHECK(stream_);
    243   stream_->QueueBuffer(buffer, new_size);
    244 }
    245 
    246 }  // namespace content
    247