Better handling of error condition in MediaCodecVideoEncoder.

BUG=b/36082499

Review-Url: https://codereview.webrtc.org/2748123002
Cr-Commit-Position: refs/heads/master@{#17246}
This commit is contained in:
sakal
2017-03-15 05:53:14 -07:00
committed by Commit bot
parent 8444405aa4
commit 996a83c4c8
3 changed files with 66 additions and 29 deletions

View File

@ -454,6 +454,7 @@ public class MediaCodecVideoEncoder {
this.type = type;
if (mediaCodec == null) {
Logging.e(TAG, "Can not create media encoder");
release();
return false;
}
mediaCodec.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
@ -471,6 +472,7 @@ public class MediaCodecVideoEncoder {
} catch (IllegalStateException e) {
Logging.e(TAG, "initEncode failed", e);
release();
return false;
}
return true;
@ -544,36 +546,47 @@ public class MediaCodecVideoEncoder {
Logging.d(TAG, "Java releaseEncoder");
checkOnMediaCodecThread();
// Run Mediacodec stop() and release() on separate thread since sometime
// Mediacodec.stop() may hang.
final CountDownLatch releaseDone = new CountDownLatch(1);
class CaughtException {
Exception e;
}
final CaughtException caughtException = new CaughtException();
boolean stopHung = false;
Runnable runMediaCodecRelease = new Runnable() {
@Override
public void run() {
try {
if (mediaCodec != null) {
// Run Mediacodec stop() and release() on separate thread since sometime
// Mediacodec.stop() may hang.
final CountDownLatch releaseDone = new CountDownLatch(1);
Runnable runMediaCodecRelease = new Runnable() {
@Override
public void run() {
Logging.d(TAG, "Java releaseEncoder on release thread");
mediaCodec.stop();
mediaCodec.release();
try {
mediaCodec.stop();
} catch (Exception e) {
Logging.e(TAG, "Media encoder stop failed", e);
}
try {
mediaCodec.release();
} catch (Exception e) {
Logging.e(TAG, "Media encoder release failed", e);
caughtException.e = e;
}
Logging.d(TAG, "Java releaseEncoder on release thread done");
} catch (Exception e) {
Logging.e(TAG, "Media encoder release failed", e);
}
releaseDone.countDown();
}
};
new Thread(runMediaCodecRelease).start();
if (!ThreadUtils.awaitUninterruptibly(releaseDone, MEDIA_CODEC_RELEASE_TIMEOUT_MS)) {
Logging.e(TAG, "Media encoder release timeout");
codecErrors++;
if (errorCallback != null) {
Logging.e(TAG, "Invoke codec error callback. Errors: " + codecErrors);
errorCallback.onMediaCodecVideoEncoderCriticalError(codecErrors);
releaseDone.countDown();
}
};
new Thread(runMediaCodecRelease).start();
if (!ThreadUtils.awaitUninterruptibly(releaseDone, MEDIA_CODEC_RELEASE_TIMEOUT_MS)) {
Logging.e(TAG, "Media encoder release timeout");
stopHung = true;
}
mediaCodec = null;
}
mediaCodec = null;
mediaCodecThread = null;
if (drawer != null) {
drawer.release();
@ -588,6 +601,25 @@ public class MediaCodecVideoEncoder {
inputSurface = null;
}
runningInstance = null;
if (stopHung) {
codecErrors++;
if (errorCallback != null) {
Logging.e(TAG, "Invoke codec error callback. Errors: " + codecErrors);
errorCallback.onMediaCodecVideoEncoderCriticalError(codecErrors);
}
throw new RuntimeException("Media encoder release timeout.");
}
// Re-throw any runtime exception caught inside the other thread. Since this is an invoke, add
// stack trace for the waiting thread as well.
if (caughtException.e != null) {
final RuntimeException runtimeException = new RuntimeException(caughtException.e);
runtimeException.setStackTrace(ThreadUtils.concatStackTraces(
caughtException.e.getStackTrace(), runtimeException.getStackTrace()));
throw runtimeException;
}
Logging.d(TAG, "Java releaseEncoder done");
}