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 "media/filters/decoder_stream.h"
8 #include "base/callback_helpers.h"
9 #include "base/debug/trace_event.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/single_thread_task_runner.h"
13 #include "media/base/bind_to_current_loop.h"
14 #include "media/base/decoder_buffer.h"
15 #include "media/base/demuxer_stream.h"
16 #include "media/base/video_decoder.h"
17 #include "media/filters/decrypting_demuxer_stream.h"
21 // TODO(rileya): Devise a better way of specifying trace/UMA/etc strings for
22 // templated classes such as this.
23 template <DemuxerStream::Type StreamType
>
24 static const char* GetTraceString();
27 const char* GetTraceString
<DemuxerStream::VIDEO
>() {
28 return "DecoderStream<VIDEO>::Decode";
31 template <DemuxerStream::Type StreamType
>
32 DecoderStream
<StreamType
>::DecoderStream(
33 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
34 ScopedVector
<Decoder
> decoders
,
35 const SetDecryptorReadyCB
& set_decryptor_ready_cb
)
36 : task_runner_(task_runner
),
38 state_(STATE_UNINITIALIZED
),
41 new DecoderSelector
<StreamType
>(task_runner
,
43 set_decryptor_ready_cb
)) {}
45 template <DemuxerStream::Type StreamType
>
46 DecoderStream
<StreamType
>::~DecoderStream() {
47 DCHECK(state_
== STATE_UNINITIALIZED
|| state_
== STATE_STOPPED
) << state_
;
50 template <DemuxerStream::Type StreamType
>
51 void DecoderStream
<StreamType
>::Initialize(DemuxerStream
* stream
,
52 const StatisticsCB
& statistics_cb
,
53 const InitCB
& init_cb
) {
54 DVLOG(2) << __FUNCTION__
;
55 DCHECK(task_runner_
->BelongsToCurrentThread());
56 DCHECK_EQ(state_
, STATE_UNINITIALIZED
) << state_
;
57 DCHECK(init_cb_
.is_null());
58 DCHECK(!init_cb
.is_null());
60 statistics_cb_
= statistics_cb
;
64 state_
= STATE_INITIALIZING
;
65 // TODO(xhwang): DecoderSelector only needs a config to select a decoder.
66 decoder_selector_
->SelectDecoder(
69 base::Bind(&DecoderStream
<StreamType
>::OnDecoderSelected
,
70 weak_factory_
.GetWeakPtr()));
73 template <DemuxerStream::Type StreamType
>
74 void DecoderStream
<StreamType
>::Read(const ReadCB
& read_cb
) {
75 DVLOG(2) << __FUNCTION__
;
76 DCHECK(task_runner_
->BelongsToCurrentThread());
77 DCHECK(state_
== STATE_NORMAL
|| state_
== STATE_FLUSHING_DECODER
||
78 state_
== STATE_ERROR
) << state_
;
79 // No two reads in the flight at any time.
80 DCHECK(read_cb_
.is_null());
81 // No read during resetting or stopping process.
82 DCHECK(reset_cb_
.is_null());
83 DCHECK(stop_cb_
.is_null());
85 if (state_
== STATE_ERROR
) {
86 task_runner_
->PostTask(FROM_HERE
, base::Bind(
87 read_cb
, DECODE_ERROR
, scoped_refptr
<Output
>()));
93 if (state_
== STATE_FLUSHING_DECODER
) {
98 ReadFromDemuxerStream();
101 template <DemuxerStream::Type StreamType
>
102 void DecoderStream
<StreamType
>::Reset(const base::Closure
& closure
) {
103 DVLOG(2) << __FUNCTION__
;
104 DCHECK(task_runner_
->BelongsToCurrentThread());
105 DCHECK(state_
!= STATE_UNINITIALIZED
&& state_
!= STATE_STOPPED
) << state_
;
106 DCHECK(reset_cb_
.is_null());
107 DCHECK(stop_cb_
.is_null());
111 // During decoder reinitialization, the Decoder does not need to be and
112 // cannot be Reset(). |decrypting_demuxer_stream_| was reset before decoder
114 if (state_
== STATE_REINITIALIZING_DECODER
)
117 // During pending demuxer read and when not using DecryptingDemuxerStream,
118 // the Decoder will be reset after demuxer read is returned
119 // (in OnBufferReady()).
120 if (state_
== STATE_PENDING_DEMUXER_READ
&& !decrypting_demuxer_stream_
)
123 // The Decoder API guarantees that if Decoder::Reset() is called during
124 // a pending decode, the decode callback must be fired before the reset
125 // callback is fired. Therefore, we can call Decoder::Reset() regardless
126 // of if we have a pending decode and always satisfy the reset callback when
127 // the decoder reset is finished.
128 if (decrypting_demuxer_stream_
) {
129 decrypting_demuxer_stream_
->Reset(base::Bind(
130 &DecoderStream
<StreamType
>::ResetDecoder
, weak_factory_
.GetWeakPtr()));
137 template <DemuxerStream::Type StreamType
>
138 void DecoderStream
<StreamType
>::Stop(const base::Closure
& closure
) {
139 DVLOG(2) << __FUNCTION__
;
140 DCHECK(task_runner_
->BelongsToCurrentThread());
141 DCHECK_NE(state_
, STATE_STOPPED
) << state_
;
142 DCHECK(stop_cb_
.is_null());
146 if (state_
== STATE_INITIALIZING
) {
147 decoder_selector_
->Abort();
151 DCHECK(init_cb_
.is_null());
153 // All pending callbacks will be dropped.
154 weak_factory_
.InvalidateWeakPtrs();
156 // Post callbacks to prevent reentrance into this object.
157 if (!read_cb_
.is_null())
158 task_runner_
->PostTask(FROM_HERE
, base::Bind(
159 base::ResetAndReturn(&read_cb_
), ABORTED
, scoped_refptr
<Output
>()));
160 if (!reset_cb_
.is_null())
161 task_runner_
->PostTask(FROM_HERE
, base::ResetAndReturn(&reset_cb_
));
163 if (decrypting_demuxer_stream_
) {
164 decrypting_demuxer_stream_
->Stop(base::Bind(
165 &DecoderStream
<StreamType
>::StopDecoder
, weak_factory_
.GetWeakPtr()));
169 // We may not have a |decoder_| if Stop() was called during initialization.
175 state_
= STATE_STOPPED
;
178 decrypting_demuxer_stream_
.reset();
179 task_runner_
->PostTask(FROM_HERE
, base::ResetAndReturn(&stop_cb_
));
182 template <DemuxerStream::Type StreamType
>
183 bool DecoderStream
<StreamType
>::CanReadWithoutStalling() const {
184 DCHECK(task_runner_
->BelongsToCurrentThread());
185 return decoder_
->CanReadWithoutStalling();
188 template <DemuxerStream::Type StreamType
>
189 void DecoderStream
<StreamType
>::OnDecoderSelected(
190 scoped_ptr
<Decoder
> selected_decoder
,
191 scoped_ptr
<DecryptingDemuxerStream
> decrypting_demuxer_stream
) {
192 DVLOG(2) << __FUNCTION__
;
193 DCHECK(task_runner_
->BelongsToCurrentThread());
194 DCHECK_EQ(state_
, STATE_INITIALIZING
) << state_
;
195 DCHECK(!init_cb_
.is_null());
196 DCHECK(read_cb_
.is_null());
197 DCHECK(reset_cb_
.is_null());
199 decoder_selector_
.reset();
200 if (decrypting_demuxer_stream
)
201 stream_
= decrypting_demuxer_stream
.get();
203 if (!selected_decoder
) {
204 state_
= STATE_UNINITIALIZED
;
205 StreamTraits::FinishInitialization(
206 base::ResetAndReturn(&init_cb_
), selected_decoder
.get(), stream_
);
208 state_
= STATE_NORMAL
;
209 decoder_
= selected_decoder
.Pass();
210 decrypting_demuxer_stream_
= decrypting_demuxer_stream
.Pass();
211 StreamTraits::FinishInitialization(
212 base::ResetAndReturn(&init_cb_
), decoder_
.get(), stream_
);
215 // Stop() called during initialization.
216 if (!stop_cb_
.is_null()) {
217 Stop(base::ResetAndReturn(&stop_cb_
));
222 template <DemuxerStream::Type StreamType
>
223 void DecoderStream
<StreamType
>::SatisfyRead(
225 const scoped_refptr
<Output
>& output
) {
226 DCHECK(!read_cb_
.is_null());
227 base::ResetAndReturn(&read_cb_
).Run(status
, output
);
230 template <DemuxerStream::Type StreamType
>
231 void DecoderStream
<StreamType
>::AbortRead() {
232 // Abort read during pending reset. It is safe to fire the |read_cb_| directly
233 // instead of posting it because the renderer won't call into this class
234 // again when it's in kFlushing state.
235 // TODO(xhwang): Improve the resetting process to avoid this dependency on the
237 DCHECK(!reset_cb_
.is_null());
238 SatisfyRead(ABORTED
, NULL
);
241 template <DemuxerStream::Type StreamType
>
242 void DecoderStream
<StreamType
>::Decode(
243 const scoped_refptr
<DecoderBuffer
>& buffer
) {
244 DVLOG(2) << __FUNCTION__
;
245 DCHECK(state_
== STATE_NORMAL
|| state_
== STATE_FLUSHING_DECODER
) << state_
;
246 DCHECK(!read_cb_
.is_null());
247 DCHECK(reset_cb_
.is_null());
248 DCHECK(stop_cb_
.is_null());
251 int buffer_size
= buffer
->end_of_stream() ? 0 : buffer
->data_size();
253 TRACE_EVENT_ASYNC_BEGIN0("media", GetTraceString
<StreamType
>(), this);
254 decoder_
->Decode(buffer
,
255 base::Bind(&DecoderStream
<StreamType
>::OnDecodeOutputReady
,
256 weak_factory_
.GetWeakPtr(),
260 template <DemuxerStream::Type StreamType
>
261 void DecoderStream
<StreamType
>::FlushDecoder() {
262 Decode(DecoderBuffer::CreateEOSBuffer());
265 template <DemuxerStream::Type StreamType
>
266 void DecoderStream
<StreamType
>::OnDecodeOutputReady(
268 typename
Decoder::Status status
,
269 const scoped_refptr
<Output
>& output
) {
270 DVLOG(2) << __FUNCTION__
;
271 DCHECK(state_
== STATE_NORMAL
|| state_
== STATE_FLUSHING_DECODER
) << state_
;
272 DCHECK(!read_cb_
.is_null());
273 DCHECK(stop_cb_
.is_null());
274 DCHECK_EQ(status
== Decoder::kOk
, output
!= NULL
);
276 TRACE_EVENT_ASYNC_END0("media", GetTraceString
<StreamType
>(), this);
278 if (status
== Decoder::kDecodeError
) {
279 state_
= STATE_ERROR
;
280 SatisfyRead(DECODE_ERROR
, NULL
);
284 if (status
== Decoder::kDecryptError
) {
285 state_
= STATE_ERROR
;
286 SatisfyRead(DECRYPT_ERROR
, NULL
);
290 if (status
== Decoder::kAborted
) {
291 SatisfyRead(ABORTED
, NULL
);
295 // Any successful decode counts!
296 if (buffer_size
> 0) {
297 StreamTraits::ReportStatistics(statistics_cb_
, buffer_size
);
300 // Drop decoding result if Reset() was called during decoding.
301 // The resetting process will be handled when the decoder is reset.
302 if (!reset_cb_
.is_null()) {
307 // Decoder flushed. Reinitialize the decoder.
308 if (state_
== STATE_FLUSHING_DECODER
&&
309 status
== Decoder::kOk
&& output
->end_of_stream()) {
310 ReinitializeDecoder();
314 if (status
== Decoder::kNotEnoughData
) {
315 if (state_
== STATE_NORMAL
)
316 ReadFromDemuxerStream();
317 else if (state_
== STATE_FLUSHING_DECODER
)
322 SatisfyRead(OK
, output
);
325 template <DemuxerStream::Type StreamType
>
326 void DecoderStream
<StreamType
>::ReadFromDemuxerStream() {
327 DVLOG(2) << __FUNCTION__
;
328 DCHECK_EQ(state_
, STATE_NORMAL
) << state_
;
329 DCHECK(!read_cb_
.is_null());
330 DCHECK(reset_cb_
.is_null());
331 DCHECK(stop_cb_
.is_null());
333 state_
= STATE_PENDING_DEMUXER_READ
;
334 stream_
->Read(base::Bind(&DecoderStream
<StreamType
>::OnBufferReady
,
335 weak_factory_
.GetWeakPtr()));
338 template <DemuxerStream::Type StreamType
>
339 void DecoderStream
<StreamType
>::OnBufferReady(
340 DemuxerStream::Status status
,
341 const scoped_refptr
<DecoderBuffer
>& buffer
) {
342 DVLOG(2) << __FUNCTION__
;
343 DCHECK(task_runner_
->BelongsToCurrentThread());
344 DCHECK_EQ(state_
, STATE_PENDING_DEMUXER_READ
) << state_
;
345 DCHECK_EQ(buffer
.get() != NULL
, status
== DemuxerStream::kOk
) << status
;
346 DCHECK(!read_cb_
.is_null());
347 DCHECK(stop_cb_
.is_null());
349 state_
= STATE_NORMAL
;
351 if (status
== DemuxerStream::kConfigChanged
) {
352 state_
= STATE_FLUSHING_DECODER
;
353 if (!reset_cb_
.is_null()) {
355 // If we are using DecryptingDemuxerStream, we already called DDS::Reset()
356 // which will continue the resetting process in it's callback.
357 if (!decrypting_demuxer_stream_
)
358 Reset(base::ResetAndReturn(&reset_cb_
));
359 // Reinitialization will continue after Reset() is done.
366 if (!reset_cb_
.is_null()) {
368 // If we are using DecryptingDemuxerStream, we already called DDS::Reset()
369 // which will continue the resetting process in it's callback.
370 if (!decrypting_demuxer_stream_
)
371 Reset(base::ResetAndReturn(&reset_cb_
));
375 if (status
== DemuxerStream::kAborted
) {
376 SatisfyRead(DEMUXER_READ_ABORTED
, NULL
);
380 DCHECK(status
== DemuxerStream::kOk
) << status
;
384 template <DemuxerStream::Type StreamType
>
385 void DecoderStream
<StreamType
>::ReinitializeDecoder() {
386 DVLOG(2) << __FUNCTION__
;
387 DCHECK(task_runner_
->BelongsToCurrentThread());
388 DCHECK_EQ(state_
, STATE_FLUSHING_DECODER
) << state_
;
390 // TODO(rileya): Specialize this for audio, or, better yet, change
391 // DemuxerStream config getters to be templated.
392 DCHECK(stream_
->video_decoder_config().IsValidConfig());
393 state_
= STATE_REINITIALIZING_DECODER
;
394 decoder_
->Initialize(
395 stream_
->video_decoder_config(),
396 base::Bind(&DecoderStream
<StreamType
>::OnDecoderReinitialized
,
397 weak_factory_
.GetWeakPtr()));
400 template <DemuxerStream::Type StreamType
>
401 void DecoderStream
<StreamType
>::OnDecoderReinitialized(PipelineStatus status
) {
402 DVLOG(2) << __FUNCTION__
;
403 DCHECK(task_runner_
->BelongsToCurrentThread());
404 DCHECK_EQ(state_
, STATE_REINITIALIZING_DECODER
) << state_
;
405 DCHECK(stop_cb_
.is_null());
407 // ReinitializeDecoder() can be called in two cases:
408 // 1, Flushing decoder finished (see OnDecodeOutputReady()).
409 // 2, Reset() was called during flushing decoder (see OnDecoderReset()).
410 // Also, Reset() can be called during pending ReinitializeDecoder().
411 // This function needs to handle them all!
413 state_
= (status
== PIPELINE_OK
) ? STATE_NORMAL
: STATE_ERROR
;
415 if (!reset_cb_
.is_null()) {
416 if (!read_cb_
.is_null())
418 base::ResetAndReturn(&reset_cb_
).Run();
421 if (read_cb_
.is_null())
424 if (state_
== STATE_ERROR
) {
425 SatisfyRead(DECODE_ERROR
, NULL
);
429 ReadFromDemuxerStream();
432 template <DemuxerStream::Type StreamType
>
433 void DecoderStream
<StreamType
>::ResetDecoder() {
434 DVLOG(2) << __FUNCTION__
;
435 DCHECK(task_runner_
->BelongsToCurrentThread());
436 DCHECK(state_
== STATE_NORMAL
|| state_
== STATE_FLUSHING_DECODER
||
437 state_
== STATE_ERROR
) << state_
;
438 DCHECK(!reset_cb_
.is_null());
440 decoder_
->Reset(base::Bind(&DecoderStream
<StreamType
>::OnDecoderReset
,
441 weak_factory_
.GetWeakPtr()));
444 template <DemuxerStream::Type StreamType
>
445 void DecoderStream
<StreamType
>::OnDecoderReset() {
446 DVLOG(2) << __FUNCTION__
;
447 DCHECK(task_runner_
->BelongsToCurrentThread());
448 DCHECK(state_
== STATE_NORMAL
|| state_
== STATE_FLUSHING_DECODER
||
449 state_
== STATE_ERROR
) << state_
;
450 // If Reset() was called during pending read, read callback should be fired
451 // before the reset callback is fired.
452 DCHECK(read_cb_
.is_null());
453 DCHECK(!reset_cb_
.is_null());
454 DCHECK(stop_cb_
.is_null());
456 if (state_
!= STATE_FLUSHING_DECODER
) {
457 base::ResetAndReturn(&reset_cb_
).Run();
461 // The resetting process will be continued in OnDecoderReinitialized().
462 ReinitializeDecoder();
465 template <DemuxerStream::Type StreamType
>
466 void DecoderStream
<StreamType
>::StopDecoder() {
467 DVLOG(2) << __FUNCTION__
;
468 DCHECK(task_runner_
->BelongsToCurrentThread());
469 DCHECK(state_
!= STATE_UNINITIALIZED
&& state_
!= STATE_STOPPED
) << state_
;
470 DCHECK(!stop_cb_
.is_null());
472 decoder_
->Stop(base::Bind(&DecoderStream
<StreamType
>::OnDecoderStopped
,
473 weak_factory_
.GetWeakPtr()));
476 template <DemuxerStream::Type StreamType
>
477 void DecoderStream
<StreamType
>::OnDecoderStopped() {
478 DVLOG(2) << __FUNCTION__
;
479 DCHECK(task_runner_
->BelongsToCurrentThread());
480 DCHECK(state_
!= STATE_UNINITIALIZED
&& state_
!= STATE_STOPPED
) << state_
;
481 // If Stop() was called during pending read/reset, read/reset callback should
482 // be fired before the stop callback is fired.
483 DCHECK(read_cb_
.is_null());
484 DCHECK(reset_cb_
.is_null());
485 DCHECK(!stop_cb_
.is_null());
487 state_
= STATE_STOPPED
;
490 decrypting_demuxer_stream_
.reset();
491 base::ResetAndReturn(&stop_cb_
).Run();
494 template class DecoderStream
<DemuxerStream::VIDEO
>;