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