Added MediaCodec.releaseOutputBuffer() method with render timestamp

Bug: 11784827
Change-Id: I67097c8e69b40ef3baa436f0e7731d28c696735c
diff --git a/api/current.txt b/api/current.txt
index d90116f..2bdca9a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13825,6 +13825,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 releaseOutputBuffer(int, long);
     method public void setNotificationCallback(android.media.MediaCodec.NotificationCallback);
     method public final void setParameters(android.os.Bundle);
     method public final void setVideoScalingMode(int);
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index 115786c..34c55202 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -585,11 +585,63 @@
      * the codec. If you previously specified a surface when configuring this
      * video decoder you can optionally render the buffer.
      * @param index The index of a client-owned output buffer previously returned
-     *              in a call to {@link #dequeueOutputBuffer}.
+     *              from a call to {@link #dequeueOutputBuffer}.
      * @param render If a valid surface was specified when configuring the codec,
      *               passing true renders this output buffer to the surface.
      */
-    public native final void releaseOutputBuffer(int index, boolean render);
+    public final void releaseOutputBuffer(int index, boolean render) {
+        releaseOutputBuffer(index, render, false /* updatePTS */, 0 /* dummy */);
+    }
+
+    /**
+     * If you are done with a buffer, use this call to update its surface timestamp
+     * and return it to the codec to render it on the output surface. If you
+     * have not specified an output surface when configuring this video codec,
+     * this call will simply return the buffer to the codec.<p>
+     *
+     * The timestamp may have special meaning depending on the destination surface.
+     *
+     * <table>
+     * <tr><th>SurfaceView specifics</th></tr>
+     * <tr><td>
+     * If you render your buffer on a {@link android.view.SurfaceView},
+     * you can use the timestamp to render the buffer at a specific time (at the
+     * VSYNC at or after the buffer timestamp).  For this to work, the timestamp
+     * needs to be <i>reasonably close</i> to the current {@link System#nanoTime}.
+     * Currently, this is set as within one (1) second. A few notes:
+     *
+     * <ul>
+     * <li>the buffer will not be returned to the codec until the timestamp
+     * has passed and the buffer is no longer used by the {@link android.view.Surface}.
+     * <li>buffers are processed sequentially, so you may block subsequent buffers to
+     * be displayed on the {@link android.view.Surface}.  This is important if you
+     * want to react to user action, e.g. stop the video or seek.
+     * <li>if multiple buffers are sent to the {@link android.view.Surface} to be
+     * rendered at the same VSYNC, the last one will be shown, and the other ones
+     * will be dropped.
+     * <li>if the timestamp is <em>not</em> "reasonably close" to the current system
+     * time, the {@link android.view.Surface} will ignore the timestamp, and
+     * display the buffer at the earliest feasible time.  In this mode it will not
+     * drop frames.
+     * <li>for best performance and quality, call this method when you are about
+     * two VSYNCs' time before the desired render time.  For 60Hz displays, this is
+     * about 33 msec.
+     * </ul>
+     * </td></tr>
+     * </table>
+     *
+     * @param index The index of a client-owned output buffer previously returned
+     *              from a call to {@link #dequeueOutputBuffer}.
+     * @param renderTimestampNs The timestamp to associate with this buffer when
+     *              it is sent to the Surface.
+     */
+    public final void releaseOutputBuffer(int index, long renderTimestampNs) {
+        releaseOutputBuffer(
+                index, true /* render */, true /* updatePTS */, renderTimestampNs);
+    }
+
+    private native final void releaseOutputBuffer(
+            int index, boolean render, boolean updatePTS, long timeNs);
 
     /**
      * Signals end-of-stream on input.  Equivalent to submitting an empty buffer with
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index a710c03..4a7c096 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -260,7 +260,11 @@
     return OK;
 }
 
-status_t JMediaCodec::releaseOutputBuffer(size_t index, bool render) {
+status_t JMediaCodec::releaseOutputBuffer(
+        size_t index, bool render, bool updatePTS, int64_t timestampNs) {
+    if (updatePTS) {
+        return mCodec->renderOutputBufferAndRelease(index, timestampNs);
+    }
     return render
         ? mCodec->renderOutputBufferAndRelease(index)
         : mCodec->releaseOutputBuffer(index);
@@ -873,7 +877,8 @@
 }
 
 static void android_media_MediaCodec_releaseOutputBuffer(
-        JNIEnv *env, jobject thiz, jint index, jboolean render) {
+        JNIEnv *env, jobject thiz,
+        jint index, jboolean render, jboolean updatePTS, jlong timestampNs) {
     ALOGV("android_media_MediaCodec_renderOutputBufferAndRelease");
 
     sp<JMediaCodec> codec = getMediaCodec(env, thiz);
@@ -883,7 +888,7 @@
         return;
     }
 
-    status_t err = codec->releaseOutputBuffer(index, render);
+    status_t err = codec->releaseOutputBuffer(index, render, updatePTS, timestampNs);
 
     throwExceptionAsNecessary(env, err);
 }
@@ -1138,7 +1143,7 @@
     { "dequeueOutputBuffer", "(Landroid/media/MediaCodec$BufferInfo;J)I",
       (void *)android_media_MediaCodec_dequeueOutputBuffer },
 
-    { "releaseOutputBuffer", "(IZ)V",
+    { "releaseOutputBuffer", "(IZZJ)V",
       (void *)android_media_MediaCodec_releaseOutputBuffer },
 
     { "signalEndOfInputStream", "()V",
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 2f2ea96..bf9f4ea 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -79,7 +79,8 @@
     status_t dequeueOutputBuffer(
             JNIEnv *env, jobject bufferInfo, size_t *index, int64_t timeoutUs);
 
-    status_t releaseOutputBuffer(size_t index, bool render);
+    status_t releaseOutputBuffer(
+            size_t index, bool render, bool updatePTS, int64_t timestampNs);
 
     status_t signalEndOfInputStream();