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/decrypt_config.h"
26 namespace chromecast
{
31 const int kNoCallbackId
= -1;
35 AvPipelineImpl::AvPipelineImpl(
36 MediaComponentDevice
* media_component_device
,
37 const UpdateConfigCB
& update_config_cb
)
38 : update_config_cb_(update_config_cb
),
39 media_component_device_(media_component_device
),
40 state_(kUninitialized
),
41 buffered_time_(::media::kNoTimestamp()),
42 playable_buffered_time_(::media::kNoTimestamp()),
43 enable_feeding_(false),
46 enable_time_update_(false),
47 pending_time_update_task_(false),
49 media_keys_callback_id_(kNoCallbackId
),
51 DCHECK(media_component_device
);
52 weak_this_
= weak_factory_
.GetWeakPtr();
53 thread_checker_
.DetachFromThread();
56 AvPipelineImpl::~AvPipelineImpl() {
57 DCHECK(thread_checker_
.CalledOnValidThread());
58 media_component_device_
->SetClient(MediaComponentDevice::Client());
60 if (media_keys_
&& media_keys_callback_id_
!= kNoCallbackId
)
61 media_keys_
->UnregisterPlayer(media_keys_callback_id_
);
64 void AvPipelineImpl::TransitionToState(State state
) {
65 DCHECK(thread_checker_
.CalledOnValidThread());
69 void AvPipelineImpl::SetCodedFrameProvider(
70 scoped_ptr
<CodedFrameProvider
> frame_provider
,
71 size_t max_buffer_size
,
72 size_t max_frame_size
) {
73 DCHECK_EQ(state_
, kUninitialized
);
74 DCHECK(frame_provider
);
76 // Wrap the incoming frame provider to add some buffering capabilities.
77 frame_provider_
.reset(
78 new BufferingFrameProvider(
79 frame_provider
.Pass(),
82 base::Bind(&AvPipelineImpl::OnFrameBuffered
, weak_this_
)));
85 void AvPipelineImpl::SetClient(const AvPipelineClient
& client
) {
86 DCHECK(thread_checker_
.CalledOnValidThread());
87 DCHECK_EQ(state_
, kUninitialized
);
91 bool AvPipelineImpl::Initialize() {
92 DCHECK(thread_checker_
.CalledOnValidThread());
93 DCHECK_EQ(state_
, kUninitialized
);
95 MediaComponentDevice::Client client
;
96 client
.eos_cb
= base::Bind(&AvPipelineImpl::OnEos
, weak_this_
);
97 media_component_device_
->SetClient(client
);
98 if (!media_component_device_
->SetState(MediaComponentDevice::kStateIdle
))
104 bool AvPipelineImpl::StartPlayingFrom(
105 base::TimeDelta time
,
106 const scoped_refptr
<BufferingState
>& buffering_state
) {
107 DCHECK(thread_checker_
.CalledOnValidThread());
108 DCHECK_EQ(state_
, kFlushed
);
110 // Media time where rendering should start
111 // and switch to a state where the audio device accepts incoming buffers.
112 if (!media_component_device_
->SetStartPts(time
) ||
113 !media_component_device_
->SetState(MediaComponentDevice::kStatePaused
)) {
117 // Buffering related initialization.
118 DCHECK(frame_provider_
);
119 buffering_state_
= buffering_state
;
120 if (buffering_state_
.get())
121 buffering_state_
->SetMediaTime(time
);
123 if (!media_component_device_
->SetState(MediaComponentDevice::kStateRunning
))
126 // Start feeding the pipeline.
127 enable_feeding_
= true;
128 base::ThreadTaskRunnerHandle::Get()->PostTask(
129 FROM_HERE
, base::Bind(&AvPipelineImpl::FetchBufferIfNeeded
, weak_this_
));
134 void AvPipelineImpl::Flush(const base::Closure
& done_cb
) {
135 DCHECK(thread_checker_
.CalledOnValidThread());
136 DCHECK_EQ(state_
, kFlushing
);
138 media_component_device_
->GetState(), MediaComponentDevice::kStateRunning
);
139 // Note: returning to idle state aborts any pending frame push.
140 media_component_device_
->SetState(MediaComponentDevice::kStateIdle
);
141 pending_push_
= false;
143 // Break the feeding loop.
144 enable_feeding_
= false;
146 // Remove any pending buffer.
147 pending_buffer_
= scoped_refptr
<DecoderBufferBase
>();
149 // Finally, remove any frames left in the frame provider.
150 pending_read_
= false;
151 buffered_time_
= ::media::kNoTimestamp();
152 playable_buffered_time_
= ::media::kNoTimestamp();
153 non_playable_frames_
.clear();
154 frame_provider_
->Flush(done_cb
);
157 void AvPipelineImpl::Stop() {
158 DCHECK(thread_checker_
.CalledOnValidThread());
160 // Stop can be called from any state.
161 if (state_
== kUninitialized
|| state_
== kStopped
)
164 // Stop feeding the pipeline.
165 enable_feeding_
= false;
167 // Release hardware resources on Stop.
168 if (media_component_device_
->GetState() ==
169 MediaComponentDevice::kStatePaused
||
170 media_component_device_
->GetState() ==
171 MediaComponentDevice::kStateRunning
) {
172 media_component_device_
->SetState(MediaComponentDevice::kStateIdle
);
174 if (media_component_device_
->GetState() == MediaComponentDevice::kStateIdle
) {
175 media_component_device_
->SetState(
176 MediaComponentDevice::kStateUninitialized
);
180 void AvPipelineImpl::SetCdm(BrowserCdmCast
* media_keys
) {
181 DCHECK(thread_checker_
.CalledOnValidThread());
184 if (media_keys_
&& media_keys_callback_id_
!= kNoCallbackId
)
185 media_keys_
->UnregisterPlayer(media_keys_callback_id_
);
187 media_keys_
= media_keys
;
188 media_keys_callback_id_
= media_keys_
->RegisterPlayer(
189 base::Bind(&AvPipelineImpl::OnCdmStateChanged
, weak_this_
),
190 base::Bind(&AvPipelineImpl::OnCdmDestroyed
, weak_this_
));
193 void AvPipelineImpl::OnEos() {
194 DCHECK(thread_checker_
.CalledOnValidThread());
195 CMALOG(kLogControl
) << __FUNCTION__
;
196 if (state_
!= kPlaying
)
199 if (!client_
.eos_cb
.is_null())
200 client_
.eos_cb
.Run();
203 void AvPipelineImpl::FetchBufferIfNeeded() {
204 DCHECK(thread_checker_
.CalledOnValidThread());
205 if (!enable_feeding_
)
208 if (pending_read_
|| pending_buffer_
.get())
211 pending_read_
= true;
212 frame_provider_
->Read(
213 base::Bind(&AvPipelineImpl::OnNewFrame
, weak_this_
));
216 void AvPipelineImpl::OnNewFrame(
217 const scoped_refptr
<DecoderBufferBase
>& buffer
,
218 const ::media::AudioDecoderConfig
& audio_config
,
219 const ::media::VideoDecoderConfig
& video_config
) {
220 DCHECK(thread_checker_
.CalledOnValidThread());
221 pending_read_
= false;
223 if (audio_config
.IsValidConfig() || video_config
.IsValidConfig())
224 update_config_cb_
.Run(buffer
->stream_id(), audio_config
, video_config
);
226 pending_buffer_
= buffer
;
227 ProcessPendingBuffer();
229 base::ThreadTaskRunnerHandle::Get()->PostTask(
230 FROM_HERE
, base::Bind(&AvPipelineImpl::FetchBufferIfNeeded
, weak_this_
));
233 void AvPipelineImpl::ProcessPendingBuffer() {
234 if (!enable_feeding_
)
237 // Initiate a read if there isn't already one.
238 if (!pending_buffer_
.get() && !pending_read_
) {
239 base::ThreadTaskRunnerHandle::Get()->PostTask(
241 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded
, weak_this_
));
245 if (!pending_buffer_
.get() || pending_push_
)
248 // Break the feeding loop when the end of stream is reached.
249 if (pending_buffer_
->end_of_stream()) {
250 CMALOG(kLogControl
) << __FUNCTION__
<< ": EOS reached, stopped feeding";
251 enable_feeding_
= false;
254 scoped_refptr
<DecryptContext
> decrypt_context
;
255 if (!pending_buffer_
->end_of_stream() &&
256 pending_buffer_
->decrypt_config()) {
257 // Verify that CDM has the key ID.
258 // Should not send the frame if the key ID is not available yet.
259 std::string
key_id(pending_buffer_
->decrypt_config()->key_id());
261 CMALOG(kLogControl
) << "No CDM for frame: pts="
262 << pending_buffer_
->timestamp().InMilliseconds();
265 decrypt_context
= media_keys_
->GetDecryptContext(key_id
);
266 if (!decrypt_context
.get()) {
267 CMALOG(kLogControl
) << "frame(pts="
268 << pending_buffer_
->timestamp().InMilliseconds()
269 << "): waiting for key id "
270 << base::HexEncode(&key_id
[0], key_id
.size());
274 // If we do have the clear key, decrypt the pending buffer
275 // and reset the decryption context (not needed anymore).
276 crypto::SymmetricKey
* key
= decrypt_context
->GetKey();
278 pending_buffer_
= DecryptDecoderBuffer(pending_buffer_
, key
);
279 decrypt_context
= scoped_refptr
<DecryptContext
>();
283 if (!pending_buffer_
->end_of_stream() && buffering_state_
.get()) {
284 base::TimeDelta timestamp
= pending_buffer_
->timestamp();
285 if (timestamp
!= ::media::kNoTimestamp())
286 buffering_state_
->SetMaxRenderingTime(timestamp
);
289 MediaComponentDevice::FrameStatus status
= media_component_device_
->PushFrame(
292 base::Bind(&AvPipelineImpl::OnFramePushed
, weak_this_
));
293 pending_buffer_
= scoped_refptr
<DecoderBufferBase
>();
295 pending_push_
= (status
== MediaComponentDevice::kFramePending
);
297 OnFramePushed(status
);
300 void AvPipelineImpl::OnFramePushed(MediaComponentDevice::FrameStatus status
) {
301 DCHECK(thread_checker_
.CalledOnValidThread());
302 pending_push_
= false;
303 if (status
== MediaComponentDevice::kFrameFailed
) {
304 LOG(WARNING
) << "AvPipelineImpl: PushFrame failed";
305 enable_feeding_
= false;
309 base::ThreadTaskRunnerHandle::Get()->PostTask(
310 FROM_HERE
, base::Bind(&AvPipelineImpl::ProcessPendingBuffer
, weak_this_
));
313 void AvPipelineImpl::OnCdmStateChanged() {
314 DCHECK(thread_checker_
.CalledOnValidThread());
316 // Update the buffering state if needed.
317 if (buffering_state_
.get())
318 UpdatePlayableFrames();
320 // Process the pending buffer in case the CDM now has the frame key id.
321 ProcessPendingBuffer();
324 void AvPipelineImpl::OnCdmDestroyed() {
325 DCHECK(thread_checker_
.CalledOnValidThread());
329 void AvPipelineImpl::OnFrameBuffered(
330 const scoped_refptr
<DecoderBufferBase
>& buffer
,
331 bool is_at_max_capacity
) {
332 DCHECK(thread_checker_
.CalledOnValidThread());
334 if (!buffering_state_
.get())
337 if (!buffer
->end_of_stream() &&
338 (buffered_time_
== ::media::kNoTimestamp() ||
339 buffered_time_
< buffer
->timestamp())) {
340 buffered_time_
= buffer
->timestamp();
343 if (is_at_max_capacity
)
344 buffering_state_
->NotifyMaxCapacity(buffered_time_
);
346 // No need to update the list of playable frames,
347 // if we are already blocking on a frame.
348 bool update_playable_frames
= non_playable_frames_
.empty();
349 non_playable_frames_
.push_back(buffer
);
350 if (update_playable_frames
)
351 UpdatePlayableFrames();
354 void AvPipelineImpl::UpdatePlayableFrames() {
355 while (!non_playable_frames_
.empty()) {
356 const scoped_refptr
<DecoderBufferBase
>& non_playable_frame
=
357 non_playable_frames_
.front();
359 if (non_playable_frame
->end_of_stream()) {
360 buffering_state_
->NotifyEos();
362 const ::media::DecryptConfig
* decrypt_config
=
363 non_playable_frame
->decrypt_config();
364 if (decrypt_config
&&
366 media_keys_
->GetDecryptContext(decrypt_config
->key_id()).get())) {
367 // The frame is still not playable. All the following are thus not
372 if (playable_buffered_time_
== ::media::kNoTimestamp() ||
373 playable_buffered_time_
< non_playable_frame
->timestamp()) {
374 playable_buffered_time_
= non_playable_frame
->timestamp();
375 buffering_state_
->SetBufferedTime(playable_buffered_time_
);
379 // The frame is playable: remove it from the list of non playable frames.
380 non_playable_frames_
.pop_front();
385 } // namespace chromecast