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.
4
5 #include "decoder_selector.h"
6
7 #include "base/bind.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/decoder_stream_traits.h"
17 #include "media/filters/decrypting_audio_decoder.h"
18 #include "media/filters/decrypting_demuxer_stream.h"
19 #include "media/filters/decrypting_video_decoder.h"
20
21 namespace media {
22
HasValidStreamConfig(DemuxerStream * stream)23 static bool HasValidStreamConfig(DemuxerStream* stream) {
24 switch (stream->type()) {
25 case DemuxerStream::AUDIO:
26 return stream->audio_decoder_config().IsValidConfig();
27 case DemuxerStream::VIDEO:
28 return stream->video_decoder_config().IsValidConfig();
29 case DemuxerStream::UNKNOWN:
30 case DemuxerStream::TEXT:
31 case DemuxerStream::NUM_TYPES:
32 NOTREACHED();
33 }
34 return false;
35 }
36
IsStreamEncrypted(DemuxerStream * stream)37 static bool IsStreamEncrypted(DemuxerStream* stream) {
38 switch (stream->type()) {
39 case DemuxerStream::AUDIO:
40 return stream->audio_decoder_config().is_encrypted();
41 case DemuxerStream::VIDEO:
42 return stream->video_decoder_config().is_encrypted();
43 case DemuxerStream::UNKNOWN:
44 case DemuxerStream::TEXT:
45 case DemuxerStream::NUM_TYPES:
46 NOTREACHED();
47 }
48 return false;
49 }
50
51 template <DemuxerStream::Type StreamType>
DecoderSelector(const scoped_refptr<base::SingleThreadTaskRunner> & task_runner,ScopedVector<Decoder> decoders,const SetDecryptorReadyCB & set_decryptor_ready_cb)52 DecoderSelector<StreamType>::DecoderSelector(
53 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
54 ScopedVector<Decoder> decoders,
55 const SetDecryptorReadyCB& set_decryptor_ready_cb)
56 : task_runner_(task_runner),
57 decoders_(decoders.Pass()),
58 set_decryptor_ready_cb_(set_decryptor_ready_cb),
59 input_stream_(NULL),
60 weak_ptr_factory_(this) {}
61
62 template <DemuxerStream::Type StreamType>
~DecoderSelector()63 DecoderSelector<StreamType>::~DecoderSelector() {
64 DVLOG(2) << __FUNCTION__;
65 DCHECK(select_decoder_cb_.is_null());
66 }
67
68 template <DemuxerStream::Type StreamType>
SelectDecoder(DemuxerStream * stream,bool low_delay,const SelectDecoderCB & select_decoder_cb,const typename Decoder::OutputCB & output_cb)69 void DecoderSelector<StreamType>::SelectDecoder(
70 DemuxerStream* stream,
71 bool low_delay,
72 const SelectDecoderCB& select_decoder_cb,
73 const typename Decoder::OutputCB& output_cb) {
74 DVLOG(2) << __FUNCTION__;
75 DCHECK(task_runner_->BelongsToCurrentThread());
76 DCHECK(stream);
77
78 // Make sure |select_decoder_cb| runs on a different execution stack.
79 select_decoder_cb_ = BindToCurrentLoop(select_decoder_cb);
80
81 if (!HasValidStreamConfig(stream)) {
82 DLOG(ERROR) << "Invalid stream config.";
83 ReturnNullDecoder();
84 return;
85 }
86
87 input_stream_ = stream;
88 low_delay_ = low_delay;
89 output_cb_ = output_cb;
90
91 if (!IsStreamEncrypted(input_stream_)) {
92 InitializeDecoder();
93 return;
94 }
95
96 // This could happen if Encrypted Media Extension (EME) is not enabled.
97 if (set_decryptor_ready_cb_.is_null()) {
98 ReturnNullDecoder();
99 return;
100 }
101
102 decoder_.reset(new typename StreamTraits::DecryptingDecoderType(
103 task_runner_, set_decryptor_ready_cb_));
104
105 DecoderStreamTraits<StreamType>::Initialize(
106 decoder_.get(),
107 StreamTraits::GetDecoderConfig(*input_stream_),
108 low_delay_,
109 base::Bind(&DecoderSelector<StreamType>::DecryptingDecoderInitDone,
110 weak_ptr_factory_.GetWeakPtr()),
111 output_cb_);
112 }
113
114 template <DemuxerStream::Type StreamType>
Abort()115 void DecoderSelector<StreamType>::Abort() {
116 DVLOG(2) << __FUNCTION__;
117 DCHECK(task_runner_->BelongsToCurrentThread());
118
119 // This could happen when SelectDecoder() was not called or when
120 // |select_decoder_cb_| was already posted but not fired (e.g. in the
121 // message loop queue).
122 if (select_decoder_cb_.is_null())
123 return;
124
125 // We must be trying to initialize the |decoder_| or the
126 // |decrypted_stream_|. Invalid all weak pointers so that all initialization
127 // callbacks won't fire.
128 weak_ptr_factory_.InvalidateWeakPtrs();
129
130 if (decoder_) {
131 // |decrypted_stream_| is either NULL or already initialized. We don't
132 // need to Stop() |decrypted_stream_| in either case.
133 decoder_->Stop();
134 ReturnNullDecoder();
135 return;
136 }
137
138 if (decrypted_stream_) {
139 decrypted_stream_->Stop(
140 base::Bind(&DecoderSelector<StreamType>::ReturnNullDecoder,
141 weak_ptr_factory_.GetWeakPtr()));
142 return;
143 }
144
145 NOTREACHED();
146 }
147
148 template <DemuxerStream::Type StreamType>
DecryptingDecoderInitDone(PipelineStatus status)149 void DecoderSelector<StreamType>::DecryptingDecoderInitDone(
150 PipelineStatus status) {
151 DVLOG(2) << __FUNCTION__;
152 DCHECK(task_runner_->BelongsToCurrentThread());
153
154 if (status == PIPELINE_OK) {
155 base::ResetAndReturn(&select_decoder_cb_)
156 .Run(decoder_.Pass(), scoped_ptr<DecryptingDemuxerStream>());
157 return;
158 }
159
160 decoder_.reset();
161
162 decrypted_stream_.reset(
163 new DecryptingDemuxerStream(task_runner_, set_decryptor_ready_cb_));
164
165 decrypted_stream_->Initialize(
166 input_stream_,
167 base::Bind(&DecoderSelector<StreamType>::DecryptingDemuxerStreamInitDone,
168 weak_ptr_factory_.GetWeakPtr()));
169 }
170
171 template <DemuxerStream::Type StreamType>
DecryptingDemuxerStreamInitDone(PipelineStatus status)172 void DecoderSelector<StreamType>::DecryptingDemuxerStreamInitDone(
173 PipelineStatus status) {
174 DVLOG(2) << __FUNCTION__;
175 DCHECK(task_runner_->BelongsToCurrentThread());
176
177 if (status != PIPELINE_OK) {
178 ReturnNullDecoder();
179 return;
180 }
181
182 DCHECK(!IsStreamEncrypted(decrypted_stream_.get()));
183 input_stream_ = decrypted_stream_.get();
184 InitializeDecoder();
185 }
186
187 template <DemuxerStream::Type StreamType>
InitializeDecoder()188 void DecoderSelector<StreamType>::InitializeDecoder() {
189 DVLOG(2) << __FUNCTION__;
190 DCHECK(task_runner_->BelongsToCurrentThread());
191 DCHECK(!decoder_);
192
193 if (decoders_.empty()) {
194 ReturnNullDecoder();
195 return;
196 }
197
198 decoder_.reset(decoders_.front());
199 decoders_.weak_erase(decoders_.begin());
200
201 DecoderStreamTraits<StreamType>::Initialize(
202 decoder_.get(),
203 StreamTraits::GetDecoderConfig(*input_stream_),
204 low_delay_,
205 base::Bind(&DecoderSelector<StreamType>::DecoderInitDone,
206 weak_ptr_factory_.GetWeakPtr()),
207 output_cb_);
208 }
209
210 template <DemuxerStream::Type StreamType>
DecoderInitDone(PipelineStatus status)211 void DecoderSelector<StreamType>::DecoderInitDone(PipelineStatus status) {
212 DVLOG(2) << __FUNCTION__;
213 DCHECK(task_runner_->BelongsToCurrentThread());
214
215 if (status != PIPELINE_OK) {
216 decoder_.reset();
217 InitializeDecoder();
218 return;
219 }
220
221 base::ResetAndReturn(&select_decoder_cb_)
222 .Run(decoder_.Pass(), decrypted_stream_.Pass());
223 }
224
225 template <DemuxerStream::Type StreamType>
ReturnNullDecoder()226 void DecoderSelector<StreamType>::ReturnNullDecoder() {
227 DVLOG(2) << __FUNCTION__;
228 DCHECK(task_runner_->BelongsToCurrentThread());
229 base::ResetAndReturn(&select_decoder_cb_)
230 .Run(scoped_ptr<Decoder>(),
231 scoped_ptr<DecryptingDemuxerStream>());
232 }
233
234 // These forward declarations tell the compiler that we will use
235 // DecoderSelector with these arguments, allowing us to keep these definitions
236 // in our .cc without causing linker errors. This also means if anyone tries to
237 // instantiate a DecoderSelector with anything but these two specializations
238 // they'll most likely get linker errors.
239 template class DecoderSelector<DemuxerStream::AUDIO>;
240 template class DecoderSelector<DemuxerStream::VIDEO>;
241
242 } // namespace media
243