Chromium Code Reviews| Index: media/gpu/android_video_decode_accelerator.cc |
| diff --git a/media/gpu/android_video_decode_accelerator.cc b/media/gpu/android_video_decode_accelerator.cc |
| index abf37769f7cef53617262c3ec58443d2af14ecf5..bc98ed6604771d2f538478d7911036ab9eb4a13d 100644 |
| --- a/media/gpu/android_video_decode_accelerator.cc |
| +++ b/media/gpu/android_video_decode_accelerator.cc |
| @@ -231,7 +231,6 @@ AndroidVideoDecodeAccelerator::AndroidVideoDecodeAccelerator( |
| state_(NO_ERROR), |
| picturebuffers_requested_(false), |
| picture_buffer_manager_(this), |
| - drain_type_(DRAIN_TYPE_NONE), |
| media_drm_bridge_cdm_context_(nullptr), |
| cdm_registration_id_(0), |
| pending_input_buf_index_(-1), |
| @@ -593,9 +592,9 @@ bool AndroidVideoDecodeAccelerator::DequeueOutput() { |
| switch (status) { |
| case MEDIA_CODEC_ERROR: |
| // Do not post an error if we are draining for reset and destroy. |
| - // Instead, run the drain completion task. |
| + // Instead, signal completion of the drain. |
| if (IsDrainingForResetOrDestroy()) { |
| - DVLOG(1) << __func__ << ": error while codec draining"; |
| + DVLOG(1) << __func__ << ": error while draining"; |
| state_ = ERROR; |
| OnDrainCompleted(); |
| } else { |
| @@ -771,7 +770,7 @@ void AndroidVideoDecodeAccelerator::Decode( |
| // If we previously deferred a codec restart, take care of it now. This can |
| // happen on older devices where configuration changes require a codec reset. |
| if (codec_needs_reset_) { |
| - DCHECK_EQ(drain_type_, DRAIN_TYPE_NONE); |
| + DCHECK(!drain_type_); |
| ResetCodecState(); |
| } |
| @@ -864,11 +863,7 @@ void AndroidVideoDecodeAccelerator::ReusePictureBuffer( |
| void AndroidVideoDecodeAccelerator::Flush() { |
| DVLOG(1) << __func__; |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - |
| - if (state_ == SURFACE_DESTROYED || defer_surface_creation_) |
|
watk
2016/12/07 23:30:32
These both imply media_codec == nullptr so I used
|
| - NotifyFlushDone(); |
| - else |
| - StartCodecDrain(DRAIN_FOR_FLUSH); |
| + StartCodecDrain(DRAIN_FOR_FLUSH); |
| } |
| void AndroidVideoDecodeAccelerator::ConfigureMediaCodecAsynchronously() { |
| @@ -962,17 +957,26 @@ void AndroidVideoDecodeAccelerator::StartCodecDrain(DrainType drain_type) { |
| DVLOG(2) << __func__ << " drain_type:" << drain_type; |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - // We assume that DRAIN_FOR_FLUSH and DRAIN_FOR_RESET cannot come while |
| - // another drain request is present, but DRAIN_FOR_DESTROY can. |
| - DCHECK_NE(drain_type, DRAIN_TYPE_NONE); |
| - DCHECK(drain_type_ == DRAIN_TYPE_NONE || drain_type == DRAIN_FOR_DESTROY) |
| - << "Unexpected StartCodecDrain() with drain type " << drain_type |
| - << " while already draining with drain type " << drain_type_; |
| - |
| - const bool enqueue_eos = drain_type_ == DRAIN_TYPE_NONE; |
| + auto previous_drain_type = drain_type_; |
| drain_type_ = drain_type; |
| - if (enqueue_eos) |
| + // Only DRAIN_FOR_DESTROY is allowed while a drain is already in progress. |
| + DCHECK(!previous_drain_type || drain_type == DRAIN_FOR_DESTROY) |
| + << "StartCodecDrain(" << drain_type |
| + << ") while already draining with type " << previous_drain_type.value(); |
| + |
| + // Skip the drain if possible. We still need to drain VP8 for destroy and |
| + // reset because MediaCodec might hang in release() or flush() if we don't. |
|
DaleCurtis
2016/12/08 00:11:13
Comment is a bit misleading, code skips drain if t
|
| + // http://crbug.com/598963 |
| + if (!media_codec_ || (pending_bitstream_records_.empty() && |
|
DaleCurtis
2016/12/08 00:11:14
Maybe clarify that in the case of Reset() pending
|
| + bitstream_buffers_in_decoder_.empty()) || |
| + (drain_type != DRAIN_FOR_FLUSH && codec_config_->codec != kCodecVP8)) { |
| + OnDrainCompleted(); |
| + return; |
| + } |
| + |
| + // Queue EOS if one is not already queued. |
| + if (!previous_drain_type) |
| DecodeBuffer(BitstreamBuffer(-1, base::SharedMemoryHandle(), 0)); |
| } |
| @@ -984,39 +988,33 @@ void AndroidVideoDecodeAccelerator::OnDrainCompleted() { |
| DVLOG(2) << __func__; |
| DCHECK(thread_checker_.CalledOnValidThread()); |
| - // If we were waiting for an EOS, clear the state and reset the MediaCodec |
| - // as normal. |
| - // |
| - // Some Android platforms seem to send an EOS buffer even when we're not |
| - // expecting it. In this case, destroy and reset the codec but don't notify |
| - // flush done since it violates the state machine. http://crbug.com/585959. |
| + // Sometimes MediaCodec returns an EOS buffer even if we didn't queue one. |
| + // Consider it an error. http://crbug.com/585959. |
| + if (!drain_type_) { |
| + state_ = ERROR; |
| + ResetCodecState(); |
| + return; |
| + } |
| - switch (drain_type_) { |
| - case DRAIN_TYPE_NONE: |
| - // Unexpected EOS. |
| - state_ = ERROR; |
| - ResetCodecState(); |
| - break; |
| + ResetCodecState(); |
| + switch (*drain_type_) { |
| case DRAIN_FOR_FLUSH: |
| - ResetCodecState(); |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyFlushDone, |
| weak_this_factory_.GetWeakPtr())); |
| break; |
| case DRAIN_FOR_RESET: |
| - ResetCodecState(); |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyResetDone, |
| weak_this_factory_.GetWeakPtr())); |
| break; |
| case DRAIN_FOR_DESTROY: |
| - ResetCodecState(); |
| base::ThreadTaskRunnerHandle::Get()->PostTask( |
| FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::ActualDestroy, |
| weak_this_factory_.GetWeakPtr())); |
| break; |
| } |
| - drain_type_ = DRAIN_TYPE_NONE; |
| + drain_type_.reset(); |
| } |
| void AndroidVideoDecodeAccelerator::ResetCodecState() { |
| @@ -1097,19 +1095,7 @@ void AndroidVideoDecodeAccelerator::Reset() { |
| bitstreams_notified_in_advance_.clear(); |
| picture_buffer_manager_.ReleaseCodecBuffers(output_picture_buffers_); |
| - |
| - // Some VP8 files require complete MediaCodec drain before we can call |
| - // MediaCodec.flush() or MediaCodec.reset(). http://crbug.com/598963. |
| - if (media_codec_ && codec_config_->codec == kCodecVP8 && |
| - !bitstream_buffers_in_decoder_.empty()) { |
| - // Postpone ResetCodecState() after the drain. |
| - StartCodecDrain(DRAIN_FOR_RESET); |
| - } else { |
| - ResetCodecState(); |
| - base::ThreadTaskRunnerHandle::Get()->PostTask( |
| - FROM_HERE, base::Bind(&AndroidVideoDecodeAccelerator::NotifyResetDone, |
| - weak_this_factory_.GetWeakPtr())); |
| - } |
| + StartCodecDrain(DRAIN_FOR_RESET); |
| } |
| void AndroidVideoDecodeAccelerator::SetSurface(int32_t surface_id) { |
| @@ -1135,18 +1121,10 @@ void AndroidVideoDecodeAccelerator::Destroy() { |
| client_ = nullptr; |
| - // Some VP8 files require a complete MediaCodec drain before we can call |
| - // MediaCodec.flush() or MediaCodec.release(). http://crbug.com/598963. In |
| - // that case, postpone ActualDestroy() until after the drain. |
| - if (media_codec_ && codec_config_->codec == kCodecVP8) { |
| - // Clear |pending_bitstream_records_|. |
| - while (!pending_bitstream_records_.empty()) |
| - pending_bitstream_records_.pop(); |
| - |
| - StartCodecDrain(DRAIN_FOR_DESTROY); |
| - } else { |
| - ActualDestroy(); |
| - } |
| + // We don't want to queue more inputs while draining. |
| + while (!pending_bitstream_records_.empty()) |
|
DaleCurtis
2016/12/08 00:29:35
Because I was curious and have been benchmarking t
|
| + pending_bitstream_records_.pop(); |
| + StartCodecDrain(DRAIN_FOR_DESTROY); |
| } |
| void AndroidVideoDecodeAccelerator::ActualDestroy() { |
| @@ -1222,7 +1200,7 @@ void AndroidVideoDecodeAccelerator::OnSurfaceDestroyed() { |
| // If we're draining, signal completion now because the drain can no longer |
| // proceed. |
| - if (drain_type_ != DRAIN_TYPE_NONE) |
| + if (drain_type_) |
| OnDrainCompleted(); |
| } |