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.
5 #include "chromecast/media/cma/pipeline/av_pipeline_impl.h"
8 #include "base/location.h"
9 #include "base/single_thread_task_runner.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "chromecast/media/base/decrypt_context.h"
13 #include "chromecast/media/cdm/browser_cdm_cast.h"
14 #include "chromecast/media/cma/backend/media_clock_device.h"
15 #include "chromecast/media/cma/backend/media_component_device.h"
16 #include "chromecast/media/cma/base/buffering_frame_provider.h"
17 #include "chromecast/media/cma/base/buffering_state.h"
18 #include "chromecast/media/cma/base/cma_logging.h"
19 #include "chromecast/media/cma/base/coded_frame_provider.h"
20 #include "chromecast/media/cma/base/decoder_buffer_base.h"
21 #include "chromecast/media/cma/pipeline/decrypt_util.h"
22 #include "media/base/audio_decoder_config.h"
23 #include "media/base/bind_to_current_loop.h"
24 #include "media/base/buffers.h"
25 #include "media/base/decrypt_config.h"
27 namespace chromecast
{
32 const int kNoCallbackId
= -1;
36 AvPipelineImpl::AvPipelineImpl(
37 MediaComponentDevice
* media_component_device
,
38 const UpdateConfigCB
& update_config_cb
)
39 : update_config_cb_(update_config_cb
),
40 media_component_device_(media_component_device
),
41 state_(kUninitialized
),
42 buffered_time_(::media::kNoTimestamp()),
43 playable_buffered_time_(::media::kNoTimestamp()),
44 enable_feeding_(false),
47 enable_time_update_(false),
48 pending_time_update_task_(false),
50 media_keys_callback_id_(kNoCallbackId
),
52 DCHECK(media_component_device
);
53 weak_this_
= weak_factory_
.GetWeakPtr();
54 thread_checker_
.DetachFromThread();
57 AvPipelineImpl::~AvPipelineImpl() {
58 DCHECK(thread_checker_
.CalledOnValidThread());
59 media_component_device_
->SetClient(MediaComponentDevice::Client());
61 if (media_keys_
&& media_keys_callback_id_
!= kNoCallbackId
)
62 media_keys_
->UnregisterPlayer(media_keys_callback_id_
);
65 void AvPipelineImpl::TransitionToState(State state
) {
66 DCHECK(thread_checker_
.CalledOnValidThread());
70 void AvPipelineImpl::SetCodedFrameProvider(
71 scoped_ptr
<CodedFrameProvider
> frame_provider
,
72 size_t max_buffer_size
,
73 size_t max_frame_size
) {
74 DCHECK_EQ(state_
, kUninitialized
);
75 DCHECK(frame_provider
);
77 // Wrap the incoming frame provider to add some buffering capabilities.
78 frame_provider_
.reset(
79 new BufferingFrameProvider(
80 frame_provider
.Pass(),
83 base::Bind(&AvPipelineImpl::OnFrameBuffered
, weak_this_
)));
86 void AvPipelineImpl::SetClient(const AvPipelineClient
& client
) {
87 DCHECK(thread_checker_
.CalledOnValidThread());
88 DCHECK_EQ(state_
, kUninitialized
);
92 bool AvPipelineImpl::Initialize() {
93 DCHECK(thread_checker_
.CalledOnValidThread());
94 DCHECK_EQ(state_
, kUninitialized
);
96 MediaComponentDevice::Client client
;
97 client
.eos_cb
= base::Bind(&AvPipelineImpl::OnEos
, weak_this_
);
98 media_component_device_
->SetClient(client
);
99 if (!media_component_device_
->SetState(MediaComponentDevice::kStateIdle
))
105 bool AvPipelineImpl::StartPlayingFrom(
106 base::TimeDelta time
,
107 const scoped_refptr
<BufferingState
>& buffering_state
) {
108 DCHECK(thread_checker_
.CalledOnValidThread());
109 DCHECK_EQ(state_
, kFlushed
);
111 // Media time where rendering should start
112 // and switch to a state where the audio device accepts incoming buffers.
113 if (!media_component_device_
->SetStartPts(time
) ||
114 !media_component_device_
->SetState(MediaComponentDevice::kStatePaused
)) {
118 // Buffering related initialization.
119 DCHECK(frame_provider_
);
120 buffering_state_
= buffering_state
;
121 if (buffering_state_
.get())
122 buffering_state_
->SetMediaTime(time
);
124 if (!media_component_device_
->SetState(MediaComponentDevice::kStateRunning
))
127 // Start feeding the pipeline.
128 enable_feeding_
= true;
129 base::ThreadTaskRunnerHandle::Get()->PostTask(
130 FROM_HERE
, base::Bind(&AvPipelineImpl::FetchBufferIfNeeded
, weak_this_
));
135 void AvPipelineImpl::Flush(const base::Closure
& done_cb
) {
136 DCHECK(thread_checker_
.CalledOnValidThread());
137 DCHECK_EQ(state_
, kFlushing
);
139 media_component_device_
->GetState(), MediaComponentDevice::kStateRunning
);
140 // Note: returning to idle state aborts any pending frame push.
141 media_component_device_
->SetState(MediaComponentDevice::kStateIdle
);
142 pending_push_
= false;
144 // Break the feeding loop.
145 enable_feeding_
= false;
147 // Remove any pending buffer.
148 pending_buffer_
= scoped_refptr
<DecoderBufferBase
>();
150 // Finally, remove any frames left in the frame provider.
151 pending_read_
= false;
152 buffered_time_
= ::media::kNoTimestamp();
153 playable_buffered_time_
= ::media::kNoTimestamp();
154 non_playable_frames_
.clear();
155 frame_provider_
->Flush(done_cb
);
158 void AvPipelineImpl::Stop() {
159 DCHECK(thread_checker_
.CalledOnValidThread());
161 // Stop can be called from any state.
162 if (state_
== kUninitialized
|| state_
== kStopped
)
165 // Stop feeding the pipeline.
166 enable_feeding_
= false;
168 // Release hardware resources on Stop.
169 if (media_component_device_
->GetState() ==
170 MediaComponentDevice::kStatePaused
||
171 media_component_device_
->GetState() ==
172 MediaComponentDevice::kStateRunning
) {
173 media_component_device_
->SetState(MediaComponentDevice::kStateIdle
);
175 if (media_component_device_
->GetState() == MediaComponentDevice::kStateIdle
) {
176 media_component_device_
->SetState(
177 MediaComponentDevice::kStateUninitialized
);
181 void AvPipelineImpl::SetCdm(BrowserCdmCast
* media_keys
) {
182 DCHECK(thread_checker_
.CalledOnValidThread());
185 if (media_keys_
&& media_keys_callback_id_
!= kNoCallbackId
)
186 media_keys_
->UnregisterPlayer(media_keys_callback_id_
);
188 media_keys_
= media_keys
;
189 media_keys_callback_id_
= media_keys_
->RegisterPlayer(
190 base::Bind(&AvPipelineImpl::OnCdmStateChanged
, weak_this_
),
191 base::Bind(&AvPipelineImpl::OnCdmDestroyed
, weak_this_
));
194 void AvPipelineImpl::OnEos() {
195 DCHECK(thread_checker_
.CalledOnValidThread());
196 CMALOG(kLogControl
) << __FUNCTION__
;
197 if (state_
!= kPlaying
)
200 if (!client_
.eos_cb
.is_null())
201 client_
.eos_cb
.Run();
204 void AvPipelineImpl::FetchBufferIfNeeded() {
205 DCHECK(thread_checker_
.CalledOnValidThread());
206 if (!enable_feeding_
)
209 if (pending_read_
|| pending_buffer_
.get())
212 pending_read_
= true;
213 frame_provider_
->Read(
214 base::Bind(&AvPipelineImpl::OnNewFrame
, weak_this_
));
217 void AvPipelineImpl::OnNewFrame(
218 const scoped_refptr
<DecoderBufferBase
>& buffer
,
219 const ::media::AudioDecoderConfig
& audio_config
,
220 const ::media::VideoDecoderConfig
& video_config
) {
221 DCHECK(thread_checker_
.CalledOnValidThread());
222 pending_read_
= false;
224 if (audio_config
.IsValidConfig() || video_config
.IsValidConfig())
225 update_config_cb_
.Run(buffer
->stream_id(), audio_config
, video_config
);
227 pending_buffer_
= buffer
;
228 ProcessPendingBuffer();
230 base::ThreadTaskRunnerHandle::Get()->PostTask(
231 FROM_HERE
, base::Bind(&AvPipelineImpl::FetchBufferIfNeeded
, weak_this_
));
234 void AvPipelineImpl::ProcessPendingBuffer() {
235 if (!enable_feeding_
)
238 // Initiate a read if there isn't already one.
239 if (!pending_buffer_
.get() && !pending_read_
) {
240 base::ThreadTaskRunnerHandle::Get()->PostTask(
242 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded
, weak_this_
));
246 if (!pending_buffer_
.get() || pending_push_
)
249 // Break the feeding loop when the end of stream is reached.
250 if (pending_buffer_
->end_of_stream()) {
251 CMALOG(kLogControl
) << __FUNCTION__
<< ": EOS reached, stopped feeding";
252 enable_feeding_
= false;
255 scoped_refptr
<DecryptContext
> decrypt_context
;
256 if (!pending_buffer_
->end_of_stream() &&
257 pending_buffer_
->decrypt_config()) {
258 // Verify that CDM has the key ID.
259 // Should not send the frame if the key ID is not available yet.
260 std::string
key_id(pending_buffer_
->decrypt_config()->key_id());
262 CMALOG(kLogControl
) << "No CDM for frame: pts="
263 << pending_buffer_
->timestamp().InMilliseconds();
266 decrypt_context
= media_keys_
->GetDecryptContext(key_id
);
267 if (!decrypt_context
.get()) {
268 CMALOG(kLogControl
) << "frame(pts="
269 << pending_buffer_
->timestamp().InMilliseconds()
270 << "): waiting for key id "
271 << base::HexEncode(&key_id
[0], key_id
.size());
275 // If we do have the clear key, decrypt the pending buffer
276 // and reset the decryption context (not needed anymore).
277 crypto::SymmetricKey
* key
= decrypt_context
->GetKey();
279 pending_buffer_
= DecryptDecoderBuffer(pending_buffer_
, key
);
280 decrypt_context
= scoped_refptr
<DecryptContext
>();
284 if (!pending_buffer_
->end_of_stream() && buffering_state_
.get()) {
285 base::TimeDelta timestamp
= pending_buffer_
->timestamp();
286 if (timestamp
!= ::media::kNoTimestamp())
287 buffering_state_
->SetMaxRenderingTime(timestamp
);
290 MediaComponentDevice::FrameStatus status
= media_component_device_
->PushFrame(
293 base::Bind(&AvPipelineImpl::OnFramePushed
, weak_this_
));
294 pending_buffer_
= scoped_refptr
<DecoderBufferBase
>();
296 pending_push_
= (status
== MediaComponentDevice::kFramePending
);
298 OnFramePushed(status
);
301 void AvPipelineImpl::OnFramePushed(MediaComponentDevice::FrameStatus status
) {
302 DCHECK(thread_checker_
.CalledOnValidThread());
303 pending_push_
= false;
304 if (status
== MediaComponentDevice::kFrameFailed
) {
305 LOG(WARNING
) << "AvPipelineImpl: PushFrame failed";
306 enable_feeding_
= false;
310 base::ThreadTaskRunnerHandle::Get()->PostTask(
311 FROM_HERE
, base::Bind(&AvPipelineImpl::ProcessPendingBuffer
, weak_this_
));
314 void AvPipelineImpl::OnCdmStateChanged() {
315 DCHECK(thread_checker_
.CalledOnValidThread());
317 // Update the buffering state if needed.
318 if (buffering_state_
.get())
319 UpdatePlayableFrames();
321 // Process the pending buffer in case the CDM now has the frame key id.
322 ProcessPendingBuffer();
325 void AvPipelineImpl::OnCdmDestroyed() {
326 DCHECK(thread_checker_
.CalledOnValidThread());
330 void AvPipelineImpl::OnFrameBuffered(
331 const scoped_refptr
<DecoderBufferBase
>& buffer
,
332 bool is_at_max_capacity
) {
333 DCHECK(thread_checker_
.CalledOnValidThread());
335 if (!buffering_state_
.get())
338 if (!buffer
->end_of_stream() &&
339 (buffered_time_
== ::media::kNoTimestamp() ||
340 buffered_time_
< buffer
->timestamp())) {
341 buffered_time_
= buffer
->timestamp();
344 if (is_at_max_capacity
)
345 buffering_state_
->NotifyMaxCapacity(buffered_time_
);
347 // No need to update the list of playable frames,
348 // if we are already blocking on a frame.
349 bool update_playable_frames
= non_playable_frames_
.empty();
350 non_playable_frames_
.push_back(buffer
);
351 if (update_playable_frames
)
352 UpdatePlayableFrames();
355 void AvPipelineImpl::UpdatePlayableFrames() {
356 while (!non_playable_frames_
.empty()) {
357 const scoped_refptr
<DecoderBufferBase
>& non_playable_frame
=
358 non_playable_frames_
.front();
360 if (non_playable_frame
->end_of_stream()) {
361 buffering_state_
->NotifyEos();
363 const ::media::DecryptConfig
* decrypt_config
=
364 non_playable_frame
->decrypt_config();
365 if (decrypt_config
&&
367 media_keys_
->GetDecryptContext(decrypt_config
->key_id()).get())) {
368 // The frame is still not playable. All the following are thus not
373 if (playable_buffered_time_
== ::media::kNoTimestamp() ||
374 playable_buffered_time_
< non_playable_frame
->timestamp()) {
375 playable_buffered_time_
= non_playable_frame
->timestamp();
376 buffering_state_
->SetBufferedTime(playable_buffered_time_
);
380 // The frame is playable: remove it from the list of non playable frames.
381 non_playable_frames_
.pop_front();
386 } // namespace chromecast