1 // Copyright 2015 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.
5 #include "chromecast/media/cma/backend/media_component_device_default.h"
8 #include "base/callback_helpers.h"
9 #include "base/location.h"
10 #include "base/thread_task_runner_handle.h"
11 #include "chromecast/public/media/cast_decoder_buffer.h"
12 #include "chromecast/public/media/decrypt_context.h"
13 #include "chromecast/public/media/media_pipeline_device_params.h"
14 #include "chromecast/public/task_runner.h"
15 #include "media/base/buffers.h"
17 namespace chromecast
{
22 // Maximum number of frames that can be buffered.
23 const size_t kMaxFrameCount
= 20;
25 // Wraps base::Closure in the chromecast/public TaskRunner interface.
26 class ClosureTask
: public TaskRunner::Task
{
28 ClosureTask(const base::Closure
& cb
) : cb_(cb
) {}
29 void Run() override
{ cb_
.Run(); }
35 // Returns whether or not transitioning from |state1| to |state2| is valid.
36 inline static bool IsValidStateTransition(MediaComponentDevice::State state1
,
37 MediaComponentDevice::State state2
) {
41 // All states can transition to |kStateError|.
42 if (state2
== MediaComponentDevice::kStateError
)
45 // All the other valid FSM transitions.
47 case MediaComponentDevice::kStateUninitialized
:
48 return state2
== MediaComponentDevice::kStateIdle
;
49 case MediaComponentDevice::kStateIdle
:
50 return state2
== MediaComponentDevice::kStateRunning
||
51 state2
== MediaComponentDevice::kStatePaused
||
52 state2
== MediaComponentDevice::kStateUninitialized
;
53 case MediaComponentDevice::kStatePaused
:
54 return state2
== MediaComponentDevice::kStateIdle
||
55 state2
== MediaComponentDevice::kStateRunning
;
56 case MediaComponentDevice::kStateRunning
:
57 return state2
== MediaComponentDevice::kStateIdle
||
58 state2
== MediaComponentDevice::kStatePaused
;
59 case MediaComponentDevice::kStateError
:
60 return state2
== MediaComponentDevice::kStateUninitialized
;
69 MediaComponentDeviceDefault::DefaultDecoderBuffer::DefaultDecoderBuffer()
73 MediaComponentDeviceDefault::DefaultDecoderBuffer::~DefaultDecoderBuffer() {
76 MediaComponentDeviceDefault::MediaComponentDeviceDefault(
77 const MediaPipelineDeviceParams
& params
,
78 MediaClockDevice
* media_clock_device
)
79 : task_runner_(params
.task_runner
),
80 media_clock_device_(media_clock_device
),
81 state_(kStateUninitialized
),
82 rendering_time_(::media::kNoTimestamp()),
83 decoded_frame_count_(0),
84 decoded_byte_count_(0),
85 scheduled_rendering_task_(false),
87 weak_this_
= weak_factory_
.GetWeakPtr();
88 thread_checker_
.DetachFromThread();
91 MediaComponentDeviceDefault::~MediaComponentDeviceDefault() {
94 void MediaComponentDeviceDefault::SetClient(Client
* client
) {
95 DCHECK(thread_checker_
.CalledOnValidThread());
96 client_
.reset(client
);
99 MediaComponentDevice::State
MediaComponentDeviceDefault::GetState() const {
100 DCHECK(thread_checker_
.CalledOnValidThread());
104 bool MediaComponentDeviceDefault::SetState(State new_state
) {
105 DCHECK(thread_checker_
.CalledOnValidThread());
106 DCHECK(IsValidStateTransition(state_
, new_state
));
109 if (state_
== kStateIdle
) {
110 // Back to the idle state: reset a bunch of parameters.
112 rendering_time_
= ::media::kNoTimestamp();
113 decoded_frame_count_
= 0;
114 decoded_byte_count_
= 0;
116 pending_buffer_
= scoped_ptr
<CastDecoderBuffer
>();
117 frame_pushed_cb_
.reset();
121 if (state_
== kStateRunning
) {
122 if (!scheduled_rendering_task_
) {
123 scheduled_rendering_task_
= true;
124 task_runner_
->PostTask(
126 base::Bind(&MediaComponentDeviceDefault::RenderTask
, weak_this_
)),
135 bool MediaComponentDeviceDefault::SetStartPts(int64_t time_microseconds
) {
136 DCHECK(thread_checker_
.CalledOnValidThread());
137 DCHECK_EQ(state_
, kStateIdle
);
138 rendering_time_
= base::TimeDelta::FromMicroseconds(time_microseconds
);
142 MediaComponentDevice::FrameStatus
MediaComponentDeviceDefault::PushFrame(
143 DecryptContext
* decrypt_context_in
,
144 CastDecoderBuffer
* buffer_in
,
145 FrameStatusCB
* completion_cb_in
) {
146 DCHECK(thread_checker_
.CalledOnValidThread());
147 DCHECK(state_
== kStatePaused
|| state_
== kStateRunning
);
149 DCHECK(!pending_buffer_
.get());
152 scoped_ptr
<DecryptContext
> decrypt_context(decrypt_context_in
);
153 scoped_ptr
<FrameStatusCB
> completion_cb(completion_cb_in
);
155 scoped_ptr
<CastDecoderBuffer
> buffer(buffer_in
);
156 if (buffer
->end_of_stream()) {
158 return kFrameSuccess
;
161 if (frames_
.size() > kMaxFrameCount
) {
162 pending_buffer_
= buffer
.Pass();
163 frame_pushed_cb_
= completion_cb
.Pass();
164 return kFramePending
;
167 DefaultDecoderBuffer fake_buffer
;
168 fake_buffer
.size
= buffer
->data_size();
169 fake_buffer
.pts
= base::TimeDelta::FromMicroseconds(buffer
->timestamp());
170 frames_
.push_back(fake_buffer
);
171 return kFrameSuccess
;
174 MediaComponentDeviceDefault::RenderingDelay
175 MediaComponentDeviceDefault::GetRenderingDelay() const {
177 return RenderingDelay();
180 void MediaComponentDeviceDefault::RenderTask() {
181 scheduled_rendering_task_
= false;
183 if (state_
!= kStateRunning
)
186 base::TimeDelta media_time
= base::TimeDelta::FromMicroseconds(
187 media_clock_device_
->GetTimeMicroseconds());
188 if (media_time
== ::media::kNoTimestamp()) {
189 scheduled_rendering_task_
= true;
190 task_runner_
->PostTask(
192 base::Bind(&MediaComponentDeviceDefault::RenderTask
, weak_this_
)),
197 while (!frames_
.empty() && frames_
.front().pts
<= media_time
) {
198 rendering_time_
= frames_
.front().pts
;
199 decoded_frame_count_
++;
200 decoded_byte_count_
+= frames_
.front().size
;
202 if (pending_buffer_
.get()) {
203 DefaultDecoderBuffer fake_buffer
;
204 fake_buffer
.size
= pending_buffer_
->data_size();
206 base::TimeDelta::FromMicroseconds(pending_buffer_
->timestamp());
207 frames_
.push_back(fake_buffer
);
208 pending_buffer_
= scoped_ptr
<CastDecoderBuffer
>();
209 frame_pushed_cb_
->Run(kFrameSuccess
);
210 frame_pushed_cb_
.reset();
214 if (frames_
.empty() && is_eos_
) {
216 client_
->OnEndOfStream();
221 scheduled_rendering_task_
= true;
222 task_runner_
->PostTask(
224 base::Bind(&MediaComponentDeviceDefault::RenderTask
, weak_this_
)),
228 bool MediaComponentDeviceDefault::GetStatistics(Statistics
* stats
) const {
229 if (state_
!= kStateRunning
)
232 // Note: what is returned here is not the number of samples but the number of
233 // frames. The value is different for audio.
234 stats
->decoded_bytes
= decoded_byte_count_
;
235 stats
->decoded_samples
= decoded_frame_count_
;
236 stats
->dropped_samples
= 0;
241 } // namespace chromecast