Merge "Fix uncertainty of one normal mix buffer in AudioTrack::getTimestamp" into lmp-dev
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index df0dc58..28e5c56 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -77,8 +77,14 @@
     };
 
     static bool isFlexibleColorFormat(
-        const sp<IOMX> &omx, IOMX::node_id node,
-        uint32_t colorFormat, OMX_U32 *flexibleEquivalent);
+            const sp<IOMX> &omx, IOMX::node_id node,
+            uint32_t colorFormat, OMX_U32 *flexibleEquivalent);
+
+    // Returns 0 if configuration is not supported.  NOTE: this is treated by
+    // some OMX components as auto level, and by others as invalid level.
+    static int /* OMX_VIDEO_AVCLEVELTYPE */ getAVCLevelFor(
+            int width, int height, int rate, int bitrate,
+            OMX_VIDEO_AVCPROFILETYPE profile = OMX_VIDEO_AVCProfileBaseline);
 
 protected:
     virtual ~ACodec();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index b904aa8..17190fb 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -30,6 +30,7 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/ACodec.h>
 #include <media/stagefright/AudioSource.h>
 #include <media/stagefright/AMRWriter.h>
 #include <media/stagefright/AACWriter.h>
@@ -1243,6 +1244,10 @@
         if (videoCodec == VIDEO_ENCODER_H264) {
             ALOGI("Force to use AVC baseline profile");
             setParamVideoEncoderProfile(OMX_VIDEO_AVCProfileBaseline);
+            // set 0 for invalid levels - this will be rejected by the
+            // codec if it cannot handle it during configure
+            setParamVideoEncoderLevel(ACodec::getAVCLevelFor(
+                    videoFrameWidth, videoFrameHeight, videoFrameRate, videoBitRate));
         }
     }
 }
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 7814bf1..27f6131 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -189,6 +189,8 @@
     for (size_t i = 0; i < mInputBufferIsDequeued.size(); i++) {
         mInputBufferIsDequeued.editItemAt(i) = false;
     }
+
+    mPendingInputMessages.clear();
 }
 
 void NuPlayer::Decoder::requestCodecNotification() {
@@ -274,7 +276,19 @@
         ALOGI("[%s] resubmitting CSD", mComponentName.c_str());
         reply->setBuffer("buffer", buffer);
         mCSDsToSubmit.removeAt(0);
-        reply->post();
+        CHECK(onInputBufferFilled(reply));
+        return true;
+    }
+
+    while (!mPendingInputMessages.empty()) {
+        sp<AMessage> msg = *mPendingInputMessages.begin();
+        if (!onInputBufferFilled(msg)) {
+            break;
+        }
+        mPendingInputMessages.erase(mPendingInputMessages.begin());
+    }
+
+    if (!mInputBufferIsDequeued.editItemAt(bufferIx)) {
         return true;
     }
 
@@ -286,7 +300,7 @@
     return true;
 }
 
-void android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
+bool android::NuPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) {
     size_t bufferIx;
     CHECK(msg->findSize("buffer-ix", &bufferIx));
     CHECK_LT(bufferIx, mInputBuffers.size());
@@ -306,9 +320,12 @@
                 const sp<ABuffer> &buf = mInputBuffers[ix];
                 if (buf->data() == mediaBuffer->data()) {
                     // all input buffers are dequeued on start, hence the check
-                    CHECK(mInputBufferIsDequeued[ix]);
-                    ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu",
-                            mComponentName.c_str(), ix, bufferIx);
+                    if (!mInputBufferIsDequeued[ix]) {
+                        ALOGV("[%s] received MediaBuffer for #%zu instead of #%zu",
+                                mComponentName.c_str(), ix, bufferIx);
+                        mediaBuffer->release();
+                        return false;
+                    }
 
                     // TRICKY: need buffer for the metadata, so instead, set
                     // codecBuffer to the same (though incorrect) buffer to
@@ -333,7 +350,7 @@
 
         if (streamErr == OK) {
             /* buffers are returned to hold on to */
-            return;
+            return true;
         }
 
         // attempt to queue EOS
@@ -398,6 +415,7 @@
             }
         }
     }
+    return true;
 }
 
 bool NuPlayer::Decoder::handleAnOutputBuffer() {
@@ -604,13 +622,21 @@
         case kWhatCodecNotify:
         {
             if (!isStaleReply(msg)) {
-                if (!mPaused) {
-                    while (handleAnInputBuffer()) {
-                    }
+                int32_t numInput, numOutput;
+
+                if (!msg->findInt32("input-buffers", &numInput)) {
+                    numInput = INT32_MAX;
                 }
 
-                while (handleAnOutputBuffer()) {
+                if (!msg->findInt32("output-buffers", &numOutput)) {
+                    numOutput = INT32_MAX;
                 }
+
+                if (!mPaused) {
+                    while (numInput-- > 0 && handleAnInputBuffer()) {}
+                }
+
+                while (numOutput-- > 0 && handleAnOutputBuffer()) {}
             }
 
             requestCodecNotification();
@@ -620,7 +646,10 @@
         case kWhatInputBufferFilled:
         {
             if (!isStaleReply(msg)) {
-                onInputBufferFilled(msg);
+                if (!mPendingInputMessages.empty()
+                        || !onInputBufferFilled(msg)) {
+                    mPendingInputMessages.push_back(msg);
+                }
             }
 
             break;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index cc1bdff..dba3eee 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -80,6 +80,8 @@
     sp<ALooper> mCodecLooper;
     sp<ALooper> mDecoderLooper;
 
+    List<sp<AMessage> > mPendingInputMessages;
+
     Vector<sp<ABuffer> > mInputBuffers;
     Vector<sp<ABuffer> > mOutputBuffers;
     Vector<sp<ABuffer> > mCSDsForCurrentFormat;
@@ -98,7 +100,7 @@
     void onConfigure(const sp<AMessage> &format);
     void onFlush();
     void onResume();
-    void onInputBufferFilled(const sp<AMessage> &msg);
+    bool onInputBufferFilled(const sp<AMessage> &msg);
     void onRenderBuffer(const sp<AMessage> &msg);
     void onShutdown();
 
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index d6fba98..b6ac2a0 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -32,6 +32,7 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
 
 #include <media/stagefright/BufferProducerWrapper.h>
 #include <media/stagefright/MediaCodecList.h>
@@ -2490,6 +2491,58 @@
     return setupErrorCorrectionParameters();
 }
 
+// static
+int /* OMX_VIDEO_AVCLEVELTYPE */ ACodec::getAVCLevelFor(
+        int width, int height, int rate, int bitrate,
+        OMX_VIDEO_AVCPROFILETYPE profile) {
+    // convert bitrate to main/baseline profile kbps equivalent
+    switch (profile) {
+        case OMX_VIDEO_AVCProfileHigh10:
+            bitrate = divUp(bitrate, 3000); break;
+        case OMX_VIDEO_AVCProfileHigh:
+            bitrate = divUp(bitrate, 1250); break;
+        default:
+            bitrate = divUp(bitrate, 1000); break;
+    }
+
+    // convert size and rate to MBs
+    width = divUp(width, 16);
+    height = divUp(height, 16);
+    int mbs = width * height;
+    rate *= mbs;
+    int maxDimension = max(width, height);
+
+    static const int limits[][5] = {
+        /*   MBps     MB   dim  bitrate        level */
+        {    1485,    99,  28,     64, OMX_VIDEO_AVCLevel1  },
+        {    1485,    99,  28,    128, OMX_VIDEO_AVCLevel1b },
+        {    3000,   396,  56,    192, OMX_VIDEO_AVCLevel11 },
+        {    6000,   396,  56,    384, OMX_VIDEO_AVCLevel12 },
+        {   11880,   396,  56,    768, OMX_VIDEO_AVCLevel13 },
+        {   11880,   396,  56,   2000, OMX_VIDEO_AVCLevel2  },
+        {   19800,   792,  79,   4000, OMX_VIDEO_AVCLevel21 },
+        {   20250,  1620, 113,   4000, OMX_VIDEO_AVCLevel22 },
+        {   40500,  1620, 113,  10000, OMX_VIDEO_AVCLevel3  },
+        {  108000,  3600, 169,  14000, OMX_VIDEO_AVCLevel31 },
+        {  216000,  5120, 202,  20000, OMX_VIDEO_AVCLevel32 },
+        {  245760,  8192, 256,  20000, OMX_VIDEO_AVCLevel4  },
+        {  245760,  8192, 256,  50000, OMX_VIDEO_AVCLevel41 },
+        {  522240,  8704, 263,  50000, OMX_VIDEO_AVCLevel42 },
+        {  589824, 22080, 420, 135000, OMX_VIDEO_AVCLevel5  },
+        {  983040, 36864, 543, 240000, OMX_VIDEO_AVCLevel51 },
+        { 2073600, 36864, 543, 240000, OMX_VIDEO_AVCLevel52 },
+    };
+
+    for (size_t i = 0; i < ARRAY_SIZE(limits); i++) {
+        const int (&limit)[5] = limits[i];
+        if (rate <= limit[0] && mbs <= limit[1] && maxDimension <= limit[2]
+                && bitrate <= limit[3]) {
+            return limit[4];
+        }
+    }
+    return 0;
+}
+
 status_t ACodec::setupAVCEncoderParameters(const sp<AMessage> &msg) {
     int32_t bitrate, iFrameInterval;
     if (!msg->findInt32("bitrate", &bitrate)
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index b56819c..b568063 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2141,11 +2141,24 @@
         return;
     }
 
-    if ((mFlags & (kFlagStickyError
+    bool isErrorOrOutputChanged =
+            (mFlags & (kFlagStickyError
                     | kFlagOutputBuffersChanged
-                    | kFlagOutputFormatChanged))
+                    | kFlagOutputFormatChanged));
+
+    if (isErrorOrOutputChanged
             || !mAvailPortBuffers[kPortIndexInput].empty()
             || !mAvailPortBuffers[kPortIndexOutput].empty()) {
+        mActivityNotify->setInt32("input-buffers",
+                mAvailPortBuffers[kPortIndexInput].size());
+
+        if (isErrorOrOutputChanged) {
+            // we want consumer to dequeue as many times as it can
+            mActivityNotify->setInt32("output-buffers", INT32_MAX);
+        } else {
+            mActivityNotify->setInt32("output-buffers",
+                    mAvailPortBuffers[kPortIndexOutput].size());
+        }
         mActivityNotify->post();
         mActivityNotify.clear();
     }