MediaCodec: add reset() + documentation fixes

Bug: 12034929
Change-Id: I38f89a2e4c41e0ceb3fdae4522b9c04f6c43a4f1
diff --git a/api/current.txt b/api/current.txt
index 2e25e33..9c09f14 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14427,6 +14427,7 @@
     method public final void release();
     method public final void releaseOutputBuffer(int, boolean);
     method public final void releaseOutputBuffer(int, long);
+    method public final void reset();
     method public void setCallback(android.media.MediaCodec.Callback);
     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 4abcb81..f84c383 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -136,14 +136,17 @@
  * cycle is necessary.
  *
  * <p> During its life, a codec conceptually exists in one of the following states:
- * Initialized, Configured, Executing, Uninitialized, (omitting transitory states
+ * Initialized, Configured, Executing, Error, Uninitialized, (omitting transitory states
  * between them). When created by one of the factory methods,
  * the codec is in the Initialized state; {@link #configure} brings it to the
  * Configured state; {@link #start} brings it to the Executing state.
  * In the Executing state, decoding or encoding occurs through the buffer queue
  * manipulation described above. The method {@link #stop}
  * returns the codec to the Initialized state, whereupon it may be configured again,
- * and {@link #release} brings the codec to the terminal Uninitialized state.
+ * and {@link #release} brings the codec to the terminal Uninitialized state.  When
+ * a codec error occurs, the codec moves to the Error state.  Use {@link #reset} to
+ * bring the codec back to the Initialized state, or {@link #release} to move it
+ * to the Uninitialized state.
  *
  * <p> The factory methods
  * {@link #createByCodecName},
@@ -170,7 +173,8 @@
  * then resources are temporarily unavailable and the method may be retried at a later time.
  * If both {@link MediaCodec.CodecException#isRecoverable}
  * and {@link MediaCodec.CodecException#isTransient} return false,
- * then the {@link MediaCodec.CodecException} is fatal and the codec must be released.
+ * then the {@link MediaCodec.CodecException} is fatal and the codec must be
+ * {@link #reset reset} or {@link #release released}.
  * Both {@link MediaCodec.CodecException#isRecoverable} and
  * {@link MediaCodec.CodecException#isTransient} do not return true at the same time.
  */
@@ -429,6 +433,23 @@
     }
 
     /**
+     * Returns the codec to its initial (Initialized) state.
+     *
+     * Call this if an {@link MediaCodec.CodecException#isRecoverable unrecoverable}
+     * error has occured to reset the codec to its initial state after creation.
+     *
+     * @throws CodecException if an unrecoverable error has occured and the codec
+     * could not be reset.
+     * @throws IllegalStateException if in the Uninitialized state.
+     */
+    public final void reset() {
+        freeAllTrackedBuffers(); // free buffers first
+        native_reset();
+    }
+
+    private native final void native_reset();
+
+    /**
      * Make sure you call this when you're done to free up any opened
      * component instance instead of relying on the garbage collector
      * to do this for you at some point in the future.
@@ -646,9 +667,10 @@
     /**
      * After filling a range of the input buffer at the specified index
      * submit it to the component. Once an input buffer is queued to
-     * the codec, it MUST not be used until it is later retrieved by
-     * {#getInputBuffer} in response to a {#dequeueInputBuffer}
-     * response.
+     * the codec, it MUST NOT be used until it is later retrieved by
+     * {@link #getInputBuffer} in response to a {@link #dequeueInputBuffer}
+     * return value or a {@link Callback#onInputBufferAvailable}
+     * callback.
      * <p>
      * Many decoders require the actual compressed data stream to be
      * preceded by "codec specific data", i.e. setup data used to initialize
@@ -905,9 +927,10 @@
      * the codec. If you previously specified a surface when configuring this
      * video decoder you can optionally render the buffer.
      *
-     * Once an output buffer is released to the codec, it MUST not
-     * be used until it is later retrieved by {#getOutputBuffer} in
-     * response to a {#dequeueOutputBuffer} response
+     * Once an output buffer is released to the codec, it MUST NOT
+     * be used until it is later retrieved by {@link #getOutputBuffer} in response
+     * to a {@link #dequeueOutputBuffer} return value or a
+     * {@link Callback#onOutputBufferAvailable} callback.
      *
      * @param index The index of a client-owned output buffer previously returned
      *              from a call to {@link #dequeueOutputBuffer}.
@@ -961,9 +984,10 @@
      * </td></tr>
      * </table>
      *
-     * Once an output buffer is released to the codec, it MUST not
-     * be used until it is later retrieved by {#getOutputBuffer} in
-     * response to a {#dequeueOutputBuffer} response
+     * Once an output buffer is released to the codec, it MUST NOT
+     * be used until it is later retrieved by {@link #getOutputBuffer} in response
+     * to a {@link #dequeueOutputBuffer} return value or a
+     * {@link Callback#onOutputBufferAvailable} callback.
      *
      * @param index The index of a client-owned output buffer previously returned
      *              from a call to {@link #dequeueOutputBuffer}.
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index b7294b8..04ff098 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -197,6 +197,10 @@
     return mCodec->flush();
 }
 
+status_t JMediaCodec::reset() {
+    return mCodec->reset();
+}
+
 status_t JMediaCodec::queueInputBuffer(
         size_t index,
         size_t offset, size_t size, int64_t timeUs, uint32_t flags,
@@ -854,6 +858,26 @@
     throwExceptionAsNecessary(env, err);
 }
 
+static void android_media_MediaCodec_reset(JNIEnv *env, jobject thiz) {
+    ALOGV("android_media_MediaCodec_reset");
+
+    sp<JMediaCodec> codec = getMediaCodec(env, thiz);
+
+    if (codec == NULL) {
+        // should never be here
+        jniThrowException(env, "java/lang/IllegalStateException", NULL);
+        return;
+    }
+
+    status_t err = codec->reset();
+    if (err != OK) {
+        // treat all errors as fatal for now, though resource not available
+        // errors could be treated as transient.
+        err = 0x80000000;
+    }
+    throwExceptionAsNecessary(env, err);
+}
+
 static void android_media_MediaCodec_flush(JNIEnv *env, jobject thiz) {
     ALOGV("android_media_MediaCodec_flush");
 
@@ -1398,6 +1422,8 @@
 static JNINativeMethod gMethods[] = {
     { "native_release", "()V", (void *)android_media_MediaCodec_release },
 
+    { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
+
     { "native_setCallback",
       "(Landroid/media/MediaCodec$Callback;)V",
       (void *)android_media_MediaCodec_native_setCallback },
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 2e650e3..dbccb0f 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -56,6 +56,7 @@
 
     status_t start();
     status_t stop();
+    status_t reset();
 
     status_t flush();