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_impl.h"
13 #include "chromecast/media/cdm/browser_cdm_cast.h"
14 #include "chromecast/media/cma/base/buffering_frame_provider.h"
15 #include "chromecast/media/cma/base/buffering_state.h"
16 #include "chromecast/media/cma/base/cast_decoder_buffer_impl.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 "chromecast/media/cma/pipeline/frame_status_cb_impl.h"
22 #include "chromecast/media/cma/pipeline/media_component_device_client_impl.h"
23 #include "chromecast/public/media/cast_decrypt_config.h"
24 #include "chromecast/public/media/media_clock_device.h"
25 #include "chromecast/public/media/media_component_device.h"
26 #include "media/base/audio_decoder_config.h"
27 #include "media/base/bind_to_current_loop.h"
28 #include "media/base/decrypt_config.h"
29 #include "media/base/timestamp_constants.h"
31 namespace chromecast
{
36 const int kNoCallbackId
= -1;
40 AvPipelineImpl::AvPipelineImpl(MediaComponentDevice
* media_component_device
,
41 const UpdateConfigCB
& update_config_cb
)
42 : update_config_cb_(update_config_cb
),
43 media_component_device_(media_component_device
),
44 state_(kUninitialized
),
45 buffered_time_(::media::kNoTimestamp()),
46 playable_buffered_time_(::media::kNoTimestamp()),
47 enable_feeding_(false),
50 enable_time_update_(false),
51 pending_time_update_task_(false),
53 media_keys_callback_id_(kNoCallbackId
),
55 DCHECK(media_component_device
);
56 weak_this_
= weak_factory_
.GetWeakPtr();
57 thread_checker_
.DetachFromThread();
60 AvPipelineImpl::~AvPipelineImpl() {
61 DCHECK(thread_checker_
.CalledOnValidThread());
62 media_component_device_
->SetClient(nullptr);
64 if (media_keys_
&& media_keys_callback_id_
!= kNoCallbackId
)
65 media_keys_
->UnregisterPlayer(media_keys_callback_id_
);
68 void AvPipelineImpl::TransitionToState(State state
) {
69 DCHECK(thread_checker_
.CalledOnValidThread());
73 void AvPipelineImpl::SetCodedFrameProvider(
74 scoped_ptr
<CodedFrameProvider
> frame_provider
,
75 size_t max_buffer_size
,
76 size_t max_frame_size
) {
77 DCHECK_EQ(state_
, kUninitialized
);
78 DCHECK(frame_provider
);
80 // Wrap the incoming frame provider to add some buffering capabilities.
81 frame_provider_
.reset(
82 new BufferingFrameProvider(
83 frame_provider
.Pass(),
86 base::Bind(&AvPipelineImpl::OnFrameBuffered
, weak_this_
)));
89 void AvPipelineImpl::SetClient(const AvPipelineClient
& client
) {
90 DCHECK(thread_checker_
.CalledOnValidThread());
91 DCHECK_EQ(state_
, kUninitialized
);
95 bool AvPipelineImpl::Initialize() {
96 DCHECK(thread_checker_
.CalledOnValidThread());
97 DCHECK_EQ(state_
, kUninitialized
);
99 media_component_device_
->SetClient(new MediaComponentDeviceClientImpl(
100 base::Bind(&AvPipelineImpl::OnEos
, weak_this_
)));
101 if (!media_component_device_
->SetState(MediaComponentDevice::kStateIdle
))
107 bool AvPipelineImpl::StartPlayingFrom(
108 base::TimeDelta time
,
109 const scoped_refptr
<BufferingState
>& buffering_state
) {
110 DCHECK(thread_checker_
.CalledOnValidThread());
111 DCHECK_EQ(state_
, kFlushed
);
113 // Media time where rendering should start
114 // and switch to a state where the audio device accepts incoming buffers.
115 if (!media_component_device_
->SetStartPts(time
.InMicroseconds()) ||
116 !media_component_device_
->SetState(MediaComponentDevice::kStatePaused
)) {
120 // Buffering related initialization.
121 DCHECK(frame_provider_
);
122 buffering_state_
= buffering_state
;
123 if (buffering_state_
.get())
124 buffering_state_
->SetMediaTime(time
);
126 if (!media_component_device_
->SetState(MediaComponentDevice::kStateRunning
))
129 // Start feeding the pipeline.
130 enable_feeding_
= true;
131 base::ThreadTaskRunnerHandle::Get()->PostTask(
132 FROM_HERE
, base::Bind(&AvPipelineImpl::FetchBufferIfNeeded
, weak_this_
));
137 void AvPipelineImpl::Flush(const base::Closure
& done_cb
) {
138 DCHECK(thread_checker_
.CalledOnValidThread());
139 DCHECK_EQ(state_
, kFlushing
);
141 media_component_device_
->GetState(), MediaComponentDevice::kStateRunning
);
142 // Note: returning to idle state aborts any pending frame push.
143 media_component_device_
->SetState(MediaComponentDevice::kStateIdle
);
144 pending_push_
= false;
146 // Break the feeding loop.
147 enable_feeding_
= false;
149 // Remove any pending buffer.
150 pending_buffer_
= scoped_refptr
<DecoderBufferBase
>();
152 // Finally, remove any frames left in the frame provider.
153 pending_read_
= false;
154 buffered_time_
= ::media::kNoTimestamp();
155 playable_buffered_time_
= ::media::kNoTimestamp();
156 non_playable_frames_
.clear();
157 frame_provider_
->Flush(done_cb
);
160 void AvPipelineImpl::Stop() {
161 DCHECK(thread_checker_
.CalledOnValidThread());
163 // Stop can be called from any state.
164 if (state_
== kUninitialized
|| state_
== kStopped
)
167 // Stop feeding the pipeline.
168 enable_feeding_
= false;
170 // Release hardware resources on Stop.
171 if (media_component_device_
->GetState() ==
172 MediaComponentDevice::kStatePaused
||
173 media_component_device_
->GetState() ==
174 MediaComponentDevice::kStateRunning
) {
175 media_component_device_
->SetState(MediaComponentDevice::kStateIdle
);
177 if (media_component_device_
->GetState() == MediaComponentDevice::kStateIdle
) {
178 media_component_device_
->SetState(
179 MediaComponentDevice::kStateUninitialized
);
183 void AvPipelineImpl::SetCdm(BrowserCdmCast
* media_keys
) {
184 DCHECK(thread_checker_
.CalledOnValidThread());
187 if (media_keys_
&& media_keys_callback_id_
!= kNoCallbackId
)
188 media_keys_
->UnregisterPlayer(media_keys_callback_id_
);
190 media_keys_
= media_keys
;
191 media_keys_callback_id_
= media_keys_
->RegisterPlayer(
192 base::Bind(&AvPipelineImpl::OnCdmStateChanged
, weak_this_
),
193 base::Bind(&AvPipelineImpl::OnCdmDestroyed
, weak_this_
));
196 void AvPipelineImpl::OnEos() {
197 DCHECK(thread_checker_
.CalledOnValidThread());
198 CMALOG(kLogControl
) << __FUNCTION__
;
199 if (state_
!= kPlaying
)
202 if (!client_
.eos_cb
.is_null())
203 client_
.eos_cb
.Run();
206 void AvPipelineImpl::FetchBufferIfNeeded() {
207 DCHECK(thread_checker_
.CalledOnValidThread());
208 if (!enable_feeding_
)
211 if (pending_read_
|| pending_buffer_
.get())
214 pending_read_
= true;
215 frame_provider_
->Read(
216 base::Bind(&AvPipelineImpl::OnNewFrame
, weak_this_
));
219 void AvPipelineImpl::OnNewFrame(
220 const scoped_refptr
<DecoderBufferBase
>& buffer
,
221 const ::media::AudioDecoderConfig
& audio_config
,
222 const ::media::VideoDecoderConfig
& video_config
) {
223 DCHECK(thread_checker_
.CalledOnValidThread());
224 pending_read_
= false;
226 if (audio_config
.IsValidConfig() || video_config
.IsValidConfig())
227 update_config_cb_
.Run(buffer
->stream_id(), audio_config
, video_config
);
229 pending_buffer_
= buffer
;
230 ProcessPendingBuffer();
232 base::ThreadTaskRunnerHandle::Get()->PostTask(
233 FROM_HERE
, base::Bind(&AvPipelineImpl::FetchBufferIfNeeded
, weak_this_
));
236 void AvPipelineImpl::ProcessPendingBuffer() {
237 if (!enable_feeding_
)
240 // Initiate a read if there isn't already one.
241 if (!pending_buffer_
.get() && !pending_read_
) {
242 base::ThreadTaskRunnerHandle::Get()->PostTask(
244 base::Bind(&AvPipelineImpl::FetchBufferIfNeeded
, weak_this_
));
248 if (!pending_buffer_
.get() || pending_push_
)
251 // Break the feeding loop when the end of stream is reached.
252 if (pending_buffer_
->end_of_stream()) {
253 CMALOG(kLogControl
) << __FUNCTION__
<< ": EOS reached, stopped feeding";
254 enable_feeding_
= false;
257 scoped_ptr
<DecryptContextImpl
> decrypt_context
;
258 if (!pending_buffer_
->end_of_stream() &&
259 pending_buffer_
->decrypt_config()) {
260 // Verify that CDM has the key ID.
261 // Should not send the frame if the key ID is not available yet.
262 std::string
key_id(pending_buffer_
->decrypt_config()->key_id());
264 CMALOG(kLogControl
) << "No CDM for frame: pts="
265 << pending_buffer_
->timestamp().InMilliseconds();
268 decrypt_context
= media_keys_
->GetDecryptContext(key_id
);
269 if (!decrypt_context
.get()) {
270 CMALOG(kLogControl
) << "frame(pts="
271 << pending_buffer_
->timestamp().InMilliseconds()
272 << "): waiting for key id "
273 << base::HexEncode(&key_id
[0], key_id
.size());
277 // If we do have the clear key, decrypt the pending buffer
278 // and reset the decryption context (not needed anymore).
279 crypto::SymmetricKey
* key
= decrypt_context
->GetKey();
281 pending_buffer_
= DecryptDecoderBuffer(pending_buffer_
, key
);
282 decrypt_context
.reset();
286 if (!pending_buffer_
->end_of_stream() && buffering_state_
.get()) {
287 base::TimeDelta timestamp
= pending_buffer_
->timestamp();
288 if (timestamp
!= ::media::kNoTimestamp())
289 buffering_state_
->SetMaxRenderingTime(timestamp
);
292 MediaComponentDevice::FrameStatus status
= media_component_device_
->PushFrame(
293 decrypt_context
.release(), new CastDecoderBufferImpl(pending_buffer_
),
294 new FrameStatusCBImpl(
295 base::Bind(&AvPipelineImpl::OnFramePushed
, weak_this_
)));
296 pending_buffer_
= scoped_refptr
<DecoderBufferBase
>();
298 pending_push_
= (status
== MediaComponentDevice::kFramePending
);
300 OnFramePushed(status
);
303 void AvPipelineImpl::OnFramePushed(MediaComponentDevice::FrameStatus status
) {
304 DCHECK(thread_checker_
.CalledOnValidThread());
305 pending_push_
= false;
306 if (status
== MediaComponentDevice::kFrameFailed
) {
307 LOG(WARNING
) << "AvPipelineImpl: PushFrame failed";
308 enable_feeding_
= false;
312 base::ThreadTaskRunnerHandle::Get()->PostTask(
313 FROM_HERE
, base::Bind(&AvPipelineImpl::ProcessPendingBuffer
, weak_this_
));
316 void AvPipelineImpl::OnCdmStateChanged() {
317 DCHECK(thread_checker_
.CalledOnValidThread());
319 // Update the buffering state if needed.
320 if (buffering_state_
.get())
321 UpdatePlayableFrames();
323 // Process the pending buffer in case the CDM now has the frame key id.
324 ProcessPendingBuffer();
327 void AvPipelineImpl::OnCdmDestroyed() {
328 DCHECK(thread_checker_
.CalledOnValidThread());
332 void AvPipelineImpl::OnFrameBuffered(
333 const scoped_refptr
<DecoderBufferBase
>& buffer
,
334 bool is_at_max_capacity
) {
335 DCHECK(thread_checker_
.CalledOnValidThread());
337 if (!buffering_state_
.get())
340 if (!buffer
->end_of_stream() && (buffered_time_
== ::media::kNoTimestamp() ||
341 buffered_time_
< buffer
->timestamp())) {
342 buffered_time_
= buffer
->timestamp();
345 if (is_at_max_capacity
)
346 buffering_state_
->NotifyMaxCapacity(buffered_time_
);
348 // No need to update the list of playable frames,
349 // if we are already blocking on a frame.
350 bool update_playable_frames
= non_playable_frames_
.empty();
351 non_playable_frames_
.push_back(buffer
);
352 if (update_playable_frames
)
353 UpdatePlayableFrames();
356 void AvPipelineImpl::UpdatePlayableFrames() {
357 while (!non_playable_frames_
.empty()) {
358 const scoped_refptr
<DecoderBufferBase
>& non_playable_frame
=
359 non_playable_frames_
.front();
361 if (non_playable_frame
->end_of_stream()) {
362 buffering_state_
->NotifyEos();
364 const CastDecryptConfig
* decrypt_config
=
365 non_playable_frame
->decrypt_config();
366 if (decrypt_config
&&
368 media_keys_
->GetDecryptContext(decrypt_config
->key_id()).get())) {
369 // The frame is still not playable. All the following are thus not
374 if (playable_buffered_time_
== ::media::kNoTimestamp() ||
375 playable_buffered_time_
< non_playable_frame
->timestamp()) {
376 playable_buffered_time_
= non_playable_frame
->timestamp();
377 buffering_state_
->SetBufferedTime(playable_buffered_time_
);
381 // The frame is playable: remove it from the list of non playable frames.
382 non_playable_frames_
.pop_front();
387 } // namespace chromecast