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/message_loop/message_loop_proxy.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "chromecast/media/base/decrypt_context.h"
12 #include "chromecast/media/cdm/browser_cdm_cast.h"
13 #include "chromecast/media/cma/backend/media_clock_device.h"
14 #include "chromecast/media/cma/backend/media_component_device.h"
15 #include "chromecast/media/cma/base/buffering_frame_provider.h"
16 #include "chromecast/media/cma/base/buffering_state.h"
17 #include "chromecast/media/cma/base/cma_logging.h"
18 #include "chromecast/media/cma/base/coded_frame_provider.h"
19 #include "chromecast/media/cma/base/decoder_buffer_base.h"
20 #include "chromecast/media/cma/pipeline/decrypt_util.h"
21 #include "media/base/audio_decoder_config.h"
22 #include "media/base/bind_to_current_loop.h"
23 #include "media/base/decrypt_config.h"
25 namespace chromecast
{
30 const int kNoCallbackId
= -1;
34 AvPipelineImpl::AvPipelineImpl(
35 MediaComponentDevice
* media_component_device
,
36 const UpdateConfigCB
& update_config_cb
)
37 : update_config_cb_(update_config_cb
),
38 media_component_device_(media_component_device
),
39 state_(kUninitialized
),
40 buffered_time_(::media::kNoTimestamp()),
41 playable_buffered_time_(::media::kNoTimestamp()),
42 enable_feeding_(false),
45 enable_time_update_(false),
46 pending_time_update_task_(false),
48 media_keys_callback_id_(kNoCallbackId
),
50 DCHECK(media_component_device
);
51 weak_this_
= weak_factory_
.GetWeakPtr();
52 thread_checker_
.DetachFromThread();
55 AvPipelineImpl::~AvPipelineImpl() {
56 // If there are weak pointers in the wild, they must be invalidated
57 // on the right thread.
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::MessageLoopProxy::current()->PostTask(
131 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded
, weak_this_
));
136 void AvPipelineImpl::Flush(const base::Closure
& done_cb
) {
137 DCHECK(thread_checker_
.CalledOnValidThread());
138 DCHECK_EQ(state_
, kFlushing
);
140 media_component_device_
->GetState(), MediaComponentDevice::kStateRunning
);
141 // Note: returning to idle state aborts any pending frame push.
142 media_component_device_
->SetState(MediaComponentDevice::kStateIdle
);
143 pending_push_
= false;
145 // Break the feeding loop.
146 enable_feeding_
= false;
148 // Remove any pending buffer.
149 pending_buffer_
= scoped_refptr
<DecoderBufferBase
>();
151 // Finally, remove any frames left in the frame provider.
152 pending_read_
= false;
153 buffered_time_
= ::media::kNoTimestamp();
154 playable_buffered_time_
= ::media::kNoTimestamp();
155 non_playable_frames_
.clear();
156 frame_provider_
->Flush(done_cb
);
159 void AvPipelineImpl::Stop() {
160 DCHECK(thread_checker_
.CalledOnValidThread());
162 // Stop can be called from any state.
163 if (state_
== kUninitialized
|| state_
== kStopped
)
166 // Stop feeding the pipeline.
167 enable_feeding_
= false;
169 // Release hardware resources on Stop.
170 if (media_component_device_
->GetState() ==
171 MediaComponentDevice::kStatePaused
||
172 media_component_device_
->GetState() ==
173 MediaComponentDevice::kStateRunning
) {
174 media_component_device_
->SetState(MediaComponentDevice::kStateIdle
);
176 if (media_component_device_
->GetState() == MediaComponentDevice::kStateIdle
) {
177 media_component_device_
->SetState(
178 MediaComponentDevice::kStateUninitialized
);
182 void AvPipelineImpl::SetCdm(BrowserCdmCast
* media_keys
) {
183 DCHECK(thread_checker_
.CalledOnValidThread());
186 if (media_keys_
&& media_keys_callback_id_
!= kNoCallbackId
)
187 media_keys_
->UnregisterPlayer(media_keys_callback_id_
);
189 media_keys_
= media_keys
;
190 media_keys_callback_id_
= media_keys_
->RegisterPlayer(
191 ::media::BindToCurrentLoop(
192 base::Bind(&AvPipelineImpl::OnCdmStateChanged
, weak_this_
)),
193 ::media::BindToCurrentLoop(
194 base::Bind(&AvPipelineImpl::OnCdmDestroyed
, weak_this_
)));
197 void AvPipelineImpl::OnEos() {
198 DCHECK(thread_checker_
.CalledOnValidThread());
199 CMALOG(kLogControl
) << __FUNCTION__
;
200 if (state_
!= kPlaying
)
203 if (!client_
.eos_cb
.is_null())
204 client_
.eos_cb
.Run();
207 void AvPipelineImpl::FetchBufferIfNeeded() {
208 DCHECK(thread_checker_
.CalledOnValidThread());
209 if (!enable_feeding_
)
212 if (pending_read_
|| pending_buffer_
.get())
215 pending_read_
= true;
216 frame_provider_
->Read(
217 base::Bind(&AvPipelineImpl::OnNewFrame
, weak_this_
));
220 void AvPipelineImpl::OnNewFrame(
221 const scoped_refptr
<DecoderBufferBase
>& buffer
,
222 const ::media::AudioDecoderConfig
& audio_config
,
223 const ::media::VideoDecoderConfig
& video_config
) {
224 DCHECK(thread_checker_
.CalledOnValidThread());
225 pending_read_
= false;
227 if (audio_config
.IsValidConfig() || video_config
.IsValidConfig())
228 update_config_cb_
.Run(audio_config
, video_config
);
230 pending_buffer_
= buffer
;
231 ProcessPendingBuffer();
233 base::MessageLoopProxy::current()->PostTask(
235 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded
, weak_this_
));
238 void AvPipelineImpl::ProcessPendingBuffer() {
239 if (!enable_feeding_
)
242 // Initiate a read if there isn't already one.
243 if (!pending_buffer_
.get() && !pending_read_
) {
244 base::MessageLoopProxy::current()->PostTask(
246 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded
, weak_this_
));
250 if (!pending_buffer_
.get() || pending_push_
)
253 // Break the feeding loop when the end of stream is reached.
254 if (pending_buffer_
->end_of_stream()) {
255 CMALOG(kLogControl
) << __FUNCTION__
<< ": EOS reached, stopped feeding";
256 enable_feeding_
= false;
259 scoped_refptr
<DecryptContext
> decrypt_context
;
260 if (!pending_buffer_
->end_of_stream() &&
261 pending_buffer_
->decrypt_config()) {
262 // Verify that CDM has the key ID.
263 // Should not send the frame if the key ID is not available yet.
264 std::string
key_id(pending_buffer_
->decrypt_config()->key_id());
266 CMALOG(kLogControl
) << "No CDM for frame: pts="
267 << pending_buffer_
->timestamp().InMilliseconds();
270 decrypt_context
= media_keys_
->GetDecryptContext(key_id
);
271 if (!decrypt_context
.get()) {
272 CMALOG(kLogControl
) << "frame(pts="
273 << pending_buffer_
->timestamp().InMilliseconds()
274 << "): waiting for key id "
275 << base::HexEncode(&key_id
[0], key_id
.size());
279 // If we do have the clear key, decrypt the pending buffer
280 // and reset the decryption context (not needed anymore).
281 crypto::SymmetricKey
* key
= decrypt_context
->GetKey();
283 pending_buffer_
= DecryptDecoderBuffer(pending_buffer_
, key
);
284 decrypt_context
= scoped_refptr
<DecryptContext
>();
288 if (!pending_buffer_
->end_of_stream() && buffering_state_
.get()) {
289 base::TimeDelta timestamp
= pending_buffer_
->timestamp();
290 if (timestamp
!= ::media::kNoTimestamp())
291 buffering_state_
->SetMaxRenderingTime(timestamp
);
294 MediaComponentDevice::FrameStatus status
= media_component_device_
->PushFrame(
297 base::Bind(&AvPipelineImpl::OnFramePushed
, weak_this_
));
298 pending_buffer_
= scoped_refptr
<DecoderBufferBase
>();
300 pending_push_
= (status
== MediaComponentDevice::kFramePending
);
302 OnFramePushed(status
);
305 void AvPipelineImpl::OnFramePushed(MediaComponentDevice::FrameStatus status
) {
306 DCHECK(thread_checker_
.CalledOnValidThread());
307 pending_push_
= false;
308 if (status
== MediaComponentDevice::kFrameFailed
) {
309 LOG(WARNING
) << "AvPipelineImpl: PushFrame failed";
310 enable_feeding_
= false;
314 base::MessageLoopProxy::current()->PostTask(
316 base::Bind(&AvPipelineImpl::ProcessPendingBuffer
, weak_this_
));
319 void AvPipelineImpl::OnCdmStateChanged() {
320 DCHECK(thread_checker_
.CalledOnValidThread());
322 // Update the buffering state if needed.
323 if (buffering_state_
.get())
324 UpdatePlayableFrames();
326 // Process the pending buffer in case the CDM now has the frame key id.
327 ProcessPendingBuffer();
330 void AvPipelineImpl::OnCdmDestroyed() {
331 DCHECK(thread_checker_
.CalledOnValidThread());
335 void AvPipelineImpl::OnFrameBuffered(
336 const scoped_refptr
<DecoderBufferBase
>& buffer
,
337 bool is_at_max_capacity
) {
338 DCHECK(thread_checker_
.CalledOnValidThread());
340 if (!buffering_state_
.get())
343 if (!buffer
->end_of_stream() &&
344 (buffered_time_
== ::media::kNoTimestamp() ||
345 buffered_time_
< buffer
->timestamp())) {
346 buffered_time_
= buffer
->timestamp();
349 if (is_at_max_capacity
)
350 buffering_state_
->NotifyMaxCapacity(buffered_time_
);
352 // No need to update the list of playable frames,
353 // if we are already blocking on a frame.
354 bool update_playable_frames
= non_playable_frames_
.empty();
355 non_playable_frames_
.push_back(buffer
);
356 if (update_playable_frames
)
357 UpdatePlayableFrames();
360 void AvPipelineImpl::UpdatePlayableFrames() {
361 while (!non_playable_frames_
.empty()) {
362 const scoped_refptr
<DecoderBufferBase
>& non_playable_frame
=
363 non_playable_frames_
.front();
365 if (non_playable_frame
->end_of_stream()) {
366 buffering_state_
->NotifyEos();
368 const ::media::DecryptConfig
* decrypt_config
=
369 non_playable_frame
->decrypt_config();
370 if (decrypt_config
&&
372 media_keys_
->GetDecryptContext(decrypt_config
->key_id()).get())) {
373 // The frame is still not playable. All the following are thus not
378 if (playable_buffered_time_
== ::media::kNoTimestamp() ||
379 playable_buffered_time_
< non_playable_frame
->timestamp()) {
380 playable_buffered_time_
= non_playable_frame
->timestamp();
381 buffering_state_
->SetBufferedTime(playable_buffered_time_
);
385 // The frame is playable: remove it from the list of non playable frames.
386 non_playable_frames_
.pop_front();
391 } // namespace chromecast