decoder_selector.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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
21namespace media {
22
23static 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
37static 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
51template <DemuxerStream::Type StreamType>
52DecoderSelector<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
62template <DemuxerStream::Type StreamType>
63DecoderSelector<StreamType>::~DecoderSelector() {
64  DVLOG(2) << __FUNCTION__;
65  DCHECK(select_decoder_cb_.is_null());
66}
67
68template <DemuxerStream::Type StreamType>
69void DecoderSelector<StreamType>::SelectDecoder(
70    DemuxerStream* stream,
71    const SelectDecoderCB& select_decoder_cb) {
72  DVLOG(2) << __FUNCTION__;
73  DCHECK(task_runner_->BelongsToCurrentThread());
74  DCHECK(stream);
75
76  // Make sure |select_decoder_cb| runs on a different execution stack.
77  select_decoder_cb_ = BindToCurrentLoop(select_decoder_cb);
78
79  if (!HasValidStreamConfig(stream)) {
80    DLOG(ERROR) << "Invalid stream config.";
81    ReturnNullDecoder();
82    return;
83  }
84
85  input_stream_ = stream;
86
87  if (!IsStreamEncrypted(input_stream_)) {
88    InitializeDecoder();
89    return;
90  }
91
92  // This could happen if Encrypted Media Extension (EME) is not enabled.
93  if (set_decryptor_ready_cb_.is_null()) {
94    ReturnNullDecoder();
95    return;
96  }
97
98  decoder_.reset(new typename StreamTraits::DecryptingDecoderType(
99      task_runner_, set_decryptor_ready_cb_));
100
101  decoder_->Initialize(
102      StreamTraits::GetDecoderConfig(*input_stream_),
103      base::Bind(&DecoderSelector<StreamType>::DecryptingDecoderInitDone,
104                 weak_ptr_factory_.GetWeakPtr()));
105}
106
107template <DemuxerStream::Type StreamType>
108void DecoderSelector<StreamType>::Abort() {
109  DVLOG(2) << __FUNCTION__;
110  DCHECK(task_runner_->BelongsToCurrentThread());
111
112  // This could happen when SelectDecoder() was not called or when
113  // |select_decoder_cb_| was already posted but not fired (e.g. in the
114  // message loop queue).
115  if (select_decoder_cb_.is_null())
116    return;
117
118  // We must be trying to initialize the |decoder_| or the
119  // |decrypted_stream_|. Invalid all weak pointers so that all initialization
120  // callbacks won't fire.
121  weak_ptr_factory_.InvalidateWeakPtrs();
122
123  if (decoder_) {
124    // |decrypted_stream_| is either NULL or already initialized. We don't
125    // need to Stop() |decrypted_stream_| in either case.
126    decoder_->Stop();
127    ReturnNullDecoder();
128    return;
129  }
130
131  if (decrypted_stream_) {
132    decrypted_stream_->Stop(
133        base::Bind(&DecoderSelector<StreamType>::ReturnNullDecoder,
134                   weak_ptr_factory_.GetWeakPtr()));
135    return;
136  }
137
138  NOTREACHED();
139}
140
141template <DemuxerStream::Type StreamType>
142void DecoderSelector<StreamType>::DecryptingDecoderInitDone(
143    PipelineStatus status) {
144  DVLOG(2) << __FUNCTION__;
145  DCHECK(task_runner_->BelongsToCurrentThread());
146
147  if (status == PIPELINE_OK) {
148    base::ResetAndReturn(&select_decoder_cb_)
149        .Run(decoder_.Pass(), scoped_ptr<DecryptingDemuxerStream>());
150    return;
151  }
152
153  decoder_.reset();
154
155  decrypted_stream_.reset(
156      new DecryptingDemuxerStream(task_runner_, set_decryptor_ready_cb_));
157
158  decrypted_stream_->Initialize(
159      input_stream_,
160      base::Bind(&DecoderSelector<StreamType>::DecryptingDemuxerStreamInitDone,
161                 weak_ptr_factory_.GetWeakPtr()));
162}
163
164template <DemuxerStream::Type StreamType>
165void DecoderSelector<StreamType>::DecryptingDemuxerStreamInitDone(
166    PipelineStatus status) {
167  DVLOG(2) << __FUNCTION__;
168  DCHECK(task_runner_->BelongsToCurrentThread());
169
170  if (status != PIPELINE_OK) {
171    ReturnNullDecoder();
172    return;
173  }
174
175  DCHECK(!IsStreamEncrypted(decrypted_stream_.get()));
176  input_stream_ = decrypted_stream_.get();
177  InitializeDecoder();
178}
179
180template <DemuxerStream::Type StreamType>
181void DecoderSelector<StreamType>::InitializeDecoder() {
182  DVLOG(2) << __FUNCTION__;
183  DCHECK(task_runner_->BelongsToCurrentThread());
184  DCHECK(!decoder_);
185
186  if (decoders_.empty()) {
187    ReturnNullDecoder();
188    return;
189  }
190
191  decoder_.reset(decoders_.front());
192  decoders_.weak_erase(decoders_.begin());
193
194  decoder_->Initialize(StreamTraits::GetDecoderConfig(*input_stream_),
195                       base::Bind(&DecoderSelector<StreamType>::DecoderInitDone,
196                                  weak_ptr_factory_.GetWeakPtr()));
197}
198
199template <DemuxerStream::Type StreamType>
200void DecoderSelector<StreamType>::DecoderInitDone(PipelineStatus status) {
201  DVLOG(2) << __FUNCTION__;
202  DCHECK(task_runner_->BelongsToCurrentThread());
203
204  if (status != PIPELINE_OK) {
205    decoder_.reset();
206    InitializeDecoder();
207    return;
208  }
209
210  base::ResetAndReturn(&select_decoder_cb_)
211      .Run(decoder_.Pass(), decrypted_stream_.Pass());
212}
213
214template <DemuxerStream::Type StreamType>
215void 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>());
221}
222
223// These forward declarations tell the compiler that we will use
224// DecoderSelector with these arguments, allowing us to keep these definitions
225// in our .cc without causing linker errors. This also means if anyone tries to
226// instantiate a DecoderSelector with anything but these two specializations
227// they'll most likely get linker errors.
228template class DecoderSelector<DemuxerStream::AUDIO>;
229template class DecoderSelector<DemuxerStream::VIDEO>;
230
231}  // namespace media
232