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

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: Comments 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
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 weak_factory_(this) {} 62 weak_factory_(this),
63 decode_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();
sandersd (OOO until July 31) 2016/04/14 23:10:30 You don't actually need to do this, the destructor
tguilbert 2016/04/15 00:29:18 Done.
85 fallback_buffers_.clear();
83 decoder_.reset(); 86 decoder_.reset();
84 decrypting_demuxer_stream_.reset(); 87 decrypting_demuxer_stream_.reset();
85 } 88 }
86 89
87 template <DemuxerStream::Type StreamType> 90 template <DemuxerStream::Type StreamType>
88 std::string DecoderStream<StreamType>::GetStreamTypeString() { 91 std::string DecoderStream<StreamType>::GetStreamTypeString() {
89 return DecoderStreamTraits<StreamType>::ToString(); 92 return DecoderStreamTraits<StreamType>::ToString();
90 } 93 }
91 94
92 template <DemuxerStream::Type StreamType> 95 template <DemuxerStream::Type StreamType>
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 } 239 }
237 240
238 template <DemuxerStream::Type StreamType> 241 template <DemuxerStream::Type StreamType>
239 void DecoderStream<StreamType>::OnDecoderSelected( 242 void DecoderStream<StreamType>::OnDecoderSelected(
240 scoped_ptr<Decoder> selected_decoder, 243 scoped_ptr<Decoder> selected_decoder,
241 scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) { 244 scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) {
242 FUNCTION_DVLOG(2) << ": " 245 FUNCTION_DVLOG(2) << ": "
243 << (selected_decoder ? selected_decoder->GetDisplayName() 246 << (selected_decoder ? selected_decoder->GetDisplayName()
244 : "No decoder selected."); 247 : "No decoder selected.");
245 DCHECK(task_runner_->BelongsToCurrentThread()); 248 DCHECK(task_runner_->BelongsToCurrentThread());
246 DCHECK(state_ == STATE_INITIALIZING || state_ == STATE_REINITIALIZING_DECODER) 249 DCHECK(state_ == STATE_INITIALIZING ||
250 state_ == STATE_REINITIALIZING_DECODER ||
251 state_ == STATE_CONFIG_CHANGE_RECEIVED_WHILE_REINITIALIZING_DECODER)
247 << state_; 252 << state_;
248 if (state_ == STATE_INITIALIZING) { 253 if (state_ == STATE_INITIALIZING) {
249 DCHECK(!init_cb_.is_null()); 254 DCHECK(!init_cb_.is_null());
250 DCHECK(read_cb_.is_null()); 255 DCHECK(read_cb_.is_null());
251 DCHECK(reset_cb_.is_null()); 256 DCHECK(reset_cb_.is_null());
257 } else if (state_ == STATE_REINITIALIZING_DECODER) {
258 DCHECK(decoder_);
259 }
260
261 // TODO(tguilbert): crbug.com/603713 support config changes on decoder reinit.
262 if (state_ == STATE_CONFIG_CHANGE_RECEIVED_WHILE_REINITIALIZING_DECODER) {
263 CompleteDecoderReinitialization(false);
tguilbert 2016/04/14 22:26:42 Sorry, I didn't take into account what should be d
tguilbert 2016/04/15 00:29:18 Done.
264 return;
265 }
266
267 // Push the pending buffers to the front of the fallback buffers
268 if (fallback_buffers_.empty()) {
269 fallback_buffers_.swap(pending_buffers_);
252 } else { 270 } else {
253 DCHECK(decoder_); 271 fallback_buffers_.insert(fallback_buffers_.begin(),
272 pending_buffers_.begin(), pending_buffers_.end());
273 pending_buffers_.clear();
254 } 274 }
255 275
256 previous_decoder_ = std::move(decoder_); 276 previous_decoder_ = std::move(decoder_);
257 decoded_frames_since_fallback_ = 0; 277 decoded_frames_since_fallback_ = 0;
258 decoder_ = std::move(selected_decoder); 278 decoder_ = std::move(selected_decoder);
259 if (decrypting_demuxer_stream) { 279 if (decrypting_demuxer_stream) {
260 decrypting_demuxer_stream_ = std::move(decrypting_demuxer_stream); 280 decrypting_demuxer_stream_ = std::move(decrypting_demuxer_stream);
261 stream_ = decrypting_demuxer_stream_.get(); 281 stream_ = decrypting_demuxer_stream_.get();
262 } 282 }
263 283
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 TRACE_EVENT_ASYNC_BEGIN2( 332 TRACE_EVENT_ASYNC_BEGIN2(
313 "media", GetTraceString<StreamType>(), this, "key frame", 333 "media", GetTraceString<StreamType>(), this, "key frame",
314 !buffer->end_of_stream() && buffer->is_key_frame(), "timestamp (ms)", 334 !buffer->end_of_stream() && buffer->is_key_frame(), "timestamp (ms)",
315 !buffer->end_of_stream() ? buffer->timestamp().InMilliseconds() : 0); 335 !buffer->end_of_stream() ? buffer->timestamp().InMilliseconds() : 0);
316 336
317 if (buffer->end_of_stream()) 337 if (buffer->end_of_stream())
318 decoding_eos_ = true; 338 decoding_eos_ = true;
319 else if (buffer->duration() != kNoTimestamp()) 339 else if (buffer->duration() != kNoTimestamp())
320 duration_tracker_.AddSample(buffer->duration()); 340 duration_tracker_.AddSample(buffer->duration());
321 341
342 // Don't save the buffer if we have successfully decoded a frame or if it's
343 // the EOS buffer we send to flush the decoder.
sandersd (OOO until July 31) 2016/04/14 23:10:30 I still think this would be more clear if ReadFrom
tguilbert 2016/04/15 00:29:18 Done. After our offline discussion, I realized you
344 if (!decoded_frames_since_fallback_ &&
345 !(state_ == STATE_FLUSHING_DECODER && buffer->end_of_stream())) {
346 pending_buffers_.push_back(buffer);
347 }
348
322 ++pending_decode_requests_; 349 ++pending_decode_requests_;
323 decoder_->Decode(buffer, 350 decoder_->Decode(buffer, base::Bind(&DecoderStream<StreamType>::OnDecodeDone,
324 base::Bind(&DecoderStream<StreamType>::OnDecodeDone, 351 decode_weak_factory_.GetWeakPtr(),
325 weak_factory_.GetWeakPtr(), 352 buffer_size, buffer->end_of_stream()));
326 buffer_size,
327 buffer->end_of_stream()));
328 } 353 }
329 354
330 template <DemuxerStream::Type StreamType> 355 template <DemuxerStream::Type StreamType>
331 void DecoderStream<StreamType>::FlushDecoder() { 356 void DecoderStream<StreamType>::FlushDecoder() {
332 Decode(DecoderBuffer::CreateEOSBuffer()); 357 Decode(DecoderBuffer::CreateEOSBuffer());
333 } 358 }
334 359
335 template <DemuxerStream::Type StreamType> 360 template <DemuxerStream::Type StreamType>
336 void DecoderStream<StreamType>::OnDecodeDone(int buffer_size, 361 void DecoderStream<StreamType>::OnDecodeDone(int buffer_size,
337 bool end_of_stream, 362 bool end_of_stream,
338 DecodeStatus status) { 363 DecodeStatus status) {
339 FUNCTION_DVLOG(2) << ": " << status; 364 FUNCTION_DVLOG(2) << ": " << status;
365
340 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || 366 DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER ||
341 state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) 367 state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR)
342 << state_; 368 << state_;
343 DCHECK_GT(pending_decode_requests_, 0); 369 DCHECK_GT(pending_decode_requests_, 0);
344 370
345 --pending_decode_requests_; 371 --pending_decode_requests_;
346 372
347 TRACE_EVENT_ASYNC_END0("media", GetTraceString<StreamType>(), this); 373 TRACE_EVENT_ASYNC_END0("media", GetTraceString<StreamType>(), this);
348 374
349 if (end_of_stream) { 375 if (end_of_stream) {
350 DCHECK(!pending_decode_requests_); 376 DCHECK(!pending_decode_requests_);
351 decoding_eos_ = false; 377 decoding_eos_ = false;
352 } 378 }
353 379
354 if (state_ == STATE_ERROR) { 380 if (state_ == STATE_ERROR) {
355 DCHECK(read_cb_.is_null()); 381 DCHECK(read_cb_.is_null());
356 return; 382 return;
357 } 383 }
358 384
359 // Drop decoding result if Reset() was called during decoding. 385 // Drop decoding result if Reset() was called during decoding.
360 // The resetting process will be handled when the decoder is reset. 386 // The resetting process will be handled when the decoder is reset.
361 if (!reset_cb_.is_null()) 387 if (!reset_cb_.is_null())
362 return; 388 return;
363 389
364 switch (status) { 390 switch (status) {
365 case DecodeStatus::DECODE_ERROR: 391 case DecodeStatus::DECODE_ERROR:
392 if (!decoded_frames_since_fallback_) {
393 pending_decode_requests_ = 0;
394 // Prevent all pending decode requests from being called back.
sandersd (OOO until July 31) 2016/04/14 23:10:30 Newline before comment.
tguilbert 2016/04/15 00:29:18 Done.
395 decode_weak_factory_.InvalidateWeakPtrs();
396
397 state_ = STATE_REINITIALIZING_DECODER;
398 decoder_selector_->SelectDecoder(
399 stream_, nullptr,
400 base::Bind(&DecoderStream<StreamType>::OnDecoderSelected,
401 weak_factory_.GetWeakPtr()),
402 base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady,
403 weak_factory_.GetWeakPtr()),
404 waiting_for_decryption_key_cb_);
405 return;
406 }
366 state_ = STATE_ERROR; 407 state_ = STATE_ERROR;
367 MEDIA_LOG(ERROR, media_log_) << GetStreamTypeString() << " decode error"; 408 MEDIA_LOG(ERROR, media_log_) << GetStreamTypeString() << " decode error";
368 ready_outputs_.clear(); 409 ready_outputs_.clear();
369 if (!read_cb_.is_null()) 410 if (!read_cb_.is_null())
370 SatisfyRead(DECODE_ERROR, NULL); 411 SatisfyRead(DECODE_ERROR, NULL);
371 return; 412 return;
372 413
373 case DecodeStatus::ABORTED: 414 case DecodeStatus::ABORTED:
374 // Decoder can return DecodeStatus::ABORTED during Reset() or during 415 // Decoder can return DecodeStatus::ABORTED during Reset() or during
375 // destruction. 416 // destruction.
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
411 if (state_ == STATE_ERROR) { 452 if (state_ == STATE_ERROR) {
412 DCHECK(read_cb_.is_null()); 453 DCHECK(read_cb_.is_null());
413 return; 454 return;
414 } 455 }
415 456
416 // Drop decoding result if Reset() was called during decoding. 457 // Drop decoding result if Reset() was called during decoding.
417 // The resetting process will be handled when the decoder is reset. 458 // The resetting process will be handled when the decoder is reset.
418 if (!reset_cb_.is_null()) 459 if (!reset_cb_.is_null())
419 return; 460 return;
420 461
462 ++decoded_frames_since_fallback_;
463
464 if (!pending_buffers_.empty())
sandersd (OOO until July 31) 2016/04/14 23:10:30 No need for a condition, it can just be unconditio
tguilbert 2016/04/15 00:29:18 Oops! Artifact of the previous patchset.
465 pending_buffers_.clear();
466
421 if (!read_cb_.is_null()) { 467 if (!read_cb_.is_null()) {
422 // If |ready_outputs_| was non-empty, the read would have already been 468 // If |ready_outputs_| was non-empty, the read would have already been
423 // satisifed by Read(). 469 // satisifed by Read().
424 DCHECK(ready_outputs_.empty()); 470 DCHECK(ready_outputs_.empty());
425 SatisfyRead(OK, output); 471 SatisfyRead(OK, output);
426 return; 472 return;
427 } 473 }
428 474
429 // Store decoded output. 475 // Store decoded output.
430 ready_outputs_.push_back(output); 476 ready_outputs_.push_back(output);
431 477
432 // Destruct any previous decoder once we've decoded enough frames to ensure 478 // Destruct any previous decoder once we've decoded enough frames to ensure
433 // that it's no longer in use. 479 // that it's no longer in use.
434 if (previous_decoder_ && 480 if (previous_decoder_ &&
435 ++decoded_frames_since_fallback_ > limits::kMaxVideoFrames) { 481 decoded_frames_since_fallback_ > limits::kMaxVideoFrames) {
436 previous_decoder_.reset(); 482 previous_decoder_.reset();
437 } 483 }
438 } 484 }
439 485
440 template <DemuxerStream::Type StreamType> 486 template <DemuxerStream::Type StreamType>
441 void DecoderStream<StreamType>::ReadFromDemuxerStream() { 487 void DecoderStream<StreamType>::ReadFromDemuxerStream() {
442 FUNCTION_DVLOG(2); 488 FUNCTION_DVLOG(2);
443 DCHECK_EQ(state_, STATE_NORMAL); 489 DCHECK_EQ(state_, STATE_NORMAL);
444 DCHECK(CanDecodeMore()); 490 DCHECK(CanDecodeMore());
445 DCHECK(reset_cb_.is_null()); 491 DCHECK(reset_cb_.is_null());
446 492
493 if (!fallback_buffers_.empty()) {
494 scoped_refptr<DecoderBuffer> buffer = fallback_buffers_.front();
495 fallback_buffers_.pop_front();
496 Decode(buffer);
497 return;
498 }
499
447 state_ = STATE_PENDING_DEMUXER_READ; 500 state_ = STATE_PENDING_DEMUXER_READ;
448 stream_->Read(base::Bind(&DecoderStream<StreamType>::OnBufferReady, 501 stream_->Read(base::Bind(&DecoderStream<StreamType>::OnBufferReady,
449 weak_factory_.GetWeakPtr())); 502 weak_factory_.GetWeakPtr()));
450 } 503 }
451 504
452 template <DemuxerStream::Type StreamType> 505 template <DemuxerStream::Type StreamType>
453 void DecoderStream<StreamType>::OnBufferReady( 506 void DecoderStream<StreamType>::OnBufferReady(
454 DemuxerStream::Status status, 507 DemuxerStream::Status status,
455 const scoped_refptr<DecoderBuffer>& buffer) { 508 const scoped_refptr<DecoderBuffer>& buffer) {
456 FUNCTION_DVLOG(2) << ": " << status << ", " 509 FUNCTION_DVLOG(2) << ": " << status << ", "
457 << (buffer.get() ? buffer->AsHumanReadableString() 510 << (buffer.get() ? buffer->AsHumanReadableString()
458 : "NULL"); 511 : "NULL");
459 512
460 DCHECK(task_runner_->BelongsToCurrentThread()); 513 DCHECK(task_runner_->BelongsToCurrentThread());
461 DCHECK(state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) 514 if (decoded_frames_since_fallback_) {
462 << state_; 515 DCHECK(state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR)
516 << state_;
517 } else {
518 DCHECK(state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR ||
519 STATE_REINITIALIZING_DECODER)
520 << state_;
521 }
463 DCHECK_EQ(buffer.get() != NULL, status == DemuxerStream::kOk) << status; 522 DCHECK_EQ(buffer.get() != NULL, status == DemuxerStream::kOk) << status;
464 523
524 // If parallel decode requests are supported, multiple read requests might
525 // have been sent to the demuxer. The buffers might arrive while the decoder
526 // is reinitializing after falling back on first decode error.
527 if (state_ == STATE_REINITIALIZING_DECODER &&
528 !decoded_frames_since_fallback_) {
529 switch (status) {
530 case DemuxerStream::kOk:
531 // Save valid buffers to be consumed by the new decoder.
532 // |pending_buffers_| is copied to |fallback_buffers| in
533 // OnDecoderSelected().
534 pending_buffers_.push_back(buffer);
535 break;
536 case DemuxerStream::kConfigChanged:
537 // TODO(tguilbert): crbug.com/603713
538 // |decoder_| might have a stale config by the time it is reinitialized.
539 // Ideally, we would save the config from |stream_| and reinitialize the
540 // decoder by playing back the sequence of buffers and config changes.
541 state_ = STATE_CONFIG_CHANGE_RECEIVED_WHILE_REINITIALIZING_DECODER;
542 pending_buffers_.clear();
543 break;
544 case DemuxerStream::kAborted:
545 // |this| will read from the demuxer stream again in OnDecoderSelected()
546 // and receive a kAborted then.
547 pending_buffers_.clear();
548 break;
549 default:
550 NOTREACHED();
551 break;
552 }
553 return;
554 }
555
465 // Decoding has been stopped (e.g due to an error). 556 // Decoding has been stopped (e.g due to an error).
466 if (state_ != STATE_PENDING_DEMUXER_READ) { 557 if (state_ != STATE_PENDING_DEMUXER_READ) {
467 DCHECK(state_ == STATE_ERROR); 558 DCHECK(state_ == STATE_ERROR);
468 DCHECK(read_cb_.is_null()); 559 DCHECK(read_cb_.is_null());
469 return; 560 return;
470 } 561 }
471 562
472 state_ = STATE_NORMAL; 563 state_ = STATE_NORMAL;
473 564
474 if (status == DemuxerStream::kConfigChanged) { 565 if (status == DemuxerStream::kConfigChanged) {
475 FUNCTION_DVLOG(2) << ": " << "ConfigChanged"; 566 FUNCTION_DVLOG(2) << ": " << "ConfigChanged";
476 DCHECK(stream_->SupportsConfigChanges()); 567 DCHECK(stream_->SupportsConfigChanges());
477 568
569 // Pending buffers might not match the reinitialiazed decoder's new config
570 pending_buffers_.clear();
571
478 if (!config_change_observer_cb_.is_null()) 572 if (!config_change_observer_cb_.is_null())
479 config_change_observer_cb_.Run(); 573 config_change_observer_cb_.Run();
480 574
481 state_ = STATE_FLUSHING_DECODER; 575 state_ = STATE_FLUSHING_DECODER;
482 if (!reset_cb_.is_null()) { 576 if (!reset_cb_.is_null()) {
483 // If we are using DecryptingDemuxerStream, we already called DDS::Reset() 577 // If we are using DecryptingDemuxerStream, we already called DDS::Reset()
484 // which will continue the resetting process in it's callback. 578 // which will continue the resetting process in it's callback.
485 if (!decrypting_demuxer_stream_) 579 if (!decrypting_demuxer_stream_)
486 Reset(base::ResetAndReturn(&reset_cb_)); 580 Reset(base::ResetAndReturn(&reset_cb_));
487 // Reinitialization will continue after Reset() is done. 581 // Reinitialization will continue after Reset() is done.
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
619 } 713 }
620 714
621 // The resetting process will be continued in OnDecoderReinitialized(). 715 // The resetting process will be continued in OnDecoderReinitialized().
622 ReinitializeDecoder(); 716 ReinitializeDecoder();
623 } 717 }
624 718
625 template class DecoderStream<DemuxerStream::VIDEO>; 719 template class DecoderStream<DemuxerStream::VIDEO>;
626 template class DecoderStream<DemuxerStream::AUDIO>; 720 template class DecoderStream<DemuxerStream::AUDIO>;
627 721
628 } // namespace media 722 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698