Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Unified Diff: chromecast/media/cma/base/buffering_frame_provider.cc

Issue 554893003: Introduce some buffering into the cast media pipeline. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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..c2dfa18070fc5fa98481ec7118b24f2bdb64719b
--- /dev/null
+++ b/chromecast/media/cma/base/buffering_frame_provider.cc
@@ -0,0 +1,139 @@
+// 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_(new base::WeakPtrFactory<BufferingFrameProvider>(this)) {
gunsch 2014/09/09 15:58:18 weak_factory_(this)
damienv1 2014/09/09 16:24:17 I am using a pointer in this case (to be able to r
+ DCHECK_LE(max_frame_size, max_buffer_size);
+ weak_this_ = weak_factory_->GetWeakPtr();
gunsch 2014/09/09 15:58:18 since initializers are executed in order, you shou
damienv1 2014/09/09 16:24:17 Done.
+ 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();
+ weak_factory_.reset(new base::WeakPtrFactory<BufferingFrameProvider>(this));
+ 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 we consider the max buffering capacity as reached.
gunsch 2014/09/09 15:58:18 nit: I think we've been chided for using "we" in c
damienv1 2014/09/09 16:24:17 Done.
+ bool max_capacity_flag =
+ (total_buffer_size_ + max_frame_size_ >= max_buffer_size_);
gunsch 2014/09/09 15:58:18 nit: unnecessary parens
damienv1 2014/09/09 16:24:17 I find it easier to read though.
+ 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

Powered by Google App Engine
This is Rietveld 408576698