stagefright: add MediaCodec.reset()

Bug: 12034929
Change-Id: I326f1356df89474aa088c1c87f8505b33654139d
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index a0ff997..3f7508b 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -73,6 +73,10 @@
     // unconfigured.
     status_t stop();
 
+    // Resets the codec to the INITIALIZED state.  Can be called after an error
+    // has occured to make the codec usable.
+    status_t reset();
+
     // Client MUST call release before releasing final reference to this
     // object.
     status_t release();
@@ -221,6 +225,11 @@
     sp<AMessage> mInputFormat;
     sp<AMessage> mCallback;
 
+    // initial create parameters
+    AString mInitName;
+    bool mInitNameIsType;
+    bool mInitIsEncoder;
+
     // Used only to synchronize asynchronous getBufferAndFormat
     // across all the other (synchronous) buffer state change
     // operations, such as de/queueIn/OutputBuffer, start and
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 24fd7ad..7a9cb0b 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -106,6 +106,11 @@
 }
 
 status_t MediaCodec::init(const char *name, bool nameIsType, bool encoder) {
+    // save init parameters for reset
+    mInitName = name;
+    mInitNameIsType = nameIsType;
+    mInitIsEncoder = encoder;
+
     // Current video decoders do not return from OMX_FillThisBuffer
     // quickly, violating the OpenMAX specs, until that is remedied
     // we need to invest in an extra looper to free the main event
@@ -235,6 +240,40 @@
     return PostAndAwaitResponse(msg, &response);
 }
 
+status_t MediaCodec::reset() {
+    /* When external-facing MediaCodec object is created,
+       it is already initialized.  Thus, reset is essentially
+       release() followed by init(), plus clearing the state */
+
+    status_t err = release();
+
+    // unregister handlers
+    if (mCodec != NULL) {
+        if (mCodecLooper != NULL) {
+            mCodecLooper->unregisterHandler(mCodec->id());
+        } else {
+            mLooper->unregisterHandler(mCodec->id());
+        }
+        mCodec = NULL;
+    }
+    mLooper->unregisterHandler(id());
+
+    mFlags = 0;    // clear all flags
+
+    // reset state not reset by setState(UNINITIALIZED)
+    mReplyID = 0;
+    mDequeueInputReplyID = 0;
+    mDequeueOutputReplyID = 0;
+    mDequeueInputTimeoutGeneration = 0;
+    mDequeueOutputTimeoutGeneration = 0;
+    mHaveInputSurface = false;
+
+    if (err == OK) {
+        err = init(mInitName.c_str(), mInitNameIsType, mInitIsEncoder);
+    }
+    return err;
+}
+
 status_t MediaCodec::queueInputBuffer(
         size_t index,
         size_t offset,
@@ -1553,6 +1592,7 @@
         mCrypto.clear();
         setNativeWindow(NULL);
 
+        mInputFormat.clear();
         mOutputFormat.clear();
         mFlags &= ~kFlagOutputFormatChanged;
         mFlags &= ~kFlagOutputBuffersChanged;
@@ -1566,6 +1606,9 @@
     }
 
     if (newState == UNINITIALIZED) {
+        // return any straggling buffers, e.g. if we got here on an error
+        returnBuffersToCodec();
+
         mComponentName.clear();
 
         // The component is gone, mediaserver's probably back up already