| Index: media/base/android/media_codec_decoder.cc
|
| diff --git a/media/base/android/media_codec_decoder.cc b/media/base/android/media_codec_decoder.cc
|
| index dc51904ee953b070b33b21733a1091beaaea8d28..67425c6c3bba0759dffddb0050e58e2db7b59a2d 100644
|
| --- a/media/base/android/media_codec_decoder.cc
|
| +++ b/media/base/android/media_codec_decoder.cc
|
| @@ -40,6 +40,7 @@ MediaCodecDecoder::MediaCodecDecoder(
|
| const char* decoder_thread_name)
|
| : media_task_runner_(media_task_runner),
|
| decoder_thread_(decoder_thread_name),
|
| + needs_reconfigure_(false),
|
| external_request_data_cb_(external_request_data_cb),
|
| starvation_cb_(starvation_cb),
|
| stop_done_cb_(stop_done_cb),
|
| @@ -82,8 +83,12 @@ void MediaCodecDecoder::ReleaseDecoderResources() {
|
|
|
| DVLOG(1) << class_name() << "::" << __FUNCTION__;
|
|
|
| + // Set [kInEmergencyStop| state to block already posted ProcessNextFrame().
|
| + SetState(kInEmergencyStop);
|
| +
|
| decoder_thread_.Stop(); // synchronous
|
| - state_ = kStopped;
|
| +
|
| + SetState(kStopped);
|
| media_codec_bridge_.reset();
|
| }
|
|
|
| @@ -180,14 +185,26 @@ MediaCodecDecoder::ConfigStatus MediaCodecDecoder::Configure() {
|
|
|
| if (GetState() == kError) {
|
| DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state kError";
|
| - return CONFIG_FAILURE;
|
| + return kConfigFailure;
|
| + }
|
| +
|
| + if (needs_reconfigure_) {
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__
|
| + << ": needs reconfigure, deleting MediaCodec";
|
| + needs_reconfigure_ = false;
|
| + media_codec_bridge_.reset();
|
| +
|
| + // No need to release these buffers since the MediaCodec is deleted, just
|
| + // remove their indexes from |delayed_buffers_|.
|
| +
|
| + ClearDelayedBuffers(false);
|
| }
|
|
|
| MediaCodecDecoder::ConfigStatus result;
|
| if (media_codec_bridge_) {
|
| DVLOG(1) << class_name() << "::" << __FUNCTION__
|
| << ": reconfiguration is not required, ignoring";
|
| - result = CONFIG_OK;
|
| + result = kConfigOk;
|
| } else {
|
| result = ConfigureInternal();
|
|
|
| @@ -197,7 +214,7 @@ MediaCodecDecoder::ConfigStatus MediaCodecDecoder::Configure() {
|
| DCHECK(!decoder_thread_.IsRunning());
|
|
|
| // For video the first frame after reconfiguration must be key frame.
|
| - if (result == CONFIG_OK)
|
| + if (result == kConfigOk)
|
| verify_next_frame_is_key_ = true;
|
| #endif
|
| }
|
| @@ -219,7 +236,7 @@ bool MediaCodecDecoder::Start(base::TimeDelta current_time) {
|
|
|
| if (state != kPrefetched) {
|
| DVLOG(0) << class_name() << "::" << __FUNCTION__ << ": wrong state "
|
| - << AsString(state) << " ignoring";
|
| + << AsString(state) << ", ignoring";
|
| return false;
|
| }
|
|
|
| @@ -266,11 +283,14 @@ void MediaCodecDecoder::SyncStop() {
|
|
|
| // After this method returns, decoder thread will not be running.
|
|
|
| + // Set [kInEmergencyStop| state to block already posted ProcessNextFrame().
|
| + SetState(kInEmergencyStop);
|
| +
|
| decoder_thread_.Stop(); // synchronous
|
| - state_ = kStopped;
|
|
|
| - // Shall we move |delayed_buffers_| from VideoDecoder to Decoder class?
|
| - ReleaseDelayedBuffers();
|
| + SetState(kStopped);
|
| +
|
| + ClearDelayedBuffers(true); // release prior to clearing |delayed_buffers_|.
|
| }
|
|
|
| void MediaCodecDecoder::RequestToStop() {
|
| @@ -310,7 +330,8 @@ void MediaCodecDecoder::OnLastFrameRendered(bool completed) {
|
| << " completed:" << completed;
|
|
|
| decoder_thread_.Stop(); // synchronous
|
| - state_ = kStopped;
|
| +
|
| + SetState(kStopped);
|
| completed_ = completed;
|
|
|
| media_task_runner_->PostTask(FROM_HERE, stop_done_cb_);
|
| @@ -330,10 +351,10 @@ void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) {
|
| : (aborted_data ? " skipped as aborted" : "");
|
|
|
| for (const auto& unit : data.access_units)
|
| - DVLOG(1) << class_name() << "::" << __FUNCTION__ << explain_if_skipped
|
| + DVLOG(2) << class_name() << "::" << __FUNCTION__ << explain_if_skipped
|
| << " au: " << unit;
|
| for (const auto& configs : data.demuxer_configs)
|
| - DVLOG(1) << class_name() << "::" << __FUNCTION__ << " configs: " << configs;
|
| + DVLOG(2) << class_name() << "::" << __FUNCTION__ << " configs: " << configs;
|
| #endif
|
|
|
| if (!is_incoming_data_invalid_ && !aborted_data)
|
| @@ -344,7 +365,7 @@ void MediaCodecDecoder::OnDemuxerDataAvailable(const DemuxerData& data) {
|
|
|
| // Do not request data if we got kAborted. There is no point to request the
|
| // data after kAborted and before the OnDemuxerSeekDone.
|
| - if (state_ == kPrefetching && !aborted_data)
|
| + if (GetState() == kPrefetching && !aborted_data)
|
| PrefetchNextChunk();
|
| }
|
|
|
| @@ -369,6 +390,14 @@ void MediaCodecDecoder::CheckLastFrame(bool eos_encountered,
|
| void MediaCodecDecoder::OnCodecError() {
|
| DCHECK(media_task_runner_->BelongsToCurrentThread());
|
|
|
| + // Ignore codec errors from the moment surface is changed till the
|
| + // |media_codec_bridge_| is deleted.
|
| + if (needs_reconfigure_) {
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__
|
| + << ": needs reconfigure, ignoring";
|
| + return;
|
| + }
|
| +
|
| SetState(kError);
|
| error_cb_.Run();
|
| }
|
| @@ -434,15 +463,8 @@ void MediaCodecDecoder::ProcessNextFrame() {
|
| if (!EnqueueInputBuffer())
|
| return;
|
|
|
| - bool eos_encountered = false;
|
| - if (!DepleteOutputBufferQueue(&eos_encountered))
|
| - return;
|
| -
|
| - if (eos_encountered) {
|
| - DVLOG(1) << class_name() << "::" << __FUNCTION__
|
| - << " EOS dequeued, stopping frame processing";
|
| + if (!DepleteOutputBufferQueue())
|
| return;
|
| - }
|
|
|
| // We need a small delay if we want to stop this thread by
|
| // decoder_thread_.Stop() reliably.
|
| @@ -566,7 +588,7 @@ bool MediaCodecDecoder::EnqueueInputBuffer() {
|
| }
|
|
|
| // Returns false if there was MediaCodec error.
|
| -bool MediaCodecDecoder::DepleteOutputBufferQueue(bool* eos_encountered) {
|
| +bool MediaCodecDecoder::DepleteOutputBufferQueue() {
|
| DCHECK(decoder_thread_.task_runner()->BelongsToCurrentThread());
|
|
|
| DVLOG(2) << class_name() << "::" << __FUNCTION__;
|
| @@ -576,6 +598,7 @@ bool MediaCodecDecoder::DepleteOutputBufferQueue(bool* eos_encountered) {
|
| size_t size = 0;
|
| base::TimeDelta pts;
|
| MediaCodecStatus status;
|
| + bool eos_encountered = false;
|
|
|
| base::TimeDelta timeout =
|
| base::TimeDelta::FromMilliseconds(kOutputBufferTimeout);
|
| @@ -585,7 +608,8 @@ bool MediaCodecDecoder::DepleteOutputBufferQueue(bool* eos_encountered) {
|
| // MEDIA_CODEC_OUTPUT_BUFFERS_CHANGED or MEDIA_CODEC_OUTPUT_FORMAT_CHANGED.
|
| do {
|
| status = media_codec_bridge_->DequeueOutputBuffer(
|
| - timeout, &buffer_index, &offset, &size, &pts, eos_encountered, nullptr);
|
| + timeout, &buffer_index, &offset, &size, &pts, &eos_encountered,
|
| + nullptr);
|
|
|
| // Reset the timeout to 0 for the subsequent DequeueOutputBuffer() calls
|
| // to quickly break the loop after we got all currently available buffers.
|
| @@ -604,7 +628,7 @@ bool MediaCodecDecoder::DepleteOutputBufferQueue(bool* eos_encountered) {
|
|
|
| case MEDIA_CODEC_OK:
|
| // We got the decoded frame
|
| - Render(buffer_index, size, true, pts, *eos_encountered);
|
| + Render(buffer_index, size, true, pts, eos_encountered);
|
| break;
|
|
|
| case MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER:
|
| @@ -623,9 +647,21 @@ bool MediaCodecDecoder::DepleteOutputBufferQueue(bool* eos_encountered) {
|
| }
|
|
|
| } while (status != MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER &&
|
| - status != MEDIA_CODEC_ERROR && !*eos_encountered);
|
| + status != MEDIA_CODEC_ERROR && !eos_encountered);
|
|
|
| - return status != MEDIA_CODEC_ERROR;
|
| + if (eos_encountered) {
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__
|
| + << " EOS dequeued, stopping frame processing";
|
| + return false;
|
| + }
|
| +
|
| + if (status == MEDIA_CODEC_ERROR) {
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__
|
| + << " MediaCodec error, stopping frame processing";
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| }
|
|
|
| MediaCodecDecoder::DecoderState MediaCodecDecoder::GetState() const {
|
| @@ -634,7 +670,7 @@ MediaCodecDecoder::DecoderState MediaCodecDecoder::GetState() const {
|
| }
|
|
|
| void MediaCodecDecoder::SetState(DecoderState state) {
|
| - DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << state;
|
| + DVLOG(1) << class_name() << "::" << __FUNCTION__ << " " << AsString(state);
|
|
|
| base::AutoLock lock(state_lock_);
|
| state_ = state;
|
| @@ -652,6 +688,7 @@ const char* MediaCodecDecoder::AsString(DecoderState state) {
|
| RETURN_STRING(kPrefetched);
|
| RETURN_STRING(kRunning);
|
| RETURN_STRING(kStopping);
|
| + RETURN_STRING(kInEmergencyStop);
|
| RETURN_STRING(kError);
|
| default:
|
| return "Unknown DecoderState";
|
|
|