Media Galleries API Metadata: Enable GetMetadata call and fix bugs
[chromium-blink-merge.git] / media / filters / decoder_selector.cc
blobcaf1440e9ac4a58f4f1b0d347ec6c0cb8e7f03d3
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"
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/decrypting_audio_decoder.h"
17 #include "media/filters/decrypting_demuxer_stream.h"
18 #include "media/filters/decrypting_video_decoder.h"
20 namespace media {
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:
31 NOTREACHED();
33 return false;
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:
45 NOTREACHED();
47 return false;
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),
58 input_stream_(NULL),
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());
74 DCHECK(stream);
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.";
83 ReturnNullDecoder();
84 return;
87 input_stream_ = stream;
89 if (!IsStreamEncrypted(input_stream_)) {
90 InitializeDecoder();
91 return;
94 // This could happen if Encrypted Media Extension (EME) is not enabled.
95 if (set_decryptor_ready_cb_.is_null()) {
96 ReturnNullDecoder();
97 return;
100 decoder_.reset(new typename StreamTraits::DecryptingDecoderType(
101 task_runner_, set_decryptor_ready_cb_));
103 DoInitializeDecoder(
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())
117 return;
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();
124 if (decoder_) {
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()));
129 return;
132 if (decrypted_stream_) {
133 decrypted_stream_->Stop(
134 base::Bind(&DecoderSelector<StreamType>::ReturnNullDecoder,
135 weak_ptr_factory_.GetWeakPtr()));
136 return;
139 NOTREACHED();
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>());
151 return;
154 decoder_.reset();
156 decrypted_stream_.reset(
157 new DecryptingDemuxerStream(task_runner_, set_decryptor_ready_cb_));
159 decrypted_stream_->Initialize(
160 input_stream_,
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) {
172 ReturnNullDecoder();
173 return;
176 DCHECK(!IsStreamEncrypted(decrypted_stream_.get()));
177 input_stream_ = decrypted_stream_.get();
178 InitializeDecoder();
181 template <DemuxerStream::Type StreamType>
182 void DecoderSelector<StreamType>::InitializeDecoder() {
183 DVLOG(2) << __FUNCTION__;
184 DCHECK(task_runner_->BelongsToCurrentThread());
185 DCHECK(!decoder_);
187 if (decoders_.empty()) {
188 ReturnNullDecoder();
189 return;
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) {
205 decoder_.reset();
206 InitializeDecoder();
207 return;
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).
233 template <>
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>;
247 } // namespace media