Index: talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java |
diff --git a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java |
index 4809cf65b29b13d7d59b0bf623b4b657f489a7c6..7221a36190efed15b3605b2adc2a40280fba84da 100644 |
--- a/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java |
+++ b/talk/app/webrtc/java/src/org/webrtc/MediaCodecVideoDecoder.java |
@@ -42,6 +42,8 @@ import android.view.Surface; |
import org.webrtc.Logging; |
import java.nio.ByteBuffer; |
+import java.util.List; |
+import java.util.Arrays; |
// Java-side of peerconnection_jni.cc:MediaCodecVideoDecoder. |
// This class is an implementation detail of the Java PeerConnection API. |
@@ -80,19 +82,18 @@ public class MediaCodecVideoDecoder { |
private static final int |
COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m = 0x7FA30C04; |
// Allowable color formats supported by codec - in order of preference. |
- private static final int[] supportedColorList = { |
+ private static final List<Integer> supportedColorList = Arrays.asList( |
CodecCapabilities.COLOR_FormatYUV420Planar, |
CodecCapabilities.COLOR_FormatYUV420SemiPlanar, |
CodecCapabilities.COLOR_QCOM_FormatYUV420SemiPlanar, |
- COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m |
- }; |
+ COLOR_QCOM_FORMATYUV420PackedSemiPlanar32m); |
private int colorFormat; |
private int width; |
private int height; |
private int stride; |
private int sliceHeight; |
private boolean useSurface; |
- private int textureID = -1; |
+ private int textureID = 0; |
private SurfaceTexture surfaceTexture = null; |
private Surface surface = null; |
private EglBase eglBase; |
@@ -171,9 +172,9 @@ public class MediaCodecVideoDecoder { |
return findDecoder(H264_MIME_TYPE, supportedH264HwCodecPrefixes) != null; |
} |
- private void checkOnMediaCodecThread() { |
+ private void checkOnMediaCodecThread() throws IllegalStateException { |
if (mediaCodecThread.getId() != Thread.currentThread().getId()) { |
- throw new RuntimeException( |
+ throw new IllegalStateException( |
"MediaCodecVideoDecoder previously operated on " + mediaCodecThread + |
" but is now called on " + Thread.currentThread()); |
} |
@@ -208,7 +209,6 @@ public class MediaCodecVideoDecoder { |
} |
mediaCodecThread = Thread.currentThread(); |
try { |
- Surface decodeSurface = null; |
this.width = width; |
this.height = height; |
stride = width; |
@@ -225,7 +225,6 @@ public class MediaCodecVideoDecoder { |
Logging.d(TAG, "Video decoder TextureID = " + textureID); |
surfaceTexture = new SurfaceTexture(textureID); |
surface = new Surface(surfaceTexture); |
- decodeSurface = surface; |
} |
MediaFormat format = MediaFormat.createVideoFormat(mime, width, height); |
@@ -238,7 +237,7 @@ public class MediaCodecVideoDecoder { |
if (mediaCodec == null) { |
return false; |
} |
- mediaCodec.configure(format, decodeSurface, null, 0); |
+ mediaCodec.configure(format, surface, null, 0); |
mediaCodec.start(); |
colorFormat = properties.colorFormat; |
outputBuffers = mediaCodec.getOutputBuffers(); |
@@ -265,11 +264,10 @@ public class MediaCodecVideoDecoder { |
mediaCodecThread = null; |
if (useSurface) { |
surface.release(); |
- if (textureID != 0) { |
- Logging.d(TAG, "Delete video decoder TextureID " + textureID); |
- GLES20.glDeleteTextures(1, new int[] {textureID}, 0); |
- textureID = 0; |
- } |
+ surface = null; |
+ Logging.d(TAG, "Delete video decoder TextureID " + textureID); |
+ GLES20.glDeleteTextures(1, new int[] {textureID}, 0); |
+ textureID = 0; |
eglBase.release(); |
eglBase = null; |
} |
@@ -318,19 +316,26 @@ public class MediaCodecVideoDecoder { |
private final long presentationTimestampUs; |
} |
- // Dequeue and return an output buffer index, -1 if no output |
- // buffer available or -2 if error happened. |
- private DecoderOutputBufferInfo dequeueOutputBuffer(int dequeueTimeoutUs) { |
+ // Dequeue and return a DecoderOutputBufferInfo, or null if no decoded buffer is ready. |
+ // Throws IllegalStateException if call is made on the wrong thread, if color format changes to an |
+ // unsupported format, or if |mediaCodec| is not in the Executing state. Throws CodecException |
+ // upon codec error. |
+ private DecoderOutputBufferInfo dequeueOutputBuffer(int dequeueTimeoutUs) |
+ throws IllegalStateException, MediaCodec.CodecException { |
checkOnMediaCodecThread(); |
- try { |
- MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); |
- int result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs); |
- while (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED || |
- result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
- if (result == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { |
+ // Drain the decoder until receiving a decoded buffer or hitting |
+ // MediaCodec.INFO_TRY_AGAIN_LATER. |
+ final MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); |
+ while (true) { |
+ final int result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs); |
+ switch (result) { |
+ case MediaCodec.INFO_TRY_AGAIN_LATER: |
+ return null; |
+ case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED: |
outputBuffers = mediaCodec.getOutputBuffers(); |
Logging.d(TAG, "Decoder output buffers changed: " + outputBuffers.length); |
- } else if (result == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { |
+ break; |
+ case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED: |
MediaFormat format = mediaCodec.getOutputFormat(); |
Logging.d(TAG, "Decoder format changed: " + format.toString()); |
width = format.getInteger(MediaFormat.KEY_WIDTH); |
@@ -338,17 +343,8 @@ public class MediaCodecVideoDecoder { |
if (!useSurface && format.containsKey(MediaFormat.KEY_COLOR_FORMAT)) { |
colorFormat = format.getInteger(MediaFormat.KEY_COLOR_FORMAT); |
Logging.d(TAG, "Color: 0x" + Integer.toHexString(colorFormat)); |
- // Check if new color space is supported. |
- boolean validColorFormat = false; |
- for (int supportedColorFormat : supportedColorList) { |
- if (colorFormat == supportedColorFormat) { |
- validColorFormat = true; |
- break; |
- } |
- } |
- if (!validColorFormat) { |
- Logging.e(TAG, "Non supported color format"); |
- return new DecoderOutputBufferInfo(-1, 0, 0, -1); |
+ if (!supportedColorList.contains(colorFormat)) { |
+ throw new IllegalStateException("Non supported color format: " + colorFormat); |
} |
} |
if (format.containsKey("stride")) { |
@@ -357,34 +353,24 @@ public class MediaCodecVideoDecoder { |
if (format.containsKey("slice-height")) { |
sliceHeight = format.getInteger("slice-height"); |
} |
- Logging.d(TAG, "Frame stride and slice height: " |
- + stride + " x " + sliceHeight); |
+ Logging.d(TAG, "Frame stride and slice height: " + stride + " x " + sliceHeight); |
stride = Math.max(width, stride); |
sliceHeight = Math.max(height, sliceHeight); |
- } |
- result = mediaCodec.dequeueOutputBuffer(info, dequeueTimeoutUs); |
- } |
- if (result >= 0) { |
- return new DecoderOutputBufferInfo(result, info.offset, info.size, |
- info.presentationTimeUs); |
+ break; |
+ default: |
+ // Output buffer decoded. |
+ return new DecoderOutputBufferInfo( |
+ result, info.offset, info.size, info.presentationTimeUs); |
} |
- return null; |
- } catch (IllegalStateException e) { |
- Logging.e(TAG, "dequeueOutputBuffer failed", e); |
- return new DecoderOutputBufferInfo(-1, 0, 0, -1); |
} |
} |
- // Release a dequeued output buffer back to the codec for re-use. Return |
- // false if the codec is no longer operable. |
- private boolean releaseOutputBuffer(int index) { |
+ // Release a dequeued output buffer back to the codec for re-use. |
+ // Throws IllegalStateException if the call is made on the wrong thread or if |mediaCodec| is not |
+ // in the Executing state. Throws MediaCodec.CodecException upon codec error. |
+ private void releaseOutputBuffer(int index) |
+ throws IllegalStateException, MediaCodec.CodecException { |
checkOnMediaCodecThread(); |
- try { |
- mediaCodec.releaseOutputBuffer(index, useSurface); |
- return true; |
- } catch (IllegalStateException e) { |
- Logging.e(TAG, "releaseOutputBuffer failed", e); |
- return false; |
- } |
+ mediaCodec.releaseOutputBuffer(index, useSurface); |
} |
} |