| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/filters/decrypting_video_decoder.h" | 5 #include "media/filters/decrypting_video_decoder.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback_helpers.h" | 8 #include "base/callback_helpers.h" |
| 9 #include "base/location.h" | 9 #include "base/location.h" |
| 10 #include "base/message_loop_proxy.h" | 10 #include "base/message_loop_proxy.h" |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 49 &DecryptingVideoDecoder::DoRead, this, read_cb)); | 49 &DecryptingVideoDecoder::DoRead, this, read_cb)); |
| 50 } | 50 } |
| 51 | 51 |
| 52 void DecryptingVideoDecoder::Reset(const base::Closure& closure) { | 52 void DecryptingVideoDecoder::Reset(const base::Closure& closure) { |
| 53 if (!message_loop_->BelongsToCurrentThread()) { | 53 if (!message_loop_->BelongsToCurrentThread()) { |
| 54 message_loop_->PostTask(FROM_HERE, base::Bind( | 54 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 55 &DecryptingVideoDecoder::Reset, this, closure)); | 55 &DecryptingVideoDecoder::Reset, this, closure)); |
| 56 return; | 56 return; |
| 57 } | 57 } |
| 58 | 58 |
| 59 DVLOG(2) << "Reset() - state: " << state_; |
| 59 DCHECK(state_ == kIdle || | 60 DCHECK(state_ == kIdle || |
| 60 state_ == kPendingDemuxerRead || | 61 state_ == kPendingDemuxerRead || |
| 61 state_ == kPendingDecode || | 62 state_ == kPendingDecode || |
| 62 state_ == kWaitingForKey || | 63 state_ == kWaitingForKey || |
| 63 state_ == kDecodeFinished) << state_; | 64 state_ == kDecodeFinished) << state_; |
| 64 DCHECK(init_cb_.is_null()); // No Reset() during pending initialization. | 65 DCHECK(init_cb_.is_null()); // No Reset() during pending initialization. |
| 65 DCHECK(stop_cb_.is_null()); // No Reset() during pending Stop(). | 66 DCHECK(stop_cb_.is_null()); // No Reset() during pending Stop(). |
| 66 DCHECK(reset_cb_.is_null()); | 67 DCHECK(reset_cb_.is_null()); |
| 67 | 68 |
| 68 reset_cb_ = closure; | 69 reset_cb_ = closure; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 88 DoReset(); | 89 DoReset(); |
| 89 } | 90 } |
| 90 | 91 |
| 91 void DecryptingVideoDecoder::Stop(const base::Closure& closure) { | 92 void DecryptingVideoDecoder::Stop(const base::Closure& closure) { |
| 92 if (!message_loop_->BelongsToCurrentThread()) { | 93 if (!message_loop_->BelongsToCurrentThread()) { |
| 93 message_loop_->PostTask(FROM_HERE, base::Bind( | 94 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 94 &DecryptingVideoDecoder::Stop, this, closure)); | 95 &DecryptingVideoDecoder::Stop, this, closure)); |
| 95 return; | 96 return; |
| 96 } | 97 } |
| 97 | 98 |
| 99 DVLOG(2) << "Stop() - state: " << state_; |
| 98 DCHECK(stop_cb_.is_null()); | 100 DCHECK(stop_cb_.is_null()); |
| 99 stop_cb_ = closure; | 101 stop_cb_ = closure; |
| 100 | 102 |
| 101 // We need to call Decryptor::StopVideoDecoder() if we ever called | 103 // We need to call Decryptor::StopVideoDecoder() if we ever called |
| 102 // Decryptor::InitializeVideoDecoder() to cancel the pending initialization if | 104 // Decryptor::InitializeVideoDecoder() to cancel the pending initialization if |
| 103 // the initialization is still pending, or to stop the video decoder if | 105 // the initialization is still pending, or to stop the video decoder if |
| 104 // the initialization has completed. | 106 // the initialization has completed. |
| 105 // When the state is kUninitialized and kDecryptorRequested, | 107 // When the state is kUninitialized and kDecryptorRequested, |
| 106 // InitializeVideoDecoder() has not been called, so we are okay. | 108 // InitializeVideoDecoder() has not been called, so we are okay. |
| 107 // When the state is kStopped, the video decoder should have already been | 109 // When the state is kStopped, the video decoder should have already been |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 147 } | 149 } |
| 148 | 150 |
| 149 DecryptingVideoDecoder::~DecryptingVideoDecoder() { | 151 DecryptingVideoDecoder::~DecryptingVideoDecoder() { |
| 150 DCHECK(state_ == kUninitialized || state_ == kStopped) << state_; | 152 DCHECK(state_ == kUninitialized || state_ == kStopped) << state_; |
| 151 } | 153 } |
| 152 | 154 |
| 153 void DecryptingVideoDecoder::DoInitialize( | 155 void DecryptingVideoDecoder::DoInitialize( |
| 154 const scoped_refptr<DemuxerStream>& stream, | 156 const scoped_refptr<DemuxerStream>& stream, |
| 155 const PipelineStatusCB& status_cb, | 157 const PipelineStatusCB& status_cb, |
| 156 const StatisticsCB& statistics_cb) { | 158 const StatisticsCB& statistics_cb) { |
| 159 DVLOG(2) << "DoInitialize()"; |
| 157 DCHECK(message_loop_->BelongsToCurrentThread()); | 160 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 158 DCHECK_EQ(state_, kUninitialized) << state_; | 161 DCHECK_EQ(state_, kUninitialized) << state_; |
| 159 DCHECK(stream); | 162 DCHECK(stream); |
| 160 | 163 |
| 161 const VideoDecoderConfig& config = stream->video_decoder_config(); | 164 const VideoDecoderConfig& config = stream->video_decoder_config(); |
| 162 if (!config.IsValidConfig()) { | 165 if (!config.IsValidConfig()) { |
| 163 DLOG(ERROR) << "Invalid video stream config: " | 166 DLOG(ERROR) << "Invalid video stream config: " |
| 164 << config.AsHumanReadableString(); | 167 << config.AsHumanReadableString(); |
| 165 status_cb.Run(PIPELINE_ERROR_DECODE); | 168 status_cb.Run(PIPELINE_ERROR_DECODE); |
| 166 return; | 169 return; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 177 statistics_cb_ = statistics_cb; | 180 statistics_cb_ = statistics_cb; |
| 178 | 181 |
| 179 init_cb_ = status_cb; | 182 init_cb_ = status_cb; |
| 180 | 183 |
| 181 state_ = kDecryptorRequested; | 184 state_ = kDecryptorRequested; |
| 182 request_decryptor_notification_cb_.Run( | 185 request_decryptor_notification_cb_.Run( |
| 183 BIND_TO_LOOP(&DecryptingVideoDecoder::SetDecryptor)); | 186 BIND_TO_LOOP(&DecryptingVideoDecoder::SetDecryptor)); |
| 184 } | 187 } |
| 185 | 188 |
| 186 void DecryptingVideoDecoder::SetDecryptor(Decryptor* decryptor) { | 189 void DecryptingVideoDecoder::SetDecryptor(Decryptor* decryptor) { |
| 190 DVLOG(2) << "SetDecryptor()"; |
| 187 DCHECK(message_loop_->BelongsToCurrentThread()); | 191 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 188 DCHECK_EQ(state_, kDecryptorRequested) << state_; | 192 DCHECK_EQ(state_, kDecryptorRequested) << state_; |
| 189 DCHECK(!init_cb_.is_null()); | 193 DCHECK(!init_cb_.is_null()); |
| 190 | 194 |
| 191 if (!stop_cb_.is_null()) { | 195 if (!stop_cb_.is_null()) { |
| 192 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); | 196 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); |
| 193 DoStop(); | 197 DoStop(); |
| 194 return; | 198 return; |
| 195 } | 199 } |
| 196 | 200 |
| 197 decryptor_ = decryptor; | 201 decryptor_ = decryptor; |
| 198 | 202 |
| 199 scoped_ptr<VideoDecoderConfig> scoped_config(new VideoDecoderConfig()); | 203 scoped_ptr<VideoDecoderConfig> scoped_config(new VideoDecoderConfig()); |
| 200 scoped_config->CopyFrom(demuxer_stream_->video_decoder_config()); | 204 scoped_config->CopyFrom(demuxer_stream_->video_decoder_config()); |
| 201 | 205 |
| 202 state_ = kPendingDecoderInit; | 206 state_ = kPendingDecoderInit; |
| 203 decryptor_->InitializeVideoDecoder( | 207 decryptor_->InitializeVideoDecoder( |
| 204 scoped_config.Pass(), | 208 scoped_config.Pass(), |
| 205 BIND_TO_LOOP(&DecryptingVideoDecoder::FinishInitialization), | 209 BIND_TO_LOOP(&DecryptingVideoDecoder::FinishInitialization), |
| 206 BIND_TO_LOOP(&DecryptingVideoDecoder::OnKeyAdded)); | 210 BIND_TO_LOOP(&DecryptingVideoDecoder::OnKeyAdded)); |
| 207 } | 211 } |
| 208 | 212 |
| 209 void DecryptingVideoDecoder::FinishInitialization(bool success) { | 213 void DecryptingVideoDecoder::FinishInitialization(bool success) { |
| 214 DVLOG(2) << "FinishInitialization()"; |
| 210 DCHECK(message_loop_->BelongsToCurrentThread()); | 215 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 211 DCHECK_EQ(state_, kPendingDecoderInit) << state_; | 216 DCHECK_EQ(state_, kPendingDecoderInit) << state_; |
| 212 DCHECK(!init_cb_.is_null()); | 217 DCHECK(!init_cb_.is_null()); |
| 213 DCHECK(reset_cb_.is_null()); // No Reset() before initialization finished. | 218 DCHECK(reset_cb_.is_null()); // No Reset() before initialization finished. |
| 214 DCHECK(read_cb_.is_null()); // No Read() before initialization finished. | 219 DCHECK(read_cb_.is_null()); // No Read() before initialization finished. |
| 215 | 220 |
| 216 if (!stop_cb_.is_null()) { | 221 if (!stop_cb_.is_null()) { |
| 217 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); | 222 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); |
| 218 DoStop(); | 223 DoStop(); |
| 219 return; | 224 return; |
| 220 } | 225 } |
| 221 | 226 |
| 222 if (!success) { | 227 if (!success) { |
| 223 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); | 228 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED); |
| 224 state_ = kStopped; | 229 state_ = kStopped; |
| 225 return; | 230 return; |
| 226 } | 231 } |
| 227 | 232 |
| 228 // Success! | 233 // Success! |
| 229 state_ = kIdle; | 234 state_ = kIdle; |
| 230 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); | 235 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK); |
| 231 } | 236 } |
| 232 | 237 |
| 233 void DecryptingVideoDecoder::DoRead(const ReadCB& read_cb) { | 238 void DecryptingVideoDecoder::DoRead(const ReadCB& read_cb) { |
| 239 DVLOG(3) << "DoRead()"; |
| 234 DCHECK(message_loop_->BelongsToCurrentThread()); | 240 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 235 DCHECK(state_ == kIdle || state_ == kDecodeFinished) << state_; | 241 DCHECK(state_ == kIdle || state_ == kDecodeFinished) << state_; |
| 236 DCHECK(!read_cb.is_null()); | 242 DCHECK(!read_cb.is_null()); |
| 237 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; | 243 CHECK(read_cb_.is_null()) << "Overlapping decodes are not supported."; |
| 238 | 244 |
| 239 // Return empty frames if decoding has finished. | 245 // Return empty frames if decoding has finished. |
| 240 if (state_ == kDecodeFinished) { | 246 if (state_ == kDecodeFinished) { |
| 241 read_cb.Run(kOk, VideoFrame::CreateEmptyFrame()); | 247 read_cb.Run(kOk, VideoFrame::CreateEmptyFrame()); |
| 242 return; | 248 return; |
| 243 } | 249 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 264 // demuxer_stream_->Read() execute the read callback on the same execution | 270 // demuxer_stream_->Read() execute the read callback on the same execution |
| 265 // stack we are still fine. But it looks like a force post task makes the | 271 // stack we are still fine. But it looks like a force post task makes the |
| 266 // logic more understandable and manageable, so why not? | 272 // logic more understandable and manageable, so why not? |
| 267 message_loop_->PostTask(FROM_HERE, base::Bind( | 273 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 268 &DecryptingVideoDecoder::DoDecryptAndDecodeBuffer, this, status, buffer)); | 274 &DecryptingVideoDecoder::DoDecryptAndDecodeBuffer, this, status, buffer)); |
| 269 } | 275 } |
| 270 | 276 |
| 271 void DecryptingVideoDecoder::DoDecryptAndDecodeBuffer( | 277 void DecryptingVideoDecoder::DoDecryptAndDecodeBuffer( |
| 272 DemuxerStream::Status status, | 278 DemuxerStream::Status status, |
| 273 const scoped_refptr<DecoderBuffer>& buffer) { | 279 const scoped_refptr<DecoderBuffer>& buffer) { |
| 280 DVLOG(3) << "DoDecryptAndDecodeBuffer()"; |
| 274 DCHECK(message_loop_->BelongsToCurrentThread()); | 281 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 275 DCHECK_EQ(state_, kPendingDemuxerRead) << state_; | 282 DCHECK_EQ(state_, kPendingDemuxerRead) << state_; |
| 276 DCHECK(!read_cb_.is_null()); | 283 DCHECK(!read_cb_.is_null()); |
| 277 DCHECK_EQ(buffer != NULL, status == DemuxerStream::kOk) << status; | 284 DCHECK_EQ(buffer != NULL, status == DemuxerStream::kOk) << status; |
| 278 | 285 |
| 279 if (!reset_cb_.is_null() || !stop_cb_.is_null()) { | 286 if (!reset_cb_.is_null() || !stop_cb_.is_null()) { |
| 280 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); | 287 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); |
| 281 if (!reset_cb_.is_null()) | 288 if (!reset_cb_.is_null()) |
| 282 DoReset(); | 289 DoReset(); |
| 283 if (!stop_cb_.is_null()) | 290 if (!stop_cb_.is_null()) |
| 284 DoStop(); | 291 DoStop(); |
| 285 return; | 292 return; |
| 286 } | 293 } |
| 287 | 294 |
| 288 if (status == DemuxerStream::kAborted) { | 295 if (status == DemuxerStream::kAborted) { |
| 296 DVLOG(2) << "DoDecryptAndDecodeBuffer() - kAborted"; |
| 297 state_ = kIdle; |
| 289 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); | 298 base::ResetAndReturn(&read_cb_).Run(kOk, NULL); |
| 290 state_ = kIdle; | |
| 291 return; | 299 return; |
| 292 } | 300 } |
| 293 | 301 |
| 294 if (status == DemuxerStream::kConfigChanged) { | 302 if (status == DemuxerStream::kConfigChanged) { |
| 295 // TODO(xhwang): Add config change support. | 303 // TODO(xhwang): Add config change support. |
| 296 // The |state_| is chosen to be kDecodeFinished here to be consistent with | 304 // The |state_| is chosen to be kDecodeFinished here to be consistent with |
| 297 // the implementation of FFmpegVideoDecoder. | 305 // the implementation of FFmpegVideoDecoder. |
| 306 DVLOG(2) << "DoDecryptAndDecodeBuffer() - kConfigChanged"; |
| 298 state_ = kDecodeFinished; | 307 state_ = kDecodeFinished; |
| 299 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); | 308 base::ResetAndReturn(&read_cb_).Run(kDecodeError, NULL); |
| 300 return; | 309 return; |
| 301 } | 310 } |
| 302 | 311 |
| 303 DCHECK_EQ(status, DemuxerStream::kOk); | 312 DCHECK_EQ(status, DemuxerStream::kOk); |
| 304 pending_buffer_to_decode_ = buffer; | 313 pending_buffer_to_decode_ = buffer; |
| 305 state_ = kPendingDecode; | 314 state_ = kPendingDecode; |
| 306 DecodePendingBuffer(); | 315 DecodePendingBuffer(); |
| 307 } | 316 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 325 // simple and clear? | 334 // simple and clear? |
| 326 message_loop_->PostTask(FROM_HERE, base::Bind( | 335 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 327 &DecryptingVideoDecoder::DoDeliverFrame, this, | 336 &DecryptingVideoDecoder::DoDeliverFrame, this, |
| 328 buffer_size, status, frame)); | 337 buffer_size, status, frame)); |
| 329 } | 338 } |
| 330 | 339 |
| 331 void DecryptingVideoDecoder::DoDeliverFrame( | 340 void DecryptingVideoDecoder::DoDeliverFrame( |
| 332 int buffer_size, | 341 int buffer_size, |
| 333 Decryptor::Status status, | 342 Decryptor::Status status, |
| 334 const scoped_refptr<VideoFrame>& frame) { | 343 const scoped_refptr<VideoFrame>& frame) { |
| 344 DVLOG(3) << "DoDeliverFrame()"; |
| 335 DCHECK(message_loop_->BelongsToCurrentThread()); | 345 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 336 DCHECK_EQ(state_, kPendingDecode) << state_; | 346 DCHECK_EQ(state_, kPendingDecode) << state_; |
| 337 DCHECK(!read_cb_.is_null()); | 347 DCHECK(!read_cb_.is_null()); |
| 338 DCHECK(pending_buffer_to_decode_); | 348 DCHECK(pending_buffer_to_decode_); |
| 339 | 349 |
| 340 bool need_to_try_again_if_nokey_is_returned = key_added_while_pending_decode_; | 350 bool need_to_try_again_if_nokey_is_returned = key_added_while_pending_decode_; |
| 341 key_added_while_pending_decode_ = false; | 351 key_added_while_pending_decode_ = false; |
| 342 | 352 |
| 343 if (!reset_cb_.is_null() || !stop_cb_.is_null()) { | 353 if (!reset_cb_.is_null() || !stop_cb_.is_null()) { |
| 344 pending_buffer_to_decode_ = NULL; | 354 pending_buffer_to_decode_ = NULL; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 ReadFromDemuxerStream(); | 392 ReadFromDemuxerStream(); |
| 383 return; | 393 return; |
| 384 } | 394 } |
| 385 | 395 |
| 386 DCHECK_EQ(status, Decryptor::kSuccess); | 396 DCHECK_EQ(status, Decryptor::kSuccess); |
| 387 state_ = frame->IsEndOfStream() ? kDecodeFinished : kIdle; | 397 state_ = frame->IsEndOfStream() ? kDecodeFinished : kIdle; |
| 388 base::ResetAndReturn(&read_cb_).Run(kOk, frame); | 398 base::ResetAndReturn(&read_cb_).Run(kOk, frame); |
| 389 } | 399 } |
| 390 | 400 |
| 391 void DecryptingVideoDecoder::OnKeyAdded() { | 401 void DecryptingVideoDecoder::OnKeyAdded() { |
| 402 DVLOG(2) << "OnKeyAdded()"; |
| 392 DCHECK(message_loop_->BelongsToCurrentThread()); | 403 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 393 | 404 |
| 394 if (state_ == kPendingDecode) { | 405 if (state_ == kPendingDecode) { |
| 395 key_added_while_pending_decode_ = true; | 406 key_added_while_pending_decode_ = true; |
| 396 return; | 407 return; |
| 397 } | 408 } |
| 398 | 409 |
| 399 if (state_ == kWaitingForKey) { | 410 if (state_ == kWaitingForKey) { |
| 400 state_ = kPendingDecode; | 411 state_ = kPendingDecode; |
| 401 DecodePendingBuffer(); | 412 DecodePendingBuffer(); |
| 402 } | 413 } |
| 403 } | 414 } |
| 404 | 415 |
| 405 void DecryptingVideoDecoder::DoReset() { | 416 void DecryptingVideoDecoder::DoReset() { |
| 406 DCHECK(init_cb_.is_null()); | 417 DCHECK(init_cb_.is_null()); |
| 407 DCHECK(read_cb_.is_null()); | 418 DCHECK(read_cb_.is_null()); |
| 408 state_ = kIdle; | 419 state_ = kIdle; |
| 409 base::ResetAndReturn(&reset_cb_).Run(); | 420 base::ResetAndReturn(&reset_cb_).Run(); |
| 410 } | 421 } |
| 411 | 422 |
| 412 void DecryptingVideoDecoder::DoStop() { | 423 void DecryptingVideoDecoder::DoStop() { |
| 413 DCHECK(init_cb_.is_null()); | 424 DCHECK(init_cb_.is_null()); |
| 414 DCHECK(read_cb_.is_null()); | 425 DCHECK(read_cb_.is_null()); |
| 415 state_ = kStopped; | 426 state_ = kStopped; |
| 416 base::ResetAndReturn(&stop_cb_).Run(); | 427 base::ResetAndReturn(&stop_cb_).Run(); |
| 417 } | 428 } |
| 418 | 429 |
| 419 } // namespace media | 430 } // namespace media |
| OLD | NEW |