Added more MediaCodec tests
The MediaCodecTest methods test various API edge cases.
Also, fixed file permissions on MediaCodecListTest.java, and reduced
import lists on existing tests.
Bug 7991062
Change-Id: I777cbeef428e5e7aabf4ce65094a2320c1e55c07
diff --git a/tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java b/tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java
index 23c10a5..cfa0cc3 100644
--- a/tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java
+++ b/tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java
@@ -16,16 +16,11 @@
package android.media.cts;
-import android.graphics.SurfaceTexture;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
-import android.opengl.EGL14;
import android.opengl.GLES20;
-import android.opengl.GLES11Ext;
-import android.opengl.GLSurfaceView;
-import android.opengl.Matrix;
import android.test.AndroidTestCase;
import android.util.Log;
import android.view.Surface;
@@ -35,17 +30,9 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
import java.util.ArrayList;
import java.util.Arrays;
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.egl.EGLSurface;
-import javax.microedition.khronos.opengles.GL;
import javax.microedition.khronos.opengles.GL10;
diff --git a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java b/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
index 5b9c37e..37a3ffd 100644
--- a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
@@ -29,8 +29,6 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
import java.util.Arrays;
import javax.microedition.khronos.opengles.GL10;
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
old mode 100755
new mode 100644
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
new file mode 100644
index 0000000..7f678b8
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import android.media.MediaCodec;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecList;
+import android.media.MediaFormat;
+import android.opengl.GLES20;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import android.view.Surface;
+
+
+/**
+ * General MediaCodec tests.
+ *
+ * In particular, check various API edge cases.
+ */
+public class MediaCodecTest extends AndroidTestCase {
+ private static final String TAG = "MediaCodecTest";
+ private static final boolean VERBOSE = false; // lots of logging
+
+ // parameters for the encoder
+ private static final String MIME_TYPE = "video/avc"; // H.264 Advanced Video Coding
+ private static final int BIT_RATE = 2000000; // 2Mbps
+ private static final int FRAME_RATE = 15; // 15fps
+ private static final int IFRAME_INTERVAL = 10; // 10 seconds between I-frames
+ private static final int WIDTH = 1280;
+ private static final int HEIGHT = 720;
+
+ /**
+ * Tests:
+ * <br> calling createInputSurface() before configure() throws exception
+ * <br> calling createInputSurface() after start() throws exception
+ * <br> calling createInputSurface() with a non-AndroidOpaque color format throws exception
+ */
+ public void testCreateInputSurfaceErrors() {
+ MediaFormat format = createMediaFormat();
+ MediaCodec encoder = null;
+ Surface surface = null;
+
+ // Replace color format with something that isn't COLOR_FormatAndroidOpaque.
+ MediaCodecInfo codecInfo = selectCodec(MIME_TYPE);
+ int colorFormat = findNonAndroidOpaqueColorFormat(codecInfo, MIME_TYPE);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
+
+ try {
+ encoder = MediaCodec.createByCodecName(codecInfo.getName());;
+ try {
+ surface = encoder.createInputSurface();
+ fail("createInputSurface should not work pre-configure");
+ } catch (IllegalStateException ise) {
+ // good
+ }
+ encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+
+ try {
+ surface = encoder.createInputSurface();
+ fail("createInputSurface should require AndroidOpaque");
+ } catch (IllegalStateException ise) {
+ // good
+ }
+
+ encoder.start();
+
+ try {
+ surface = encoder.createInputSurface();
+ fail("createInputSurface should not work post-start");
+ } catch (IllegalStateException ise) {
+ // good
+ }
+ } finally {
+ if (encoder != null) {
+ encoder.stop();
+ encoder.release();
+ }
+ }
+ assertNull(surface);
+ }
+
+
+ /**
+ * Tests:
+ * <br> signaling end-of-stream before any data is sent works
+ * <br> signaling EOS twice throws exception
+ * <br> submitting a frame after EOS throws exception [TODO]
+ */
+ public void testSignalSurfaceEOS() {
+ MediaFormat format = createMediaFormat();
+ MediaCodec encoder = null;
+ InputSurface inputSurface = null;
+
+ try {
+ encoder = MediaCodec.createEncoderByType(MIME_TYPE);
+ encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ inputSurface = new InputSurface(encoder.createInputSurface());
+ inputSurface.makeCurrent();
+ encoder.start();
+
+ // send an immediate EOS
+ encoder.signalEndOfInputStream();
+
+ try {
+ encoder.signalEndOfInputStream();
+ fail("should not be able to signal EOS twice");
+ } catch (IllegalStateException ise) {
+ // good
+ }
+
+ // submit a frame post-EOS
+ GLES20.glClearColor(0.0f, 0.5f, 0.0f, 1.0f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
+ try {
+ inputSurface.swapBuffers();
+ if (false) { // TODO
+ fail("should not be able to submit frame after EOS");
+ }
+ } catch (Exception ex) {
+ // good
+ }
+ } finally {
+ if (encoder != null) {
+ encoder.stop();
+ encoder.release();
+ }
+ if (inputSurface != null) {
+ inputSurface.release();
+ }
+ }
+ }
+
+ /**
+ * Tests:
+ * <br> dequeueInputBuffer() fails when encoder configured with an input Surface
+ */
+ public void testDequeueSurface() {
+ MediaFormat format = createMediaFormat();
+ MediaCodec encoder = null;
+ Surface surface = null;
+
+ try {
+ encoder = MediaCodec.createEncoderByType(MIME_TYPE);
+ encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ surface = encoder.createInputSurface();
+ encoder.start();
+
+ try {
+ encoder.dequeueInputBuffer(-1);
+ fail("dequeueInputBuffer should fail on encoder with input surface");
+ } catch (IllegalStateException ise) {
+ // good
+ }
+
+ } finally {
+ if (encoder != null) {
+ encoder.stop();
+ encoder.release();
+ }
+ if (surface != null) {
+ surface.release();
+ }
+ }
+ }
+
+ /**
+ * Tests:
+ * <br> configure() encoder with Surface, re-configure() without Surface works
+ * <br> sending EOS with signalEndOfInputStream on non-Surface encoder fails
+ */
+ public void testReconfigureWithoutSurface() {
+ MediaFormat format = createMediaFormat();
+ MediaCodec encoder = null;
+ Surface surface = null;
+
+ try {
+ encoder = MediaCodec.createEncoderByType(MIME_TYPE);
+ encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ surface = encoder.createInputSurface();
+ encoder.start();
+
+ encoder.getOutputBuffers();
+
+ // re-configure, this time without an input surface
+ if (VERBOSE) Log.d(TAG, "reconfiguring");
+ encoder.stop();
+ encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ encoder.start();
+ if (VERBOSE) Log.d(TAG, "reconfigured");
+
+ encoder.getOutputBuffers();
+ encoder.dequeueInputBuffer(-1);
+
+ try {
+ encoder.signalEndOfInputStream();
+ fail("signalEndOfInputStream only works on surface input");
+ } catch (IllegalStateException ise) {
+ // good
+ }
+ } finally {
+ if (encoder != null) {
+ encoder.stop();
+ encoder.release();
+ }
+ if (surface != null) {
+ surface.release();
+ }
+ }
+ }
+
+ /**
+ * Creates a MediaFormat with the basic set of values.
+ */
+ private static MediaFormat createMediaFormat() {
+ MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, WIDTH, HEIGHT);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
+ MediaCodecInfo.CodecCapabilities.COLOR_FormatAndroidOpaque);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
+ format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
+ return format;
+ }
+
+ /**
+ * Returns the first codec capable of encoding the specified MIME type, or null if no
+ * match was found.
+ */
+ private static MediaCodecInfo selectCodec(String mimeType) {
+ int numCodecs = MediaCodecList.getCodecCount();
+ for (int i = 0; i < numCodecs; i++) {
+ MediaCodecInfo codecInfo = MediaCodecList.getCodecInfoAt(i);
+
+ if (!codecInfo.isEncoder()) {
+ continue;
+ }
+
+ String[] types = codecInfo.getSupportedTypes();
+ for (int j = 0; j < types.length; j++) {
+ if (types[j].equalsIgnoreCase(mimeType)) {
+ return codecInfo;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a color format that is supported by the codec and isn't AndroidOpaque. Throws
+ * an exception if none found.
+ */
+ private static int findNonAndroidOpaqueColorFormat(MediaCodecInfo codecInfo, String mimeType) {
+ MediaCodecInfo.CodecCapabilities capabilities = codecInfo.getCapabilitiesForType(mimeType);
+ for (int i = 0; i < capabilities.colorFormats.length; i++) {
+ int colorFormat = capabilities.colorFormats[i];
+ if (colorFormat != MediaCodecInfo.CodecCapabilities.COLOR_FormatAndroidOpaque) {
+ return colorFormat;
+ }
+ }
+ fail("couldn't find a good color format for " + codecInfo.getName() + " / " + MIME_TYPE);
+ return 0; // not reached
+ }
+}