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