media: surface parity for MediaCodec & Recorder

allow setting output surface dynamically on MediaCodec
allow creating persistent input surface for MediaCodec and MediaRecorder

Bug: 19127604
Bug: 19489395
Change-Id: I68d95ce012574f1cc161556fd7d016be104e5076
diff --git a/api/current.txt b/api/current.txt
index 09ef131..0572604 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15274,6 +15274,7 @@
     method public static android.media.MediaCodec createDecoderByType(java.lang.String) throws java.io.IOException;
     method public static android.media.MediaCodec createEncoderByType(java.lang.String) throws java.io.IOException;
     method public final android.view.Surface createInputSurface();
+    method public static android.view.Surface createPersistentInputSurface();
     method public final int dequeueInputBuffer(long);
     method public final int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long);
     method public final void flush();
@@ -15296,10 +15297,12 @@
     method public final void reset();
     method public void setCallback(android.media.MediaCodec.Callback);
     method public final void setParameters(android.os.Bundle);
+    method public void setSurface(android.view.Surface);
     method public final void setVideoScalingMode(int);
     method public final void signalEndOfInputStream();
     method public final void start();
     method public final void stop();
+    method public void usePersistentInputSurface(android.view.Surface);
     field public static final int BUFFER_FLAG_CODEC_CONFIG = 2; // 0x2
     field public static final int BUFFER_FLAG_END_OF_STREAM = 4; // 0x4
     field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
@@ -16144,6 +16147,7 @@
     method public void setVideoSource(int) throws java.lang.IllegalStateException;
     method public void start() throws java.lang.IllegalStateException;
     method public void stop() throws java.lang.IllegalStateException;
+    method public void usePersistentSurface(android.view.Surface);
     field public static final int MEDIA_ERROR_SERVER_DIED = 100; // 0x64
     field public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1; // 0x1
     field public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800; // 0x320
diff --git a/api/system-current.txt b/api/system-current.txt
index 26a06c3..70e4eb1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -16486,6 +16486,7 @@
     method public static android.media.MediaCodec createDecoderByType(java.lang.String) throws java.io.IOException;
     method public static android.media.MediaCodec createEncoderByType(java.lang.String) throws java.io.IOException;
     method public final android.view.Surface createInputSurface();
+    method public static android.view.Surface createPersistentInputSurface();
     method public final int dequeueInputBuffer(long);
     method public final int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long);
     method public final void flush();
@@ -16508,10 +16509,12 @@
     method public final void reset();
     method public void setCallback(android.media.MediaCodec.Callback);
     method public final void setParameters(android.os.Bundle);
+    method public void setSurface(android.view.Surface);
     method public final void setVideoScalingMode(int);
     method public final void signalEndOfInputStream();
     method public final void start();
     method public final void stop();
+    method public void usePersistentInputSurface(android.view.Surface);
     field public static final int BUFFER_FLAG_CODEC_CONFIG = 2; // 0x2
     field public static final int BUFFER_FLAG_END_OF_STREAM = 4; // 0x4
     field public static final int BUFFER_FLAG_KEY_FRAME = 1; // 0x1
@@ -17357,6 +17360,7 @@
     method public void setVideoSource(int) throws java.lang.IllegalStateException;
     method public void start() throws java.lang.IllegalStateException;
     method public void stop() throws java.lang.IllegalStateException;
+    method public void usePersistentSurface(android.view.Surface);
     field public static final int MEDIA_ERROR_SERVER_DIED = 100; // 0x64
     field public static final int MEDIA_RECORDER_ERROR_UNKNOWN = 1; // 0x1
     field public static final int MEDIA_RECORDER_INFO_MAX_DURATION_REACHED = 800; // 0x320
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index b0cd3e4..680c3769 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -610,6 +610,61 @@
         native_configure(keys, values, surface, crypto, flags);
     }
 
+    /**
+     *  Dynamically sets the output surface of a codec.
+     *  <p>
+     *  This can only be used if the codec was configured with an output surface.  The
+     *  new output surface should have a compatible usage type to the original output surface.
+     *  E.g. codecs may not support switching from a SurfaceTexture (GPU readable) output
+     *  to ImageReader (software readable) output.
+     *  @param surface the output surface to use. It must not be {@code null}.
+     *  @throws IllegalStateException if the codec does not support setting the output
+     *            surface in the current state.
+     *  @throws IllegalArgumentException if the new surface is not of a suitable type for the codec.
+     */
+    public void setSurface(@NonNull Surface surface) {
+        if (!mHasSurface) {
+            throw new IllegalStateException("codec was not configured for an output surface");
+        }
+
+        // TODO implement this
+        throw new IllegalArgumentException("codec does not support this surface");
+    }
+
+    /**
+     * Create a persistent input surface that can be used with codecs that normally have an input
+     * surface, such as video encoders. A persistent input can be reused by subsequent
+     * {@link MediaCodec} or {@link MediaRecorder} instances, but can only be used by at
+     * most one codec or recorder instance concurrently.
+     * <p>
+     * The application is responsible for calling release() on the Surface when done.
+     *
+     * @return an input surface that can be used with {@link #usePersistentInputSurface}.
+     */
+    @NonNull
+    public static Surface createPersistentInputSurface() {
+        // TODO implement this
+        return new PersistentSurface();
+    }
+
+    static class PersistentSurface extends Surface {
+        PersistentSurface() {}
+    };
+
+    /**
+     * Configures the codec (e.g. encoder) to use a persistent input surface in place of input
+     * buffers.  This may only be called after {@link #configure} and before {@link #start}, in
+     * lieu of {@link #createInputSurface}.
+     * @param surface a persistent input surface created by {@link #createPersistentInputSurface}
+     * @throws IllegalStateException if not in the Configured state or does not require an input
+     *           surface.
+     * @throws IllegalArgumentException if the surface was not created by
+     *           {@link #createPersistentInputSurface}.
+     */
+    public void usePersistentInputSurface(@NonNull Surface surface) {
+        throw new IllegalArgumentException("not implemented");
+    }
+
     private native final void native_setCallback(@Nullable Callback cb);
 
     private native final void native_configure(
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 876aebc..78fd9f0 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -140,6 +140,24 @@
     public native Surface getSurface();
 
     /**
+     * Configures the recorder to use a persistent surface when using SURFACE video source.
+     * <p> May only be called after {@link #prepare} in lieu of {@link #getSurface}.
+     * Frames rendered to the Surface before {@link #start} will be discarded.</p>
+
+     * @param surface a persistent input surface created by
+     *           {@link MediaCodec#createPersistentInputSurface}
+     * @throws IllegalStateException if it is called before {@link #prepare}, after
+     * {@link #stop}, or is called when VideoSource is not set to SURFACE.
+     * @throws IllegalArgumentException if the surface was not created by
+     *           {@link MediaCodec#createPersistentInputSurface}.
+     * @see MediaCodec#createPersistentInputSurface
+     * @see MediaRecorder.VideoSource
+     */
+    public void usePersistentSurface(Surface surface) {
+        throw new IllegalArgumentException("not implemented");
+    }
+
+    /**
      * Sets a Surface to show a preview of recorded media (video). Calls this
      * before prepare() to make sure that the desirable preview display is
      * set. If {@link #setCamera(Camera)} is used and the surface has been