Chromium Code Reviews| Index: media/filters/decoder_stream.cc |
| diff --git a/media/filters/decoder_stream.cc b/media/filters/decoder_stream.cc |
| index 19ae054d64e7ab73d786a44d5050bca508ca7390..8fd7c72a6cfbdaa5389dd69ec280d9505beeebd8 100644 |
| --- a/media/filters/decoder_stream.cc |
| +++ b/media/filters/decoder_stream.cc |
| @@ -59,7 +59,8 @@ DecoderStream<StreamType>::DecoderStream( |
| decoding_eos_(false), |
| pending_decode_requests_(0), |
| duration_tracker_(8), |
| - weak_factory_(this) {} |
| + weak_factory_(this), |
| + decode_weak_factory_(this) {} |
| template <DemuxerStream::Type StreamType> |
| DecoderStream<StreamType>::~DecoderStream() { |
| @@ -243,13 +244,15 @@ void DecoderStream<StreamType>::OnDecoderSelected( |
| << (selected_decoder ? selected_decoder->GetDisplayName() |
| : "No decoder selected."); |
| DCHECK(task_runner_->BelongsToCurrentThread()); |
| - DCHECK(state_ == STATE_INITIALIZING || state_ == STATE_REINITIALIZING_DECODER) |
| + DCHECK(state_ == STATE_INITIALIZING || |
| + state_ == STATE_REINITIALIZING_DECODER || |
| + state_ == STATE_CONFIG_CHANGE_RECEIVED_WHILE_REINITIALIZING_DECODER) |
| << state_; |
| if (state_ == STATE_INITIALIZING) { |
| DCHECK(!init_cb_.is_null()); |
| DCHECK(read_cb_.is_null()); |
| DCHECK(reset_cb_.is_null()); |
| - } else { |
| + } else if (state_ == STATE_REINITIALIZING_DECODER) { |
| DCHECK(decoder_); |
| } |
| @@ -261,6 +264,21 @@ void DecoderStream<StreamType>::OnDecoderSelected( |
| stream_ = decrypting_demuxer_stream_.get(); |
| } |
| + // TODO(tguilbert): crbug.com/603713 support config changes on decoder reinit. |
| + if (state_ == STATE_CONFIG_CHANGE_RECEIVED_WHILE_REINITIALIZING_DECODER) { |
| + CompleteDecoderReinitialization(false); |
| + return; |
| + } |
| + |
| + // Push the pending buffers to the front of the fallback buffers |
| + if (fallback_buffers_.empty()) { |
| + fallback_buffers_.swap(pending_buffers_); |
| + } else { |
| + fallback_buffers_.insert(fallback_buffers_.begin(), |
|
DaleCurtis
2016/04/15 01:19:16
Is it better to just insert at the end of pending_
tguilbert
2016/04/15 20:45:51
While I assume that the amortized cost would be fi
|
| + pending_buffers_.begin(), pending_buffers_.end()); |
| + pending_buffers_.clear(); |
| + } |
| + |
| if (!decoder_) { |
| if (state_ == STATE_INITIALIZING) { |
| state_ = STATE_UNINITIALIZED; |
| @@ -302,6 +320,19 @@ template <DemuxerStream::Type StreamType> |
| void DecoderStream<StreamType>::Decode( |
| const scoped_refptr<DecoderBuffer>& buffer) { |
| FUNCTION_DVLOG(2); |
| + |
| + // We don't know if the decoder will error out on first decode yet. Save the |
| + // buffer to feed it to the fallback decoder later if needed. |
| + if (!decoded_frames_since_fallback_) |
| + pending_buffers_.push_back(buffer); |
| + |
| + DecodeInternal(buffer); |
| +} |
| + |
| +template <DemuxerStream::Type StreamType> |
| +void DecoderStream<StreamType>::DecodeInternal( |
| + const scoped_refptr<DecoderBuffer>& buffer) { |
| + FUNCTION_DVLOG(2); |
| DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER) << state_; |
| DCHECK_LT(pending_decode_requests_, GetMaxDecodeRequests()); |
| DCHECK(reset_cb_.is_null()); |
| @@ -320,16 +351,15 @@ void DecoderStream<StreamType>::Decode( |
| duration_tracker_.AddSample(buffer->duration()); |
| ++pending_decode_requests_; |
| - decoder_->Decode(buffer, |
| - base::Bind(&DecoderStream<StreamType>::OnDecodeDone, |
| - weak_factory_.GetWeakPtr(), |
| - buffer_size, |
| - buffer->end_of_stream())); |
| + decoder_->Decode(buffer, base::Bind(&DecoderStream<StreamType>::OnDecodeDone, |
| + decode_weak_factory_.GetWeakPtr(), |
| + buffer_size, buffer->end_of_stream())); |
| } |
| template <DemuxerStream::Type StreamType> |
| void DecoderStream<StreamType>::FlushDecoder() { |
| - Decode(DecoderBuffer::CreateEOSBuffer()); |
| + // Decode directly and bypass saving the EOS into |pending_buffers_|. |
| + DecodeInternal(DecoderBuffer::CreateEOSBuffer()); |
| } |
| template <DemuxerStream::Type StreamType> |
| @@ -337,6 +367,7 @@ void DecoderStream<StreamType>::OnDecodeDone(int buffer_size, |
| bool end_of_stream, |
| DecodeStatus status) { |
| FUNCTION_DVLOG(2) << ": " << status; |
| + |
|
DaleCurtis
2016/04/15 01:19:17
Delete?
tguilbert
2016/04/15 20:45:52
Done.
|
| DCHECK(state_ == STATE_NORMAL || state_ == STATE_FLUSHING_DECODER || |
| state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) |
| << state_; |
| @@ -363,6 +394,22 @@ void DecoderStream<StreamType>::OnDecodeDone(int buffer_size, |
| switch (status) { |
| case DecodeStatus::DECODE_ERROR: |
| + if (!decoded_frames_since_fallback_) { |
| + pending_decode_requests_ = 0; |
| + |
| + // Prevent all pending decode requests from being called back. |
| + decode_weak_factory_.InvalidateWeakPtrs(); |
| + |
| + 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(); |
| @@ -418,6 +465,14 @@ void DecoderStream<StreamType>::OnDecodeOutputReady( |
| if (!reset_cb_.is_null()) |
| return; |
| + ++decoded_frames_since_fallback_; |
| + |
| + // |decoder_| sucessfully decoded a frame. No need to keep buffers for a |
| + // fallback decoder. |
| + // Note: |fallback_buffers_| might still have buffers, and we will keep |
| + // reading from there before requesting new buffers from |stream_|. |
| + pending_buffers_.clear(); |
| + |
| if (!read_cb_.is_null()) { |
| // If |ready_outputs_| was non-empty, the read would have already been |
| // satisifed by Read(). |
| @@ -432,7 +487,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 +499,13 @@ void DecoderStream<StreamType>::ReadFromDemuxerStream() { |
| DCHECK(CanDecodeMore()); |
| DCHECK(reset_cb_.is_null()); |
| + if (!fallback_buffers_.empty()) { |
| + scoped_refptr<DecoderBuffer> buffer = fallback_buffers_.front(); |
| + fallback_buffers_.pop_front(); |
| + Decode(buffer); |
| + return; |
| + } |
| + |
| state_ = STATE_PENDING_DEMUXER_READ; |
| stream_->Read(base::Bind(&DecoderStream<StreamType>::OnBufferReady, |
| weak_factory_.GetWeakPtr())); |
| @@ -458,10 +520,48 @@ void DecoderStream<StreamType>::OnBufferReady( |
| : "NULL"); |
| DCHECK(task_runner_->BelongsToCurrentThread()); |
| - DCHECK(state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) |
| - << state_; |
| + if (decoded_frames_since_fallback_) { |
| + DCHECK(state_ == STATE_PENDING_DEMUXER_READ || state_ == STATE_ERROR) |
| + << state_; |
| + } else { |
| + 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_) { |
| + switch (status) { |
| + case DemuxerStream::kOk: |
| + // Save valid buffers to be consumed by the new decoder. |
| + // |pending_buffers_| is copied to |fallback_buffers| in |
| + // OnDecoderSelected(). |
| + pending_buffers_.push_back(buffer); |
| + break; |
| + case DemuxerStream::kConfigChanged: |
| + // TODO(tguilbert): crbug.com/603713 |
| + // |decoder_| might have a stale config by the time it is reinitialized. |
| + // Ideally, we would save the config from |stream_| and reinitialize the |
| + // decoder by playing back the sequence of buffers and config changes. |
| + state_ = STATE_CONFIG_CHANGE_RECEIVED_WHILE_REINITIALIZING_DECODER; |
| + pending_buffers_.clear(); |
| + break; |
| + case DemuxerStream::kAborted: |
| + // |this| will read from the demuxer stream again in OnDecoderSelected() |
| + // and receive a kAborted then. |
| + pending_buffers_.clear(); |
| + break; |
| + default: |
|
DaleCurtis
2016/04/15 01:19:17
No need for default? We typically prefer to enumer
tguilbert
2016/04/15 20:45:52
Good to know. TY!
|
| + NOTREACHED(); |
| + break; |
| + } |
| + return; |
| + } |
| + |
| // Decoding has been stopped (e.g due to an error). |
| if (state_ != STATE_PENDING_DEMUXER_READ) { |
| DCHECK(state_ == STATE_ERROR); |
| @@ -475,6 +575,9 @@ void DecoderStream<StreamType>::OnBufferReady( |
| FUNCTION_DVLOG(2) << ": " << "ConfigChanged"; |
| DCHECK(stream_->SupportsConfigChanges()); |
| + // Pending buffers might not match the reinitialiazed decoder's new config |
|
DaleCurtis
2016/04/15 01:19:17
Reinitialized.
tguilbert
2016/04/15 20:45:52
Done.
|
| + pending_buffers_.clear(); |
| + |
| if (!config_change_observer_cb_.is_null()) |
| config_change_observer_cb_.Run(); |
| @@ -611,6 +714,10 @@ void DecoderStream<StreamType>::OnDecoderReset() { |
| DCHECK(read_cb_.is_null()); |
| DCHECK(!reset_cb_.is_null()); |
| + // Make sure we read directly from the demuxer after a reset. |
| + fallback_buffers_.clear(); |
| + pending_buffers_.clear(); |
| + |
| if (state_ != STATE_FLUSHING_DECODER) { |
| state_ = STATE_NORMAL; |
| active_splice_ = false; |