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

Unified 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 side-by-side diff with in-line comments
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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/decoder_stream.cc
diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc
index 19ae054d64e7ab73d786a44d5050bca508ca7390..731eb5d24ecda24ead065de092acc08da05d4218 100644
--- a/media/filters/decoder_stream.cc
+++ b/media/filters/decoder_stream.cc
@@ -59,6 +59,7 @@ DecoderStream<StreamType>::DecoderStream(
decoding_eos_(false),
pending_decode_requests_(0),
duration_tracker_(8),
+ sequence_token_(0),
weak_factory_(this) {}
template <DemuxerStream::Type StreamType>
@@ -80,6 +81,7 @@ DecoderStream<StreamType>::~DecoderStream() {
task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&reset_cb_));
stream_ = NULL;
+ pending_buffers_.clear();
decoder_.reset();
decrypting_demuxer_stream_.reset();
}
@@ -319,12 +321,14 @@ void DecoderStream<StreamType>::Decode(
else if (buffer->duration() != kNoTimestamp())
duration_tracker_.AddSample(buffer->duration());
+ if (!previous_decoder_ && !decoded_frames_since_fallback_ && !decoding_eos_)
+ 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
+
++pending_decode_requests_;
decoder_->Decode(buffer,
base::Bind(&DecoderStream<StreamType>::OnDecodeDone,
- weak_factory_.GetWeakPtr(),
- buffer_size,
- buffer->end_of_stream()));
+ 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
+ buffer_size, buffer->end_of_stream()));
}
template <DemuxerStream::Type StreamType>
@@ -333,10 +337,15 @@ void DecoderStream<StreamType>::FlushDecoder() {
}
template <DemuxerStream::Type StreamType>
-void DecoderStream<StreamType>::OnDecodeDone(int buffer_size,
+void DecoderStream<StreamType>::OnDecodeDone(int sequence_token,
+ int buffer_size,
bool end_of_stream,
DecodeStatus status) {
FUNCTION_DVLOG(2) << ": " << status;
+ // Ignore stale calls from a previous decoder.
+ if (sequence_token_ != sequence_token)
+ return;
+
DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER ||
state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR)
<< state_;
@@ -363,6 +372,24 @@ void DecoderStream<StreamType>::OnDecodeDone(int buffer_size,
switch (status) {
case DecodeStatus::DECODE_ERROR:
+ if (!decoded_frames_since_fallback_) {
+ pending_decode_requests_ = 0;
+ // Note: increment |sequence_token_| here rather than in
+ // OnDecoderSelected. This covers the case where parallel decode
+ // requests were sent to |decoder_|, and responses are received before
+ // a new decoder is selected. This prevents |pending_decode_request_|
+ // from going below 0.
+ ++sequence_token_;
+ state_ = STATE_REINITIALIZING_DECODER;
+ decoder_selector_->SelectDecoder(
+ stream_, nullptr,
+ base::Bind(&DecoderStream<StreamType>::OnDecoderSelected,
+ weak_factory_.GetWeakPtr()),
+ base::Bind(&DecoderStream<StreamType>::OnDecodeOutputReady,
+ weak_factory_.GetWeakPtr()),
+ waiting_for_decryption_key_cb_);
+ return;
+ }
state_ = STATE_ERROR;
MEDIA_LOG(ERROR, media_log_) << GetStreamTypeString() << " decode error";
ready_outputs_.clear();
@@ -408,6 +435,13 @@ void DecoderStream<StreamType>::OnDecodeOutputReady(
state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR)
<< state_;
+ // Note: Checking that we have decoded more frames than the max number of
+ // parallel requests ensures we don't delete the buffers before the fallback
+ // decoder has had a chance to use them.
+ 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.
+ decoded_frames_since_fallback_ > GetMaxDecodeRequests())
+ pending_buffers_.clear();
+
if (state_ == STATE_ERROR) {
DCHECK(read_cb_.is_null());
return;
@@ -418,6 +452,8 @@ void DecoderStream<StreamType>::OnDecodeOutputReady(
if (!reset_cb_.is_null())
return;
+ ++decoded_frames_since_fallback_;
+
if (!read_cb_.is_null()) {
// If |ready_outputs_| was non-empty, the read would have already been
// satisifed by Read().
@@ -432,7 +468,7 @@ void DecoderStream<StreamType>::OnDecodeOutputReady(
// Destruct any previous decoder once we've decoded enough frames to ensure
// that it's no longer in use.
if (previous_decoder_ &&
- ++decoded_frames_since_fallback_ > limits::kMaxVideoFrames) {
+ decoded_frames_since_fallback_ > limits::kMaxVideoFrames) {
previous_decoder_.reset();
}
}
@@ -444,6 +480,13 @@ void DecoderStream<StreamType>::ReadFromDemuxerStream() {
DCHECK(CanDecodeMore());
DCHECK(reset_cb_.is_null());
+ 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
+ scoped_refptr<DecoderBuffer> buffer = pending_buffers_.front();
+ pending_buffers_.pop_front();
+ Decode(buffer);
+ return;
+ }
+
state_ = STATE_PENDING_DEMUXER_READ;
stream_->Read(base::Bind(&DecoderStream<StreamType>::OnBufferReady,
weak_factory_.GetWeakPtr()));
@@ -458,10 +501,25 @@ void DecoderStream<StreamType>::OnBufferReady(
: "NULL");
DCHECK(task_runner_->BelongsToCurrentThread());
- DCHECK(state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR)
+ DCHECK(state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR ||
+ STATE_REINITIALIZING_DECODER)
<< state_;
DCHECK_EQ(buffer.get() != NULL, status == DemuxerStream::kOk) << status;
+ // If parallel decode requests are supported, multiple read requests might
+ // have been sent to the demuxer. The buffers might arrive while the decoder
+ // is reinitializing after falling back on first decode error.
+ if (state_ == STATE_REINITIALIZING_DECODER &&
+ !decoded_frames_since_fallback_) {
+ // 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
+ // TODO(tguilbert): Question for CR: what is the proper way to error out?
+ if (status == DemuxerStream::kOk)
+ pending_buffers_.push_back(buffer);
+ else
+ pending_buffers_.clear();
+ return;
+ }
+
// Decoding has been stopped (e.g due to an error).
if (state_ != STATE_PENDING_DEMUXER_READ) {
DCHECK(state_ == STATE_ERROR);
@@ -475,6 +533,9 @@ void DecoderStream<StreamType>::OnBufferReady(
FUNCTION_DVLOG(2) << ": " << "ConfigChanged";
DCHECK(stream_->SupportsConfigChanges());
+ // 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
+ pending_buffers_.clear();
+
if (!config_change_observer_cb_.is_null())
config_change_observer_cb_.Run();
« 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