stagefright: handle removal of a tracked buffer in ACodec

Bug: 21815057
Change-Id: Idd1c71b4b0b68028020c3e10615936870ffd2dec
diff --git a/include/media/stagefright/FrameRenderTracker.h b/include/media/stagefright/FrameRenderTracker.h
index 3b0db5a..9333e8f 100644
--- a/include/media/stagefright/FrameRenderTracker.h
+++ b/include/media/stagefright/FrameRenderTracker.h
@@ -119,8 +119,9 @@
     std::list<Info> checkFencesAndGetRenderedFrames(const Info *until, bool dropIncomplete);
 
     // Stop tracking a queued frame (e.g. if the frame has been discarded). If |info| is NULL or is
-    // not tracked, this method is a no-op.
-    void untrackFrame(const Info *info);
+    // not tracked, this method is a no-op. If |index| is specified, all indices larger that |index|
+    // are decremented. This is useful if the untracked frame is deleted from the frame vector.
+    void untrackFrame(const Info *info, ssize_t index = SSIZE_MAX);
 
     void dumpRenderQueue() const;
 
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 527e9cd..478a0f5 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1271,8 +1271,12 @@
     // unlink untracked frames
     for (std::list<FrameRenderTracker::Info>::const_iterator it = done.cbegin();
             it != done.cend(); ++it) {
-        if (it->getIndex() >= 0) {
-            mBuffers[kPortIndexOutput].editItemAt(it->getIndex()).mRenderInfo = NULL;
+        ssize_t index = it->getIndex();
+        if (index >= 0 && (size_t)index < mBuffers[kPortIndexOutput].size()) {
+            mBuffers[kPortIndexOutput].editItemAt(index).mRenderInfo = NULL;
+        } else if (index >= 0) {
+            // THIS SHOULD NEVER HAPPEN
+            ALOGE("invalid index %zd in %zu", index, mBuffers[kPortIndexOutput].size());
         }
     }
 
@@ -1467,12 +1471,13 @@
         ::close(info->mFenceFd);
     }
 
-    mRenderTracker.untrackFrame(info->mRenderInfo);
-    info->mRenderInfo = NULL;
+    if (portIndex == kPortIndexOutput) {
+        mRenderTracker.untrackFrame(info->mRenderInfo, i);
+        info->mRenderInfo = NULL;
+    }
 
     // remove buffer even if mOMX->freeBuffer fails
     mBuffers[portIndex].removeAt(i);
-
     return err;
 }
 
diff --git a/media/libstagefright/FrameRenderTracker.cpp b/media/libstagefright/FrameRenderTracker.cpp
index ebd2197..917870f 100644
--- a/media/libstagefright/FrameRenderTracker.cpp
+++ b/media/libstagefright/FrameRenderTracker.cpp
@@ -149,14 +149,21 @@
     return done;
 }
 
-void FrameRenderTracker::untrackFrame(const FrameRenderTracker::Info *info) {
-    if (info != NULL) {
-        for (std::list<Info>::iterator it = mRenderQueue.begin();
-                it != mRenderQueue.end(); ++it) {
-            if (&*it == info) {
-                mRenderQueue.erase(it);
-                return;
+void FrameRenderTracker::untrackFrame(const FrameRenderTracker::Info *info, ssize_t index) {
+    if (info == NULL && index == SSIZE_MAX) {
+        // nothing to do
+        return;
+    }
+
+    for (std::list<Info>::iterator it = mRenderQueue.begin();
+            it != mRenderQueue.end(); ) {
+        if (&*it == info) {
+            mRenderQueue.erase(it++);
+        } else {
+            if (it->mIndex > index) {
+                --(it->mIndex);
             }
+            ++it;
         }
     }
 }