Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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/decoder_stream.h" | 5 #include "media/filters/decoder_stream.h" |
| 6 | 6 |
| 7 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/callback_helpers.h" | 10 #include "base/callback_helpers.h" |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 52 state_(STATE_UNINITIALIZED), | 52 state_(STATE_UNINITIALIZED), |
| 53 stream_(NULL), | 53 stream_(NULL), |
| 54 decoder_selector_(new DecoderSelector<StreamType>(task_runner, | 54 decoder_selector_(new DecoderSelector<StreamType>(task_runner, |
| 55 std::move(decoders), | 55 std::move(decoders), |
| 56 media_log)), | 56 media_log)), |
| 57 decoded_frames_since_fallback_(0), | 57 decoded_frames_since_fallback_(0), |
| 58 active_splice_(false), | 58 active_splice_(false), |
| 59 decoding_eos_(false), | 59 decoding_eos_(false), |
| 60 pending_decode_requests_(0), | 60 pending_decode_requests_(0), |
| 61 duration_tracker_(8), | 61 duration_tracker_(8), |
| 62 sequence_token_(0), | |
| 62 weak_factory_(this) {} | 63 weak_factory_(this) {} |
| 63 | 64 |
| 64 template <DemuxerStream::Type StreamType> | 65 template <DemuxerStream::Type StreamType> |
| 65 DecoderStream<StreamType>::~DecoderStream() { | 66 DecoderStream<StreamType>::~DecoderStream() { |
| 66 FUNCTION_DVLOG(2); | 67 FUNCTION_DVLOG(2); |
| 67 DCHECK(task_runner_->BelongsToCurrentThread()); | 68 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 68 | 69 |
| 69 decoder_selector_.reset(); | 70 decoder_selector_.reset(); |
| 70 | 71 |
| 71 if (!init_cb_.is_null()) { | 72 if (!init_cb_.is_null()) { |
| 72 task_runner_->PostTask(FROM_HERE, | 73 task_runner_->PostTask(FROM_HERE, |
| 73 base::Bind(base::ResetAndReturn(&init_cb_), false)); | 74 base::Bind(base::ResetAndReturn(&init_cb_), false)); |
| 74 } | 75 } |
| 75 if (!read_cb_.is_null()) { | 76 if (!read_cb_.is_null()) { |
| 76 task_runner_->PostTask(FROM_HERE, base::Bind( | 77 task_runner_->PostTask(FROM_HERE, base::Bind( |
| 77 base::ResetAndReturn(&read_cb_), ABORTED, scoped_refptr<Output>())); | 78 base::ResetAndReturn(&read_cb_), ABORTED, scoped_refptr<Output>())); |
| 78 } | 79 } |
| 79 if (!reset_cb_.is_null()) | 80 if (!reset_cb_.is_null()) |
| 80 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&reset_cb_)); | 81 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&reset_cb_)); |
| 81 | 82 |
| 82 stream_ = NULL; | 83 stream_ = NULL; |
| 84 pending_buffers_.clear(); | |
| 83 decoder_.reset(); | 85 decoder_.reset(); |
| 84 decrypting_demuxer_stream_.reset(); | 86 decrypting_demuxer_stream_.reset(); |
| 85 } | 87 } |
| 86 | 88 |
| 87 template <DemuxerStream::Type StreamType> | 89 template <DemuxerStream::Type StreamType> |
| 88 std::string DecoderStream<StreamType>::GetStreamTypeString() { | 90 std::string DecoderStream<StreamType>::GetStreamTypeString() { |
| 89 return DecoderStreamTraits<StreamType>::ToString(); | 91 return DecoderStreamTraits<StreamType>::ToString(); |
| 90 } | 92 } |
| 91 | 93 |
| 92 template <DemuxerStream::Type StreamType> | 94 template <DemuxerStream::Type StreamType> |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 312 TRACE_EVENT_ASYNC_BEGIN2( | 314 TRACE_EVENT_ASYNC_BEGIN2( |
| 313 "media", GetTraceString<StreamType>(), this, "key frame", | 315 "media", GetTraceString<StreamType>(), this, "key frame", |
| 314 !buffer->end_of_stream() && buffer->is_key_frame(), "timestamp (ms)", | 316 !buffer->end_of_stream() && buffer->is_key_frame(), "timestamp (ms)", |
| 315 !buffer->end_of_stream() ? buffer->timestamp().InMilliseconds() : 0); | 317 !buffer->end_of_stream() ? buffer->timestamp().InMilliseconds() : 0); |
| 316 | 318 |
| 317 if (buffer->end_of_stream()) | 319 if (buffer->end_of_stream()) |
| 318 decoding_eos_ = true; | 320 decoding_eos_ = true; |
| 319 else if (buffer->duration() != kNoTimestamp()) | 321 else if (buffer->duration() != kNoTimestamp()) |
| 320 duration_tracker_.AddSample(buffer->duration()); | 322 duration_tracker_.AddSample(buffer->duration()); |
| 321 | 323 |
| 324 if (!previous_decoder_ && !decoded_frames_since_fallback_ && !decoding_eos_) | |
| 325 pending_buffers_.push_back(buffer); | |
|
sandersd (OOO until July 31)
2016/04/14 00:38:04
Why don't we queue EOS buffers?
tguilbert
2016/04/14 22:08:35
In order to reinitialize the decoders on a config
| |
| 326 | |
| 322 ++pending_decode_requests_; | 327 ++pending_decode_requests_; |
| 323 decoder_->Decode(buffer, | 328 decoder_->Decode(buffer, |
| 324 base::Bind(&DecoderStream<StreamType>::OnDecodeDone, | 329 base::Bind(&DecoderStream<StreamType>::OnDecodeDone, |
| 325 weak_factory_.GetWeakPtr(), | 330 weak_factory_.GetWeakPtr(), sequence_token_, |
|
sandersd (OOO until July 31)
2016/04/14 00:38:04
If OnDecodeDone() should never be called when the
tguilbert
2016/04/14 22:08:35
I did not know this was something that could be do
| |
| 326 buffer_size, | 331 buffer_size, buffer->end_of_stream())); |
| 327 buffer->end_of_stream())); | |
| 328 } | 332 } |
| 329 | 333 |
| 330 template <DemuxerStream::Type StreamType> | 334 template <DemuxerStream::Type StreamType> |
| 331 void DecoderStream<StreamType>::FlushDecoder() { | 335 void DecoderStream<StreamType>::FlushDecoder() { |
| 332 Decode(DecoderBuffer::CreateEOSBuffer()); | 336 Decode(DecoderBuffer::CreateEOSBuffer()); |
| 333 } | 337 } |
| 334 | 338 |
| 335 template <DemuxerStream::Type StreamType> | 339 template <DemuxerStream::Type StreamType> |
| 336 void DecoderStream<StreamType>::OnDecodeDone(int buffer_size, | 340 void DecoderStream<StreamType>::OnDecodeDone(int sequence_token, |
| 341 int buffer_size, | |
| 337 bool end_of_stream, | 342 bool end_of_stream, |
| 338 DecodeStatus status) { | 343 DecodeStatus status) { |
| 339 FUNCTION_DVLOG(2) << ": " << status; | 344 FUNCTION_DVLOG(2) << ": " << status; |
| 345 // Ignore stale calls from a previous decoder. | |
| 346 if (sequence_token_ != sequence_token) | |
| 347 return; | |
| 348 | |
| 340 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || | 349 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || |
| 341 state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) | 350 state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) |
| 342 << state_; | 351 << state_; |
| 343 DCHECK_GT(pending_decode_requests_, 0); | 352 DCHECK_GT(pending_decode_requests_, 0); |
| 344 | 353 |
| 345 --pending_decode_requests_; | 354 --pending_decode_requests_; |
| 346 | 355 |
| 347 TRACE_EVENT_ASYNC_END0("media", GetTraceString<StreamType>(), this); | 356 TRACE_EVENT_ASYNC_END0("media", GetTraceString<StreamType>(), this); |
| 348 | 357 |
| 349 if (end_of_stream) { | 358 if (end_of_stream) { |
| 350 DCHECK(!pending_decode_requests_); | 359 DCHECK(!pending_decode_requests_); |
| 351 decoding_eos_ = false; | 360 decoding_eos_ = false; |
| 352 } | 361 } |
| 353 | 362 |
| 354 if (state_ == STATE_ERROR) { | 363 if (state_ == STATE_ERROR) { |
| 355 DCHECK(read_cb_.is_null()); | 364 DCHECK(read_cb_.is_null()); |
| 356 return; | 365 return; |
| 357 } | 366 } |
| 358 | 367 |
| 359 // Drop decoding result if Reset() was called during decoding. | 368 // Drop decoding result if Reset() was called during decoding. |
| 360 // The resetting process will be handled when the decoder is reset. | 369 // The resetting process will be handled when the decoder is reset. |
| 361 if (!reset_cb_.is_null()) | 370 if (!reset_cb_.is_null()) |
| 362 return; | 371 return; |
| 363 | 372 |
| 364 switch (status) { | 373 switch (status) { |
| 365 case DecodeStatus::DECODE_ERROR: | 374 case DecodeStatus::DECODE_ERROR: |
| 375 if (!decoded_frames_since_fallback_) { | |
| 376 pending_decode_requests_ = 0; | |
| 377 // Note: increment |sequence_token_| here rather than in | |
| 378 // OnDecoderSelected. This covers the case where parallel decode | |
| 379 // requests were sent to |decoder_|, and responses are received before | |
| 380 // a new decoder is selected. This prevents |pending_decode_request_| | |
| 381 // from going below 0. | |
| 382 ++sequence_token_; | |
| 383 state_ = STATE_REINITIALIZING_DECODER; | |
| 384 decoder_selector_->SelectDecoder( | |
| 385 stream_, nullptr, | |
| 386 base::Bind(&DecoderStream<StreamType>::OnDecoderSelected, | |
| 387 weak_factory_.GetWeakPtr()), | |
| 388 base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady, | |
| 389 weak_factory_.GetWeakPtr()), | |
| 390 waiting_for_decryption_key_cb_); | |
| 391 return; | |
| 392 } | |
| 366 state_ = STATE_ERROR; | 393 state_ = STATE_ERROR; |
| 367 MEDIA_LOG(ERROR, media_log_) << GetStreamTypeString() << " decode error"; | 394 MEDIA_LOG(ERROR, media_log_) << GetStreamTypeString() << " decode error"; |
| 368 ready_outputs_.clear(); | 395 ready_outputs_.clear(); |
| 369 if (!read_cb_.is_null()) | 396 if (!read_cb_.is_null()) |
| 370 SatisfyRead(DECODE_ERROR, NULL); | 397 SatisfyRead(DECODE_ERROR, NULL); |
| 371 return; | 398 return; |
| 372 | 399 |
| 373 case DecodeStatus::ABORTED: | 400 case DecodeStatus::ABORTED: |
| 374 // Decoder can return DecodeStatus::ABORTED during Reset() or during | 401 // Decoder can return DecodeStatus::ABORTED during Reset() or during |
| 375 // destruction. | 402 // destruction. |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 401 | 428 |
| 402 template <DemuxerStream::Type StreamType> | 429 template <DemuxerStream::Type StreamType> |
| 403 void DecoderStream<StreamType>::OnDecodeOutputReady( | 430 void DecoderStream<StreamType>::OnDecodeOutputReady( |
| 404 const scoped_refptr<Output>& output) { | 431 const scoped_refptr<Output>& output) { |
| 405 FUNCTION_DVLOG(2) << ": " << output->timestamp().InMilliseconds() << " ms"; | 432 FUNCTION_DVLOG(2) << ": " << output->timestamp().InMilliseconds() << " ms"; |
| 406 DCHECK(output.get()); | 433 DCHECK(output.get()); |
| 407 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || | 434 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || |
| 408 state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) | 435 state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) |
| 409 << state_; | 436 << state_; |
| 410 | 437 |
| 438 // Note: Checking that we have decoded more frames than the max number of | |
| 439 // parallel requests ensures we don't delete the buffers before the fallback | |
| 440 // decoder has had a chance to use them. | |
| 441 if (!pending_buffers_.empty() && | |
|
DaleCurtis
2016/04/14 00:42:53
Multiline if needs {}
tguilbert
2016/04/14 22:08:35
CL format pushed it to multiline :(...
Done.
| |
| 442 decoded_frames_since_fallback_ > GetMaxDecodeRequests()) | |
| 443 pending_buffers_.clear(); | |
| 444 | |
| 411 if (state_ == STATE_ERROR) { | 445 if (state_ == STATE_ERROR) { |
| 412 DCHECK(read_cb_.is_null()); | 446 DCHECK(read_cb_.is_null()); |
| 413 return; | 447 return; |
| 414 } | 448 } |
| 415 | 449 |
| 416 // Drop decoding result if Reset() was called during decoding. | 450 // Drop decoding result if Reset() was called during decoding. |
| 417 // The resetting process will be handled when the decoder is reset. | 451 // The resetting process will be handled when the decoder is reset. |
| 418 if (!reset_cb_.is_null()) | 452 if (!reset_cb_.is_null()) |
| 419 return; | 453 return; |
| 420 | 454 |
| 455 ++decoded_frames_since_fallback_; | |
| 456 | |
| 421 if (!read_cb_.is_null()) { | 457 if (!read_cb_.is_null()) { |
| 422 // If |ready_outputs_| was non-empty, the read would have already been | 458 // If |ready_outputs_| was non-empty, the read would have already been |
| 423 // satisifed by Read(). | 459 // satisifed by Read(). |
| 424 DCHECK(ready_outputs_.empty()); | 460 DCHECK(ready_outputs_.empty()); |
| 425 SatisfyRead(OK, output); | 461 SatisfyRead(OK, output); |
| 426 return; | 462 return; |
| 427 } | 463 } |
| 428 | 464 |
| 429 // Store decoded output. | 465 // Store decoded output. |
| 430 ready_outputs_.push_back(output); | 466 ready_outputs_.push_back(output); |
| 431 | 467 |
| 432 // Destruct any previous decoder once we've decoded enough frames to ensure | 468 // Destruct any previous decoder once we've decoded enough frames to ensure |
| 433 // that it's no longer in use. | 469 // that it's no longer in use. |
| 434 if (previous_decoder_ && | 470 if (previous_decoder_ && |
| 435 ++decoded_frames_since_fallback_ > limits::kMaxVideoFrames) { | 471 decoded_frames_since_fallback_ > limits::kMaxVideoFrames) { |
| 436 previous_decoder_.reset(); | 472 previous_decoder_.reset(); |
| 437 } | 473 } |
| 438 } | 474 } |
| 439 | 475 |
| 440 template <DemuxerStream::Type StreamType> | 476 template <DemuxerStream::Type StreamType> |
| 441 void DecoderStream<StreamType>::ReadFromDemuxerStream() { | 477 void DecoderStream<StreamType>::ReadFromDemuxerStream() { |
| 442 FUNCTION_DVLOG(2); | 478 FUNCTION_DVLOG(2); |
| 443 DCHECK_EQ(state_, STATE_NORMAL); | 479 DCHECK_EQ(state_, STATE_NORMAL); |
| 444 DCHECK(CanDecodeMore()); | 480 DCHECK(CanDecodeMore()); |
| 445 DCHECK(reset_cb_.is_null()); | 481 DCHECK(reset_cb_.is_null()); |
| 446 | 482 |
| 483 if (!pending_buffers_.empty() && previous_decoder_) { | |
|
sandersd (OOO until July 31)
2016/04/14 00:38:04
It seems that there really needs to be two lists o
tguilbert
2016/04/14 22:08:35
Good idea. Really simplifies the logic in many pla
| |
| 484 scoped_refptr<DecoderBuffer> buffer = pending_buffers_.front(); | |
| 485 pending_buffers_.pop_front(); | |
| 486 Decode(buffer); | |
| 487 return; | |
| 488 } | |
| 489 | |
| 447 state_ = STATE_PENDING_DEMUXER_READ; | 490 state_ = STATE_PENDING_DEMUXER_READ; |
| 448 stream_->Read(base::Bind(&DecoderStream<StreamType>::OnBufferReady, | 491 stream_->Read(base::Bind(&DecoderStream<StreamType>::OnBufferReady, |
| 449 weak_factory_.GetWeakPtr())); | 492 weak_factory_.GetWeakPtr())); |
| 450 } | 493 } |
| 451 | 494 |
| 452 template <DemuxerStream::Type StreamType> | 495 template <DemuxerStream::Type StreamType> |
| 453 void DecoderStream<StreamType>::OnBufferReady( | 496 void DecoderStream<StreamType>::OnBufferReady( |
| 454 DemuxerStream::Status status, | 497 DemuxerStream::Status status, |
| 455 const scoped_refptr<DecoderBuffer>& buffer) { | 498 const scoped_refptr<DecoderBuffer>& buffer) { |
| 456 FUNCTION_DVLOG(2) << ": " << status << ", " | 499 FUNCTION_DVLOG(2) << ": " << status << ", " |
| 457 << (buffer.get() ? buffer->AsHumanReadableString() | 500 << (buffer.get() ? buffer->AsHumanReadableString() |
| 458 : "NULL"); | 501 : "NULL"); |
| 459 | 502 |
| 460 DCHECK(task_runner_->BelongsToCurrentThread()); | 503 DCHECK(task_runner_->BelongsToCurrentThread()); |
| 461 DCHECK(state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) | 504 DCHECK(state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR || |
| 505 STATE_REINITIALIZING_DECODER) | |
| 462 << state_; | 506 << state_; |
| 463 DCHECK_EQ(buffer.get() != NULL, status == DemuxerStream::kOk) << status; | 507 DCHECK_EQ(buffer.get() != NULL, status == DemuxerStream::kOk) << status; |
| 464 | 508 |
| 509 // If parallel decode requests are supported, multiple read requests might | |
| 510 // have been sent to the demuxer. The buffers might arrive while the decoder | |
| 511 // is reinitializing after falling back on first decode error. | |
| 512 if (state_ == STATE_REINITIALIZING_DECODER && | |
| 513 !decoded_frames_since_fallback_) { | |
| 514 // Save valid buffers to be consumed by the new decoder | |
|
DaleCurtis
2016/04/14 00:42:53
You'll need to set STATE_ERROR in the non-kOk case
tguilbert
2016/04/14 22:08:35
Talked a bit offline with Dan. Created https://bug
| |
| 515 // TODO(tguilbert): Question for CR: what is the proper way to error out? | |
| 516 if (status == DemuxerStream::kOk) | |
| 517 pending_buffers_.push_back(buffer); | |
| 518 else | |
| 519 pending_buffers_.clear(); | |
| 520 return; | |
| 521 } | |
| 522 | |
| 465 // Decoding has been stopped (e.g due to an error). | 523 // Decoding has been stopped (e.g due to an error). |
| 466 if (state_ != STATE_PENDING_DEMUXER_READ) { | 524 if (state_ != STATE_PENDING_DEMUXER_READ) { |
| 467 DCHECK(state_ == STATE_ERROR); | 525 DCHECK(state_ == STATE_ERROR); |
| 468 DCHECK(read_cb_.is_null()); | 526 DCHECK(read_cb_.is_null()); |
| 469 return; | 527 return; |
| 470 } | 528 } |
| 471 | 529 |
| 472 state_ = STATE_NORMAL; | 530 state_ = STATE_NORMAL; |
| 473 | 531 |
| 474 if (status == DemuxerStream::kConfigChanged) { | 532 if (status == DemuxerStream::kConfigChanged) { |
| 475 FUNCTION_DVLOG(2) << ": " << "ConfigChanged"; | 533 FUNCTION_DVLOG(2) << ": " << "ConfigChanged"; |
| 476 DCHECK(stream_->SupportsConfigChanges()); | 534 DCHECK(stream_->SupportsConfigChanges()); |
| 477 | 535 |
| 536 // Pending buffers might not match the reinitiliazed decoder's new config | |
|
DaleCurtis
2016/04/14 00:42:53
DCHECK(pending_buffers_.empty()); ? I think this c
tguilbert
2016/04/14 22:08:35
This is when we receive a normal config change bef
| |
| 537 pending_buffers_.clear(); | |
| 538 | |
| 478 if (!config_change_observer_cb_.is_null()) | 539 if (!config_change_observer_cb_.is_null()) |
| 479 config_change_observer_cb_.Run(); | 540 config_change_observer_cb_.Run(); |
| 480 | 541 |
| 481 state_ = STATE_FLUSHING_DECODER; | 542 state_ = STATE_FLUSHING_DECODER; |
| 482 if (!reset_cb_.is_null()) { | 543 if (!reset_cb_.is_null()) { |
| 483 // If we are using DecryptingDemuxerStream, we already called DDS::Reset() | 544 // If we are using DecryptingDemuxerStream, we already called DDS::Reset() |
| 484 // which will continue the resetting process in it's callback. | 545 // which will continue the resetting process in it's callback. |
| 485 if (!decrypting_demuxer_stream_) | 546 if (!decrypting_demuxer_stream_) |
| 486 Reset(base::ResetAndReturn(&reset_cb_)); | 547 Reset(base::ResetAndReturn(&reset_cb_)); |
| 487 // Reinitialization will continue after Reset() is done. | 548 // Reinitialization will continue after Reset() is done. |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 619 } | 680 } |
| 620 | 681 |
| 621 // The resetting process will be continued in OnDecoderReinitialized(). | 682 // The resetting process will be continued in OnDecoderReinitialized(). |
| 622 ReinitializeDecoder(); | 683 ReinitializeDecoder(); |
| 623 } | 684 } |
| 624 | 685 |
| 625 template class DecoderStream<DemuxerStream::VIDEO>; | 686 template class DecoderStream<DemuxerStream::VIDEO>; |
| 626 template class DecoderStream<DemuxerStream::AUDIO>; | 687 template class DecoderStream<DemuxerStream::AUDIO>; |
| 627 | 688 |
| 628 } // namespace media | 689 } // namespace media |
| OLD | NEW |