Merge "Modified loadPlugIns to load from /vendor and /system; skip libraries that are already loaded. BUG: 5284436"
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 923518d..d1a8105 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -486,6 +486,7 @@
     int                     mSessionId;
     int                     mAuxEffectId;
     Mutex                   mLock;
+    status_t                mRestoreStatus;
 };
 
 
diff --git a/include/media/MediaProfiles.h b/include/media/MediaProfiles.h
index 4b023d1..eab7648 100644
--- a/include/media/MediaProfiles.h
+++ b/include/media/MediaProfiles.h
@@ -32,7 +32,8 @@
     CAMCORDER_QUALITY_480P = 4,
     CAMCORDER_QUALITY_720P = 5,
     CAMCORDER_QUALITY_1080P = 6,
-    CAMCORDER_QUALITY_LIST_END = 6,
+    CAMCORDER_QUALITY_QVGA = 7,
+    CAMCORDER_QUALITY_LIST_END = 7,
 
     CAMCORDER_QUALITY_TIME_LAPSE_LIST_START = 1000,
     CAMCORDER_QUALITY_TIME_LAPSE_LOW  = 1000,
@@ -42,7 +43,8 @@
     CAMCORDER_QUALITY_TIME_LAPSE_480P = 1004,
     CAMCORDER_QUALITY_TIME_LAPSE_720P = 1005,
     CAMCORDER_QUALITY_TIME_LAPSE_1080P = 1006,
-    CAMCORDER_QUALITY_TIME_LAPSE_LIST_END = 1006,
+    CAMCORDER_QUALITY_TIME_LAPSE_QVGA = 1007,
+    CAMCORDER_QUALITY_TIME_LAPSE_LIST_END = 1007,
 };
 
 /**
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index e965f14..b7286e5 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -164,6 +164,8 @@
 
     void sendFormatChange();
 
+    void signalError(OMX_ERRORTYPE error = OMX_ErrorUndefined);
+
     DISALLOW_EVIL_CONSTRUCTORS(ACodec);
 };
 
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 2932744..8baf5ec 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -303,7 +303,7 @@
     bool flushPortAsync(OMX_U32 portIndex);
 
     void disablePortAsync(OMX_U32 portIndex);
-    void enablePortAsync(OMX_U32 portIndex);
+    status_t enablePortAsync(OMX_U32 portIndex);
 
     static size_t countBuffersWeOwn(const Vector<BufferInfo> &buffers);
     static bool isIntermediateState(State state);
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index c2c6715..8ebb652 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -262,7 +262,7 @@
     mFlushed = false;
     mFlags = flags;
     AudioSystem::acquireAudioSessionId(mSessionId);
-
+    mRestoreStatus = NO_ERROR;
     return NO_ERROR;
 }
 
@@ -1161,8 +1161,8 @@
     status_t result;
 
     if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) {
-        LOGW("dead IAudioTrack, creating a new one from %s",
-             fromStart ? "start()" : "obtainBuffer()");
+        LOGW("dead IAudioTrack, creating a new one from %s TID %d",
+             fromStart ? "start()" : "obtainBuffer()", gettid());
 
         // signal old cblk condition so that other threads waiting for available buffers stop
         // waiting now
@@ -1217,33 +1217,35 @@
             }
             if (mActive) {
                 result = mAudioTrack->start();
+                LOGW_IF(result != NO_ERROR, "restoreTrack_l() start() failed status %d", result);
             }
             if (fromStart && result == NO_ERROR) {
                 mNewPosition = mCblk->server + mUpdatePeriod;
             }
         }
         if (result != NO_ERROR) {
-            mActive = false;
+            android_atomic_and(~CBLK_RESTORING_ON, &cblk->flags);
+            LOGW_IF(result != NO_ERROR, "restoreTrack_l() failed status %d", result);
         }
-
+        mRestoreStatus = result;
         // signal old cblk condition for other threads waiting for restore completion
         android_atomic_or(CBLK_RESTORED_ON, &cblk->flags);
         cblk->cv.broadcast();
     } else {
         if (!(cblk->flags & CBLK_RESTORED_MSK)) {
-            LOGW("dead IAudioTrack, waiting for a new one");
+            LOGW("dead IAudioTrack, waiting for a new one TID %d", gettid());
             mLock.unlock();
             result = cblk->cv.waitRelative(cblk->lock, milliseconds(RESTORE_TIMEOUT_MS));
+            if (result == NO_ERROR) {
+                result = mRestoreStatus;
+            }
             cblk->lock.unlock();
             mLock.lock();
         } else {
-            LOGW("dead IAudioTrack, already restored");
-            result = NO_ERROR;
+            LOGW("dead IAudioTrack, already restored TID %d", gettid());
+            result = mRestoreStatus;
             cblk->lock.unlock();
         }
-        if (result != NO_ERROR || mActive == 0) {
-            result = status_t(STOPPED);
-        }
     }
     LOGV("restoreTrack_l() status %d mActive %d cblk %p, old cblk %p flags %08x old flags %08x",
          result, mActive, mCblk, cblk, mCblk->flags, cblk->flags);
@@ -1254,7 +1256,7 @@
     }
     cblk->lock.lock();
 
-    LOGW_IF(result != NO_ERROR, "restoreTrack_l() error %d", result);
+    LOGW_IF(result != NO_ERROR, "restoreTrack_l() error %d TID %d", result, gettid());
 
     return result;
 }
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index 5a8bc60..ad55ff8 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -67,6 +67,7 @@
     {"480p", CAMCORDER_QUALITY_480P},
     {"720p", CAMCORDER_QUALITY_720P},
     {"1080p", CAMCORDER_QUALITY_1080P},
+    {"qvga", CAMCORDER_QUALITY_QVGA},
 
     {"timelapselow",  CAMCORDER_QUALITY_TIME_LAPSE_LOW},
     {"timelapsehigh", CAMCORDER_QUALITY_TIME_LAPSE_HIGH},
@@ -74,7 +75,8 @@
     {"timelapsecif", CAMCORDER_QUALITY_TIME_LAPSE_CIF},
     {"timelapse480p", CAMCORDER_QUALITY_TIME_LAPSE_480P},
     {"timelapse720p", CAMCORDER_QUALITY_TIME_LAPSE_720P},
-    {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P}
+    {"timelapse1080p", CAMCORDER_QUALITY_TIME_LAPSE_1080P},
+    {"timelapseqvga", CAMCORDER_QUALITY_TIME_LAPSE_QVGA},
 };
 
 /*static*/ void
@@ -1139,7 +1141,7 @@
     if (index >= 0) {
         offsetTimeMs = mStartTimeOffsets.valueFor(cameraId);
     }
-    LOGV("%s: offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
+    LOGV("offsetTime=%d ms and cameraId=%d", offsetTimeMs, cameraId);
     return offsetTimeMs;
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index ee77f47..7218faf 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -34,17 +34,21 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/ACodec.h>
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 #include <surfaceflinger/Surface.h>
 #include <gui/ISurfaceTexture.h>
 
+#include "avc_utils.h"
+
 namespace android {
 
 ////////////////////////////////////////////////////////////////////////////////
 
 NuPlayer::NuPlayer()
     : mUIDValid(false),
+      mVideoIsAVC(false),
       mAudioEOS(false),
       mVideoEOS(false),
       mScanSourcesPending(false),
@@ -52,7 +56,12 @@
       mFlushingAudio(NONE),
       mFlushingVideo(NONE),
       mResetInProgress(false),
-      mResetPostponed(false) {
+      mResetPostponed(false),
+      mSkipRenderingAudioUntilMediaTimeUs(-1ll),
+      mSkipRenderingVideoUntilMediaTimeUs(-1ll),
+      mVideoLateByUs(0ll),
+      mNumFramesTotal(0ll),
+      mNumFramesDropped(0ll) {
 }
 
 NuPlayer::~NuPlayer() {
@@ -185,10 +194,14 @@
         {
             LOGV("kWhatStart");
 
+            mVideoIsAVC = false;
             mAudioEOS = false;
             mVideoEOS = false;
             mSkipRenderingAudioUntilMediaTimeUs = -1;
             mSkipRenderingVideoUntilMediaTimeUs = -1;
+            mVideoLateByUs = 0;
+            mNumFramesTotal = 0;
+            mNumFramesDropped = 0;
 
             mSource->start();
 
@@ -269,6 +282,8 @@
                 } else {
                     CHECK(IsFlushingState(mFlushingVideo, &needShutdown));
                     mFlushingVideo = FLUSHED;
+
+                    mVideoLateByUs = 0;
                 }
 
                 LOGV("decoder %s flush completed", audio ? "audio" : "video");
@@ -299,7 +314,12 @@
                          sampleRate, numChannels);
 
                     mAudioSink->close();
-                    CHECK_EQ(mAudioSink->open(sampleRate, numChannels), (status_t)OK);
+                    CHECK_EQ(mAudioSink->open(
+                                sampleRate,
+                                numChannels,
+                                AUDIO_FORMAT_PCM_16_BIT,
+                                8 /* bufferCount */),
+                             (status_t)OK);
                     mAudioSink->start();
 
                     mRenderer->signalAudioSinkChanged();
@@ -392,13 +412,18 @@
                 int64_t positionUs;
                 CHECK(msg->findInt64("positionUs", &positionUs));
 
+                CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs));
+
                 if (mDriver != NULL) {
                     sp<NuPlayerDriver> driver = mDriver.promote();
                     if (driver != NULL) {
                         driver->notifyPosition(positionUs);
+
+                        driver->notifyFrameStats(
+                                mNumFramesTotal, mNumFramesDropped);
                     }
                 }
-            } else {
+            } else if (what == Renderer::kWhatFlushComplete) {
                 CHECK_EQ(what, (int32_t)Renderer::kWhatFlushComplete);
 
                 int32_t audio;
@@ -560,6 +585,12 @@
         return -EWOULDBLOCK;
     }
 
+    if (!audio) {
+        const char *mime;
+        CHECK(meta->findCString(kKeyMIMEType, &mime));
+        mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime);
+    }
+
     sp<AMessage> notify =
         new AMessage(audio ? kWhatAudioNotify : kWhatVideoNotify,
                      id());
@@ -593,53 +624,70 @@
     }
 
     sp<ABuffer> accessUnit;
-    status_t err = mSource->dequeueAccessUnit(audio, &accessUnit);
 
-    if (err == -EWOULDBLOCK) {
-        return err;
-    } else if (err != OK) {
-        if (err == INFO_DISCONTINUITY) {
-            int32_t type;
-            CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
+    bool dropAccessUnit;
+    do {
+        status_t err = mSource->dequeueAccessUnit(audio, &accessUnit);
 
-            bool formatChange =
-                type == ATSParser::DISCONTINUITY_FORMATCHANGE;
+        if (err == -EWOULDBLOCK) {
+            return err;
+        } else if (err != OK) {
+            if (err == INFO_DISCONTINUITY) {
+                int32_t type;
+                CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
 
-            LOGV("%s discontinuity (formatChange=%d)",
-                 audio ? "audio" : "video", formatChange);
+                bool formatChange =
+                    type == ATSParser::DISCONTINUITY_FORMATCHANGE;
 
-            if (audio) {
-                mSkipRenderingAudioUntilMediaTimeUs = -1;
-            } else {
-                mSkipRenderingVideoUntilMediaTimeUs = -1;
-            }
+                LOGV("%s discontinuity (formatChange=%d)",
+                     audio ? "audio" : "video", formatChange);
 
-            sp<AMessage> extra;
-            if (accessUnit->meta()->findMessage("extra", &extra)
-                    && extra != NULL) {
-                int64_t resumeAtMediaTimeUs;
-                if (extra->findInt64(
-                            "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
-                    LOGI("suppressing rendering of %s until %lld us",
-                            audio ? "audio" : "video", resumeAtMediaTimeUs);
+                if (audio) {
+                    mSkipRenderingAudioUntilMediaTimeUs = -1;
+                } else {
+                    mSkipRenderingVideoUntilMediaTimeUs = -1;
+                }
 
-                    if (audio) {
-                        mSkipRenderingAudioUntilMediaTimeUs =
-                            resumeAtMediaTimeUs;
-                    } else {
-                        mSkipRenderingVideoUntilMediaTimeUs =
-                            resumeAtMediaTimeUs;
+                sp<AMessage> extra;
+                if (accessUnit->meta()->findMessage("extra", &extra)
+                        && extra != NULL) {
+                    int64_t resumeAtMediaTimeUs;
+                    if (extra->findInt64(
+                                "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
+                        LOGI("suppressing rendering of %s until %lld us",
+                                audio ? "audio" : "video", resumeAtMediaTimeUs);
+
+                        if (audio) {
+                            mSkipRenderingAudioUntilMediaTimeUs =
+                                resumeAtMediaTimeUs;
+                        } else {
+                            mSkipRenderingVideoUntilMediaTimeUs =
+                                resumeAtMediaTimeUs;
+                        }
                     }
                 }
+
+                flushDecoder(audio, formatChange);
             }
 
-            flushDecoder(audio, formatChange);
+            reply->setInt32("err", err);
+            reply->post();
+            return OK;
         }
 
-        reply->setInt32("err", err);
-        reply->post();
-        return OK;
-    }
+        if (!audio) {
+            ++mNumFramesTotal;
+        }
+
+        dropAccessUnit = false;
+        if (!audio
+                && mVideoLateByUs > 100000ll
+                && mVideoIsAVC
+                && !IsAVCReferenceFrame(accessUnit)) {
+            dropAccessUnit = true;
+            ++mNumFramesDropped;
+        }
+    } while (dropAccessUnit);
 
     // LOGV("returned a valid buffer of %s data", audio ? "audio" : "video");
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index cf9185b..a5382b4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -70,19 +70,19 @@
     struct StreamingSource;
 
     enum {
-        kWhatSetDataSource,
-        kWhatSetVideoNativeWindow,
-        kWhatSetAudioSink,
-        kWhatMoreDataQueued,
-        kWhatStart,
-        kWhatScanSources,
-        kWhatVideoNotify,
-        kWhatAudioNotify,
-        kWhatRendererNotify,
-        kWhatReset,
-        kWhatSeek,
-        kWhatPause,
-        kWhatResume,
+        kWhatSetDataSource              = '=DaS',
+        kWhatSetVideoNativeWindow       = '=NaW',
+        kWhatSetAudioSink               = '=AuS',
+        kWhatMoreDataQueued             = 'more',
+        kWhatStart                      = 'strt',
+        kWhatScanSources                = 'scan',
+        kWhatVideoNotify                = 'vidN',
+        kWhatAudioNotify                = 'audN',
+        kWhatRendererNotify             = 'renN',
+        kWhatReset                      = 'rset',
+        kWhatSeek                       = 'seek',
+        kWhatPause                      = 'paus',
+        kWhatResume                     = 'rsme',
     };
 
     wp<NuPlayerDriver> mDriver;
@@ -92,6 +92,7 @@
     sp<NativeWindowWrapper> mNativeWindow;
     sp<MediaPlayerBase::AudioSink> mAudioSink;
     sp<Decoder> mVideoDecoder;
+    bool mVideoIsAVC;
     sp<Decoder> mAudioDecoder;
     sp<Renderer> mRenderer;
 
@@ -119,6 +120,9 @@
     int64_t mSkipRenderingAudioUntilMediaTimeUs;
     int64_t mSkipRenderingVideoUntilMediaTimeUs;
 
+    int64_t mVideoLateByUs;
+    int64_t mNumFramesTotal, mNumFramesDropped;
+
     status_t instantiateDecoder(bool audio, sp<Decoder> *decoder);
 
     status_t feedDecoderInputData(bool audio, const sp<AMessage> &msg);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 81b41ef..56c2773 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -59,8 +59,21 @@
         format->setObject("native-window", mNativeWindow);
     }
 
+    // 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
+    // queue.
+    bool needDedicatedLooper = !strncasecmp(mime, "video/", 6);
+
     mCodec = new ACodec;
-    looper()->registerHandler(mCodec);
+
+    if (needDedicatedLooper && mCodecLooper == NULL) {
+        mCodecLooper = new ALooper;
+        mCodecLooper->setName("NuPlayerDecoder");
+        mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
+    }
+
+    (needDedicatedLooper ? mCodecLooper : looper())->registerHandler(mCodec);
 
     mCodec->setNotificationMessage(notifyMsg);
     mCodec->initiateSetup(format);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index fabc606..3ab1fcf 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -43,13 +43,14 @@
 
 private:
     enum {
-        kWhatCodecNotify,
+        kWhatCodecNotify        = 'cdcN',
     };
 
     sp<AMessage> mNotify;
     sp<NativeWindowWrapper> mNativeWindow;
 
     sp<ACodec> mCodec;
+    sp<ALooper> mCodecLooper;
 
     Vector<sp<ABuffer> > mCSD;
     size_t mCSDIndex;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index c6fca2c..b1e917d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -31,6 +31,8 @@
     : mResetInProgress(false),
       mDurationUs(-1),
       mPositionUs(-1),
+      mNumFramesTotal(0),
+      mNumFramesDropped(0),
       mLooper(new ALooper),
       mState(UNINITIALIZED),
       mStartupSeekTimeUs(-1) {
@@ -292,4 +294,30 @@
     sendEvent(MEDIA_SEEK_COMPLETE);
 }
 
+void NuPlayerDriver::notifyFrameStats(
+        int64_t numFramesTotal, int64_t numFramesDropped) {
+    Mutex::Autolock autoLock(mLock);
+    mNumFramesTotal = numFramesTotal;
+    mNumFramesDropped = numFramesDropped;
+}
+
+status_t NuPlayerDriver::dump(int fd, const Vector<String16> &args) const {
+    Mutex::Autolock autoLock(mLock);
+
+    FILE *out = fdopen(dup(fd), "w");
+
+    fprintf(out, " NuPlayer\n");
+    fprintf(out, "  numFramesTotal(%lld), numFramesDropped(%lld), "
+                 "percentageDropped(%.2f)\n",
+                 mNumFramesTotal,
+                 mNumFramesDropped,
+                 mNumFramesTotal == 0
+                    ? 0.0 : (double)mNumFramesDropped / mNumFramesTotal);
+
+    fclose(out);
+    out = NULL;
+
+    return OK;
+}
+
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 1bb7ca2..181c37d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -60,16 +60,19 @@
     virtual status_t getMetadata(
             const media::Metadata::Filter& ids, Parcel *records);
 
+    virtual status_t dump(int fd, const Vector<String16> &args) const;
+
     void notifyResetComplete();
     void notifyDuration(int64_t durationUs);
     void notifyPosition(int64_t positionUs);
     void notifySeekComplete();
+    void notifyFrameStats(int64_t numFramesTotal, int64_t numFramesDropped);
 
 protected:
     virtual ~NuPlayerDriver();
 
 private:
-    Mutex mLock;
+    mutable Mutex mLock;
     Condition mCondition;
 
     // The following are protected through "mLock"
@@ -77,6 +80,8 @@
     bool mResetInProgress;
     int64_t mDurationUs;
     int64_t mPositionUs;
+    int64_t mNumFramesTotal;
+    int64_t mNumFramesDropped;
     // <<<
 
     sp<ALooper> mLooper;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 8f213da..07e347e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -26,6 +26,9 @@
 
 namespace android {
 
+// static
+const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
+
 NuPlayer::Renderer::Renderer(
         const sp<MediaPlayerBase::AudioSink> &sink,
         const sp<AMessage> &notify)
@@ -43,7 +46,9 @@
       mHasAudio(false),
       mHasVideo(false),
       mSyncQueues(false),
-      mPaused(false) {
+      mPaused(false),
+      mLastPositionUpdateUs(-1ll),
+      mVideoLateByUs(0ll) {
 }
 
 NuPlayer::Renderer::~Renderer() {
@@ -114,9 +119,24 @@
 
             mDrainAudioQueuePending = false;
 
-            onDrainAudioQueue();
+            if (onDrainAudioQueue()) {
+                uint32_t numFramesPlayed;
+                CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed),
+                         (status_t)OK);
 
-            postDrainAudioQueue();
+                uint32_t numFramesPendingPlayout =
+                    mNumFramesWritten - numFramesPlayed;
+
+                // This is how long the audio sink will have data to
+                // play back.
+                int64_t delayUs =
+                    mAudioSink->msecsPerFrame()
+                        * numFramesPendingPlayout * 1000ll;
+
+                // Let's give it more data after about half that time
+                // has elapsed.
+                postDrainAudioQueue(delayUs / 2);
+            }
             break;
         }
 
@@ -178,7 +198,7 @@
     }
 }
 
-void NuPlayer::Renderer::postDrainAudioQueue() {
+void NuPlayer::Renderer::postDrainAudioQueue(int64_t delayUs) {
     if (mDrainAudioQueuePending || mSyncQueues || mPaused) {
         return;
     }
@@ -190,20 +210,33 @@
     mDrainAudioQueuePending = true;
     sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, id());
     msg->setInt32("generation", mAudioQueueGeneration);
-    msg->post(10000);
+    msg->post(delayUs);
 }
 
 void NuPlayer::Renderer::signalAudioSinkChanged() {
     (new AMessage(kWhatAudioSinkChanged, id()))->post();
 }
 
-void NuPlayer::Renderer::onDrainAudioQueue() {
+bool NuPlayer::Renderer::onDrainAudioQueue() {
+    uint32_t numFramesPlayed;
+    CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
 
-    for (;;) {
-        if (mAudioQueue.empty()) {
-            break;
-        }
+    ssize_t numFramesAvailableToWrite =
+        mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
 
+#if 0
+    if (numFramesAvailableToWrite == mAudioSink->frameCount()) {
+        LOGI("audio sink underrun");
+    } else {
+        LOGV("audio queue has %d frames left to play",
+             mAudioSink->frameCount() - numFramesAvailableToWrite);
+    }
+#endif
+
+    size_t numBytesAvailableToWrite =
+        numFramesAvailableToWrite * mAudioSink->frameSize();
+
+    while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) {
         QueueEntry *entry = &*mAudioQueue.begin();
 
         if (entry->mBuffer == NULL) {
@@ -213,20 +246,7 @@
 
             mAudioQueue.erase(mAudioQueue.begin());
             entry = NULL;
-            return;
-        }
-
-        uint32_t numFramesPlayed;
-        CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK);
-
-        ssize_t numFramesAvailableToWrite =
-            mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed);
-
-        size_t numBytesAvailableToWrite =
-            numFramesAvailableToWrite * mAudioSink->frameSize();
-
-        if (numBytesAvailableToWrite == 0) {
-            break;
+            return false;
         }
 
         if (entry->mOffset == 0) {
@@ -271,10 +291,14 @@
             entry = NULL;
         }
 
-        mNumFramesWritten += copy / mAudioSink->frameSize();
+        numBytesAvailableToWrite -= copy;
+        size_t copiedFrames = copy / mAudioSink->frameSize();
+        mNumFramesWritten += copiedFrames;
     }
 
     notifyPosition();
+
+    return !mAudioQueue.empty();
 }
 
 void NuPlayer::Renderer::postDrainVideoQueue() {
@@ -334,15 +358,26 @@
 
         mVideoQueue.erase(mVideoQueue.begin());
         entry = NULL;
+
+        mVideoLateByUs = 0ll;
+
+        notifyPosition();
         return;
     }
 
-#if 0
     int64_t mediaTimeUs;
     CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
 
-    LOGI("rendering video at media time %.2f secs", mediaTimeUs / 1E6);
-#endif
+    int64_t realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs;
+    mVideoLateByUs = ALooper::GetNowUs() - realTimeUs;
+
+    bool tooLate = (mVideoLateByUs > 40000);
+
+    if (tooLate) {
+        LOGV("video late by %lld us (%.2f secs)", lateByUs, lateByUs / 1E6);
+    } else {
+        LOGV("rendering video at media time %.2f secs", mediaTimeUs / 1E6);
+    }
 
     entry->mNotifyConsumed->setInt32("render", true);
     entry->mNotifyConsumed->post();
@@ -562,11 +597,19 @@
     }
 
     int64_t nowUs = ALooper::GetNowUs();
+
+    if (mLastPositionUpdateUs >= 0
+            && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) {
+        return;
+    }
+    mLastPositionUpdateUs = nowUs;
+
     int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
 
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatPosition);
     notify->setInt64("positionUs", positionUs);
+    notify->setInt64("videoLateByUs", mVideoLateByUs);
     notify->post();
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 2713031..268628b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -45,9 +45,9 @@
     void resume();
 
     enum {
-        kWhatEOS,
-        kWhatFlushComplete,
-        kWhatPosition,
+        kWhatEOS                = 'eos ',
+        kWhatFlushComplete      = 'fluC',
+        kWhatPosition           = 'posi',
     };
 
 protected:
@@ -57,14 +57,14 @@
 
 private:
     enum {
-        kWhatDrainAudioQueue,
-        kWhatDrainVideoQueue,
-        kWhatQueueBuffer,
-        kWhatQueueEOS,
-        kWhatFlush,
-        kWhatAudioSinkChanged,
-        kWhatPause,
-        kWhatResume,
+        kWhatDrainAudioQueue    = 'draA',
+        kWhatDrainVideoQueue    = 'draV',
+        kWhatQueueBuffer        = 'queB',
+        kWhatQueueEOS           = 'qEOS',
+        kWhatFlush              = 'flus',
+        kWhatAudioSinkChanged   = 'auSC',
+        kWhatPause              = 'paus',
+        kWhatResume             = 'resm',
     };
 
     struct QueueEntry {
@@ -74,6 +74,8 @@
         status_t mFinalResult;
     };
 
+    static const int64_t kMinPositionUpdateDelayUs;
+
     sp<MediaPlayerBase::AudioSink> mAudioSink;
     sp<AMessage> mNotify;
     List<QueueEntry> mAudioQueue;
@@ -98,8 +100,11 @@
 
     bool mPaused;
 
-    void onDrainAudioQueue();
-    void postDrainAudioQueue();
+    int64_t mLastPositionUpdateUs;
+    int64_t mVideoLateByUs;
+
+    bool onDrainAudioQueue();
+    void postDrainAudioQueue(int64_t delayUs = 0);
 
     void onDrainVideoQueue();
     void postDrainVideoQueue();
@@ -114,6 +119,7 @@
     void notifyEOS(bool audio, status_t finalResult);
     void notifyFlushComplete(bool audio);
     void notifyPosition();
+    void notifyVideoLateBy(int64_t lateByUs);
 
     void flushQueue(List<QueueEntry> *queue);
     bool dropBufferWhileFlushing(bool audio, const sp<AMessage> &msg);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
index df0935d..1874d80 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerStreamListener.h
@@ -41,8 +41,8 @@
 
 private:
     enum {
-        kNumBuffers = 16,
-        kBufferSize = 188 * 20
+        kNumBuffers = 8,
+        kBufferSize = 188 * 10
     };
 
     struct QueueEntry {
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index a741987..7319e4c 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -52,7 +52,7 @@
         return false;
     }
 
-    for (int32_t i = 0; i < 10; ++i) {
+    for (int32_t i = 0; i < 50; ++i) {
         char buffer[188];
         sp<AMessage> extra;
         ssize_t n = mStreamListener->read(buffer, sizeof(buffer), &extra);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index e9dc61c..a2d9e59 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1131,6 +1131,13 @@
     mSentFormat = true;
 }
 
+void ACodec::signalError(OMX_ERRORTYPE error) {
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", ACodec::kWhatError);
+    notify->setInt32("omx-error", error);
+    notify->post();
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 ACodec::BaseState::BaseState(ACodec *codec, const sp<AState> &parentState)
@@ -1252,10 +1259,7 @@
 
     LOGE("[%s] ERROR(0x%08lx)", mCodec->mComponentName.c_str(), data1);
 
-    sp<AMessage> notify = mCodec->mNotify->dup();
-    notify->setInt32("what", ACodec::kWhatError);
-    notify->setInt32("omx-error", data1);
-    notify->post();
+    mCodec->signalError((OMX_ERRORTYPE)data1);
 
     return true;
 }
@@ -1373,8 +1377,13 @@
                     memcpy(info->mData->data(), buffer->data(), buffer->size());
                 }
 
-                LOGV("[%s] calling emptyBuffer %p",
-                     mCodec->mComponentName.c_str(), bufferID);
+                if (flags & OMX_BUFFERFLAG_CODECCONFIG) {
+                    LOGV("[%s] calling emptyBuffer %p w/ codec specific data",
+                         mCodec->mComponentName.c_str(), bufferID);
+                } else {
+                    LOGV("[%s] calling emptyBuffer %p w/ time %lld us",
+                         mCodec->mComponentName.c_str(), bufferID, timeUs);
+                }
 
                 CHECK_EQ(mCodec->mOMX->emptyBuffer(
                             mCodec->mNode,
@@ -1392,7 +1401,7 @@
                 LOGV("[%s] Signalling EOS on the input port",
                      mCodec->mComponentName.c_str());
 
-                LOGV("[%s] calling emptyBuffer %p",
+                LOGV("[%s] calling emptyBuffer %p signalling EOS",
                      mCodec->mComponentName.c_str(), bufferID);
 
                 CHECK_EQ(mCodec->mOMX->emptyBuffer(
@@ -1453,8 +1462,8 @@
         int64_t timeUs,
         void *platformPrivate,
         void *dataPtr) {
-    LOGV("[%s] onOMXFillBufferDone %p",
-         mCodec->mComponentName.c_str(), bufferID);
+    LOGV("[%s] onOMXFillBufferDone %p time %lld us",
+         mCodec->mComponentName.c_str(), bufferID, timeUs);
 
     ssize_t index;
     BufferInfo *info =
@@ -1548,12 +1557,14 @@
             && msg->findInt32("render", &render) && render != 0) {
         // The client wants this buffer to be rendered.
 
-        CHECK_EQ(mCodec->mNativeWindow->queueBuffer(
+        if (mCodec->mNativeWindow->queueBuffer(
                     mCodec->mNativeWindow.get(),
-                    info->mGraphicBuffer.get()),
-                 0);
-
-        info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
+                    info->mGraphicBuffer.get()) == OK) {
+            info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW;
+        } else {
+            mCodec->signalError();
+            info->mStatus = BufferInfo::OWNED_BY_US;
+        }
     } else {
         info->mStatus = BufferInfo::OWNED_BY_US;
     }
@@ -1680,7 +1691,11 @@
             ++matchIndex) {
         componentName = matchingCodecs.itemAt(matchIndex).string();
 
+        pid_t tid = androidGetTid();
+        int prevPriority = androidGetThreadPriority(tid);
+        androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND);
         status_t err = omx->allocateNode(componentName.c_str(), observer, &node);
+        androidSetThreadPriority(tid, prevPriority);
 
         if (err == OK) {
             break;
@@ -1692,11 +1707,7 @@
     if (node == NULL) {
         LOGE("Unable to instantiate a decoder for type '%s'.", mime.c_str());
 
-        sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", ACodec::kWhatError);
-        notify->setInt32("omx-error", OMX_ErrorComponentNotFound);
-        notify->post();
-
+        mCodec->signalError(OMX_ErrorComponentNotFound);
         return;
     }
 
@@ -1744,10 +1755,7 @@
              "(error 0x%08x)",
              err);
 
-        sp<AMessage> notify = mCodec->mNotify->dup();
-        notify->setInt32("what", ACodec::kWhatError);
-        notify->setInt32("omx-error", OMX_ErrorUndefined);
-        notify->post();
+        mCodec->signalError();
     }
 }
 
@@ -2063,10 +2071,7 @@
                          "port reconfiguration (error 0x%08x)",
                          err);
 
-                    sp<AMessage> notify = mCodec->mNotify->dup();
-                    notify->setInt32("what", ACodec::kWhatError);
-                    notify->setInt32("omx-error", OMX_ErrorUndefined);
-                    notify->post();
+                    mCodec->signalError();
                 }
 
                 return true;
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
index 6313ca3..d47e5d1 100644
--- a/media/libstagefright/AVIExtractor.cpp
+++ b/media/libstagefright/AVIExtractor.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "AVIExtractor"
 #include <utils/Log.h>
 
+#include "include/avc_utils.h"
 #include "include/AVIExtractor.h"
 
 #include <binder/ProcessState.h>
@@ -117,14 +118,12 @@
         }
     }
 
-    int64_t timeUs =
-        (mSampleIndex * 1000000ll * mTrack.mRate) / mTrack.mScale;
-
     off64_t offset;
     size_t size;
     bool isKey;
+    int64_t timeUs;
     status_t err = mExtractor->getSampleInfo(
-            mTrackIndex, mSampleIndex, &offset, &size, &isKey);
+            mTrackIndex, mSampleIndex, &offset, &size, &isKey, &timeUs);
 
     ++mSampleIndex;
 
@@ -364,6 +363,13 @@
         case FOURCC('X', 'V', 'I', 'X'):
             return MEDIA_MIMETYPE_VIDEO_MPEG4;
 
+        // from http://wiki.multimedia.cx/index.php?title=H264
+        case FOURCC('a', 'v', 'c', '1'):
+        case FOURCC('d', 'a', 'v', 'c'):
+        case FOURCC('x', '2', '6', '4'):
+        case FOURCC('v', 's', 's', 'h'):
+            return MEDIA_MIMETYPE_VIDEO_AVC;
+
         default:
             return NULL;
     }
@@ -396,6 +402,8 @@
     uint32_t rate = U32LE_AT(&data[20]);
     uint32_t scale = U32LE_AT(&data[24]);
 
+    uint32_t sampleSize = U32LE_AT(&data[44]);
+
     const char *mime = NULL;
     Track::Kind kind = Track::OTHER;
 
@@ -406,6 +414,14 @@
             return ERROR_MALFORMED;
         }
 
+        if (mime == NULL) {
+            LOGW("Unsupported video format '%c%c%c%c'",
+                 (char)(handler >> 24),
+                 (char)((handler >> 16) & 0xff),
+                 (char)((handler >> 8) & 0xff),
+                 (char)(handler & 0xff));
+        }
+
         kind = Track::VIDEO;
     } else if (type == FOURCC('a', 'u', 'd', 's')) {
         if (mime && strncasecmp(mime, "audio/", 6)) {
@@ -427,6 +443,7 @@
     track->mMeta = meta;
     track->mRate = rate;
     track->mScale = scale;
+    track->mBytesPerSample = sampleSize;
     track->mKind = kind;
     track->mNumSyncSamples = 0;
     track->mThumbnailSampleSize = 0;
@@ -472,8 +489,11 @@
         track->mMeta->setInt32(kKeyHeight, height);
     } else {
         uint32_t format = U16LE_AT(data);
+
         if (format == 0x55) {
             track->mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+        } else {
+            LOGW("Unsupported audio format = 0x%04x", format);
         }
 
         uint32_t numChannels = U16LE_AT(&data[2]);
@@ -612,11 +632,12 @@
         off64_t offset;
         size_t size;
         bool isKey;
-        status_t err = getSampleInfo(0, 0, &offset, &size, &isKey);
+        int64_t timeUs;
+        status_t err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
 
         if (err != OK) {
             mOffsetsAreAbsolute = !mOffsetsAreAbsolute;
-            err = getSampleInfo(0, 0, &offset, &size, &isKey);
+            err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
 
             if (err != OK) {
                 return err;
@@ -630,8 +651,9 @@
     for (size_t i = 0; i < mTracks.size(); ++i) {
         Track *track = &mTracks.editItemAt(i);
 
-        int64_t durationUs =
-            (track->mSamples.size() * 1000000ll * track->mRate) / track->mScale;
+        int64_t durationUs;
+        CHECK_EQ((status_t)OK,
+                 getSampleTime(i, track->mSamples.size() - 1, &durationUs));
 
         LOGV("track %d duration = %.2f secs", i, durationUs / 1E6);
 
@@ -643,21 +665,42 @@
 
         AString mime = tmp;
 
-        if (!strncasecmp("video/", mime.c_str(), 6)
-                && track->mThumbnailSampleIndex >= 0) {
-            int64_t thumbnailTimeUs =
-                (track->mThumbnailSampleIndex * 1000000ll * track->mRate)
-                    / track->mScale;
+        if (!strncasecmp("video/", mime.c_str(), 6)) {
+            if (track->mThumbnailSampleIndex >= 0) {
+                int64_t thumbnailTimeUs;
+                CHECK_EQ((status_t)OK,
+                         getSampleTime(i, track->mThumbnailSampleIndex,
+                                       &thumbnailTimeUs));
 
-            track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
+                track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
+            }
+
+            status_t err = OK;
 
             if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG4)) {
-                status_t err = addMPEG4CodecSpecificData(i);
-
-                if (err != OK) {
-                    return err;
-                }
+                err = addMPEG4CodecSpecificData(i);
+            } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) {
+                err = addH264CodecSpecificData(i);
             }
+
+            if (err != OK) {
+                return err;
+            }
+        }
+
+        if (track->mBytesPerSample != 0) {
+            // Assume all chunks are the same size for now.
+
+            off64_t offset;
+            size_t size;
+            bool isKey;
+            int64_t sampleTimeUs;
+            CHECK_EQ((status_t)OK,
+                     getSampleInfo(
+                         i, 0,
+                         &offset, &size, &isKey, &sampleTimeUs));
+
+            track->mRate *= size / track->mBytesPerSample;
         }
     }
 
@@ -720,7 +763,9 @@
     off64_t offset;
     size_t size;
     bool isKey;
-    status_t err = getSampleInfo(trackIndex, 0, &offset, &size, &isKey);
+    int64_t timeUs;
+    status_t err =
+        getSampleInfo(trackIndex, 0, &offset, &size, &isKey, &timeUs);
 
     if (err != OK) {
         return err;
@@ -760,9 +805,67 @@
     return OK;
 }
 
+status_t AVIExtractor::addH264CodecSpecificData(size_t trackIndex) {
+    Track *track = &mTracks.editItemAt(trackIndex);
+
+    off64_t offset;
+    size_t size;
+    bool isKey;
+    int64_t timeUs;
+
+    // Extract codec specific data from the first non-empty sample.
+
+    size_t sampleIndex = 0;
+    for (;;) {
+        status_t err =
+            getSampleInfo(
+                    trackIndex, sampleIndex, &offset, &size, &isKey, &timeUs);
+
+        if (err != OK) {
+            return err;
+        }
+
+        if (size > 0) {
+            break;
+        }
+
+        ++sampleIndex;
+    }
+
+    sp<ABuffer> buffer = new ABuffer(size);
+    ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
+
+    if (n < (ssize_t)size) {
+        return n < 0 ? (status_t)n : ERROR_MALFORMED;
+    }
+
+    sp<MetaData> meta = MakeAVCCodecSpecificData(buffer);
+
+    if (meta == NULL) {
+        LOGE("Unable to extract AVC codec specific data");
+        return ERROR_MALFORMED;
+    }
+
+    int32_t width, height;
+    CHECK(meta->findInt32(kKeyWidth, &width));
+    CHECK(meta->findInt32(kKeyHeight, &height));
+
+    uint32_t type;
+    const void *csd;
+    size_t csdSize;
+    CHECK(meta->findData(kKeyAVCC, &type, &csd, &csdSize));
+
+    track->mMeta->setInt32(kKeyWidth, width);
+    track->mMeta->setInt32(kKeyHeight, width);
+    track->mMeta->setData(kKeyAVCC, type, csd, csdSize);
+
+    return OK;
+}
+
 status_t AVIExtractor::getSampleInfo(
         size_t trackIndex, size_t sampleIndex,
-        off64_t *offset, size_t *size, bool *isKey) {
+        off64_t *offset, size_t *size, bool *isKey,
+        int64_t *sampleTimeUs) {
     if (trackIndex >= mTracks.size()) {
         return -ERANGE;
     }
@@ -801,9 +904,20 @@
 
     *isKey = info.mIsKey;
 
+    *sampleTimeUs = (sampleIndex * 1000000ll * track.mRate) / track.mScale;
+
     return OK;
 }
 
+status_t AVIExtractor::getSampleTime(
+        size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs) {
+    off64_t offset;
+    size_t size;
+    bool isKey;
+    return getSampleInfo(
+            trackIndex, sampleIndex, &offset, &size, &isKey, sampleTimeUs);
+}
+
 status_t AVIExtractor::getSampleIndexAtTime(
         size_t trackIndex,
         int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
@@ -911,7 +1025,11 @@
 
     if (!memcmp(tmp, "RIFF", 4) && !memcmp(&tmp[8], "AVI ", 4)) {
         mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_AVI);
-        *confidence = 0.2;
+
+        // Just a tad over the mp3 extractor's confidence, since
+        // these .avi files may contain .mp3 content that otherwise would
+        // mistakenly lead to us identifying the entire file as a .mp3 file.
+        *confidence = 0.21;
 
         return true;
     }
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 9ab470b..6280f51 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -2452,13 +2452,16 @@
                     mOutputPortSettingsHaveChanged = formatChanged;
                 }
 
-                enablePortAsync(portIndex);
-
-                status_t err = allocateBuffersOnPort(portIndex);
-
+                status_t err = enablePortAsync(portIndex);
                 if (err != OK) {
-                    CODEC_LOGE("allocateBuffersOnPort failed (err = %d)", err);
+                    CODEC_LOGE("enablePortAsync(%ld) failed (err = %d)", portIndex, err);
                     setState(ERROR);
+                } else {
+                    err = allocateBuffersOnPort(portIndex);
+                    if (err != OK) {
+                        CODEC_LOGE("allocateBuffersOnPort failed (err = %d)", err);
+                        setState(ERROR);
+                    }
                 }
             }
             break;
@@ -2773,16 +2776,14 @@
     freeBuffersOnPort(portIndex, true);
 }
 
-void OMXCodec::enablePortAsync(OMX_U32 portIndex) {
+status_t OMXCodec::enablePortAsync(OMX_U32 portIndex) {
     CHECK(mState == EXECUTING || mState == RECONFIGURING);
 
     CHECK_EQ((int)mPortStatus[portIndex], (int)DISABLED);
     mPortStatus[portIndex] = ENABLING;
 
     CODEC_LOGV("sending OMX_CommandPortEnable(%ld)", portIndex);
-    status_t err =
-        mOMX->sendCommand(mNode, OMX_CommandPortEnable, portIndex);
-    CHECK_EQ(err, (status_t)OK);
+    return mOMX->sendCommand(mNode, OMX_CommandPortEnable, portIndex);
 }
 
 void OMXCodec::fillOutputBuffers() {
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 2b9d99b..ebad321 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -23,8 +23,8 @@
 
 #include <arpa/inet.h>
 
+#include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaDebug.h>
 #include <media/stagefright/Utils.h>
 
 namespace android {
@@ -40,6 +40,71 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
+struct SampleTable::CompositionDeltaLookup {
+    CompositionDeltaLookup();
+
+    void setEntries(
+            const uint32_t *deltaEntries, size_t numDeltaEntries);
+
+    uint32_t getCompositionTimeOffset(uint32_t sampleIndex);
+
+private:
+    Mutex mLock;
+
+    const uint32_t *mDeltaEntries;
+    size_t mNumDeltaEntries;
+
+    size_t mCurrentDeltaEntry;
+    size_t mCurrentEntrySampleIndex;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CompositionDeltaLookup);
+};
+
+SampleTable::CompositionDeltaLookup::CompositionDeltaLookup()
+    : mDeltaEntries(NULL),
+      mNumDeltaEntries(0),
+      mCurrentDeltaEntry(0),
+      mCurrentEntrySampleIndex(0) {
+}
+
+void SampleTable::CompositionDeltaLookup::setEntries(
+        const uint32_t *deltaEntries, size_t numDeltaEntries) {
+    Mutex::Autolock autolock(mLock);
+
+    mDeltaEntries = deltaEntries;
+    mNumDeltaEntries = numDeltaEntries;
+    mCurrentDeltaEntry = 0;
+    mCurrentEntrySampleIndex = 0;
+}
+
+uint32_t SampleTable::CompositionDeltaLookup::getCompositionTimeOffset(
+        uint32_t sampleIndex) {
+    Mutex::Autolock autolock(mLock);
+
+    if (mDeltaEntries == NULL) {
+        return 0;
+    }
+
+    if (sampleIndex < mCurrentEntrySampleIndex) {
+        mCurrentDeltaEntry = 0;
+        mCurrentEntrySampleIndex = 0;
+    }
+
+    while (mCurrentDeltaEntry < mNumDeltaEntries) {
+        uint32_t sampleCount = mDeltaEntries[2 * mCurrentDeltaEntry];
+        if (sampleIndex < mCurrentEntrySampleIndex + sampleCount) {
+            return mDeltaEntries[2 * mCurrentDeltaEntry + 1];
+        }
+
+        mCurrentEntrySampleIndex += sampleCount;
+        ++mCurrentDeltaEntry;
+    }
+
+    return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
 SampleTable::SampleTable(const sp<DataSource> &source)
     : mDataSource(source),
       mChunkOffsetOffset(-1),
@@ -56,6 +121,7 @@
       mSampleTimeEntries(NULL),
       mCompositionTimeDeltaEntries(NULL),
       mNumCompositionTimeDeltaEntries(0),
+      mCompositionDeltaLookup(new CompositionDeltaLookup),
       mSyncSampleOffset(-1),
       mNumSyncSamples(0),
       mSyncSamples(NULL),
@@ -71,6 +137,9 @@
     delete[] mSyncSamples;
     mSyncSamples = NULL;
 
+    delete mCompositionDeltaLookup;
+    mCompositionDeltaLookup = NULL;
+
     delete[] mCompositionTimeDeltaEntries;
     mCompositionTimeDeltaEntries = NULL;
 
@@ -318,6 +387,9 @@
         mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]);
     }
 
+    mCompositionDeltaLookup->setEntries(
+            mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries);
+
     return OK;
 }
 
@@ -430,8 +502,12 @@
 
                 mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
 
+                uint32_t compTimeDelta =
+                    mCompositionDeltaLookup->getCompositionTimeOffset(
+                            sampleIndex);
+
                 mSampleTimeEntries[sampleIndex].mCompositionTime =
-                    sampleTime + getCompositionTimeOffset(sampleIndex);
+                    sampleTime + compTimeDelta;
             }
 
             ++sampleIndex;
@@ -739,25 +815,8 @@
     return OK;
 }
 
-uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) const {
-    if (mCompositionTimeDeltaEntries == NULL) {
-        return 0;
-    }
-
-    uint32_t curSample = 0;
-    for (size_t i = 0; i < mNumCompositionTimeDeltaEntries; ++i) {
-        uint32_t sampleCount = mCompositionTimeDeltaEntries[2 * i];
-
-        if (sampleIndex < curSample + sampleCount) {
-            uint32_t sampleDelta = mCompositionTimeDeltaEntries[2 * i + 1];
-
-            return sampleDelta;
-        }
-
-        curSample += sampleCount;
-    }
-
-    return 0;
+uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) {
+    return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex);
 }
 
 }  // namespace android
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index 8a42e8b..153ee33 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -297,7 +297,7 @@
     sp<MetaData> meta = new MetaData;
     meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
 
-    meta->setData(kKeyAVCC, 0, csd->data(), csd->size());
+    meta->setData(kKeyAVCC, kTypeAVCC, csd->data(), csd->size());
     meta->setInt32(kKeyWidth, width);
     meta->setInt32(kKeyHeight, height);
 
@@ -329,6 +329,28 @@
     return foundIDR;
 }
 
+bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit) {
+    const uint8_t *data = accessUnit->data();
+    size_t size = accessUnit->size();
+
+    const uint8_t *nalStart;
+    size_t nalSize;
+    while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
+        CHECK_GT(nalSize, 0u);
+
+        unsigned nalType = nalStart[0] & 0x1f;
+
+        if (nalType == 5) {
+            return true;
+        } else if (nalType == 1) {
+            unsigned nal_ref_idc = (nalStart[0] >> 5) & 3;
+            return nal_ref_idc != 0;
+        }
+    }
+
+    return true;
+}
+
 sp<MetaData> MakeAACCodecSpecificData(
         unsigned profile, unsigned sampling_freq_index,
         unsigned channel_configuration) {
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
index de936c4..f15014e 100644
--- a/media/libstagefright/chromium_http/support.cpp
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -74,10 +74,32 @@
     return false;
 }
 
+struct AutoPrioritySaver {
+    AutoPrioritySaver()
+        : mTID(androidGetTid()),
+          mPrevPriority(androidGetThreadPriority(mTID)) {
+        androidSetThreadPriority(mTID, ANDROID_PRIORITY_NORMAL);
+    }
+
+    ~AutoPrioritySaver() {
+        androidSetThreadPriority(mTID, mPrevPriority);
+    }
+
+private:
+    pid_t mTID;
+    int mPrevPriority;
+
+    DISALLOW_EVIL_CONSTRUCTORS(AutoPrioritySaver);
+};
 
 static void InitializeNetworkThreadIfNecessary() {
     Mutex::Autolock autoLock(gNetworkThreadLock);
+
     if (gNetworkThread == NULL) {
+        // Make sure any threads spawned by the chromium framework are
+        // running at normal priority instead of inheriting this thread's.
+        AutoPrioritySaver saver;
+
         gNetworkThread = new base::Thread("network");
         base::Thread::Options options;
         options.message_loop_type = MessageLoop::TYPE_IO;
diff --git a/media/libstagefright/foundation/AMessage.cpp b/media/libstagefright/foundation/AMessage.cpp
index 582bdba..f039bc1 100644
--- a/media/libstagefright/foundation/AMessage.cpp
+++ b/media/libstagefright/foundation/AMessage.cpp
@@ -385,6 +385,15 @@
                             item.u.refValue)->debugString(
                                 indent + strlen(item.mName) + 14).c_str());
                 break;
+            case kTypeRect:
+                tmp = StringPrintf(
+                        "Rect %s(%d, %d, %d, %d)",
+                        item.mName,
+                        item.u.rectValue.mLeft,
+                        item.u.rectValue.mTop,
+                        item.u.rectValue.mRight,
+                        item.u.rectValue.mBottom);
+                break;
             default:
                 TRESPASS();
         }
diff --git a/media/libstagefright/include/AVIExtractor.h b/media/libstagefright/include/AVIExtractor.h
index 375a94d..75ce68d 100644
--- a/media/libstagefright/include/AVIExtractor.h
+++ b/media/libstagefright/include/AVIExtractor.h
@@ -54,6 +54,11 @@
         uint32_t mRate;
         uint32_t mScale;
 
+        // If bytes per sample == 0, each chunk represents a single sample,
+        // otherwise each chunk should me a multiple of bytes-per-sample in
+        // size.
+        uint32_t mBytesPerSample;
+
         enum Kind {
             AUDIO,
             VIDEO,
@@ -84,7 +89,11 @@
 
     status_t getSampleInfo(
             size_t trackIndex, size_t sampleIndex,
-            off64_t *offset, size_t *size, bool *isKey);
+            off64_t *offset, size_t *size, bool *isKey,
+            int64_t *sampleTimeUs);
+
+    status_t getSampleTime(
+            size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs);
 
     status_t getSampleIndexAtTime(
             size_t trackIndex,
@@ -92,6 +101,7 @@
             size_t *sampleIndex) const;
 
     status_t addMPEG4CodecSpecificData(size_t trackIndex);
+    status_t addH264CodecSpecificData(size_t trackIndex);
 
     static bool IsCorrectChunkType(
         ssize_t trackIndex, Track::Kind kind, uint32_t chunkType);
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index a6a6524..847dff7 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -86,6 +86,8 @@
     ~SampleTable();
 
 private:
+    struct CompositionDeltaLookup;
+
     static const uint32_t kChunkOffsetType32;
     static const uint32_t kChunkOffsetType64;
     static const uint32_t kSampleSizeType32;
@@ -117,6 +119,7 @@
 
     uint32_t *mCompositionTimeDeltaEntries;
     size_t mNumCompositionTimeDeltaEntries;
+    CompositionDeltaLookup *mCompositionDeltaLookup;
 
     off64_t mSyncSampleOffset;
     uint32_t mNumSyncSamples;
@@ -135,8 +138,7 @@
     friend struct SampleIterator;
 
     status_t getSampleSize_l(uint32_t sample_index, size_t *sample_size);
-
-    uint32_t getCompositionTimeOffset(uint32_t sampleIndex) const;
+    uint32_t getCompositionTimeOffset(uint32_t sampleIndex);
 
     static int CompareIncreasingTime(const void *, const void *);
 
diff --git a/media/libstagefright/include/avc_utils.h b/media/libstagefright/include/avc_utils.h
index 15cd4d4..e418822 100644
--- a/media/libstagefright/include/avc_utils.h
+++ b/media/libstagefright/include/avc_utils.h
@@ -50,6 +50,7 @@
 sp<MetaData> MakeAVCCodecSpecificData(const sp<ABuffer> &accessUnit);
 
 bool IsIDR(const sp<ABuffer> &accessUnit);
+bool IsAVCReferenceFrame(const sp<ABuffer> &accessUnit);
 
 const char *AVCProfileToString(uint8_t profile);
 
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index bc24dbb..33d3f30 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -85,7 +85,7 @@
     : mOwner(owner),
       mDone(false) {
     mThread = new CallbackDispatcherThread(this);
-    mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_AUDIO);
+    mThread->run("OMXCallbackDisp", ANDROID_PRIORITY_FOREGROUND);
 }
 
 OMX::CallbackDispatcher::~CallbackDispatcher() {
diff --git a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
index f7330f3..b705d00 100644
--- a/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SimpleSoftOMXComponent.cpp
@@ -42,7 +42,7 @@
     mLooper->start(
             false, // runOnCallingThread
             false, // canCallJava
-            PRIORITY_AUDIO);
+            ANDROID_PRIORITY_FOREGROUND);
 }
 
 void SimpleSoftOMXComponent::prepareForDestruction() {
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 94efa74..a58f64c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -87,6 +87,8 @@
 // RecordThread loop sleep time upon application overrun or audio HAL read error
 static const int kRecordThreadSleepUs = 5000;
 
+static const nsecs_t kSetParametersTimeout = seconds(2);
+
 // ----------------------------------------------------------------------------
 
 static bool recordingAllowed() {
@@ -1032,7 +1034,7 @@
     mWaitWorkCV.signal();
     // wait condition with timeout in case the thread loop has exited
     // before the request could be processed
-    if (mParamCond.waitRelative(mLock, seconds(2)) == NO_ERROR) {
+    if (mParamCond.waitRelative(mLock, kSetParametersTimeout) == NO_ERROR) {
         status = mParamStatus;
         mWaitWorkCV.signal();
     } else {
@@ -2349,7 +2351,9 @@
 
         mParamStatus = status;
         mParamCond.signal();
-        mWaitWorkCV.wait(mLock);
+        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+        // already timed out waiting for the status and will never signal the condition.
+        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
     }
     return reconfig;
 }
@@ -2828,7 +2832,9 @@
 
         mParamStatus = status;
         mParamCond.signal();
-        mWaitWorkCV.wait(mLock);
+        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+        // already timed out waiting for the status and will never signal the condition.
+        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
     }
     return reconfig;
 }
@@ -4669,7 +4675,9 @@
 
         mParamStatus = status;
         mParamCond.signal();
-        mWaitWorkCV.wait(mLock);
+        // wait for condition with time out in case the thread calling ThreadBase::setParameters()
+        // already timed out waiting for the status and will never signal the condition.
+        mWaitWorkCV.waitRelative(mLock, kSetParametersTimeout);
     }
     return reconfig;
 }
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index dca795c..9ee5a30 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -434,9 +434,9 @@
 
         // the following loop works on 2 frames
 
-        ".Y4L01:\n"
+        "1:\n"
         "   cmp r8, r2\n"                   // curOut - maxCurOut
-        "   bcs .Y4L02\n"
+        "   bcs 2f\n"
 
 #define MO_ONE_FRAME \
     "   add r0, r1, r7, asl #1\n"       /* in + inputIndex */\
@@ -460,8 +460,8 @@
         MO_ONE_FRAME    // frame 2
 
         "   cmp r7, r3\n"                   // inputIndex - maxInIdx
-        "   bcc .Y4L01\n"
-        ".Y4L02:\n"
+        "   bcc 1b\n"
+        "2:\n"
 
         "   bic r6, r6, #0xC0000000\n"             // phaseFraction & ...
         // save modified values
@@ -541,9 +541,9 @@
         // r13 sp
         // r14
 
-        ".Y5L01:\n"
+        "3:\n"
         "   cmp r8, r2\n"                   // curOut - maxCurOut
-        "   bcs .Y5L02\n"
+        "   bcs 4f\n"
 
 #define ST_ONE_FRAME \
     "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
@@ -577,8 +577,8 @@
     ST_ONE_FRAME    // frame 1
 
         "   cmp r7, r3\n"                       // inputIndex - maxInIdx
-        "   bcc .Y5L01\n"
-        ".Y5L02:\n"
+        "   bcc 3b\n"
+        "4:\n"
 
         "   bic r6, r6, #0xC0000000\n"              // phaseFraction & ...
         // save modified values