Merge "AudioPolicyManager: Use "safe" speaker for notifications if available" into lmp-dev
diff --git a/include/media/stagefright/foundation/AMessage.h b/include/media/stagefright/foundation/AMessage.h
index 5846d6b..a9e235b 100644
--- a/include/media/stagefright/foundation/AMessage.h
+++ b/include/media/stagefright/foundation/AMessage.h
@@ -137,7 +137,9 @@
             Rect rectValue;
         } u;
         const char *mName;
+        size_t      mNameLength;
         Type mType;
+        void setName(const char *name, size_t len);
     };
 
     enum {
@@ -147,12 +149,14 @@
     size_t mNumItems;
 
     Item *allocateItem(const char *name);
-    void freeItem(Item *item);
+    void freeItemValue(Item *item);
     const Item *findItem(const char *name, Type type) const;
 
     void setObjectInternal(
             const char *name, const sp<RefBase> &obj, Type type);
 
+    size_t findItemIndex(const char *name, size_t len) const;
+
     DISALLOW_EVIL_CONSTRUCTORS(AMessage);
 };
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 8ce7baf..163a0b5 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -595,7 +595,18 @@
         {
             if (!isStaleReply(msg)) {
                 onInputBufferFilled(msg);
+            } else {
+                /* release any MediaBuffer passed in the stale buffer */
+                sp<ABuffer> buffer;
+                MediaBuffer *mediaBuffer = NULL;
+                if (msg->findBuffer("buffer", &buffer) &&
+                    buffer->meta()->findPointer(
+                            "mediaBuffer", (void **)&mediaBuffer) &&
+                    mediaBuffer != NULL) {
+                    mediaBuffer->release();
+                }
             }
+
             break;
         }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index c9be0dd..ab7906a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -115,9 +115,12 @@
     notify->post();
     mPendingBuffers++;
 
-    sp<AMessage> message = new AMessage(kWhatRequestABuffer, id());
-    message->setInt32("generation", mBufferGeneration);
-    message->post();
+    // pending buffers will already result in requestABuffer
+    if (mPendingBuffers < kMaxPendingBuffers) {
+        sp<AMessage> message = new AMessage(kWhatRequestABuffer, id());
+        message->setInt32("generation", mBufferGeneration);
+        message->post();
+    }
     return;
 }
 
@@ -155,9 +158,7 @@
 void NuPlayer::DecoderPassThrough::onBufferConsumed(int32_t size) {
     mPendingBuffers--;
     mCachedBytes -= size;
-    sp<AMessage> message = new AMessage(kWhatRequestABuffer, id());
-    message->setInt32("generation", mBufferGeneration);
-    message->post();
+    requestABuffer();
 }
 
 void NuPlayer::DecoderPassThrough::onFlush() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 35cd514..7dd54c1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -626,12 +626,15 @@
     switch (msg) {
         case MEDIA_PLAYBACK_COMPLETE:
         {
-            if (mLooping && mState != STATE_RESET_IN_PROGRESS) {
-                mPlayer->seekToAsync(0);
-                break;
+            if (mState != STATE_RESET_IN_PROGRESS) {
+                if (mLooping) {
+                    mPlayer->seekToAsync(0);
+                    break;
+                }
+
+                mPlayer->pause();
+                mState = STATE_PAUSED;
             }
-            mPlayer->pause();
-            mState = STATE_PAUSED;
             // fall through
         }
 
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index fc2dd30..0bfc6e4 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -270,7 +270,20 @@
     }
 
     sp<AMessage> response;
-    return PostAndAwaitResponse(msg, &response);
+    status_t err = PostAndAwaitResponse(msg, &response);
+
+    if (err != OK && err != INVALID_OPERATION) {
+        // MediaCodec now set state to UNINITIALIZED upon any fatal error.
+        // To maintain backward-compatibility, do a reset() to put codec
+        // back into INITIALIZED state.
+        // But don't reset if the err is INVALID_OPERATION, which means
+        // the configure failure is due to wrong state.
+
+        ALOGE("configure failed with err 0x%08x, resetting...", err);
+        reset();
+    }
+
+    return err;
 }
 
 status_t MediaCodec::createInputSurface(
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 6dd9b92..8b4dd6f 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-//#define LOG_NDEBUG 0
 #define LOG_TAG "SoftAAC2"
+//#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
 #include "SoftAAC2.h"
@@ -68,6 +68,7 @@
       mOutputBufferCount(0),
       mSignalledError(false),
       mLastInHeader(NULL),
+      mCurrentInputTime(0),
       mOutputPortSettingsChange(NONE) {
     initPorts();
     CHECK_EQ(initDecoder(), (status_t)OK);
@@ -609,24 +610,9 @@
                     notify(OMX_EventError, OMX_ErrorStreamCorrupt, ERROR_MALFORMED, NULL);
                     return;
                 }
-
-                // insert buffer size and time stamp
-                mBufferSizes.add(inBufferLength[0]);
-                if (mLastInHeader != inHeader) {
-                    mBufferTimestamps.add(inHeader->nTimeStamp);
-                    mLastInHeader = inHeader;
-                } else {
-                    int64_t currentTime = mBufferTimestamps.top();
-                    currentTime += mStreamInfo->aacSamplesPerFrame *
-                            1000000ll / mStreamInfo->sampleRate;
-                    mBufferTimestamps.add(currentTime);
-                }
             } else {
                 inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
                 inBufferLength[0] = inHeader->nFilledLen;
-                mLastInHeader = inHeader;
-                mBufferTimestamps.add(inHeader->nTimeStamp);
-                mBufferSizes.add(inHeader->nFilledLen);
             }
 
             // Fill and decode
@@ -635,130 +621,136 @@
             INT prevSampleRate = mStreamInfo->sampleRate;
             INT prevNumChannels = mStreamInfo->numChannels;
 
+            if (inHeader != mLastInHeader) {
+                mLastInHeader = inHeader;
+                mCurrentInputTime = inHeader->nTimeStamp;
+            } else {
+                if (mStreamInfo->sampleRate) {
+                    mCurrentInputTime += mStreamInfo->aacSamplesPerFrame *
+                            1000000ll / mStreamInfo->sampleRate;
+                } else {
+                    ALOGW("no sample rate yet");
+                }
+            }
+            mAnchorTimes.add(mCurrentInputTime);
             aacDecoder_Fill(mAACDecoder,
                             inBuffer,
                             inBufferLength,
                             bytesValid);
 
-            // run DRC check
-            mDrcWrap.submitStreamData(mStreamInfo);
-            mDrcWrap.update();
+             // run DRC check
+             mDrcWrap.submitStreamData(mStreamInfo);
+             mDrcWrap.update();
 
-            UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
-            inHeader->nFilledLen -= inBufferUsedLength;
-            inHeader->nOffset += inBufferUsedLength;
+            AAC_DECODER_ERROR decoderErr =
+                aacDecoder_DecodeFrame(mAACDecoder,
+                                       tmpOutBuffer,
+                                       2048 * MAX_CHANNEL_COUNT,
+                                       0 /* flags */);
 
-            AAC_DECODER_ERROR decoderErr;
-            do {
-                int numconsumed = mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes;
-                decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
-                                           tmpOutBuffer,
-                                           2048 * MAX_CHANNEL_COUNT,
-                                           0 /* flags */);
+            if (decoderErr != AAC_DEC_OK) {
+                ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
+            }
 
-                numconsumed = (mStreamInfo->numTotalBytes + mStreamInfo->numBadBytes) - numconsumed;
-                if (numconsumed != 0) {
-                    mDecodedSizes.add(numconsumed);
-                }
+            if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
+                ALOGE("AAC_DEC_NOT_ENOUGH_BITS should never happen");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
 
-                if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
-                    break;
-                }
+            if (bytesValid[0] != 0) {
+                ALOGE("bytesValid[0] != 0 should never happen");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
+            }
 
-                if (decoderErr != AAC_DEC_OK) {
-                    ALOGW("aacDecoder_DecodeFrame decoderErr = 0x%4.4x", decoderErr);
-                }
+            size_t numOutBytes =
+                mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
 
-                if (bytesValid[0] != 0) {
-                    ALOGE("bytesValid[0] != 0 should never happen");
-                    mSignalledError = true;
-                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
-                    return;
-                }
-
-                size_t numOutBytes =
-                    mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
-
-                if (decoderErr == AAC_DEC_OK) {
-                    if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
-                            mStreamInfo->frameSize * mStreamInfo->numChannels)) {
-                        mSignalledError = true;
-                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
-                        return;
-                    }
-                } else {
-                    ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr);
-
-                    memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow
-
-                    if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
-                            mStreamInfo->frameSize * mStreamInfo->numChannels)) {
-                        mSignalledError = true;
-                        notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
-                        return;
-                    }
-
-                    // Discard input buffer.
-                    inHeader->nFilledLen = 0;
-
-                    aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
-
-                    // fall through
-                }
-
-                /*
-                 * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
-                 * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
-                 * rate system and the sampling rate in the final output is actually
-                 * doubled compared with the core AAC decoder sampling rate.
-                 *
-                 * Explicit signalling is done by explicitly defining SBR audio object
-                 * type in the bitstream. Implicit signalling is done by embedding
-                 * SBR content in AAC extension payload specific to SBR, and hence
-                 * requires an AAC decoder to perform pre-checks on actual audio frames.
-                 *
-                 * Thus, we could not say for sure whether a stream is
-                 * AAC+/eAAC+ until the first data frame is decoded.
-                 */
-                if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1
-                    if (mStreamInfo->sampleRate != prevSampleRate ||
-                        mStreamInfo->numChannels != prevNumChannels) {
-                        ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
-                              prevSampleRate, mStreamInfo->sampleRate,
-                              prevNumChannels, mStreamInfo->numChannels);
-
-                        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-                        mOutputPortSettingsChange = AWAITING_DISABLED;
-
-                        if (inHeader->nFilledLen == 0) {
-                            inInfo->mOwnedByUs = false;
-                            mInputBufferCount++;
-                            inQueue.erase(inQueue.begin());
-                            mLastInHeader = NULL;
-                            inInfo = NULL;
-                            notifyEmptyBufferDone(inHeader);
-                            inHeader = NULL;
-                        }
-                        return;
-                    }
-                } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
-                    ALOGW("Invalid AAC stream");
+            if (decoderErr == AAC_DEC_OK) {
+                if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
+                        mStreamInfo->frameSize * mStreamInfo->numChannels)) {
                     mSignalledError = true;
                     notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
                     return;
                 }
-                if (inHeader && inHeader->nFilledLen == 0) {
-                    inInfo->mOwnedByUs = false;
-                    mInputBufferCount++;
-                    inQueue.erase(inQueue.begin());
-                    mLastInHeader = NULL;
-                    inInfo = NULL;
-                    notifyEmptyBufferDone(inHeader);
-                    inHeader = NULL;
-                } else {
-                    ALOGV("inHeader->nFilledLen = %d", inHeader ? inHeader->nFilledLen : 0);
+                UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
+                inHeader->nFilledLen -= inBufferUsedLength;
+                inHeader->nOffset += inBufferUsedLength;
+            } else {
+                ALOGW("AAC decoder returned error 0x%4.4x, substituting silence", decoderErr);
+
+                memset(tmpOutBuffer, 0, numOutBytes); // TODO: check for overflow
+
+                if (!outputDelayRingBufferPutSamples(tmpOutBuffer,
+                        mStreamInfo->frameSize * mStreamInfo->numChannels)) {
+                    mSignalledError = true;
+                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                    return;
                 }
-            } while (decoderErr == AAC_DEC_OK);
+
+                // Discard input buffer.
+                inHeader->nFilledLen = 0;
+
+                aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
+
+                // fall through
+            }
+
+            /*
+             * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
+             * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
+             * rate system and the sampling rate in the final output is actually
+             * doubled compared with the core AAC decoder sampling rate.
+             *
+             * Explicit signalling is done by explicitly defining SBR audio object
+             * type in the bitstream. Implicit signalling is done by embedding
+             * SBR content in AAC extension payload specific to SBR, and hence
+             * requires an AAC decoder to perform pre-checks on actual audio frames.
+             *
+             * Thus, we could not say for sure whether a stream is
+             * AAC+/eAAC+ until the first data frame is decoded.
+             */
+            if (mInputBufferCount <= 2 || mOutputBufferCount > 1) { // TODO: <= 1
+                if (mStreamInfo->sampleRate != prevSampleRate ||
+                    mStreamInfo->numChannels != prevNumChannels) {
+                    ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
+                          prevSampleRate, mStreamInfo->sampleRate,
+                          prevNumChannels, mStreamInfo->numChannels);
+
+                    notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
+                    mOutputPortSettingsChange = AWAITING_DISABLED;
+
+                    if (inHeader->nFilledLen == 0) {
+                        inInfo->mOwnedByUs = false;
+                        mInputBufferCount++;
+                        inQueue.erase(inQueue.begin());
+                        mLastInHeader = NULL;
+                        inInfo = NULL;
+                        notifyEmptyBufferDone(inHeader);
+                        inHeader = NULL;
+                    }
+                    return;
+                }
+            } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
+                ALOGW("Invalid AAC stream");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                return;
+            }
+            if (inHeader->nFilledLen == 0) {
+                inInfo->mOwnedByUs = false;
+                mInputBufferCount++;
+                inQueue.erase(inQueue.begin());
+                mLastInHeader = NULL;
+                inInfo = NULL;
+                notifyEmptyBufferDone(inHeader);
+                inHeader = NULL;
+            } else {
+                ALOGV("inHeader->nFilledLen = %d", inHeader->nFilledLen);
+            }
         }
 
         int32_t outputDelay = mStreamInfo->outputDelay * mStreamInfo->numChannels;
@@ -817,9 +809,8 @@
 
             INT_PCM *outBuffer =
                     reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset);
-            int samplesize = mStreamInfo->numChannels * sizeof(int16_t);
             if (outHeader->nOffset
-                    + mStreamInfo->frameSize * samplesize
+                    + mStreamInfo->frameSize * mStreamInfo->numChannels * sizeof(int16_t)
                     > outHeader->nAllocLen) {
                 ALOGE("buffer overflow");
                 mSignalledError = true;
@@ -827,67 +818,17 @@
                 return;
 
             }
-
-            int available = outputDelayRingBufferSamplesAvailable();
-            int numSamples = outHeader->nAllocLen / samplesize;
-            if (numSamples > available) {
-                numSamples = available;
-            }
-            int64_t currentTime = 0;
-            if (available) {
-
-                int numFrames = numSamples / (mStreamInfo->frameSize * mStreamInfo->numChannels);
-                numSamples = numFrames * (mStreamInfo->frameSize * mStreamInfo->numChannels);
-
-                ALOGV("%d samples available (%d), or %d frames",
-                        numSamples, available, numFrames);
-                int64_t *nextTimeStamp = &mBufferTimestamps.editItemAt(0);
-                currentTime = *nextTimeStamp;
-                int32_t *currentBufLeft = &mBufferSizes.editItemAt(0);
-                for (int i = 0; i < numFrames; i++) {
-                    int32_t decodedSize = mDecodedSizes.itemAt(0);
-                    mDecodedSizes.removeAt(0);
-                    ALOGV("decoded %d of %d", decodedSize, *currentBufLeft);
-                    if (*currentBufLeft > decodedSize) {
-                        // adjust/interpolate next time stamp
-                        *currentBufLeft -= decodedSize;
-                        *nextTimeStamp += mStreamInfo->aacSamplesPerFrame *
-                                1000000ll / mStreamInfo->sampleRate;
-                        ALOGV("adjusted nextTimeStamp/size to %lld/%d",
-                                *nextTimeStamp, *currentBufLeft);
-                    } else {
-                        // move to next timestamp in list
-                        if (mBufferTimestamps.size() > 0) {
-                            mBufferTimestamps.removeAt(0);
-                            nextTimeStamp = &mBufferTimestamps.editItemAt(0);
-                            mBufferSizes.removeAt(0);
-                            currentBufLeft = &mBufferSizes.editItemAt(0);
-                            ALOGV("moved to next time/size: %lld/%d",
-                                    *nextTimeStamp, *currentBufLeft);
-                        }
-                        // try to limit output buffer size to match input buffers
-                        // (e.g when an input buffer contained 4 "sub" frames, output
-                        // at most 4 decoded units in the corresponding output buffer)
-                        // This is optional. Remove the next three lines to fill the output
-                        // buffer with as many units as available.
-                        numFrames = i + 1;
-                        numSamples = numFrames * mStreamInfo->frameSize * mStreamInfo->numChannels;
-                        break;
-                    }
-                }
-
-                ALOGV("getting %d from ringbuffer", numSamples);
-                int32_t ns = outputDelayRingBufferGetSamples(outBuffer, numSamples);
-                if (ns != numSamples) {
-                    ALOGE("not a complete frame of samples available");
-                    mSignalledError = true;
-                    notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
-                    return;
-                }
+            int32_t ns = outputDelayRingBufferGetSamples(outBuffer,
+                    mStreamInfo->frameSize * mStreamInfo->numChannels); // TODO: check for overflow
+            if (ns != mStreamInfo->frameSize * mStreamInfo->numChannels) {
+                ALOGE("not a complete frame of samples available");
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+                return;
             }
 
-            outHeader->nFilledLen = numSamples * sizeof(int16_t);
-
+            outHeader->nFilledLen = mStreamInfo->frameSize * mStreamInfo->numChannels
+                    * sizeof(int16_t);
             if (mEndOfInput && !outQueue.empty() && outputDelayRingBufferSamplesAvailable() == 0) {
                 outHeader->nFlags = OMX_BUFFERFLAG_EOS;
                 mEndOfOutput = true;
@@ -895,13 +836,13 @@
                 outHeader->nFlags = 0;
             }
 
-            outHeader->nTimeStamp = currentTime;
+            outHeader->nTimeStamp = mAnchorTimes.isEmpty() ? 0 : mAnchorTimes.itemAt(0);
+            mAnchorTimes.removeAt(0);
 
             mOutputBufferCount++;
             outInfo->mOwnedByUs = false;
             outQueue.erase(outQueue.begin());
             outInfo = NULL;
-            ALOGV("out timestamp %lld / %d", outHeader->nTimeStamp, outHeader->nFilledLen);
             notifyFillBufferDone(outHeader);
             outHeader = NULL;
         }
@@ -936,10 +877,8 @@
                     outHeader->nFilledLen = 0;
                     outHeader->nFlags = OMX_BUFFERFLAG_EOS;
 
-                    outHeader->nTimeStamp = mBufferTimestamps.itemAt(0);
-                    mBufferTimestamps.clear();
-                    mBufferSizes.clear();
-                    mDecodedSizes.clear();
+                    outHeader->nTimeStamp = mAnchorTimes.itemAt(0);
+                    mAnchorTimes.removeAt(0);
 
                     mOutputBufferCount++;
                     outInfo->mOwnedByUs = false;
@@ -960,9 +899,7 @@
         // depend on fragments from the last one decoded.
         // drain all existing data
         drainDecoder();
-        mBufferTimestamps.clear();
-        mBufferSizes.clear();
-        mDecodedSizes.clear();
+        mAnchorTimes.clear();
         mLastInHeader = NULL;
     } else {
         while (outputDelayRingBufferSamplesAvailable() > 0) {
@@ -1018,9 +955,7 @@
     mOutputDelayRingBufferReadPos = 0;
     mEndOfInput = false;
     mEndOfOutput = false;
-    mBufferTimestamps.clear();
-    mBufferSizes.clear();
-    mDecodedSizes.clear();
+    mAnchorTimes.clear();
     mLastInHeader = NULL;
 
     // To make the codec behave the same before and after a reset, we need to invalidate the
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index 9fcb598..865bd15 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -59,9 +59,8 @@
     size_t mOutputBufferCount;
     bool mSignalledError;
     OMX_BUFFERHEADERTYPE *mLastInHeader;
-    Vector<int32_t> mBufferSizes;
-    Vector<int32_t> mDecodedSizes;
-    Vector<int64_t> mBufferTimestamps;
+    int64_t mCurrentInputTime;
+    Vector<int64_t> mAnchorTimes;
 
     CDrcPresModeWrapper mDrcWrap;
 
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
index 2f63bdd..828577a 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -137,29 +137,10 @@
 
             uint32_t width = mImg->d_w;
             uint32_t height = mImg->d_h;
-
-            if (width != mWidth || height != mHeight) {
-                mWidth = width;
-                mHeight = height;
-
-                if (!mIsAdaptive || width > mAdaptiveMaxWidth || height > mAdaptiveMaxHeight) {
-                    if (mIsAdaptive) {
-                        if (width > mAdaptiveMaxWidth) {
-                            mAdaptiveMaxWidth = width;
-                        }
-                        if (height > mAdaptiveMaxHeight) {
-                            mAdaptiveMaxHeight = height;
-                        }
-                    }
-                    updatePortDefinitions();
-                    notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL);
-                    mOutputPortSettingsChange = AWAITING_DISABLED;
-                    return;
-                } else {
-                    updatePortDefinitions();
-                    notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
-                           OMX_IndexConfigCommonOutputCrop, NULL);
-                }
+            bool portWillReset = false;
+            handlePortSettingsChange(&portWillReset, width, height);
+            if (portWillReset) {
+                return;
             }
 
             outHeader->nOffset = 0;
@@ -167,36 +148,14 @@
             outHeader->nFlags = EOSseen ? OMX_BUFFERFLAG_EOS : 0;
             outHeader->nTimeStamp = inHeader->nTimeStamp;
 
-            uint32_t buffer_stride = mIsAdaptive ? mAdaptiveMaxWidth : mWidth;
-            uint32_t buffer_height = mIsAdaptive ? mAdaptiveMaxHeight : mHeight;
-
-            const uint8_t *srcLine = (const uint8_t *)mImg->planes[PLANE_Y];
             uint8_t *dst = outHeader->pBuffer;
-            for (size_t i = 0; i < buffer_height; ++i) {
-                if (i < mImg->d_h) {
-                    memcpy(dst, srcLine, mImg->d_w);
-                    srcLine += mImg->stride[PLANE_Y];
-                }
-                dst += buffer_stride;
-            }
-
-            srcLine = (const uint8_t *)mImg->planes[PLANE_U];
-            for (size_t i = 0; i < buffer_height / 2; ++i) {
-                if (i < mImg->d_h / 2) {
-                    memcpy(dst, srcLine, mImg->d_w / 2);
-                    srcLine += mImg->stride[PLANE_U];
-                }
-                dst += buffer_stride / 2;
-            }
-
-            srcLine = (const uint8_t *)mImg->planes[PLANE_V];
-            for (size_t i = 0; i < buffer_height / 2; ++i) {
-                if (i < mImg->d_h / 2) {
-                    memcpy(dst, srcLine, mImg->d_w / 2);
-                    srcLine += mImg->stride[PLANE_V];
-                }
-                dst += buffer_stride / 2;
-            }
+            const uint8_t *srcY = (const uint8_t *)mImg->planes[PLANE_Y];
+            const uint8_t *srcU = (const uint8_t *)mImg->planes[PLANE_U];
+            const uint8_t *srcV = (const uint8_t *)mImg->planes[PLANE_V];
+            size_t srcYStride = mImg->stride[PLANE_Y];
+            size_t srcUStride = mImg->stride[PLANE_U];
+            size_t srcVStride = mImg->stride[PLANE_V];
+            copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride);
 
             mImg = NULL;
             outInfo->mOwnedByUs = false;
diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
index a7bde97..cf3c3e3 100644
--- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
+++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
@@ -58,7 +58,6 @@
             320 /* width */, 240 /* height */, callbacks, appData, component),
       mHandle(NULL),
       mInputBufferCount(0),
-      mPictureSize(mWidth * mHeight * 3 / 2),
       mFirstPicture(NULL),
       mFirstPictureId(-1),
       mPicId(0),
@@ -118,7 +117,7 @@
     }
 
     H264SwDecRet ret = H264SWDEC_PIC_RDY;
-    bool portSettingsChanged = false;
+    bool portWillReset = false;
     while ((mEOSStatus != INPUT_DATA_AVAILABLE || !inQueue.empty())
             && outQueue.size() == kNumOutputBuffers) {
 
@@ -161,17 +160,13 @@
                     H264SwDecInfo decoderInfo;
                     CHECK(H264SwDecGetInfo(mHandle, &decoderInfo) == H264SWDEC_OK);
 
-                    if (handlePortSettingChangeEvent(&decoderInfo)) {
-                        portSettingsChanged = true;
-                    }
-
-                    if (decoderInfo.croppingFlag &&
-                        handleCropRectEvent(&decoderInfo.cropParams)) {
-                        portSettingsChanged = true;
-                    }
+                    bool cropChanged = handleCropChange(decoderInfo);
+                    handlePortSettingsChange(
+                            &portWillReset, decoderInfo.picWidth, decoderInfo.picHeight,
+                            cropChanged);
                 }
             } else {
-                if (portSettingsChanged) {
+                if (portWillReset) {
                     if (H264SwDecNextPicture(mHandle, &decodedPicture, 0)
                         == H264SWDEC_PIC_RDY) {
 
@@ -199,8 +194,7 @@
         inInfo->mOwnedByUs = false;
         notifyEmptyBufferDone(inHeader);
 
-        if (portSettingsChanged) {
-            portSettingsChanged = false;
+        if (portWillReset) {
             return;
         }
 
@@ -215,44 +209,33 @@
     }
 }
 
-bool SoftAVC::handlePortSettingChangeEvent(const H264SwDecInfo *info) {
-    if (mWidth != info->picWidth || mHeight != info->picHeight) {
-        mWidth  = info->picWidth;
-        mHeight = info->picHeight;
-        mPictureSize = mWidth * mHeight * 3 / 2;
-        updatePortDefinitions();
-        notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
-        mOutputPortSettingsChange = AWAITING_DISABLED;
-        return true;
+bool SoftAVC::handleCropChange(const H264SwDecInfo& decInfo) {
+    if (!decInfo.croppingFlag) {
+        return false;
     }
 
-    return false;
-}
-
-bool SoftAVC::handleCropRectEvent(const CropParams *crop) {
-    if (mCropLeft != crop->cropLeftOffset ||
-        mCropTop != crop->cropTopOffset ||
-        mCropWidth != crop->cropOutWidth ||
-        mCropHeight != crop->cropOutHeight) {
-        mCropLeft = crop->cropLeftOffset;
-        mCropTop = crop->cropTopOffset;
-        mCropWidth = crop->cropOutWidth;
-        mCropHeight = crop->cropOutHeight;
-
-        notify(OMX_EventPortSettingsChanged, 1,
-                OMX_IndexConfigCommonOutputCrop, NULL);
-
-        return true;
+    const CropParams& crop = decInfo.cropParams;
+    if (mCropLeft == crop.cropLeftOffset &&
+        mCropTop == crop.cropTopOffset &&
+        mCropWidth == crop.cropOutWidth &&
+        mCropHeight == crop.cropOutHeight) {
+        return false;
     }
-    return false;
+
+    mCropLeft = crop.cropLeftOffset;
+    mCropTop = crop.cropTopOffset;
+    mCropWidth = crop.cropOutWidth;
+    mCropHeight = crop.cropOutHeight;
+    return true;
 }
 
 void SoftAVC::saveFirstOutputBuffer(int32_t picId, uint8_t *data) {
     CHECK(mFirstPicture == NULL);
     mFirstPictureId = picId;
 
-    mFirstPicture = new uint8_t[mPictureSize];
-    memcpy(mFirstPicture, data, mPictureSize);
+    uint32_t pictureSize = mWidth * mHeight * 3 / 2;
+    mFirstPicture = new uint8_t[pictureSize];
+    memcpy(mFirstPicture, data, pictureSize);
 }
 
 void SoftAVC::drainOneOutputBuffer(int32_t picId, uint8_t* data) {
@@ -263,9 +246,17 @@
     OMX_BUFFERHEADERTYPE *header = mPicToHeaderMap.valueFor(picId);
     outHeader->nTimeStamp = header->nTimeStamp;
     outHeader->nFlags = header->nFlags;
-    outHeader->nFilledLen = mPictureSize;
-    memcpy(outHeader->pBuffer + outHeader->nOffset,
-            data, mPictureSize);
+    outHeader->nFilledLen = mWidth * mHeight * 3 / 2;
+
+    uint8_t *dst = outHeader->pBuffer + outHeader->nOffset;
+    const uint8_t *srcY = data;
+    const uint8_t *srcU = srcY + mWidth * mHeight;
+    const uint8_t *srcV = srcU + mWidth * mHeight / 4;
+    size_t srcYStride = mWidth;
+    size_t srcUStride = mWidth / 2;
+    size_t srcVStride = srcUStride;
+    copyYV12FrameToOutputBuffer(dst, srcY, srcU, srcV, srcYStride, srcUStride, srcVStride);
+
     mPicToHeaderMap.removeItem(picId);
     delete header;
     outInfo->mOwnedByUs = false;
diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.h b/media/libstagefright/codecs/on2/h264dec/SoftAVC.h
index ee69926..253a406 100644
--- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.h
+++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.h
@@ -55,8 +55,6 @@
 
     size_t mInputBufferCount;
 
-    uint32_t mPictureSize;
-
     uint8_t *mFirstPicture;
     int32_t mFirstPictureId;
 
@@ -75,8 +73,7 @@
     void drainAllOutputBuffers(bool eos);
     void drainOneOutputBuffer(int32_t picId, uint8_t *data);
     void saveFirstOutputBuffer(int32_t pidId, uint8_t *data);
-    bool handleCropRectEvent(const CropParams* crop);
-    bool handlePortSettingChangeEvent(const H264SwDecInfo *info);
+    bool handleCropChange(const H264SwDecInfo& decInfo);
 
     DISALLOW_EVIL_CONSTRUCTORS(SoftAVC);
 };
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index d268aa4..bc3e3fb 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -14,6 +14,11 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "AMessage"
+//#define LOG_NDEBUG 0
+//#define DUMP_STATS
+#include <cutils/log.h>
+
 #include "AMessage.h"
 
 #include <ctype.h>
@@ -60,12 +65,14 @@
 void AMessage::clear() {
     for (size_t i = 0; i < mNumItems; ++i) {
         Item *item = &mItems[i];
-        freeItem(item);
+        delete[] item->mName;
+        item->mName = NULL;
+        freeItemValue(item);
     }
     mNumItems = 0;
 }
 
-void AMessage::freeItem(Item *item) {
+void AMessage::freeItemValue(Item *item) {
     switch (item->mType) {
         case kTypeString:
         {
@@ -88,25 +95,85 @@
     }
 }
 
-AMessage::Item *AMessage::allocateItem(const char *name) {
-    name = AAtomizer::Atomize(name);
+#ifdef DUMP_STATS
+#include <utils/Mutex.h>
 
-    size_t i = 0;
-    while (i < mNumItems && mItems[i].mName != name) {
-        ++i;
+Mutex gLock;
+static int32_t gFindItemCalls = 1;
+static int32_t gDupCalls = 1;
+static int32_t gAverageNumItems = 0;
+static int32_t gAverageNumChecks = 0;
+static int32_t gAverageNumMemChecks = 0;
+static int32_t gAverageDupItems = 0;
+static int32_t gLastChecked = -1;
+
+static void reportStats() {
+    int32_t time = (ALooper::GetNowUs() / 1000);
+    if (time / 1000 != gLastChecked / 1000) {
+        gLastChecked = time;
+        ALOGI("called findItemIx %zu times (for len=%.1f i=%.1f/%.1f mem) dup %zu times (for len=%.1f)",
+                gFindItemCalls,
+                gAverageNumItems / (float)gFindItemCalls,
+                gAverageNumChecks / (float)gFindItemCalls,
+                gAverageNumMemChecks / (float)gFindItemCalls,
+                gDupCalls,
+                gAverageDupItems / (float)gDupCalls);
+        gFindItemCalls = gDupCalls = 1;
+        gAverageNumItems = gAverageNumChecks = gAverageNumMemChecks = gAverageDupItems = 0;
+        gLastChecked = time;
     }
+}
+#endif
 
+inline size_t AMessage::findItemIndex(const char *name, size_t len) const {
+#ifdef DUMP_STATS
+    size_t memchecks = 0;
+#endif
+    size_t i = 0;
+    for (; i < mNumItems; i++) {
+        if (len != mItems[i].mNameLength) {
+            continue;
+        }
+#ifdef DUMP_STATS
+        ++memchecks;
+#endif
+        if (!memcmp(mItems[i].mName, name, len)) {
+            break;
+        }
+    }
+#ifdef DUMP_STATS
+    {
+        Mutex::Autolock _l(gLock);
+        ++gFindItemCalls;
+        gAverageNumItems += mNumItems;
+        gAverageNumMemChecks += memchecks;
+        gAverageNumChecks += i;
+        reportStats();
+    }
+#endif
+    return i;
+}
+
+// assumes item's name was uninitialized or NULL
+void AMessage::Item::setName(const char *name, size_t len) {
+    mNameLength = len;
+    mName = new char[len + 1];
+    memcpy((void*)mName, name, len + 1);
+}
+
+AMessage::Item *AMessage::allocateItem(const char *name) {
+    size_t len = strlen(name);
+    size_t i = findItemIndex(name, len);
     Item *item;
 
     if (i < mNumItems) {
         item = &mItems[i];
-        freeItem(item);
+        freeItemValue(item);
     } else {
         CHECK(mNumItems < kMaxNumItems);
         i = mNumItems++;
         item = &mItems[i];
-
-        item->mName = name;
+        item->setName(name, len);
     }
 
     return item;
@@ -114,31 +181,18 @@
 
 const AMessage::Item *AMessage::findItem(
         const char *name, Type type) const {
-    name = AAtomizer::Atomize(name);
-
-    for (size_t i = 0; i < mNumItems; ++i) {
+    size_t i = findItemIndex(name, strlen(name));
+    if (i < mNumItems) {
         const Item *item = &mItems[i];
+        return item->mType == type ? item : NULL;
 
-        if (item->mName == name) {
-            return item->mType == type ? item : NULL;
-        }
     }
-
     return NULL;
 }
 
 bool AMessage::contains(const char *name) const {
-    name = AAtomizer::Atomize(name);
-
-    for (size_t i = 0; i < mNumItems; ++i) {
-        const Item *item = &mItems[i];
-
-        if (item->mName == name) {
-            return true;
-        }
-    }
-
-    return false;
+    size_t i = findItemIndex(name, strlen(name));
+    return i < mNumItems;
 }
 
 #define BASIC_TYPE(NAME,FIELDNAME,TYPENAME)                             \
@@ -297,11 +351,20 @@
     sp<AMessage> msg = new AMessage(mWhat, mTarget);
     msg->mNumItems = mNumItems;
 
+#ifdef DUMP_STATS
+    {
+        Mutex::Autolock _l(gLock);
+        ++gDupCalls;
+        gAverageDupItems += mNumItems;
+        reportStats();
+    }
+#endif
+
     for (size_t i = 0; i < mNumItems; ++i) {
         const Item *from = &mItems[i];
         Item *to = &msg->mItems[i];
 
-        to->mName = from->mName;
+        to->setName(from->mName, from->mNameLength);
         to->mType = from->mType;
 
         switch (from->mType) {
@@ -472,11 +535,11 @@
     sp<AMessage> msg = new AMessage(what);
 
     msg->mNumItems = static_cast<size_t>(parcel.readInt32());
-
     for (size_t i = 0; i < msg->mNumItems; ++i) {
         Item *item = &msg->mItems[i];
 
-        item->mName = AAtomizer::Atomize(parcel.readCString());
+        const char *name = parcel.readCString();
+        item->setName(name, strlen(name));
         item->mType = static_cast<Type>(parcel.readInt32());
 
         switch (item->mType) {
diff --git a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
index ee553d9..4a6ab63 100644
--- a/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
+++ b/media/libstagefright/include/SoftVideoDecoderOMXComponent.h
@@ -63,7 +63,14 @@
             OMX_U32 numOutputBuffers,
             const char *mimeType);
 
-    virtual void updatePortDefinitions();
+    virtual void updatePortDefinitions(bool updateCrop = true);
+
+    void handlePortSettingsChange(
+            bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged = false);
+
+    void copyYV12FrameToOutputBuffer(
+            uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
+            size_t srcYStride, size_t srcUStride, size_t srcVStride);
 
     enum {
         kInputPortIndex  = 0,
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 69b572e..e533fdd 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -123,13 +123,15 @@
     updatePortDefinitions();
 }
 
-void SoftVideoDecoderOMXComponent::updatePortDefinitions() {
+void SoftVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop) {
     OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kInputPortIndex)->mDef;
     def->format.video.nFrameWidth = mWidth;
     def->format.video.nFrameHeight = mHeight;
     def->format.video.nStride = def->format.video.nFrameWidth;
     def->format.video.nSliceHeight = def->format.video.nFrameHeight;
 
+    def->nBufferSize = def->format.video.nFrameWidth * def->format.video.nFrameHeight * 3 / 2;
+
     def = &editPortInfo(kOutputPortIndex)->mDef;
     def->format.video.nFrameWidth = mIsAdaptive ? mAdaptiveMaxWidth : mWidth;
     def->format.video.nFrameHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight;
@@ -140,10 +142,77 @@
             (def->format.video.nFrameWidth *
              def->format.video.nFrameHeight * 3) / 2;
 
-    mCropLeft = 0;
-    mCropTop = 0;
-    mCropWidth = mWidth;
-    mCropHeight = mHeight;
+    if (updateCrop) {
+        mCropLeft = 0;
+        mCropTop = 0;
+        mCropWidth = mWidth;
+        mCropHeight = mHeight;
+    }
+}
+
+void SoftVideoDecoderOMXComponent::handlePortSettingsChange(
+        bool *portWillReset, uint32_t width, uint32_t height, bool cropChanged) {
+    *portWillReset = false;
+    bool sizeChanged = (width != mWidth || height != mHeight);
+
+    if (sizeChanged || cropChanged) {
+        mWidth = width;
+        mHeight = height;
+
+        bool updateCrop = !cropChanged;
+        if ((sizeChanged && !mIsAdaptive)
+            || width > mAdaptiveMaxWidth
+            || height > mAdaptiveMaxHeight) {
+            if (mIsAdaptive) {
+                if (width > mAdaptiveMaxWidth) {
+                    mAdaptiveMaxWidth = width;
+                }
+                if (height > mAdaptiveMaxHeight) {
+                    mAdaptiveMaxHeight = height;
+                }
+            }
+            updatePortDefinitions(updateCrop);
+            notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL);
+            mOutputPortSettingsChange = AWAITING_DISABLED;
+            *portWillReset = true;
+        } else {
+            updatePortDefinitions(updateCrop);
+            notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
+                   OMX_IndexConfigCommonOutputCrop, NULL);
+        }
+    }
+}
+
+void SoftVideoDecoderOMXComponent::copyYV12FrameToOutputBuffer(
+        uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
+        size_t srcYStride, size_t srcUStride, size_t srcVStride) {
+    size_t dstYStride = mIsAdaptive ? mAdaptiveMaxWidth : mWidth;
+    size_t dstUVStride = dstYStride / 2;
+    size_t dstHeight = mIsAdaptive ? mAdaptiveMaxHeight : mHeight;
+
+    for (size_t i = 0; i < dstHeight; ++i) {
+        if (i < mHeight) {
+            memcpy(dst, srcY, mWidth);
+            srcY += srcYStride;
+        }
+        dst += dstYStride;
+    }
+
+    for (size_t i = 0; i < dstHeight / 2; ++i) {
+        if (i < mHeight / 2) {
+            memcpy(dst, srcU, mWidth / 2);
+            srcU += srcUStride;
+        }
+        dst += dstUVStride;
+    }
+
+    for (size_t i = 0; i < dstHeight / 2; ++i) {
+        if (i < mHeight / 2) {
+            memcpy(dst, srcV, mWidth / 2);
+            srcV += srcVStride;
+        }
+        dst += dstUVStride;
+    }
 }
 
 OMX_ERRORTYPE SoftVideoDecoderOMXComponent::internalGetParameter(