Home | History | Annotate | Download | only in base
      1 // Copyright 2014 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 "chromecast/media/cma/base/buffering_frame_provider.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/callback_helpers.h"
      9 #include "chromecast/media/cma/base/buffering_state.h"
     10 #include "chromecast/media/cma/base/decoder_buffer_base.h"
     11 #include "media/base/bind_to_current_loop.h"
     12 #include "media/base/buffers.h"
     13 
     14 namespace chromecast {
     15 namespace media {
     16 
     17 BufferingFrameProvider::BufferWithConfig::BufferWithConfig(
     18     const scoped_refptr<DecoderBufferBase>& buffer,
     19     const ::media::AudioDecoderConfig& audio_config,
     20     const ::media::VideoDecoderConfig& video_config)
     21     : buffer_(buffer),
     22       audio_config_(audio_config),
     23       video_config_(video_config) {
     24 }
     25 
     26 BufferingFrameProvider::BufferWithConfig::~BufferWithConfig() {
     27 }
     28 
     29 BufferingFrameProvider::BufferingFrameProvider(
     30     scoped_ptr<CodedFrameProvider> coded_frame_provider,
     31     size_t max_buffer_size,
     32     size_t max_frame_size,
     33     const FrameBufferedCB& frame_buffered_cb)
     34     : coded_frame_provider_(coded_frame_provider.Pass()),
     35       is_pending_request_(false),
     36       is_eos_(false),
     37       total_buffer_size_(0),
     38       max_buffer_size_(max_buffer_size),
     39       max_frame_size_(max_frame_size),
     40       frame_buffered_cb_(frame_buffered_cb),
     41       weak_factory_(this),
     42       weak_this_(weak_factory_.GetWeakPtr()) {
     43   DCHECK_LE(max_frame_size, max_buffer_size);
     44   thread_checker_.DetachFromThread();
     45 }
     46 
     47 BufferingFrameProvider::~BufferingFrameProvider() {
     48   // Required since some weak pointers might be released in the destructor.
     49   DCHECK(thread_checker_.CalledOnValidThread());
     50 }
     51 
     52 void BufferingFrameProvider::Read(const ReadCB& read_cb) {
     53   DCHECK(thread_checker_.CalledOnValidThread());
     54 
     55   DCHECK(!read_cb.is_null());
     56   read_cb_ = read_cb;
     57 
     58   CompleteReadIfNeeded();
     59 
     60   RequestBufferIfNeeded();
     61 }
     62 
     63 void BufferingFrameProvider::Flush(const base::Closure& flush_cb) {
     64   DCHECK(thread_checker_.CalledOnValidThread());
     65 
     66   // Invalidate all the buffers that belong to this media timeline.
     67   // This is needed since, even though |coded_frame_provider_| is flushed later
     68   // in this function, there might be a pending task holding onto a buffer.
     69   weak_factory_.InvalidateWeakPtrs();
     70 
     71   // Create a new valid weak pointer that is used for the next media timeline.
     72   weak_this_ = weak_factory_.GetWeakPtr();
     73 
     74   is_pending_request_ = false;
     75   is_eos_ = false;
     76   buffer_list_.clear();
     77   total_buffer_size_ = 0;
     78   read_cb_.Reset();
     79   coded_frame_provider_->Flush(flush_cb);
     80 }
     81 
     82 void BufferingFrameProvider::OnNewBuffer(
     83     const scoped_refptr<DecoderBufferBase>& buffer,
     84     const ::media::AudioDecoderConfig& audio_config,
     85     const ::media::VideoDecoderConfig& video_config) {
     86   is_pending_request_ = false;
     87   buffer_list_.push_back(
     88       BufferWithConfig(buffer, audio_config, video_config));
     89 
     90   if (buffer->end_of_stream()) {
     91     is_eos_ = true;
     92   } else {
     93     total_buffer_size_ += buffer->data_size();
     94   }
     95 
     96   if (!frame_buffered_cb_.is_null()) {
     97     // If the next upcoming frame is possibly filling the whole buffer,
     98     // then the buffer is considered as having reached its max capacity.
     99     bool max_capacity_flag =
    100         (total_buffer_size_ + max_frame_size_ >= max_buffer_size_);
    101     frame_buffered_cb_.Run(buffer, max_capacity_flag);
    102   }
    103 
    104   RequestBufferIfNeeded();
    105 
    106   CompleteReadIfNeeded();
    107 }
    108 
    109 void BufferingFrameProvider::RequestBufferIfNeeded() {
    110   if (is_pending_request_)
    111     return;
    112 
    113   if (is_eos_ || total_buffer_size_ >= max_buffer_size_)
    114     return;
    115 
    116   is_pending_request_ = true;
    117   coded_frame_provider_->Read(BindToCurrentLoop(
    118       base::Bind(&BufferingFrameProvider::OnNewBuffer, weak_this_)));
    119 }
    120 
    121 void BufferingFrameProvider::CompleteReadIfNeeded() {
    122   if (read_cb_.is_null())
    123     return;
    124 
    125   if (buffer_list_.empty())
    126     return;
    127 
    128   BufferWithConfig buffer_with_config(buffer_list_.front());
    129   buffer_list_.pop_front();
    130   if (!buffer_with_config.buffer()->end_of_stream())
    131     total_buffer_size_ -= buffer_with_config.buffer()->data_size();
    132 
    133   base::ResetAndReturn(&read_cb_).Run(
    134       buffer_with_config.buffer(),
    135       buffer_with_config.audio_config(),
    136       buffer_with_config.video_config());
    137 }
    138 
    139 }  // namespace media
    140 }  // namespace chromecast
    141