Implement Surface input to MediaCodec.

Adds two new public methods to MediaCodec, and one new public
constant to MediaCodecInfo (currently @hidden).

Bug 7991062

Change-Id: I830a9794e92334ad05c870cc5fc90be4652147a5
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index d5515eb..e155385 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -263,6 +263,16 @@
             Surface surface, MediaCrypto crypto, int flags);
 
     /**
+     * Requests a Surface to use instead of input buffers.  This may only be called after
+     * {@link #configure} and before {@link #start}.
+     * <p>
+     * The application is responsible for calling release() on the Surface when
+     * done.
+     * @hide -- TODO(fadden): make this public before release
+     */
+    public native final Surface createInputSurface();
+
+    /**
      * After successfully configuring the component, call start. On return
      * you can query the component for its input/output buffers.
      */
@@ -458,6 +468,14 @@
     public native final void releaseOutputBuffer(int index, boolean render);
 
     /**
+     * Signals end-of-stream on input.  Equivalent to submitting an empty buffer with
+     * {@link #BUFFER_FLAG_END_OF_STREAM} set.  This may only be used with
+     * encoders receiving input from a Surface created by {@link #createInputSurface}.
+     * @hide -- TODO(fadden): make this public before release
+     */
+    public native final void signalEndOfInputStream();
+
+    /**
      * Call this after dequeueOutputBuffer signals a format change by returning
      * {@link #INFO_OUTPUT_FORMAT_CHANGED}
      */
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index f6593e0..6c1b87a 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -93,6 +93,8 @@
         public final static int COLOR_Format24BitABGR6666           = 43;
 
         public final static int COLOR_TI_FormatYUV420PackedSemiPlanar = 0x7f000100;
+        /** @hide -- TODO(fadden): make this public before release */
+        public final static int COLOR_FormatAndroidOpaque             = 0x7F000789;
         public final static int COLOR_QCOM_FormatYUV420SemiPlanar     = 0x7fa30c00;
 
         /**
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 86700b3..3a42db2 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -123,6 +123,11 @@
     return mCodec->configure(format, mSurfaceTextureClient, crypto, flags);
 }
 
+status_t JMediaCodec::createInputSurface(
+        sp<IGraphicBufferProducer>* bufferProducer) {
+    return mCodec->createInputSurface(bufferProducer);
+}
+
 status_t JMediaCodec::start() {
     return mCodec->start();
 }
@@ -190,6 +195,10 @@
         : mCodec->releaseOutputBuffer(index);
 }
 
+status_t JMediaCodec::signalEndOfInputStream() {
+    return mCodec->signalEndOfInputStream();
+}
+
 status_t JMediaCodec::getOutputFormat(JNIEnv *env, jobject *format) const {
     sp<AMessage> msg;
     status_t err;
@@ -417,6 +426,29 @@
     throwExceptionAsNecessary(env, err);
 }
 
+static jobject android_media_MediaCodec_createInputSurface(JNIEnv* env,
+        jobject thiz) {
+    ALOGV("android_media_MediaCodec_createInputSurface");
+
+    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+    if (codec == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return NULL;
+    }
+
+    // Tell the MediaCodec that we want to use a Surface as input.
+    sp<IGraphicBufferProducer> bufferProducer;
+    status_t err = codec->createInputSurface(&bufferProducer);
+    if (err != NO_ERROR) {
+        throwExceptionAsNecessary(env, err);
+        return NULL;
+    }
+
+    // Wrap the IGBP in a Java-language Surface.
+    return android_view_Surface_createFromIGraphicBufferProducer(env,
+            bufferProducer);
+}
+
 static void android_media_MediaCodec_start(JNIEnv *env, jobject thiz) {
     ALOGV("android_media_MediaCodec_start");
 
@@ -685,6 +717,21 @@
     throwExceptionAsNecessary(env, err);
 }
 
+static void android_media_MediaCodec_signalEndOfInputStream(JNIEnv* env,
+        jobject thiz) {
+    ALOGV("android_media_MediaCodec_signalEndOfInputStream");
+
+    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+    if (codec == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    status_t err = codec->signalEndOfInputStream();
+
+    throwExceptionAsNecessary(env, err);
+}
+
 static jobject android_media_MediaCodec_getOutputFormatNative(
         JNIEnv *env, jobject thiz) {
     ALOGV("android_media_MediaCodec_getOutputFormatNative");
@@ -852,6 +899,9 @@
       "Landroid/media/MediaCrypto;I)V",
       (void *)android_media_MediaCodec_native_configure },
 
+    { "createInputSurface", "()Landroid/view/Surface;",
+      (void *)android_media_MediaCodec_createInputSurface },
+
     { "start", "()V", (void *)android_media_MediaCodec_start },
     { "stop", "()V", (void *)android_media_MediaCodec_stop },
     { "flush", "()V", (void *)android_media_MediaCodec_flush },
@@ -871,6 +921,9 @@
     { "releaseOutputBuffer", "(IZ)V",
       (void *)android_media_MediaCodec_releaseOutputBuffer },
 
+    { "signalEndOfInputStream", "()V",
+      (void *)android_media_MediaCodec_signalEndOfInputStream },
+
     { "getOutputFormatNative", "()Ljava/util/Map;",
       (void *)android_media_MediaCodec_getOutputFormatNative },
 
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index f478788..282d2c5 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -47,6 +47,8 @@
             const sp<ICrypto> &crypto,
             int flags);
 
+    status_t createInputSurface(sp<IGraphicBufferProducer>* bufferProducer);
+
     status_t start();
     status_t stop();
 
@@ -76,6 +78,8 @@
 
     status_t releaseOutputBuffer(size_t index, bool render);
 
+    status_t signalEndOfInputStream();
+
     status_t getOutputFormat(JNIEnv *env, jobject *format) const;
 
     status_t getBuffers(