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
+    }
+}