cts: add test for persistent input surface

Change-Id: I0235f9dc32076ca4e851fa619390bb2c601f2385
diff --git a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java b/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
index b6c94c14..5152d98 100644
--- a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
@@ -209,15 +209,32 @@
      */
     public void testEncodeDecodeVideoFromSurfaceToSurfaceQCIF() throws Throwable {
         setParameters(176, 144, 1000000, MIME_TYPE_AVC, true, false);
-        SurfaceToSurfaceWrapper.runTest(this);
+        SurfaceToSurfaceWrapper.runTest(this, false);
     }
     public void testEncodeDecodeVideoFromSurfaceToSurfaceQVGA() throws Throwable {
         setParameters(320, 240, 2000000, MIME_TYPE_AVC, true, false);
-        SurfaceToSurfaceWrapper.runTest(this);
+        SurfaceToSurfaceWrapper.runTest(this, false);
     }
     public void testEncodeDecodeVideoFromSurfaceToSurface720p() throws Throwable {
         setParameters(1280, 720, 6000000, MIME_TYPE_AVC, true, false);
-        SurfaceToSurfaceWrapper.runTest(this);
+        SurfaceToSurfaceWrapper.runTest(this, false);
+    }
+
+    /**
+     * Tests streaming of AVC video through the encoder and decoder.  Data is provided through
+     * a PersistentSurface and decoded onto a Surface.  The output is checked for validity.
+     */
+    public void testEncodeDecodeVideoFromPersistentSurfaceToSurfaceQCIF() throws Throwable {
+        setParameters(176, 144, 1000000, MIME_TYPE_AVC, true, false);
+        SurfaceToSurfaceWrapper.runTest(this, true);
+    }
+    public void testEncodeDecodeVideoFromPersistentSurfaceToSurfaceQVGA() throws Throwable {
+        setParameters(320, 240, 2000000, MIME_TYPE_AVC, true, false);
+        SurfaceToSurfaceWrapper.runTest(this, true);
+    }
+    public void testEncodeDecodeVideoFromPersistentSurfaceToSurface720p() throws Throwable {
+        setParameters(1280, 720, 6000000, MIME_TYPE_AVC, true, false);
+        SurfaceToSurfaceWrapper.runTest(this, true);
     }
 
     /**
@@ -226,40 +243,77 @@
      */
     public void testVP8EncodeDecodeVideoFromSurfaceToSurfaceQCIF() throws Throwable {
         setParameters(176, 144, 1000000, MIME_TYPE_VP8, true, false);
-        SurfaceToSurfaceWrapper.runTest(this);
+        SurfaceToSurfaceWrapper.runTest(this, false);
     }
     public void testVP8EncodeDecodeVideoFromSurfaceToSurfaceQVGA() throws Throwable {
         setParameters(320, 240, 2000000, MIME_TYPE_VP8, true, false);
-        SurfaceToSurfaceWrapper.runTest(this);
+        SurfaceToSurfaceWrapper.runTest(this, false);
     }
     public void testVP8EncodeDecodeVideoFromSurfaceToSurface720p() throws Throwable {
         setParameters(1280, 720, 6000000, MIME_TYPE_VP8, true, false);
-        SurfaceToSurfaceWrapper.runTest(this);
+        SurfaceToSurfaceWrapper.runTest(this, false);
+    }
+
+    /**
+     * Tests streaming of VP8 video through the encoder and decoder.  Data is provided through
+     * a PersistentSurface and decoded onto a Surface.  The output is checked for validity.
+     */
+    public void testVP8EncodeDecodeVideoFromPersistentSurfaceToSurfaceQCIF() throws Throwable {
+        setParameters(176, 144, 1000000, MIME_TYPE_VP8, true, false);
+        SurfaceToSurfaceWrapper.runTest(this, true);
+    }
+    public void testVP8EncodeDecodeVideoFromPersistentSurfaceToSurfaceQVGA() throws Throwable {
+        setParameters(320, 240, 2000000, MIME_TYPE_VP8, true, false);
+        SurfaceToSurfaceWrapper.runTest(this, true);
+    }
+    public void testVP8EncodeDecodeVideoFromPersistentSurfaceToSurface720p() throws Throwable {
+        setParameters(1280, 720, 6000000, MIME_TYPE_VP8, true, false);
+        SurfaceToSurfaceWrapper.runTest(this, true);
     }
 
     /** Wraps testEncodeDecodeVideoFromSurfaceToSurface() */
     private static class SurfaceToSurfaceWrapper implements Runnable {
         private Throwable mThrowable;
         private EncodeDecodeTest mTest;
+        private boolean mUsePersistentInput;
 
-        private SurfaceToSurfaceWrapper(EncodeDecodeTest test) {
+        private SurfaceToSurfaceWrapper(EncodeDecodeTest test, boolean persistent) {
             mTest = test;
+            mUsePersistentInput = persistent;
         }
 
         @Override
         public void run() {
+            InputSurface inputSurface = null;
             try {
-                mTest.encodeDecodeVideoFromSurfaceToSurface();
+                if (!mUsePersistentInput) {
+                    mTest.encodeDecodeVideoFromSurfaceToSurface(null);
+                } else {
+                    Log.d(TAG, "creating persistent surface");
+                    inputSurface = new InputSurface(
+                            MediaCodec.createPersistentInputSurface());
+
+                    for (int i = 0; i < 3; i++) {
+                        Log.d(TAG, "test persistent surface - round " + i);
+                        mTest.encodeDecodeVideoFromSurfaceToSurface(inputSurface);
+                    }
+                }
             } catch (Throwable th) {
                 mThrowable = th;
+            } finally {
+                if (inputSurface != null) {
+                    inputSurface.release();
+                }
             }
         }
 
         /**
          * Entry point.
          */
-        public static void runTest(EncodeDecodeTest obj) throws Throwable {
-            SurfaceToSurfaceWrapper wrapper = new SurfaceToSurfaceWrapper(obj);
+        public static void runTest(EncodeDecodeTest obj, boolean persisent)
+                throws Throwable {
+            SurfaceToSurfaceWrapper wrapper =
+                    new SurfaceToSurfaceWrapper(obj, persisent);
             Thread th = new Thread(wrapper, "codec test");
             th.start();
             th.join();
@@ -357,10 +411,10 @@
      * We encode several frames of a video test pattern using MediaCodec, then decode the
      * output with MediaCodec and do some simple checks.
      */
-    private void encodeDecodeVideoFromSurfaceToSurface() throws Exception {
+    private void encodeDecodeVideoFromSurfaceToSurface(InputSurface inSurf) throws Exception {
         MediaCodec encoder = null;
         MediaCodec decoder = null;
-        InputSurface inputSurface = null;
+        InputSurface inputSurface = inSurf;
         OutputSurface outputSurface = null;
 
         mLargestColorDelta = -1;
@@ -402,13 +456,19 @@
             // our desired properties.  Request a Surface to use for input.
             encoder = MediaCodec.createByCodecName(codec);
             encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
-            inputSurface = new InputSurface(encoder.createInputSurface());
+            if (inSurf != null) {
+                Log.d(TAG, "using persistent surface");
+                encoder.usePersistentInputSurface(inputSurface.getSurface());
+                inputSurface.updateSize(mWidth, mHeight);
+            } else {
+                inputSurface = new InputSurface(encoder.createInputSurface());
+            }
             encoder.start();
 
             doEncodeDecodeVideoFromSurfaceToSurface(encoder, inputSurface, decoder, outputSurface);
         } finally {
             if (VERBOSE) Log.d(TAG, "releasing codecs");
-            if (inputSurface != null) {
+            if (inSurf == null && inputSurface != null) {
                 inputSurface.release();
             }
             if (outputSurface != null) {
diff --git a/tests/tests/media/src/android/media/cts/InputSurface.java b/tests/tests/media/src/android/media/cts/InputSurface.java
index 157ed88..37ca423 100644
--- a/tests/tests/media/src/android/media/cts/InputSurface.java
+++ b/tests/tests/media/src/android/media/cts/InputSurface.java
@@ -41,8 +41,11 @@
     private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;
     private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;
     private EGLSurface mEGLSurface = EGL14.EGL_NO_SURFACE;
+    private EGLConfig[] mConfigs = new EGLConfig[1];
 
     private Surface mSurface;
+    private int mWidth;
+    private int mHeight;
 
     /**
      * Creates an InputSurface from a Surface.
@@ -80,9 +83,8 @@
                 EGL_RECORDABLE_ANDROID, 1,
                 EGL14.EGL_NONE
         };
-        EGLConfig[] configs = new EGLConfig[1];
         int[] numConfigs = new int[1];
-        if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length,
+        if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, mConfigs, 0, mConfigs.length,
                 numConfigs, 0)) {
             throw new RuntimeException("unable to find RGB888+recordable ES2 EGL config");
         }
@@ -92,7 +94,7 @@
                 EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
                 EGL14.EGL_NONE
         };
-        mEGLContext = EGL14.eglCreateContext(mEGLDisplay, configs[0], EGL14.EGL_NO_CONTEXT,
+        mEGLContext = EGL14.eglCreateContext(mEGLDisplay, mConfigs[0], EGL14.EGL_NO_CONTEXT,
                 attrib_list, 0);
         checkEglError("eglCreateContext");
         if (mEGLContext == null) {
@@ -100,17 +102,40 @@
         }
 
         // Create a window surface, and attach it to the Surface we received.
+        createEGLSurface();
+
+        mWidth = getWidth();
+        mHeight = getHeight();
+    }
+
+    public void updateSize(int width, int height) {
+        if (width != mWidth || height != mHeight) {
+            Log.d(TAG, "re-create EGLSurface");
+            releaseEGLSurface();
+            createEGLSurface();
+            mWidth = getWidth();
+            mHeight = getHeight();
+        }
+    }
+
+    private void createEGLSurface() {
+        //EGLConfig[] configs = new EGLConfig[1];
         int[] surfaceAttribs = {
                 EGL14.EGL_NONE
         };
-        mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, configs[0], mSurface,
+        mEGLSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mConfigs[0], mSurface,
                 surfaceAttribs, 0);
         checkEglError("eglCreateWindowSurface");
         if (mEGLSurface == null) {
             throw new RuntimeException("surface was null");
         }
     }
-
+    private void releaseEGLSurface() {
+        if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {
+            EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);
+            mEGLSurface = EGL14.EGL_NO_SURFACE;
+        }
+    }
     /**
      * Discard all resources held by this class, notably the EGL context.  Also releases the
      * Surface that was passed to our constructor.