From eeab938d2c935fcf54eabdf2f629346acde01113 Mon Sep 17 00:00:00 2001 From: peak3d Date: Tue, 2 Jun 2020 19:32:17 +0200 Subject: [PATCH] [Backport][Android] More exception handling in MediaCodec --- .../Video/DVDVideoCodecAndroidMediaCodec.cpp | 79 ++++++++++++++++--- 1 file changed, 68 insertions(+), 11 deletions(-) diff --git a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp index 362782f500b8c..e4661e33977f6 100644 --- a/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp +++ b/xbmc/cores/VideoPlayer/DVDCodecs/Video/DVDVideoCodecAndroidMediaCodec.cpp @@ -788,7 +788,9 @@ void CDVDVideoCodecAndroidMediaCodec::Dispose() if (m_codec) { m_codec->stop(); + xbmc_jnienv()->ExceptionClear(); m_codec->release(); + xbmc_jnienv()->ExceptionClear(); m_codec = nullptr; m_state = MEDIACODEC_STATE_STOPPED; } @@ -833,6 +835,12 @@ bool CDVDVideoCodecAndroidMediaCodec::AddData(const DemuxPacket &packet) // We received a packet but already reached EOS. Flush... FlushInternal(); m_codec->flush(); + if (xbmc_jnienv()->ExceptionCheck()) + { + xbmc_jnienv()->ExceptionClear(); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::AddData: flush failed"); + return false; + } m_state = MEDIACODEC_STATE_FLUSHED; } @@ -874,10 +882,17 @@ bool CDVDVideoCodecAndroidMediaCodec::AddData(const DemuxPacket &packet) m_state = MEDIACODEC_STATE_RUNNING; CJNIByteBuffer buffer = m_codec->getInputBuffer(m_indexInputBuffer); + if (xbmc_jnienv()->ExceptionCheck()) + { + xbmc_jnienv()->ExceptionClear(); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::AddData: getInputBuffer failed"); + return false; + } + size_t out_size = buffer.capacity(); if ((size_t)iSize > out_size) { - CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::AddData, iSize(%d) > size(%d)", iSize, out_size); + CLog::Log(LOGNOTICE, "CDVDVideoCodecAndroidMediaCodec::AddData: iSize(%d) > size(%d)", iSize, out_size); iSize = out_size; } uint8_t* dst_ptr = (uint8_t*)xbmc_jnienv()->GetDirectBufferAddress(buffer.get_raw()); @@ -960,7 +975,6 @@ bool CDVDVideoCodecAndroidMediaCodec::AddData(const DemuxPacket &packet) } if (xbmc_jnienv()->ExceptionCheck()) { - xbmc_jnienv()->ExceptionDescribe(); xbmc_jnienv()->ExceptionClear(); CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::AddData error"); } @@ -987,10 +1001,22 @@ void CDVDVideoCodecAndroidMediaCodec::Reset() // now we can flush the actual MediaCodec object CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec::Reset Current state (%d)", m_state); m_state = MEDIACODEC_STATE_FLUSHED; + m_codec->flush(); + if (xbmc_jnienv()->ExceptionCheck()) + { + xbmc_jnienv()->ExceptionClear(); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Reset: flush failed"); + } CJNIMediaFormat mediaFormat = m_codec->getOutputFormat(); - InjectExtraData(mediaFormat); + if (xbmc_jnienv()->ExceptionCheck()) + { + xbmc_jnienv()->ExceptionClear(); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::Reset: getOutputFormat failed"); + } + else + InjectExtraData(mediaFormat); // Invalidate our local VideoPicture bits m_videobuffer.pts = DVD_NOPTS_VALUE; @@ -1010,7 +1036,7 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecAndroidMediaCodec::GetPicture(VideoPictur if (!m_opened) return VC_NONE; - if (m_OutputDuration < m_fpsDuration || (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)!=0) + if (m_state == MEDIACODEC_STATE_RUNNING && (m_OutputDuration < m_fpsDuration || (m_codecControlFlags & DVD_CODEC_CTRL_DRAIN)!=0)) { m_videobuffer.videoBuffer = pVideoPicture->videoBuffer; @@ -1049,7 +1075,15 @@ CDVDVideoCodec::VCReturn CDVDVideoCodecAndroidMediaCodec::GetPicture(VideoPictur { // try to fetch an input buffer if (m_indexInputBuffer < 0) + { m_indexInputBuffer = m_codec->dequeueInputBuffer(5000 /*timout*/); + if (xbmc_jnienv()->ExceptionCheck()) + { + xbmc_jnienv()->ExceptionClear(); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::GetPicture dequeueInputBuffer failed"); + m_indexInputBuffer = -1; + } + } if (m_indexInputBuffer >= 0) { @@ -1096,7 +1130,15 @@ void CDVDVideoCodecAndroidMediaCodec::SignalEndOfStream() } if (m_indexInputBuffer < 0) + { m_indexInputBuffer = m_codec->dequeueInputBuffer(100000); + if (xbmc_jnienv()->ExceptionCheck()) + { + xbmc_jnienv()->ExceptionClear(); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::SignalEndOfStream: dequeueInputBuffer failed"); + } + } + xbmc_jnienv()->ExceptionClear(); if (m_indexInputBuffer >= 0) @@ -1106,8 +1148,7 @@ void CDVDVideoCodecAndroidMediaCodec::SignalEndOfStream() if (xbmc_jnienv()->ExceptionCheck()) { xbmc_jnienv()->ExceptionClear(); - CLog::Log(LOGWARNING, "CDVDVideoCodecAndroidMediaCodec::%s: queueInputBuffer failed", - __func__); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::SignalEndOfStream: queueInputBuffer failed"); } else { @@ -1186,22 +1227,20 @@ bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void) int flags = 0; m_codec->configure(mediaformat, m_jnivideosurface, m_crypto ? *m_crypto : CJNIMediaCrypto(jni::jhobject(NULL)), flags); - if (xbmc_jnienv()->ExceptionCheck()) { xbmc_jnienv()->ExceptionClear(); - CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec configure error"); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec: configure failed"); return false; } m_state = MEDIACODEC_STATE_CONFIGURED; m_codec->start(); - if (xbmc_jnienv()->ExceptionCheck()) { xbmc_jnienv()->ExceptionClear(); Dispose(); - CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec start error"); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec:ConfigureMediaCodec: start failed"); return false; } m_state = MEDIACODEC_STATE_FLUSHED; @@ -1216,10 +1255,17 @@ bool CDVDVideoCodecAndroidMediaCodec::ConfigureMediaCodec(void) int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void) { int rtn = 0; - int64_t timeout_us = 10000; CJNIMediaCodecBufferInfo bufferInfo; + ssize_t index = m_codec->dequeueOutputBuffer(bufferInfo, timeout_us); + if (xbmc_jnienv()->ExceptionCheck()) + { + xbmc_jnienv()->ExceptionClear(); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec:GetOutputPicture dequeueOutputBuffer failed"); + return -2; + } + if (index >= 0) { int64_t pts = bufferInfo.presentationTimeUs(); @@ -1238,6 +1284,11 @@ int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void) { m_noPictureLoop = 0; m_codec->releaseOutputBuffer(index, false); + if (xbmc_jnienv()->ExceptionCheck()) + { + xbmc_jnienv()->ExceptionClear(); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture: releaseOutputBuffer (drop) failed"); + } return -2; } @@ -1246,6 +1297,11 @@ int CDVDVideoCodecAndroidMediaCodec::GetOutputPicture(void) { CLog::Log(LOGDEBUG, "CDVDVideoCodecAndroidMediaCodec:: BUFFER_FLAG_END_OF_STREAM"); m_codec->releaseOutputBuffer(index, false); + if (xbmc_jnienv()->ExceptionCheck()) + { + xbmc_jnienv()->ExceptionClear(); + CLog::Log(LOGERROR, "CDVDVideoCodecAndroidMediaCodec::GetOutputPicture: releaseOutputBuffer (eof) failed"); + } return -1; } @@ -1456,5 +1512,6 @@ void CDVDVideoCodecAndroidMediaCodec::surfaceDestroyed(CJNISurfaceHolder holder) if (m_jnisurface) m_jnisurface->release(); m_codec->stop(); + xbmc_jnienv()->ExceptionClear(); } }