media: cts for CodecCapabilities.getMaxSupportedInstances.

Bug: 19620911
Change-Id: Ice7d653e0016b4f5e2d90261eed10b06a8838cf8
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index 159d13f..daf55a7 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -39,6 +39,7 @@
 import java.util.HashSet;
 import java.util.Set;
 import java.util.Arrays;
+import java.util.Vector;
 
 /**
  * Basic sanity test of data returned by MediaCodeCapabilities.
@@ -528,4 +529,84 @@
             MediaUtils.skipTest("no non-tunneled/non-secure video decoders found");
         }
     }
+
+    private static MediaFormat createMinFormat(String mime, VideoCapabilities vcaps, int color) {
+        int minWidth = vcaps.getSupportedWidths().getLower();
+        int minHeight = vcaps.getSupportedHeightsFor(minWidth).getLower();
+        int minBitrate = vcaps.getBitrateRange().getLower();
+
+        MediaFormat format = MediaFormat.createVideoFormat(mime, minWidth, minHeight);
+        format.setInteger(MediaFormat.KEY_COLOR_FORMAT, color);
+        format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate);
+        format.setInteger(MediaFormat.KEY_FRAME_RATE, 10);
+        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 10);
+        return format;
+    }
+
+    private static int getActualMax(
+            boolean isEncoder, String name, String mime, CodecCapabilities caps, int max) {
+        int flag = isEncoder ? MediaCodec.CONFIGURE_FLAG_ENCODE : 0;
+        MediaFormat format =
+                createMinFormat(mime, caps.getVideoCapabilities(), caps.colorFormats[0]);
+        Vector<MediaCodec> codecs = new Vector<MediaCodec>();
+        for (int i = 0; i < max; ++i) {
+            try {
+                Log.d(TAG, "Create codec " + name + " #" + i);
+                MediaCodec codec = MediaCodec.createByCodecName(name);
+                codec.configure(format, null, null, flag);
+                codec.start();
+                codecs.add(codec);
+            } catch (IllegalArgumentException e) {
+                fail("Got unexpected IllegalArgumentException " + e.getMessage());
+            } catch (IOException e) {
+                fail("Got unexpected IOException " + e.getMessage());
+            } catch (MediaCodec.CodecException e) {
+                // ERROR_INSUFFICIENT_RESOURCE is expected as the test keep creating codecs.
+                // But other exception should be treated as failure.
+                if (e.getErrorCode() == MediaCodec.CodecException.ERROR_INSUFFICIENT_RESOURCE) {
+                    Log.d(TAG, "Got CodecException with ERROR_INSUFFICIENT_RESOURCE.");
+                    break;
+                } else {
+                    fail("Unexpected CodecException " + e.getDiagnosticInfo());
+                }
+            }
+        }
+        int actualMax = codecs.size();
+        for (int i = 0; i < codecs.size(); ++i) {
+            codecs.get(i).release();
+        }
+        return actualMax;
+    }
+
+    private static boolean shouldTestActual(CodecCapabilities caps) {
+        if (caps.getVideoCapabilities() == null) {
+            // TODO: test audio codecs.
+            return false;
+        }
+        return true;
+    }
+
+    public void testGetMaxSupportedInstances() {
+        MediaCodecList allCodecs = new MediaCodecList(MediaCodecList.ALL_CODECS);
+        for (MediaCodecInfo info : allCodecs.getCodecInfos()) {
+            Log.d(TAG, "codec: " + info.getName());
+            Log.d(TAG, "  isEncoder = " + info.isEncoder());
+
+            String[] types = info.getSupportedTypes();
+            for (int j = 0; j < types.length; ++j) {
+                Log.d(TAG, "calling getCapabilitiesForType " + types[j]);
+                CodecCapabilities caps = info.getCapabilitiesForType(types[j]);
+                int max = caps.getMaxSupportedInstances();
+                Log.d(TAG, "getMaxSupportedInstances returns " + max);
+                assertTrue(max > 0);
+
+                if (shouldTestActual(caps)) {
+                    int actualMax = getActualMax(
+                            info.isEncoder(), info.getName(), types[j], caps, max + 1);
+                    Log.d(TAG, "actualMax " + actualMax + " vs reported max " + max);
+                    assertTrue(actualMax >= (int)(max * 0.9));
+                }
+            }
+        }
+    }
 }