decrypting_video_decoder.cc revision ca12bfac764ba476d6cd062bf1dde12cc64c3f40
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/decrypting_video_decoder.h" 6 7#include "base/bind.h" 8#include "base/callback_helpers.h" 9#include "base/debug/trace_event.h" 10#include "base/location.h" 11#include "base/logging.h" 12#include "base/message_loop/message_loop_proxy.h" 13#include "media/base/bind_to_loop.h" 14#include "media/base/decoder_buffer.h" 15#include "media/base/decryptor.h" 16#include "media/base/pipeline.h" 17#include "media/base/video_decoder_config.h" 18#include "media/base/video_frame.h" 19 20namespace media { 21 22DecryptingVideoDecoder::DecryptingVideoDecoder( 23 const scoped_refptr<base::MessageLoopProxy>& message_loop, 24 const SetDecryptorReadyCB& set_decryptor_ready_cb) 25 : message_loop_(message_loop), 26 weak_factory_(this), 27 state_(kUninitialized), 28 set_decryptor_ready_cb_(set_decryptor_ready_cb), 29 decryptor_(NULL), 30 key_added_while_decode_pending_(false), 31 trace_id_(0) { 32} 33 34void DecryptingVideoDecoder::Initialize(const VideoDecoderConfig& config, 35 const PipelineStatusCB& status_cb) { 36 DVLOG(2) << "Initialize()"; 37 DCHECK(message_loop_->BelongsToCurrentThread()); 38 DCHECK(state_ == kUninitialized || 39 state_ == kIdle || 40 state_ == kDecodeFinished) << state_; 41 DCHECK(read_cb_.is_null()); 42 DCHECK(reset_cb_.is_null()); 43 DCHECK(config.IsValidConfig()); 44 DCHECK(config.is_encrypted()); 45 46 init_cb_ = BindToCurrentLoop(status_cb); 47 weak_this_ = weak_factory_.GetWeakPtr(); 48 config_ = config; 49 50 if (state_ == kUninitialized) { 51 state_ = kDecryptorRequested; 52 set_decryptor_ready_cb_.Run(BindToCurrentLoop(base::Bind( 53 &DecryptingVideoDecoder::SetDecryptor, weak_this_))); 54 return; 55 } 56 57 // Reinitialization. 58 decryptor_->DeinitializeDecoder(Decryptor::kVideo); 59 state_ = kPendingDecoderInit; 60 decryptor_->InitializeVideoDecoder(config, BindToCurrentLoop(base::Bind( 61 &DecryptingVideoDecoder::FinishInitialization, weak_this_))); 62} 63 64void DecryptingVideoDecoder::Decode(const scoped_refptr<DecoderBuffer>& buffer, 65 const ReadCB& read_cb) { 66 DVLOG(3) << "Decode()"; 67 DCHECK(message_loop_->BelongsToCurrentThread()); 68 DCHECK(state_ == kIdle || 69 state_ == kDecodeFinished || 70 state_ == kError) << state_; 71 DCHECK(!read_cb.is_null()); 72 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; 73 74 read_cb_ = BindToCurrentLoop(read_cb); 75 76 if (state_ == kError) { 77 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); 78 return; 79 } 80 81 // Return empty frames if decoding has finished. 82 if (state_ == kDecodeFinished) { 83 base::ResetAndReturn(&read_cb_).Run(kOk, VideoFrame::CreateEmptyFrame()); 84 return; 85 } 86 87 pending_buffer_to_decode_ = buffer; 88 state_ = kPendingDecode; 89 DecodePendingBuffer(); 90} 91 92void DecryptingVideoDecoder::Reset(const base::Closure& closure) { 93 DVLOG(2) << "Reset() - state: " << state_; 94 DCHECK(message_loop_->BelongsToCurrentThread()); 95 DCHECK(state_ == kIdle || 96 state_ == kPendingDecode || 97 state_ == kWaitingForKey || 98 state_ == kDecodeFinished || 99 state_ == kError) << state_; 100 DCHECK(init_cb_.is_null()); // No Reset() during pending initialization. 101 DCHECK(reset_cb_.is_null()); 102 103 reset_cb_ = BindToCurrentLoop(closure); 104 105 decryptor_->ResetDecoder(Decryptor::kVideo); 106 107 // Reset() cannot complete if the read callback is still pending. 108 // Defer the resetting process in this case. The |reset_cb_| will be fired 109 // after the read callback is fired - see DecryptAndDecodeBuffer() and 110 // DeliverFrame(). 111 if (state_ == kPendingDecode) { 112 DCHECK(!read_cb_.is_null()); 113 return; 114 } 115 116 if (state_ == kWaitingForKey) { 117 DCHECK(!read_cb_.is_null()); 118 pending_buffer_to_decode_ = NULL; 119 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); 120 } 121 122 DCHECK(read_cb_.is_null()); 123 DoReset(); 124} 125 126void DecryptingVideoDecoder::Stop(const base::Closure& closure) { 127 DCHECK(message_loop_->BelongsToCurrentThread()); 128 DVLOG(2) << "Stop() - state: " << state_; 129 130 // At this point the render thread is likely paused (in WebMediaPlayerImpl's 131 // Destroy()), so running |closure| can't wait for anything that requires the 132 // render thread to be processing messages to complete (such as PPAPI 133 // callbacks). 134 if (decryptor_) { 135 decryptor_->RegisterNewKeyCB(Decryptor::kVideo, Decryptor::NewKeyCB()); 136 decryptor_->DeinitializeDecoder(Decryptor::kVideo); 137 decryptor_ = NULL; 138 } 139 if (!set_decryptor_ready_cb_.is_null()) 140 base::ResetAndReturn(&set_decryptor_ready_cb_).Run(DecryptorReadyCB()); 141 pending_buffer_to_decode_ = NULL; 142 if (!init_cb_.is_null()) 143 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); 144 if (!read_cb_.is_null()) 145 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); 146 if (!reset_cb_.is_null()) 147 base::ResetAndReturn(&reset_cb_).Run(); 148 state_ = kStopped; 149 BindToCurrentLoop(closure).Run(); 150} 151 152DecryptingVideoDecoder::~DecryptingVideoDecoder() { 153 DCHECK(state_ == kUninitialized || state_ == kStopped) << state_; 154} 155 156void DecryptingVideoDecoder::SetDecryptor(Decryptor* decryptor) { 157 DVLOG(2) << "SetDecryptor()"; 158 DCHECK(message_loop_->BelongsToCurrentThread()); 159 160 if (state_ == kStopped) 161 return; 162 163 DCHECK_EQ(state_, kDecryptorRequested) << state_; 164 DCHECK(!init_cb_.is_null()); 165 DCHECK(!set_decryptor_ready_cb_.is_null()); 166 set_decryptor_ready_cb_.Reset(); 167 168 if (!decryptor) { 169 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); 170 state_ = kStopped; 171 return; 172 } 173 174 decryptor_ = decryptor; 175 176 state_ = kPendingDecoderInit; 177 decryptor_->InitializeVideoDecoder( 178 config_, 179 BindToCurrentLoop(base::Bind( 180 &DecryptingVideoDecoder::FinishInitialization, weak_this_))); 181} 182 183void DecryptingVideoDecoder::FinishInitialization(bool success) { 184 DVLOG(2) << "FinishInitialization()"; 185 DCHECK(message_loop_->BelongsToCurrentThread()); 186 187 if (state_ == kStopped) 188 return; 189 190 DCHECK_EQ(state_, kPendingDecoderInit) << state_; 191 DCHECK(!init_cb_.is_null()); 192 DCHECK(reset_cb_.is_null()); // No Reset() before initialization finished. 193 DCHECK(read_cb_.is_null()); // No Read() before initialization finished. 194 195 if (!success) { 196 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); 197 state_ = kStopped; 198 return; 199 } 200 201 decryptor_->RegisterNewKeyCB(Decryptor::kVideo, BindToCurrentLoop( 202 base::Bind(&DecryptingVideoDecoder::OnKeyAdded, weak_this_))); 203 204 // Success! 205 state_ = kIdle; 206 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); 207} 208 209 210void DecryptingVideoDecoder::DecodePendingBuffer() { 211 DCHECK(message_loop_->BelongsToCurrentThread()); 212 DCHECK_EQ(state_, kPendingDecode) << state_; 213 TRACE_EVENT_ASYNC_BEGIN0( 214 "eme", "DecryptingVideoDecoder::DecodePendingBuffer", ++trace_id_); 215 216 int buffer_size = 0; 217 if (!pending_buffer_to_decode_->end_of_stream()) { 218 buffer_size = pending_buffer_to_decode_->data_size(); 219 } 220 221 decryptor_->DecryptAndDecodeVideo( 222 pending_buffer_to_decode_, BindToCurrentLoop(base::Bind( 223 &DecryptingVideoDecoder::DeliverFrame, weak_this_, buffer_size))); 224} 225 226void DecryptingVideoDecoder::DeliverFrame( 227 int buffer_size, 228 Decryptor::Status status, 229 const scoped_refptr<VideoFrame>& frame) { 230 DVLOG(3) << "DeliverFrame() - status: " << status; 231 DCHECK(message_loop_->BelongsToCurrentThread()); 232 TRACE_EVENT_ASYNC_END0( 233 "eme", "DecryptingVideoDecoder::DecodePendingBuffer", trace_id_); 234 235 if (state_ == kStopped) 236 return; 237 238 DCHECK_EQ(state_, kPendingDecode) << state_; 239 DCHECK(!read_cb_.is_null()); 240 DCHECK(pending_buffer_to_decode_.get()); 241 242 bool need_to_try_again_if_nokey_is_returned = key_added_while_decode_pending_; 243 key_added_while_decode_pending_ = false; 244 245 scoped_refptr<DecoderBuffer> scoped_pending_buffer_to_decode = 246 pending_buffer_to_decode_; 247 pending_buffer_to_decode_ = NULL; 248 249 if (!reset_cb_.is_null()) { 250 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); 251 DoReset(); 252 return; 253 } 254 255 DCHECK_EQ(status == Decryptor::kSuccess, frame.get() != NULL); 256 257 if (status == Decryptor::kError) { 258 DVLOG(2) << "DeliverFrame() - kError"; 259 state_ = kError; 260 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); 261 return; 262 } 263 264 if (status == Decryptor::kNoKey) { 265 DVLOG(2) << "DeliverFrame() - kNoKey"; 266 // Set |pending_buffer_to_decode_| back as we need to try decoding the 267 // pending buffer again when new key is added to the decryptor. 268 pending_buffer_to_decode_ = scoped_pending_buffer_to_decode; 269 270 if (need_to_try_again_if_nokey_is_returned) { 271 // The |state_| is still kPendingDecode. 272 DecodePendingBuffer(); 273 return; 274 } 275 276 state_ = kWaitingForKey; 277 return; 278 } 279 280 if (status == Decryptor::kNeedMoreData) { 281 DVLOG(2) << "DeliverFrame() - kNeedMoreData"; 282 if (scoped_pending_buffer_to_decode->end_of_stream()) { 283 state_ = kDecodeFinished; 284 base::ResetAndReturn(&read_cb_).Run( 285 kOk, media::VideoFrame::CreateEmptyFrame()); 286 return; 287 } 288 289 state_ = kIdle; 290 base::ResetAndReturn(&read_cb_).Run(kNotEnoughData, NULL); 291 return; 292 } 293 294 DCHECK_EQ(status, Decryptor::kSuccess); 295 // No frame returned with kSuccess should be end-of-stream frame. 296 DCHECK(!frame->IsEndOfStream()); 297 state_ = kIdle; 298 base::ResetAndReturn(&read_cb_).Run(kOk, frame); 299} 300 301void DecryptingVideoDecoder::OnKeyAdded() { 302 DVLOG(2) << "OnKeyAdded()"; 303 DCHECK(message_loop_->BelongsToCurrentThread()); 304 305 if (state_ == kPendingDecode) { 306 key_added_while_decode_pending_ = true; 307 return; 308 } 309 310 if (state_ == kWaitingForKey) { 311 state_ = kPendingDecode; 312 DecodePendingBuffer(); 313 } 314} 315 316void DecryptingVideoDecoder::DoReset() { 317 DCHECK(init_cb_.is_null()); 318 DCHECK(read_cb_.is_null()); 319 state_ = kIdle; 320 base::ResetAndReturn(&reset_cb_).Run(); 321} 322 323} // namespace media 324