decoder_selector.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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    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
114template <DemuxerStream::Type StreamType>
115void 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
148template <DemuxerStream::Type StreamType>
149void 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
171template <DemuxerStream::Type StreamType>
172void 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
187template <DemuxerStream::Type StreamType>
188void 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
210template <DemuxerStream::Type StreamType>
211void 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
225template <DemuxerStream::Type StreamType>
226void 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.
239template class DecoderSelector<DemuxerStream::AUDIO>;
240template class DecoderSelector<DemuxerStream::VIDEO>;
241
242}  // namespace media
243