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