Expose MediaCodec.setParameters API to

- change video target bitrate on the fly
- request sync frames
- temporarily suspend feeding input buffers to the encoder

Change-Id: If5cf1162b2eeb28ac08288ecfa9f0e9823dd972e
diff --git a/api/current.txt b/api/current.txt
index 6026cc5..bf95a71 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12046,6 +12046,7 @@
     method public final void queueSecureInputBuffer(int, int, android.media.MediaCodec.CryptoInfo, long, int) throws android.media.MediaCodec.CryptoException;
     method public final void release();
     method public final void releaseOutputBuffer(int, boolean);
+    method public final void setParameters(java.util.Map<java.lang.String, java.lang.Object>);
     method public final void setVideoScalingMode(int);
     method public final void signalEndOfInputStream();
     method public final void start();
@@ -12059,6 +12060,9 @@
     field public static final int INFO_OUTPUT_BUFFERS_CHANGED = -3; // 0xfffffffd
     field public static final int INFO_OUTPUT_FORMAT_CHANGED = -2; // 0xfffffffe
     field public static final int INFO_TRY_AGAIN_LATER = -1; // 0xffffffff
+    field public static final java.lang.String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
+    field public static final java.lang.String PARAMETER_KEY_SUSPEND = "drop-input-frames";
+    field public static final java.lang.String PARAMETER_KEY_VIDEO_BITRATE = "videoBitrate";
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
     field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
   }
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 703eb27..f4e867e 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -564,6 +564,52 @@
     public native final String getName();
 
     /**
+     * Change a video encoder's target bitrate on the fly. The value is an
+     * Integer object containing the new bitrate in bps.
+     */
+    public static final String PARAMETER_KEY_VIDEO_BITRATE = "videoBitrate";
+
+    /**
+     * Temporarily suspend/resume encoding of input data. While suspended
+     * input data is effectively discarded instead of being fed into the
+     * encoder. This parameter really only makes sense to use with an encoder
+     * in "surface-input" mode, as the client code has no control over the
+     * input-side of the encoder in that case.
+     * The value is an Integer object containing the value 1 to suspend
+     * or the value 0 to resume.
+     */
+    public static final String PARAMETER_KEY_SUSPEND = "drop-input-frames";
+
+    /**
+     * Request that the encoder produce a sync frame "soon".
+     * Provide an Integer with the value 0.
+     */
+    public static final String PARAMETER_KEY_REQUEST_SYNC_FRAME = "request-sync";
+
+    /**
+     * Communicate additional parameter changes to the component instance.
+     */
+    public final void setParameters(Map<String, Object> params) {
+        if (params == null) {
+            return;
+        }
+
+        String[] keys = new String[params.size()];
+        Object[] values = new Object[params.size()];
+
+        int i = 0;
+        for (Map.Entry<String, Object> entry: params.entrySet()) {
+            keys[i] = entry.getKey();
+            values[i] = entry.getValue();
+            ++i;
+        }
+
+        setParameters(keys, values);
+    }
+
+    private native final void setParameters(String[] keys, Object[] values);
+
+    /**
      * Get the codec info. If the codec was created by createDecoderByType
      * or createEncoderByType, what component is chosen is not known beforehand,
      * and thus the caller does not have the MediaCodecInfo.
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index ae1db87..a859506 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -310,6 +310,10 @@
     return OK;
 }
 
+status_t JMediaCodec::setParameters(const sp<AMessage> &msg) {
+    return mCodec->setParameters(msg);
+}
+
 void JMediaCodec::setVideoScalingMode(int mode) {
     if (mSurfaceTextureClient != NULL) {
         native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
@@ -837,6 +841,27 @@
     return NULL;
 }
 
+static void android_media_MediaCodec_setParameters(
+        JNIEnv *env, jobject thiz, jobjectArray keys, jobjectArray vals) {
+    ALOGV("android_media_MediaCodec_setParameters");
+
+    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+    if (codec == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    sp<AMessage> params;
+    status_t err = ConvertKeyValueArraysToMessage(env, keys, vals, &params);
+
+    if (err == OK) {
+        err = codec->setParameters(params);
+    }
+
+    throwExceptionAsNecessary(env, err);
+}
+
 static void android_media_MediaCodec_setVideoScalingMode(
         JNIEnv *env, jobject thiz, jint mode) {
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -986,6 +1011,9 @@
     { "getName", "()Ljava/lang/String;",
       (void *)android_media_MediaCodec_getName },
 
+    { "setParameters", "([Ljava/lang/String;[Ljava/lang/Object;)V",
+      (void *)android_media_MediaCodec_setParameters },
+
     { "setVideoScalingMode", "(I)V",
       (void *)android_media_MediaCodec_setVideoScalingMode },
 
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 282d2c5..2fbbd72 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -87,6 +87,8 @@
 
     status_t getName(JNIEnv *env, jstring *name) const;
 
+    status_t setParameters(const sp<AMessage> &params);
+
     void setVideoScalingMode(int mode);
 
 protected: