| Index: talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java
|
| diff --git a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java
|
| index f3f03c1d20c0dab4d5aa749c690ed2558040a82b..576537bd8e51488c83ec031ee3117c0b2e18721a 100644
|
| --- a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java
|
| +++ b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoEncoder.java
|
| @@ -40,6 +40,7 @@ import org.webrtc.Logging;
|
| import java.nio.ByteBuffer;
|
| import java.util.Arrays;
|
| import java.util.List;
|
| +import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
| // Java-side of peerconnection_jni.cc:MediaCodecVideoEncoder.
|
| // This class is an implementation detail of the Java PeerConnection API.
|
| @@ -60,10 +61,14 @@ public class MediaCodecVideoEncoder {
|
| VIDEO_CODEC_H264
|
| }
|
|
|
| + private static final int MEDIA_CODEC_RELEASE_TIMEOUT_MS = 5000; // Timeout for codec releasing.
|
| private static final int DEQUEUE_TIMEOUT = 0; // Non-blocking, no wait.
|
| // Active running encoder instance. Set in initDecode() (called from native code)
|
| // and reset to null in release() call.
|
| private static MediaCodecVideoEncoder runningInstance = null;
|
| + private static MediaCodecVideoEncoderErrorCallback errorCallback = null;
|
| + private static int codecErrors = 0;
|
| +
|
| private Thread mediaCodecThread;
|
| private MediaCodec mediaCodec;
|
| private ByteBuffer[] outputBuffers;
|
| @@ -108,6 +113,17 @@ public class MediaCodecVideoEncoder {
|
| private MediaCodecVideoEncoder() {
|
| }
|
|
|
| + // MediaCodec error handler - invoked when critical error happens
|
| + // which prevents further use of media codec API.
|
| + public static interface MediaCodecVideoEncoderErrorCallback {
|
| + void onMediaCodecVideoEncoderError(int codecErrors);
|
| + }
|
| +
|
| + public static void setErrorCallback(MediaCodecVideoEncoderErrorCallback errorCallback) {
|
| + Logging.d(TAG, "Set error callback");
|
| + MediaCodecVideoEncoder.errorCallback = errorCallback;
|
| + }
|
| +
|
| // Helper struct for findHwEncoder() below.
|
| private static class EncoderProperties {
|
| public EncoderProperties(String codecName, int colorFormat) {
|
| @@ -130,8 +146,7 @@ public class MediaCodecVideoEncoder {
|
| if (mime.equals(H264_MIME_TYPE)) {
|
| List<String> exceptionModels = Arrays.asList(H264_HW_EXCEPTION_MODELS);
|
| if (exceptionModels.contains(Build.MODEL)) {
|
| - Logging.w(TAG, "Model: " + Build.MODEL +
|
| - " has black listed H.264 encoder.");
|
| + Logging.w(TAG, "Model: " + Build.MODEL + " has black listed H.264 encoder.");
|
| return null;
|
| }
|
| }
|
| @@ -306,12 +321,48 @@ public class MediaCodecVideoEncoder {
|
| private void release() {
|
| Logging.d(TAG, "Java releaseEncoder");
|
| checkOnMediaCodecThread();
|
| - try {
|
| - mediaCodec.stop();
|
| - mediaCodec.release();
|
| - } catch (IllegalStateException e) {
|
| - Logging.e(TAG, "release failed", e);
|
| +
|
| + // Run Mediacodec stop() and release() on separate thread since sometime
|
| + // Mediacodec.stop() may hang.
|
| + final AtomicBoolean releaseDone = new AtomicBoolean(false);
|
| +
|
| + Runnable runMediaCodecRelease = new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + try {
|
| + Logging.d(TAG, "Java releaseEncoder on release thread");
|
| + mediaCodec.stop();
|
| + mediaCodec.release();
|
| + Logging.d(TAG, "Java releaseEncoder on release thread done");
|
| + } catch (Exception e) {
|
| + Logging.e(TAG, "Media encoder release failed", e);
|
| + }
|
| + synchronized (releaseDone) {
|
| + releaseDone.set(true);
|
| + releaseDone.notifyAll();
|
| + }
|
| + }
|
| + };
|
| + new Thread(runMediaCodecRelease).start();
|
| +
|
| + if (!releaseDone.get()) {
|
| + synchronized(releaseDone) {
|
| + try {
|
| + releaseDone.wait(MEDIA_CODEC_RELEASE_TIMEOUT_MS);
|
| + } catch (InterruptedException e) {
|
| + Logging.e(TAG, "Wait exception.", e);
|
| + }
|
| + }
|
| + }
|
| + if (!releaseDone.get()) {
|
| + Logging.e(TAG, "Media encoder release timeout");
|
| + codecErrors++;
|
| + if (errorCallback != null) {
|
| + Logging.e(TAG, "Invoke codec error callback. Errors: " + codecErrors);
|
| + errorCallback.onMediaCodecVideoEncoderError(codecErrors);
|
| + }
|
| }
|
| +
|
| mediaCodec = null;
|
| mediaCodecThread = null;
|
| runningInstance = null;
|
|
|