Merge "Some free chunk available notification is missing, which messes up the number of outstanding output buffer count. As a result, the media server either hangs if omx encoder node thinks it is still waiting for some buffers to be returned from the omx component, or silently crashes if the omx encoder node frees the buffer prematurely"
diff --git a/nodes/pvmp4ffcomposernode/src/pvmp4ffcn_node.cpp b/nodes/pvmp4ffcomposernode/src/pvmp4ffcn_node.cpp
index 2973a88..a5e5be3 100644
--- a/nodes/pvmp4ffcomposernode/src/pvmp4ffcn_node.cpp
+++ b/nodes/pvmp4ffcomposernode/src/pvmp4ffcn_node.cpp
@@ -70,10 +70,11 @@
         virtual ~FragmentWriter()
         {
             Mutex::Autolock l(mRequestMutex);
+
             LOG_ASSERT(mExitRequested, "Deleting an active instance.");
-            LOGD("Capacity of fragment queue reached %d", mQueue.capacity());
-            LOGD_IF(0 < mQueue.size(), "Flushing %d frags in dtor", mQueue.size());
-            while (0 < mQueue.size())  // make sure we are flushed
+            LOGD_IF(!mQueue.empty(), "Releasing %d fragments in dtor", mQueue.size());
+
+            while (!mQueue.empty())  // make sure we are flushed
             {
                 releaseQueuedFrame(mQueue.begin());
             }
@@ -85,6 +86,7 @@
         {
             mExitRequested = true;
             Thread::requestExit();
+
             mRequestMutex.lock();
             mRequestCv.signal();
             mRequestMutex.unlock();
@@ -100,15 +102,22 @@
             while (!done)
             {
                 mRequestMutex.lock();
-                done = mQueue.size() == 0 || iter > kMaxFlushAttempts;
+                done = mQueue.empty();
                 if (!done) mRequestCv.signal();
                 mRequestMutex.unlock();
                 if (!done) {
                     usleep(kFlushSleepMicros);
+                    if ((++iter % kMaxFlushAttemptsWarning) == 0) {
+                        if (iter >= kMaxFlushAttemptsCrashing) {
+                            LOGE("Fragment flush takes way too long!");
+                            // Crash media server!
+                            *((char *) 0) = 0x01;
+                        } else {
+                            LOGW("Fragement writer flush takes %d us", iter * kFlushSleepMicros);
+                        }
+                    }
                 }
-                ++iter;
             }
-            LOG_ASSERT(iter <= kMaxFlushAttempts, "Failed to flush");
         }
 
         // Called by the ProcessIncomingMsg method from the
@@ -119,7 +128,12 @@
                                          OsclRefCounterMemFrag& aMemFrag, PVMFFormatType aFormat,
                                          uint32& aTimestamp, int32 aTrackId, PVMp4FFComposerPort *aPort)
         {
-            if (mExitRequested) return PVMFErrCancelled;
+            if (mExitRequested) {
+                LOGW("Enqueue fragment after exit request!");
+                aFrame.clear();  // Release the frame
+                return PVMFErrCancelled;
+            }
+
             Mutex::Autolock lock(mRequestMutex);
             Request frame = {aFrame, aMemFrag, aFormat, aTimestamp, aTrackId, aPort};
             mQueue.push_back(frame);
@@ -130,9 +144,9 @@
     private:
         static const bool kThreadCallJava = false;
         static const OsclRefCounterMemFrag kEmptyFrag;
-        // Flush blocks for 2 seconds max.
-        static const size_t kMaxFlushAttempts = 10;
-        static const int kFlushSleepMicros = 200 * 1000;
+        static const int kFlushSleepMicros = 200 * 1000;    // 200 ms
+        static const size_t kMaxFlushAttemptsWarning = 10;  // 2 seconds
+        static const size_t kMaxFlushAttemptsCrashing = 30; // 6 seconds
 
         struct Request
         {
@@ -163,8 +177,6 @@
         // @Override Thread
         virtual bool threadLoop()
         {
-            Request frame;
-            bool addFrame = false;
             if (!mTid) mTid = androidGetThreadId();
 
             LOG_ASSERT(androidGetThreadId() == mTid,
@@ -177,19 +189,16 @@
                 mRequestCv.wait(mRequestMutex);
 
             if (!mQueue.empty()) {
-                // First copy the frame by value, since it will not be protected and the
-                // reference may change, then release the frame by reference
-                frame = mQueue[0];
-                addFrame = true;
-                releaseQueuedFrame(mQueue.begin());
-            }
-            mRequestMutex.unlock();
-
-            if (addFrame) {
+                // Hold the lock while writing the fragment
+                Request frame = mQueue[0];  // Make a local copy
                 mPrevWriteStatus = mComposer->AddMemFragToTrack(
                         frame.mFrame, frame.mFrag, frame.mFormat,
                         frame.mTimestamp, frame.mTrackId, frame.mPort);
+                if (!mQueue.empty()) {
+                    releaseQueuedFrame(mQueue.begin());
+                }
             }
+            mRequestMutex.unlock();
 
             return true;
         }