| Index: chromecast/media/cma/base/buffering_frame_provider.cc
|
| diff --git a/chromecast/media/cma/base/buffering_frame_provider.cc b/chromecast/media/cma/base/buffering_frame_provider.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..1a8fec9a1259b7a5c758117b58684b211121b79b
|
| --- /dev/null
|
| +++ b/chromecast/media/cma/base/buffering_frame_provider.cc
|
| @@ -0,0 +1,140 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chromecast/media/cma/base/buffering_frame_provider.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/callback_helpers.h"
|
| +#include "chromecast/media/cma/base/buffering_state.h"
|
| +#include "chromecast/media/cma/base/decoder_buffer_base.h"
|
| +#include "media/base/bind_to_current_loop.h"
|
| +#include "media/base/buffers.h"
|
| +
|
| +namespace chromecast {
|
| +namespace media {
|
| +
|
| +BufferingFrameProvider::BufferWithConfig::BufferWithConfig(
|
| + const scoped_refptr<DecoderBufferBase>& buffer,
|
| + const ::media::AudioDecoderConfig& audio_config,
|
| + const ::media::VideoDecoderConfig& video_config)
|
| + : buffer_(buffer),
|
| + audio_config_(audio_config),
|
| + video_config_(video_config) {
|
| +}
|
| +
|
| +BufferingFrameProvider::BufferWithConfig::~BufferWithConfig() {
|
| +}
|
| +
|
| +BufferingFrameProvider::BufferingFrameProvider(
|
| + scoped_ptr<CodedFrameProvider> coded_frame_provider,
|
| + size_t max_buffer_size,
|
| + size_t max_frame_size,
|
| + const FrameBufferedCB& frame_buffered_cb)
|
| + : coded_frame_provider_(coded_frame_provider.Pass()),
|
| + is_pending_request_(false),
|
| + is_eos_(false),
|
| + total_buffer_size_(0),
|
| + max_buffer_size_(max_buffer_size),
|
| + max_frame_size_(max_frame_size),
|
| + frame_buffered_cb_(frame_buffered_cb),
|
| + weak_factory_(this),
|
| + weak_this_(weak_factory_.GetWeakPtr()) {
|
| + DCHECK_LE(max_frame_size, max_buffer_size);
|
| + thread_checker_.DetachFromThread();
|
| +}
|
| +
|
| +BufferingFrameProvider::~BufferingFrameProvider() {
|
| + // Required since some weak pointers might be released in the destructor.
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +}
|
| +
|
| +void BufferingFrameProvider::Read(const ReadCB& read_cb) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + DCHECK(!read_cb.is_null());
|
| + read_cb_ = read_cb;
|
| +
|
| + CompleteReadIfNeeded();
|
| +
|
| + RequestBufferIfNeeded();
|
| +}
|
| +
|
| +void BufferingFrameProvider::Flush(const base::Closure& flush_cb) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| + // Invalidate all the buffers that belong to this media timeline.
|
| + // This is needed since, even though |coded_frame_provider_| is flushed later
|
| + // in this function, there might be a pending task holding onto a buffer.
|
| + weak_factory_.InvalidateWeakPtrs();
|
| +
|
| + // Create a new valid weak pointer that is used for the next media timeline.
|
| + weak_this_ = weak_factory_.GetWeakPtr();
|
| +
|
| + is_pending_request_ = false;
|
| + is_eos_ = false;
|
| + buffer_list_.clear();
|
| + total_buffer_size_ = 0;
|
| + read_cb_.Reset();
|
| + coded_frame_provider_->Flush(flush_cb);
|
| +}
|
| +
|
| +void BufferingFrameProvider::OnNewBuffer(
|
| + const scoped_refptr<DecoderBufferBase>& buffer,
|
| + const ::media::AudioDecoderConfig& audio_config,
|
| + const ::media::VideoDecoderConfig& video_config) {
|
| + is_pending_request_ = false;
|
| + buffer_list_.push_back(
|
| + BufferWithConfig(buffer, audio_config, video_config));
|
| +
|
| + if (buffer->end_of_stream()) {
|
| + is_eos_ = true;
|
| + } else {
|
| + total_buffer_size_ += buffer->data_size();
|
| + }
|
| +
|
| + if (!frame_buffered_cb_.is_null()) {
|
| + // If the next upcoming frame is possibly filling the whole buffer,
|
| + // then the buffer is considered as having reached its max capacity.
|
| + bool max_capacity_flag =
|
| + (total_buffer_size_ + max_frame_size_ >= max_buffer_size_);
|
| + frame_buffered_cb_.Run(buffer, max_capacity_flag);
|
| + }
|
| +
|
| + RequestBufferIfNeeded();
|
| +
|
| + CompleteReadIfNeeded();
|
| +}
|
| +
|
| +void BufferingFrameProvider::RequestBufferIfNeeded() {
|
| + if (is_pending_request_)
|
| + return;
|
| +
|
| + if (is_eos_ || total_buffer_size_ >= max_buffer_size_)
|
| + return;
|
| +
|
| + is_pending_request_ = true;
|
| + coded_frame_provider_->Read(BindToCurrentLoop(
|
| + base::Bind(&BufferingFrameProvider::OnNewBuffer, weak_this_)));
|
| +}
|
| +
|
| +void BufferingFrameProvider::CompleteReadIfNeeded() {
|
| + if (read_cb_.is_null())
|
| + return;
|
| +
|
| + if (buffer_list_.empty())
|
| + return;
|
| +
|
| + BufferWithConfig buffer_with_config(buffer_list_.front());
|
| + buffer_list_.pop_front();
|
| + if (!buffer_with_config.buffer()->end_of_stream())
|
| + total_buffer_size_ -= buffer_with_config.buffer()->data_size();
|
| +
|
| + base::ResetAndReturn(&read_cb_).Run(
|
| + buffer_with_config.buffer(),
|
| + buffer_with_config.audio_config(),
|
| + buffer_with_config.video_config());
|
| +}
|
| +
|
| +} // namespace media
|
| +} // namespace chromecast
|
|
|