media: update MediaCodecList test to use new API

Bug: 15141324
Change-Id: I66fc118ed396ca5920a0fc7df9c0bf11e61a9e67
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
index d8a20e9..865780e 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
@@ -16,24 +16,38 @@
 
 package android.media.cts;
 
-
+import android.content.pm.PackageManager;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecInfo.CodecProfileLevel;
 import android.media.MediaCodecInfo.CodecCapabilities;
+import android.media.MediaCodecInfo.AudioCapabilities;
+import android.media.MediaCodecInfo.VideoCapabilities;
+import android.media.MediaCodecInfo.EncoderCapabilities;
 import android.media.MediaCodecList;
+import android.media.MediaFormat;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.List;
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 
 public class MediaCodecListTest extends AndroidTestCase {
 
     private static final String TAG = "MediaCodecListTest";
     private static final String MEDIA_CODEC_XML_FILE = "/etc/media_codecs.xml";
+    private final MediaCodecList mRegularCodecs =
+            new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+    private final MediaCodecList mAllCodecs =
+            new MediaCodecList(MediaCodecList.ALL_CODECS);
+    private final MediaCodecInfo[] mRegularInfos =
+            mRegularCodecs.getCodecInfos();
+    private final MediaCodecInfo[] mAllInfos =
+            mAllCodecs.getCodecInfos();
 
     class CodecType {
         CodecType(String type, boolean isEncoder) {
@@ -55,55 +69,120 @@
         assertTrue("/etc/media_codecs.xml does not exist", file.exists());
     }
 
-    // Each component advertised by MediaCodecList should at least be
-    // instantiate-able.
-    public void testComponentInstantiation() throws IOException {
-        Log.d(TAG, "testComponentInstantiation");
+    private MediaCodecInfo[] getLegacyInfos() {
+        Log.d(TAG, "getLegacyInfos");
 
         int codecCount = MediaCodecList.getCodecCount();
-        for (int i = 0; i < codecCount; ++i) {
-            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
+        MediaCodecInfo[] res = new MediaCodecInfo[codecCount];
 
-            Log.d(TAG, (i + 1) + ": " + info.getName());
+        for (int i = 0; i < codecCount; ++i) {
+            res[i] = MediaCodecList.getCodecInfoAt(i);
+        }
+        return res;
+    }
+
+    public void assertEqualsOrSuperset(Set big, Set tiny, boolean superset) {
+        if (!superset) {
+            assertEquals(big, tiny);
+        } else {
+            assertTrue(big.containsAll(tiny));
+        }
+    }
+
+    private static <T> Set<T> asSet(T[] array) {
+        Set<T> s = new HashSet<T>();
+        for (T el : array) {
+            s.add(el);
+        }
+        return s;
+    }
+
+    private static Set<Integer> asSet(int[] array) {
+        Set<Integer> s = new HashSet<Integer>();
+        for (int el : array) {
+            s.add(el);
+        }
+        return s;
+    }
+
+    public void assertEqualsOrSuperset(
+            CodecCapabilities big, CodecCapabilities tiny, boolean superset) {
+        // ordering of enumerations may differ
+        assertEqualsOrSuperset(asSet(big.colorFormats), asSet(tiny.colorFormats), superset);
+        assertEqualsOrSuperset(asSet(big.profileLevels), asSet(tiny.profileLevels), superset);
+        AudioCapabilities bigAudCaps = big.getAudioCapabilities();
+        VideoCapabilities bigVidCaps = big.getVideoCapabilities();
+        EncoderCapabilities bigEncCaps = big.getEncoderCapabilities();
+        AudioCapabilities tinyAudCaps = tiny.getAudioCapabilities();
+        VideoCapabilities tinyVidCaps = tiny.getVideoCapabilities();
+        EncoderCapabilities tinyEncCaps = tiny.getEncoderCapabilities();
+        assertEquals(bigAudCaps != null, tinyAudCaps != null);
+        assertEquals(bigAudCaps != null, tinyAudCaps != null);
+        assertEquals(bigAudCaps != null, tinyAudCaps != null);
+    }
+
+    public void assertEqualsOrSuperset(
+            MediaCodecInfo big, MediaCodecInfo tiny, boolean superset) {
+        assertEquals(big.getName(), tiny.getName());
+        assertEquals(big.isEncoder(), tiny.isEncoder());
+        assertEqualsOrSuperset(
+                asSet(big.getSupportedTypes()), asSet(tiny.getSupportedTypes()), superset);
+        for (String type : big.getSupportedTypes()) {
+            assertEqualsOrSuperset(
+                    big.getCapabilitiesForType(type),
+                    tiny.getCapabilitiesForType(type),
+                    superset);
+        }
+    }
+
+    public void assertSuperset(MediaCodecInfo big, MediaCodecInfo tiny) {
+        assertEqualsOrSuperset(big, tiny, true /* superset */);
+    }
+
+    public void assertEquals(MediaCodecInfo big, MediaCodecInfo tiny) {
+        assertEqualsOrSuperset(big, tiny, false /* superset */);
+    }
+
+    // Each component advertised by MediaCodecList should at least be
+    // instantiable.
+    private void testComponentInstantiation(MediaCodecInfo[] infos) throws IOException {
+        for (MediaCodecInfo info : infos) {
+            Log.d(TAG, "codec: " + info.getName());
             Log.d(TAG, "  isEncoder = " + info.isEncoder());
 
-            if (!info.getName().startsWith("OMX.")) {
-                // Unfortunately for legacy reasons, "AACEncoder", a
-                // non OMX component had to be in this list for the video
-                // editor code to work... but it cannot actually be instantiated
-                // using MediaCodec.
-                Log.d(TAG, "  skipping...");
-                continue;
-            }
-
             MediaCodec codec = MediaCodec.createByCodecName(info.getName());
 
+            assertEquals(codec.getName(), info.getName());
+
+            assertEquals(codec.getCodecInfo(), info);
+
             codec.release();
             codec = null;
         }
     }
 
+    public void testRegularComponentInstantiation() throws IOException {
+        Log.d(TAG, "testRegularComponentInstantiation");
+        testComponentInstantiation(mRegularInfos);
+    }
+
+    public void testAllComponentInstantiation() throws IOException {
+        Log.d(TAG, "testAllComponentInstantiation");
+        testComponentInstantiation(mAllInfos);
+    }
+
+    public void testLegacyComponentInstantiation() throws IOException {
+        Log.d(TAG, "testLegacyComponentInstantiation");
+        testComponentInstantiation(getLegacyInfos());
+    }
+
     // For each type advertised by any of the components we should be able
     // to get capabilities.
-    public void testGetCapabilities() {
-        Log.d(TAG, "testGetCapabilities");
-
-        int codecCount = MediaCodecList.getCodecCount();
-        for (int i = 0; i < codecCount; ++i) {
-            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
-
-            Log.d(TAG, (i + 1) + ": " + info.getName());
+    private void testGetCapabilities(MediaCodecInfo[] infos) {
+        for (MediaCodecInfo info : infos) {
+            Log.d(TAG, "codec: " + info.getName());
             Log.d(TAG, "  isEncoder = " + info.isEncoder());
 
-            if (!info.getName().startsWith("OMX.")) {
-                // Unfortunately for legacy reasons, "AACEncoder", a
-                // non OMX component had to be in this list for the video
-                // editor code to work... but it cannot actually be instantiated
-                // using MediaCodec.
-                Log.d(TAG, "  skipping...");
-                continue;
-            }
-
             String[] types = info.getSupportedTypes();
             for (int j = 0; j < types.length; ++j) {
                 Log.d(TAG, "calling getCapabilitiesForType " + types[j]);
@@ -112,14 +191,71 @@
         }
     }
 
+    public void testGetRegularCapabilities() {
+        Log.d(TAG, "testGetRegularCapabilities");
+        testGetCapabilities(mRegularInfos);
+    }
+
+    public void testGetAllCapabilities() {
+        Log.d(TAG, "testGetAllCapabilities");
+        testGetCapabilities(mAllInfos);
+    }
+
+    public void testGetLegacyCapabilities() {
+        Log.d(TAG, "testGetLegacyCapabilities");
+        testGetCapabilities(getLegacyInfos());
+    }
+
+    public void testLegacyMediaCodecListIsSameAsRegular() {
+        // regular codecs should be equivalent to legacy codecs, including
+        // codec ordering
+        MediaCodecInfo[] legacyInfos = getLegacyInfos();
+        assertEquals(legacyInfos.length, mRegularInfos.length);
+        for (int i = 0; i < legacyInfos.length; ++i) {
+            assertEquals(legacyInfos[i], mRegularInfos[i]);
+        }
+    }
+
+    public void testRegularMediaCodecListIsASubsetOfAll() {
+        Log.d(TAG, "testRegularMediaCodecListIsASubsetOfAll");
+        // regular codecs should be a subsequence of all codecs, including
+        // codec ordering
+        int ix = 0;
+        for (MediaCodecInfo info : mAllInfos) {
+            if (ix == mRegularInfos.length) {
+                break;
+            }
+            if (!mRegularInfos[ix].getName().equals(info.getName())) {
+                Log.d(TAG, "skipping non-regular codec " + info.getName());
+                continue;
+            }
+            Log.d(TAG, "checking codec " + info.getName());
+            assertSuperset(info, mRegularInfos[ix]);
+            ++ix;
+        }
+        assertEquals(
+                "some regular codecs are not listed in all codecs", ix, mRegularInfos.length);
+    }
+
     public void testRequiredMediaCodecList() {
         List<CodecType> requiredList = getRequiredCodecTypes();
         List<CodecType> supportedList = getSupportedCodecTypes();
         assertTrue(areRequiredCodecTypesSupported(requiredList, supportedList));
     }
 
+    private boolean hasCamera() {
+        PackageManager pm = getContext().getPackageManager();
+        return pm.hasSystemFeature(pm.FEATURE_CAMERA_FRONT) ||
+                pm.hasSystemFeature(pm.FEATURE_CAMERA);
+    }
+
     // H263 baseline profile must be supported
     public void testIsH263BaselineProfileSupported() {
+        if (!hasCamera()) {
+            Log.d(TAG, "not required without camera");
+            return;
+        }
+
         int profile = CodecProfileLevel.H263ProfileBaseline;
         assertTrue(checkProfileSupported("video/3gpp", false, profile));
         assertTrue(checkProfileSupported("video/3gpp", true, profile));
@@ -140,6 +276,11 @@
 
     // MPEG4 simple profile must be supported
     public void testIsM4VSimpleProfileSupported() {
+        if (!hasCamera()) {
+            Log.d(TAG, "not required without camera");
+            return;
+        }
+
         int profile = CodecProfileLevel.MPEG4ProfileSimple;
         assertTrue(checkProfileSupported("video/mp4v-es", false, profile));
 
@@ -151,26 +292,24 @@
      * Find whether the given codec is supported
      */
     private boolean checkProfileSupported(
-        String codecName, boolean isEncoder, int profile) {
+            String mime, boolean isEncoder, int profile) {
+        return profileIsListed(mime, isEncoder, profile) &&
+                codecCanBeFound(mime, isEncoder);
+    }
 
-        boolean isSupported = false;
+    private boolean profileIsListed(
+        String mime, boolean isEncoder, int profile) {
 
-        int codecCount = MediaCodecList.getCodecCount();
-        for (int i = 0; i < codecCount; ++i) {
-
-            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
-            String[] types = info.getSupportedTypes();
-
+        for (MediaCodecInfo info : mRegularInfos) {
             if (isEncoder != info.isEncoder()) {
                 continue;
             }
 
-            for (int j = 0; j < types.length; ++j) {
-                if (types[j].compareTo(codecName) == 0) {
-                    CodecCapabilities cap = info.getCapabilitiesForType(types[j]);
-                    CodecProfileLevel[] profileLevels = cap.profileLevels;
-                    for (int k = 0; k < profileLevels.length; ++k) {
-                        if (profileLevels[k].profile == profile) {
+            for (String type : info.getSupportedTypes()) {
+                if (type.equalsIgnoreCase(mime)) {
+                    CodecCapabilities cap = info.getCapabilitiesForType(type);
+                    for (CodecProfileLevel pl : cap.profileLevels) {
+                        if (pl.profile == profile) {
                             return true;
                         }
                     }
@@ -180,6 +319,16 @@
         return false;
     }
 
+    // Find whether the given codec can be found using MediaCodecList.find methods.
+    private boolean codecCanBeFound(String mime, boolean isEncoder) {
+        // implicit assumption that QVGA video is always valid.
+        MediaFormat format = MediaFormat.createVideoFormat(mime, 176, 144);
+        String codecName = isEncoder
+                ? mRegularCodecs.findEncoderForFormat(format)
+                : mRegularCodecs.findDecoderForFormat(format);
+        return codecName != null;
+    }
+
     /*
      * Find whether all required media codec types are supported
      */
@@ -206,11 +355,8 @@
      * Find all the media codec types are supported.
      */
     private List<CodecType> getSupportedCodecTypes() {
-        int codecCount = MediaCodecList.getCodecCount();
-        assertTrue("Unexpected media codec count", codecCount > 0);
-        List<CodecType> supportedList = new ArrayList<CodecType>(codecCount);
-        for (int i = 0; i < codecCount; ++i) {
-            MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
+        List<CodecType> supportedList = new ArrayList<CodecType>();
+        for (MediaCodecInfo info : mRegularInfos) {
             String[] types = info.getSupportedTypes();
             assertTrue("Unexpected number of supported types", types.length > 0);
             boolean isEncoder = info.isEncoder();