media: Extend CTS EOS test to also test Software codecs.
Also extend the test to test single frame with EOS flag.

Bug: 28966925
Change-Id: I3d2d4800d6b7becb77a068aa3b0db6433095945a
diff --git a/libs/deviceutil/src/android/cts/util/MediaUtils.java b/libs/deviceutil/src/android/cts/util/MediaUtils.java
index 7ab806d..a87715d 100755
--- a/libs/deviceutil/src/android/cts/util/MediaUtils.java
+++ b/libs/deviceutil/src/android/cts/util/MediaUtils.java
@@ -35,6 +35,8 @@
 import static java.lang.reflect.Modifier.isPublic;
 import static java.lang.reflect.Modifier.isStatic;
 import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Map;
 import android.util.Log;
 
@@ -461,6 +463,29 @@
         return extractor;
     }
 
+    /**
+     * return mime type of the resourceId
+     */
+    public static Collection<String> getDecodersForFormat(MediaFormat format) {
+        ArrayList<String> decoders = new ArrayList<String>();
+        String mime = format.getString(MediaFormat.KEY_MIME);
+        MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
+        for (MediaCodecInfo info : mcl.getCodecInfos()) {
+            if (info.isEncoder()) {
+                continue;
+            }
+            CodecCapabilities caps = null;
+            try {
+                caps = info.getCapabilitiesForType(mime);
+            } catch (IllegalArgumentException e) {  // mime is not supported
+                continue;
+            }
+            if (caps.isFormatSupported(format))
+                decoders.add(info.getName());
+        }
+        return decoders;
+    }
+
     /*
      *  ------------------ HELPER METHODS FOR STATISTICS AND REPORTING ------------------
      */
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 33583be..15ac82f 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -47,6 +47,7 @@
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.zip.CRC32;
 import java.util.concurrent.TimeUnit;
@@ -1930,9 +1931,9 @@
                 testFd.getLength());
         extractor.selectTrack(0);
 
-        int numframes = decodeWithChecks(extractor, CHECKFLAG_RETURN_OUTPUTFRAMES
-                | CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH, resetMode, s,
-                eosframe, null, null);
+        int numframes = decodeWithChecks(null /* decoderName */, extractor,
+                CHECKFLAG_RETURN_OUTPUTFRAMES | CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH,
+                resetMode, s, eosframe, null, null);
 
         extractor.release();
         testFd.close();
@@ -1949,7 +1950,8 @@
         extractor.selectTrack(0);
 
         // fails CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH
-        int outputSize = decodeWithChecks(extractor, CHECKFLAG_RETURN_OUTPUTSIZE, resetMode, null,
+        int outputSize = decodeWithChecks(null /* decoderName */, extractor,
+                CHECKFLAG_RETURN_OUTPUTSIZE, resetMode, null,
                 eosframe, null, null);
 
         extractor.release();
@@ -1957,10 +1959,16 @@
         return outputSize;
     }
 
+    /*
+    * Test all decoders' EOS behavior.
+    */
     private void testEOSBehavior(int movie, int stopatsample) throws Exception {
         testEOSBehavior(movie, new int[] {stopatsample});
     }
 
+    /*
+    * Test all decoders' EOS behavior.
+    */
     private void testEOSBehavior(int movie, int[] stopAtSample) throws Exception {
         Surface s = null;
         AssetFileDescriptor testFd = mResources.openRawResourceFd(movie);
@@ -1969,42 +1977,45 @@
                 testFd.getLength());
         extractor.selectTrack(0); // consider variable looping on track
         MediaFormat format = extractor.getTrackFormat(0);
-        if (!MediaUtils.checkDecoderForFormat(format)) {
-            return; // skip
-        }
-        List<Long> outputChecksums = new ArrayList<Long>();
-        List<Long> outputTimestamps = new ArrayList<Long>();
-        Arrays.sort(stopAtSample);
-        int last = stopAtSample.length - 1;
 
-        // decode reference (longest sequence to stop at + 100) and
-        // store checksums/pts in outputChecksums and outputTimestamps
-        // (will fail CHECKFLAG_COMPAREINPUTOUTPUTSAMPLEMATCH)
-        decodeWithChecks(extractor,
-                CHECKFLAG_SETCHECKSUM | CHECKFLAG_SETPTS | CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH,
-                RESET_MODE_NONE, s,
-                stopAtSample[last] + 100, outputChecksums, outputTimestamps);
+        Collection<String> decoderNames = MediaUtils.getDecodersForFormat(format);
+        for (String decoderName: decoderNames) {
+            List<Long> outputChecksums = new ArrayList<Long>();
+            List<Long> outputTimestamps = new ArrayList<Long>();
+            Arrays.sort(stopAtSample);
+            int last = stopAtSample.length - 1;
 
-        // decode stopAtSample requests in reverse order (longest to
-        // shortest) and compare to reference checksums/pts in
-        // outputChecksums and outputTimestamps
-        for (int i = last; i >= 0; --i) {
-            if (true) { // reposition extractor
-                extractor.seekTo(0, MediaExtractor.SEEK_TO_NEXT_SYNC);
-            } else { // create new extractor
-                extractor.release();
-                extractor = new MediaExtractor();
-                extractor.setDataSource(testFd.getFileDescriptor(),
-                        testFd.getStartOffset(), testFd.getLength());
-                extractor.selectTrack(0); // consider variable looping on track
-            }
-            decodeWithChecks(extractor,
-                    CHECKFLAG_COMPARECHECKSUM | CHECKFLAG_COMPAREPTS
-                    | CHECKFLAG_COMPAREINPUTOUTPUTSAMPLEMATCH
-                    | CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH,
+            // decode reference (longest sequence to stop at + 100) and
+            // store checksums/pts in outputChecksums and outputTimestamps
+            // (will fail CHECKFLAG_COMPAREINPUTOUTPUTSAMPLEMATCH)
+            decodeWithChecks(decoderName, extractor,
+                    CHECKFLAG_SETCHECKSUM | CHECKFLAG_SETPTS | CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH,
                     RESET_MODE_NONE, s,
-                    stopAtSample[i], outputChecksums, outputTimestamps);
+                    stopAtSample[last] + 100, outputChecksums, outputTimestamps);
+
+            // decode stopAtSample requests in reverse order (longest to
+            // shortest) and compare to reference checksums/pts in
+            // outputChecksums and outputTimestamps
+            for (int i = last; i >= 0; --i) {
+                if (true) { // reposition extractor
+                    extractor.seekTo(0, MediaExtractor.SEEK_TO_NEXT_SYNC);
+                } else { // create new extractor
+                    extractor.release();
+                    extractor = new MediaExtractor();
+                    extractor.setDataSource(testFd.getFileDescriptor(),
+                            testFd.getStartOffset(), testFd.getLength());
+                    extractor.selectTrack(0); // consider variable looping on track
+                }
+                decodeWithChecks(decoderName, extractor,
+                        CHECKFLAG_COMPARECHECKSUM | CHECKFLAG_COMPAREPTS
+                        | CHECKFLAG_COMPAREINPUTOUTPUTSAMPLEMATCH
+                        | CHECKFLAG_COMPAREINPUTOUTPUTPTSMATCH,
+                        RESET_MODE_NONE, s,
+                        stopAtSample[i], outputChecksums, outputTimestamps);
+            }
+            extractor.seekTo(0, MediaExtractor.SEEK_TO_NEXT_SYNC);
         }
+
         extractor.release();
         testFd.close();
     }
@@ -2020,10 +2031,13 @@
 
     /**
      * Decodes frames with parameterized checks and return values.
+     * If decoderName is provided, mediacodec will create that decoder. Otherwise,
+     * mediacodec will use the default decoder provided by platform.
      * The integer return can be selected through the checkFlags variable.
      */
-    private static int decodeWithChecks(MediaExtractor extractor, int checkFlags, int resetMode,
-            Surface surface, int stopAtSample,
+    private static int decodeWithChecks(
+            String decoderName, MediaExtractor extractor,
+            int checkFlags, int resetMode, Surface surface, int stopAtSample,
             List<Long> outputChecksums, List<Long> outputTimestamps)
             throws Exception {
         int trackIndex = extractor.getSampleTrackIndex();
@@ -2033,7 +2047,8 @@
         ByteBuffer[] codecInputBuffers;
         ByteBuffer[] codecOutputBuffers;
 
-        MediaCodec codec = createDecoder(format);
+        MediaCodec codec =
+                decoderName == null ? createDecoder(format) : MediaCodec.createByCodecName(decoderName);
         Log.i("@@@@", "using codec: " + codec.getName());
         codec.configure(format, surface, null /* crypto */, 0 /* flags */);
         codec.start();
@@ -2253,37 +2268,42 @@
 
     public void testEOSBehaviorH264() throws Exception {
         // this video has an I frame at 44
-        testEOSBehavior(R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz,
-                new int[] {44, 45, 55});
+        testEOSBehavior(
+                R.raw.video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz,
+                new int[] {1, 44, 45, 55});
     }
     public void testEOSBehaviorHEVC() throws Exception {
-        testEOSBehavior(R.raw.video_480x360_mp4_hevc_650kbps_30fps_aac_stereo_128kbps_48000hz, 17);
-        testEOSBehavior(R.raw.video_480x360_mp4_hevc_650kbps_30fps_aac_stereo_128kbps_48000hz, 23);
-        testEOSBehavior(R.raw.video_480x360_mp4_hevc_650kbps_30fps_aac_stereo_128kbps_48000hz, 49);
+        testEOSBehavior(
+            R.raw.video_480x360_mp4_hevc_650kbps_30fps_aac_stereo_128kbps_48000hz,
+            new int[] {1, 17, 23, 49});
     }
 
     public void testEOSBehaviorH263() throws Exception {
         // this video has an I frame every 12 frames.
-        testEOSBehavior(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz,
-                new int[] {24, 25, 48, 50});
+        testEOSBehavior(
+                R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz,
+                new int[] {1, 24, 25, 48, 50});
     }
 
     public void testEOSBehaviorMpeg4() throws Exception {
         // this video has an I frame every 12 frames
-        testEOSBehavior(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz,
-                new int[] {24, 25, 48, 50, 2});
+        testEOSBehavior(
+                R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz,
+                new int[] {1, 24, 25, 48, 50, 2});
     }
 
     public void testEOSBehaviorVP8() throws Exception {
         // this video has an I frame at 46
-        testEOSBehavior(R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_48000hz,
-                new int[] {46, 47, 57, 45});
+        testEOSBehavior(
+                R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_48000hz,
+                new int[] {1, 46, 47, 57, 45});
     }
 
     public void testEOSBehaviorVP9() throws Exception {
         // this video has an I frame at 44
-        testEOSBehavior(R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_48000hz,
-                new int[] {44, 45, 55, 43});
+        testEOSBehavior(
+                R.raw.video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_48000hz,
+                new int[] {1, 44, 45, 55, 43});
     }
 
     /* from EncodeDecodeTest */