1// Copyright (c) 2012 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 "media/filters/video_decoder_selector.h"
6
7#include "base/bind.h"
8#include "base/callback_helpers.h"
9#include "base/logging.h"
10#include "base/message_loop/message_loop_proxy.h"
11#include "media/base/bind_to_loop.h"
12#include "media/base/demuxer_stream.h"
13#include "media/base/pipeline.h"
14#include "media/base/video_decoder_config.h"
15#include "media/filters/decrypting_demuxer_stream.h"
16#include "media/filters/decrypting_video_decoder.h"
17
18namespace media {
19
20VideoDecoderSelector::VideoDecoderSelector(
21    const scoped_refptr<base::MessageLoopProxy>& message_loop,
22    ScopedVector<VideoDecoder> decoders,
23    const SetDecryptorReadyCB& set_decryptor_ready_cb)
24    : message_loop_(message_loop),
25      decoders_(decoders.Pass()),
26      set_decryptor_ready_cb_(set_decryptor_ready_cb),
27      input_stream_(NULL),
28      weak_ptr_factory_(this) {
29}
30
31VideoDecoderSelector::~VideoDecoderSelector() {}
32
33void VideoDecoderSelector::SelectVideoDecoder(
34    DemuxerStream* stream,
35    const SelectDecoderCB& select_decoder_cb) {
36  DVLOG(2) << "SelectVideoDecoder()";
37  DCHECK(message_loop_->BelongsToCurrentThread());
38  DCHECK(stream);
39
40  // Make sure |select_decoder_cb| runs on a different execution stack.
41  select_decoder_cb_ = BindToCurrentLoop(select_decoder_cb);
42
43  const VideoDecoderConfig& config = stream->video_decoder_config();
44  if (!config.IsValidConfig()) {
45    DLOG(ERROR) << "Invalid video stream config.";
46    base::ResetAndReturn(&select_decoder_cb_).Run(
47        scoped_ptr<VideoDecoder>(), scoped_ptr<DecryptingDemuxerStream>());
48    return;
49  }
50
51  input_stream_ = stream;
52
53  if (!config.is_encrypted()) {
54    InitializeDecoder(decoders_.begin());
55    return;
56  }
57
58  // This could happen if Encrypted Media Extension (EME) is not enabled.
59  if (set_decryptor_ready_cb_.is_null()) {
60    base::ResetAndReturn(&select_decoder_cb_).Run(
61        scoped_ptr<VideoDecoder>(), scoped_ptr<DecryptingDemuxerStream>());
62    return;
63  }
64
65  video_decoder_.reset(new DecryptingVideoDecoder(
66      message_loop_, set_decryptor_ready_cb_));
67
68  video_decoder_->Initialize(
69      input_stream_->video_decoder_config(),
70      BindToCurrentLoop(base::Bind(
71          &VideoDecoderSelector::DecryptingVideoDecoderInitDone,
72          weak_ptr_factory_.GetWeakPtr())));
73}
74
75void VideoDecoderSelector::DecryptingVideoDecoderInitDone(
76    PipelineStatus status) {
77  DCHECK(message_loop_->BelongsToCurrentThread());
78
79  if (status == PIPELINE_OK) {
80    base::ResetAndReturn(&select_decoder_cb_).Run(
81        video_decoder_.Pass(), scoped_ptr<DecryptingDemuxerStream>());
82    return;
83  }
84
85  decrypted_stream_.reset(new DecryptingDemuxerStream(
86      message_loop_, set_decryptor_ready_cb_));
87
88  decrypted_stream_->Initialize(
89      input_stream_,
90      BindToCurrentLoop(base::Bind(
91          &VideoDecoderSelector::DecryptingDemuxerStreamInitDone,
92          weak_ptr_factory_.GetWeakPtr())));
93}
94
95void VideoDecoderSelector::DecryptingDemuxerStreamInitDone(
96    PipelineStatus status) {
97  DCHECK(message_loop_->BelongsToCurrentThread());
98
99  if (status != PIPELINE_OK) {
100    decrypted_stream_.reset();
101    base::ResetAndReturn(&select_decoder_cb_).Run(
102        scoped_ptr<VideoDecoder>(), scoped_ptr<DecryptingDemuxerStream>());
103    return;
104  }
105
106  DCHECK(!decrypted_stream_->video_decoder_config().is_encrypted());
107  input_stream_ = decrypted_stream_.get();
108  InitializeDecoder(decoders_.begin());
109}
110
111void VideoDecoderSelector::InitializeDecoder(
112    ScopedVector<VideoDecoder>::iterator iter) {
113  DCHECK(message_loop_->BelongsToCurrentThread());
114
115  if (iter == decoders_.end()) {
116    base::ResetAndReturn(&select_decoder_cb_).Run(
117        scoped_ptr<VideoDecoder>(), scoped_ptr<DecryptingDemuxerStream>());
118    return;
119  }
120
121  (*iter)->Initialize(
122      input_stream_->video_decoder_config(),
123      BindToCurrentLoop(base::Bind(&VideoDecoderSelector::DecoderInitDone,
124                                   weak_ptr_factory_.GetWeakPtr(),
125                                   iter)));
126}
127
128void VideoDecoderSelector::DecoderInitDone(
129    ScopedVector<VideoDecoder>::iterator iter, PipelineStatus status) {
130  DCHECK(message_loop_->BelongsToCurrentThread());
131
132  if (status != PIPELINE_OK) {
133    InitializeDecoder(++iter);
134    return;
135  }
136
137  scoped_ptr<VideoDecoder> video_decoder(*iter);
138  decoders_.weak_erase(iter);
139
140  base::ResetAndReturn(&select_decoder_cb_).Run(video_decoder.Pass(),
141                                                decrypted_stream_.Pass());
142}
143
144}  // namespace media
145