Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(250)

Side by Side Diff: media/filters/decoder_stream.cc

Issue 1879353003: Attempt decoder fallback if first decode fails (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/filters/decoder_stream.h ('k') | media/filters/video_frame_stream_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « media/filters/decoder_stream.h ('k') | media/filters/video_frame_stream_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698