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 "decoder_selector.h"
8 #include "base/callback_helpers.h"
9 #include "base/logging.h"
10 #include "base/single_thread_task_runner.h"
11 #include "media/base/audio_decoder.h"
12 #include "media/base/bind_to_current_loop.h"
13 #include "media/base/demuxer_stream.h"
14 #include "media/base/pipeline.h"
15 #include "media/base/video_decoder.h"
16 #include "media/filters/decrypting_audio_decoder.h"
17 #include "media/filters/decrypting_demuxer_stream.h"
18 #include "media/filters/decrypting_video_decoder.h"
22 static bool HasValidStreamConfig(DemuxerStream
* stream
) {
23 switch (stream
->type()) {
24 case DemuxerStream::AUDIO
:
25 return stream
->audio_decoder_config().IsValidConfig();
26 case DemuxerStream::VIDEO
:
27 return stream
->video_decoder_config().IsValidConfig();
28 case DemuxerStream::UNKNOWN
:
29 case DemuxerStream::TEXT
:
30 case DemuxerStream::NUM_TYPES
:
36 static bool IsStreamEncrypted(DemuxerStream
* stream
) {
37 switch (stream
->type()) {
38 case DemuxerStream::AUDIO
:
39 return stream
->audio_decoder_config().is_encrypted();
40 case DemuxerStream::VIDEO
:
41 return stream
->video_decoder_config().is_encrypted();
42 case DemuxerStream::UNKNOWN
:
43 case DemuxerStream::TEXT
:
44 case DemuxerStream::NUM_TYPES
:
50 template <DemuxerStream::Type StreamType
>
51 DecoderSelector
<StreamType
>::DecoderSelector(
52 const scoped_refptr
<base::SingleThreadTaskRunner
>& task_runner
,
53 ScopedVector
<Decoder
> decoders
,
54 const SetDecryptorReadyCB
& set_decryptor_ready_cb
)
55 : task_runner_(task_runner
),
56 decoders_(decoders
.Pass()),
57 set_decryptor_ready_cb_(set_decryptor_ready_cb
),
59 weak_ptr_factory_(this) {}
61 template <DemuxerStream::Type StreamType
>
62 DecoderSelector
<StreamType
>::~DecoderSelector() {
63 DVLOG(2) << __FUNCTION__
;
64 DCHECK(select_decoder_cb_
.is_null());
67 template <DemuxerStream::Type StreamType
>
68 void DecoderSelector
<StreamType
>::SelectDecoder(
69 DemuxerStream
* stream
,
70 StatisticsCB statistics_cb
,
71 const SelectDecoderCB
& select_decoder_cb
) {
72 DVLOG(2) << __FUNCTION__
;
73 DCHECK(task_runner_
->BelongsToCurrentThread());
76 // Make sure |select_decoder_cb| runs on a different execution stack.
77 select_decoder_cb_
= BindToCurrentLoop(select_decoder_cb
);
79 statistics_cb_
= statistics_cb
;
81 if (!HasValidStreamConfig(stream
)) {
82 DLOG(ERROR
) << "Invalid stream config.";
87 input_stream_
= stream
;
89 if (!IsStreamEncrypted(input_stream_
)) {
94 // This could happen if Encrypted Media Extension (EME) is not enabled.
95 if (set_decryptor_ready_cb_
.is_null()) {
100 decoder_
.reset(new typename
StreamTraits::DecryptingDecoderType(
101 task_runner_
, set_decryptor_ready_cb_
));
104 base::Bind(&DecoderSelector
<StreamType
>::DecryptingDecoderInitDone
,
105 weak_ptr_factory_
.GetWeakPtr()));
108 template <DemuxerStream::Type StreamType
>
109 void DecoderSelector
<StreamType
>::Abort() {
110 DVLOG(2) << __FUNCTION__
;
111 DCHECK(task_runner_
->BelongsToCurrentThread());
113 // This could happen when SelectDecoder() was not called or when
114 // |select_decoder_cb_| was already posted but not fired (e.g. in the
115 // message loop queue).
116 if (select_decoder_cb_
.is_null())
119 // We must be trying to initialize the |decoder_| or the
120 // |decrypted_stream_|. Invalid all weak pointers so that all initialization
121 // callbacks won't fire.
122 weak_ptr_factory_
.InvalidateWeakPtrs();
125 // |decrypted_stream_| is either NULL or already initialized. We don't
126 // need to Stop() |decrypted_stream_| in either case.
127 decoder_
->Stop(base::Bind(&DecoderSelector
<StreamType
>::ReturnNullDecoder
,
128 weak_ptr_factory_
.GetWeakPtr()));
132 if (decrypted_stream_
) {
133 decrypted_stream_
->Stop(
134 base::Bind(&DecoderSelector
<StreamType
>::ReturnNullDecoder
,
135 weak_ptr_factory_
.GetWeakPtr()));
142 template <DemuxerStream::Type StreamType
>
143 void DecoderSelector
<StreamType
>::DecryptingDecoderInitDone(
144 PipelineStatus status
) {
145 DVLOG(2) << __FUNCTION__
;
146 DCHECK(task_runner_
->BelongsToCurrentThread());
148 if (status
== PIPELINE_OK
) {
149 base::ResetAndReturn(&select_decoder_cb_
)
150 .Run(decoder_
.Pass(), scoped_ptr
<DecryptingDemuxerStream
>());
156 decrypted_stream_
.reset(
157 new DecryptingDemuxerStream(task_runner_
, set_decryptor_ready_cb_
));
159 decrypted_stream_
->Initialize(
161 base::Bind(&DecoderSelector
<StreamType
>::DecryptingDemuxerStreamInitDone
,
162 weak_ptr_factory_
.GetWeakPtr()));
165 template <DemuxerStream::Type StreamType
>
166 void DecoderSelector
<StreamType
>::DecryptingDemuxerStreamInitDone(
167 PipelineStatus status
) {
168 DVLOG(2) << __FUNCTION__
;
169 DCHECK(task_runner_
->BelongsToCurrentThread());
171 if (status
!= PIPELINE_OK
) {
176 DCHECK(!IsStreamEncrypted(decrypted_stream_
.get()));
177 input_stream_
= decrypted_stream_
.get();
181 template <DemuxerStream::Type StreamType
>
182 void DecoderSelector
<StreamType
>::InitializeDecoder() {
183 DVLOG(2) << __FUNCTION__
;
184 DCHECK(task_runner_
->BelongsToCurrentThread());
187 if (decoders_
.empty()) {
192 decoder_
.reset(decoders_
.front());
193 decoders_
.weak_erase(decoders_
.begin());
195 DoInitializeDecoder(base::Bind(&DecoderSelector
<StreamType
>::DecoderInitDone
,
196 weak_ptr_factory_
.GetWeakPtr()));
199 template <DemuxerStream::Type StreamType
>
200 void DecoderSelector
<StreamType
>::DecoderInitDone(PipelineStatus status
) {
201 DVLOG(2) << __FUNCTION__
;
202 DCHECK(task_runner_
->BelongsToCurrentThread());
204 if (status
!= PIPELINE_OK
) {
210 base::ResetAndReturn(&select_decoder_cb_
)
211 .Run(decoder_
.Pass(), decrypted_stream_
.Pass());
214 template <DemuxerStream::Type StreamType
>
215 void DecoderSelector
<StreamType
>::ReturnNullDecoder() {
216 DVLOG(2) << __FUNCTION__
;
217 DCHECK(task_runner_
->BelongsToCurrentThread());
218 base::ResetAndReturn(&select_decoder_cb_
)
219 .Run(scoped_ptr
<Decoder
>(),
220 scoped_ptr
<DecryptingDemuxerStream
>());
223 // TODO(rileya): Get rid of this and the specialization below once the Audio and
224 // Video Decoders' Initialize() interfaces match up (see crbug.com/338059).
225 template <DemuxerStream::Type StreamType
>
226 void DecoderSelector
<StreamType
>::DoInitializeDecoder(
227 const PipelineStatusCB
& status_cb
) {
228 decoder_
->Initialize(input_stream_
->video_decoder_config(), status_cb
);
231 // Specialization for AudioDecoder (its Initialize() signature currently doesn't
232 // match that of VideoDecoder (eventually it will, see the TODO above).
234 void AudioDecoderSelector::DoInitializeDecoder(
235 const PipelineStatusCB
& status_cb
) {
236 decoder_
->Initialize(input_stream_
, status_cb
, statistics_cb_
);
239 // These forward declarations tell the compiler that we will use
240 // DecoderSelector with these arguments, allowing us to keep these definitions
241 // in our .cc without causing linker errors. This also means if anyone tries to
242 // instantiate a DecoderSelector with anything but these two specializations
243 // they'll most likely get linker errors.
244 template class DecoderSelector
<DemuxerStream::AUDIO
>;
245 template class DecoderSelector
<DemuxerStream::VIDEO
>;