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
14namespace chromecast {
15namespace media {
16
17BufferingFrameProvider::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
26BufferingFrameProvider::BufferWithConfig::~BufferWithConfig() {
27}
28
29BufferingFrameProvider::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
47BufferingFrameProvider::~BufferingFrameProvider() {
48  // Required since some weak pointers might be released in the destructor.
49  DCHECK(thread_checker_.CalledOnValidThread());
50}
51
52void 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
63void 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
82void 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
109void 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
121void 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