Merge "audio policy: fix explicit routing and accessibility" into mnc-dev
diff --git a/media/img_utils/include/img_utils/DngUtils.h b/media/img_utils/include/img_utils/DngUtils.h
index 4389b02..3dcedc5 100644
--- a/media/img_utils/include/img_utils/DngUtils.h
+++ b/media/img_utils/include/img_utils/DngUtils.h
@@ -31,6 +31,7 @@
 namespace img_utils {
 
 #define NELEMS(x) ((int) (sizeof(x) / sizeof((x)[0])))
+#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
 
 /**
  * Utility class for building values for the OpcodeList tags specified
@@ -107,13 +108,49 @@
                                     uint32_t mapPlanes,
                                     const float* mapGains);
 
+        /**
+         * Add WarpRectilinear opcode for the given metadata parameters.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t addWarpRectilinearForMetadata(const float* kCoeffs,
+                                                       uint32_t activeArrayWidth,
+                                                       uint32_t activeArrayHeight,
+                                                       float opticalCenterX,
+                                                       float opticalCenterY);
+
+        /**
+         * Add a WarpRectilinear opcode.
+         *
+         * numPlanes - Number of planes included in this opcode.
+         * opticalCenterX, opticalCenterY - Normalized x,y coordinates of the sensor optical
+         *          center relative to the top,left pixel of the produced images (e.g. [0.5, 0.5]
+         *          gives a sensor optical center in the image center.
+         * kCoeffs - A list of coefficients for the polynomial equation representing the distortion
+         *          correction.  For each plane, 6 coefficients must be included:
+         *          {k_r0, k_r1, k_r2, k_r3, k_t0, k_t1}.  See the DNG 1.4 specification for an
+         *          outline of the polynomial used here.
+         *
+         * Returns OK on success, or a negative error code.
+         */
+        virtual status_t addWarpRectilinear(uint32_t numPlanes,
+                                            double opticalCenterX,
+                                            double opticalCenterY,
+                                            const double* kCoeffs);
+
         // TODO: Add other Opcode methods
     protected:
         static const uint32_t FLAG_OPTIONAL = 0x1u;
         static const uint32_t FLAG_OPTIONAL_FOR_PREVIEW = 0x2u;
 
+        // Opcode IDs
         enum {
+            WARP_RECTILINEAR_ID = 1,
             GAIN_MAP_ID = 9,
+        };
+
+        // LSM mosaic indices
+        enum {
             LSM_R_IND = 0,
             LSM_GE_IND = 1,
             LSM_GO_IND = 2,
diff --git a/media/img_utils/src/DngUtils.cpp b/media/img_utils/src/DngUtils.cpp
index d3b4a35..b213403 100644
--- a/media/img_utils/src/DngUtils.cpp
+++ b/media/img_utils/src/DngUtils.cpp
@@ -16,6 +16,10 @@
 
 #include <img_utils/DngUtils.h>
 
+#include <inttypes.h>
+
+#include <math.h>
+
 namespace android {
 namespace img_utils {
 
@@ -229,7 +233,7 @@
     err = mEndianOut.write(version, 0, NELEMS(version));
     if (err != OK) return err;
 
-    // Do not include optional flag for preview, as this can have a large effect on the output.
+    // Allow this opcode to be skipped if not supported
     uint32_t flags = FLAG_OPTIONAL;
 
     err = mEndianOut.write(&flags, 0, 1);
@@ -278,5 +282,96 @@
     return OK;
 }
 
+status_t OpcodeListBuilder::addWarpRectilinearForMetadata(const float* kCoeffs,
+                                                          uint32_t activeArrayWidth,
+                                                          uint32_t activeArrayHeight,
+                                                          float opticalCenterX,
+                                                          float opticalCenterY) {
+    if (activeArrayWidth <= 1 || activeArrayHeight <= 1) {
+        ALOGE("%s: Cannot add opcode for active array with dimensions w=%" PRIu32 ", h=%" PRIu32,
+                __FUNCTION__, activeArrayWidth, activeArrayHeight);
+        return BAD_VALUE;
+    }
+
+    double normalizedOCX = opticalCenterX / static_cast<double>(activeArrayWidth - 1);
+    double normalizedOCY = opticalCenterY / static_cast<double>(activeArrayHeight - 1);
+
+    normalizedOCX = CLAMP(normalizedOCX, 0, 1);
+    normalizedOCY = CLAMP(normalizedOCY, 0, 1);
+
+    // Conversion factors from Camera2 K factors to DNG spec. K factors:
+    //
+    //      Note: these are necessary because our unit system assumes a
+    //      normalized max radius of sqrt(2), whereas the DNG spec's
+    //      WarpRectilinear opcode assumes a normalized max radius of 1.
+    //      Thus, each K coefficient must include the domain scaling
+    //      factor (the DNG domain is scaled by sqrt(2) to emulate the
+    //      domain used by the Camera2 specification).
+
+    const double c_0 = sqrt(2);
+    const double c_1 = 2 * sqrt(2);
+    const double c_2 = 4 * sqrt(2);
+    const double c_3 = 8 * sqrt(2);
+    const double c_4 = 2;
+    const double c_5 = 2;
+
+    const double coeffs[] = { c_0 * kCoeffs[0],
+                              c_1 * kCoeffs[1],
+                              c_2 * kCoeffs[2],
+                              c_3 * kCoeffs[3],
+                              c_4 * kCoeffs[4],
+                              c_5 * kCoeffs[5] };
+
+
+    return addWarpRectilinear(/*numPlanes*/1,
+                              /*opticalCenterX*/normalizedOCX,
+                              /*opticalCenterY*/normalizedOCY,
+                              coeffs);
+}
+
+status_t OpcodeListBuilder::addWarpRectilinear(uint32_t numPlanes,
+                                               double opticalCenterX,
+                                               double opticalCenterY,
+                                               const double* kCoeffs) {
+
+    uint32_t opcodeId = WARP_RECTILINEAR_ID;
+
+    status_t err = mEndianOut.write(&opcodeId, 0, 1);
+    if (err != OK) return err;
+
+    uint8_t version[] = {1, 3, 0, 0};
+    err = mEndianOut.write(version, 0, NELEMS(version));
+    if (err != OK) return err;
+
+    // Allow this opcode to be skipped if not supported
+    uint32_t flags = FLAG_OPTIONAL;
+
+    err = mEndianOut.write(&flags, 0, 1);
+    if (err != OK) return err;
+
+    const uint32_t NUMBER_CENTER_ARGS = 2;
+    const uint32_t NUMBER_COEFFS = numPlanes * 6;
+    uint32_t totalSize = (NUMBER_CENTER_ARGS + NUMBER_COEFFS) * sizeof(double) + sizeof(uint32_t);
+
+    err = mEndianOut.write(&totalSize, 0, 1);
+    if (err != OK) return err;
+
+    err = mEndianOut.write(&numPlanes, 0, 1);
+    if (err != OK) return err;
+
+    err = mEndianOut.write(kCoeffs, 0, NUMBER_COEFFS);
+    if (err != OK) return err;
+
+    err = mEndianOut.write(&opticalCenterX, 0, 1);
+    if (err != OK) return err;
+
+    err = mEndianOut.write(&opticalCenterY, 0, 1);
+    if (err != OK) return err;
+
+    mCount++;
+
+    return OK;
+}
+
 } /*namespace img_utils*/
 } /*namespace android*/
diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp
index 09137ef..7e89d7f 100644
--- a/media/libmedia/IMediaHTTPConnection.cpp
+++ b/media/libmedia/IMediaHTTPConnection.cpp
@@ -70,7 +70,7 @@
         int32_t exceptionCode = reply.readExceptionCode();
 
         if (exceptionCode) {
-            return UNKNOWN_ERROR;
+            return false;
         }
 
         sp<IBinder> binder = reply.readStrongBinder();
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index ca33aed..e8d495b 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -70,12 +70,6 @@
         return STAGEFRIGHT_PLAYER;
     }
 
-    // TODO: remove this EXPERIMENTAL developer settings property
-    if (property_get("persist.sys.media.use-awesome", value, NULL)
-            && !strcasecmp("true", value)) {
-        return STAGEFRIGHT_PLAYER;
-    }
-
     return NU_PLAYER;
 }
 
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 9a37302..a5a1fa5 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -191,10 +191,13 @@
     return ret;
 }
 
+Mutex MetadataRetrieverClient::sLock;
+
 sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
 {
     ALOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
     Mutex::Autolock lock(mLock);
+    Mutex::Autolock glock(sLock);
     mThumbnail.clear();
     if (mRetriever == NULL) {
         ALOGE("retriever is not initialized");
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index e71a29e..fe7547c 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -63,6 +63,7 @@
     virtual ~MetadataRetrieverClient();
 
     mutable Mutex                          mLock;
+    static  Mutex                          sLock;
     sp<MediaMetadataRetrieverBase>         mRetriever;
     pid_t                                  mPid;
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 8760cbb..ef96a28 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1729,13 +1729,15 @@
     return renderer->getCurrentPosition(mediaUs);
 }
 
-void NuPlayer::getStats(int64_t *numFramesTotal, int64_t *numFramesDropped) {
-    sp<DecoderBase> decoder = getDecoder(false /* audio */);
-    if (decoder != NULL) {
-        decoder->getStats(numFramesTotal, numFramesDropped);
-    } else {
-        *numFramesTotal = 0;
-        *numFramesDropped = 0;
+void NuPlayer::getStats(Vector<sp<AMessage> > *mTrackStats) {
+    CHECK(mTrackStats != NULL);
+
+    mTrackStats->clear();
+    if (mVideoDecoder != NULL) {
+        mTrackStats->push_back(mVideoDecoder->getStats());
+    }
+    if (mAudioDecoder != NULL) {
+        mTrackStats->push_back(mAudioDecoder->getStats());
     }
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index d7aa830..298ea6d 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -77,7 +77,7 @@
     status_t getSelectedTrack(int32_t type, Parcel* reply) const;
     status_t selectTrack(size_t trackIndex, bool select, int64_t timeUs);
     status_t getCurrentPosition(int64_t *mediaUs);
-    void getStats(int64_t *mNumFramesTotal, int64_t *mNumFramesDropped);
+    void getStats(Vector<sp<AMessage> > *mTrackStats);
 
     sp<MetaData> getFileMeta();
     float getFrameRate();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index c649c62..99a2a84 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -58,7 +58,10 @@
       mCCDecoder(ccDecoder),
       mSkipRenderingUntilMediaTimeUs(-1ll),
       mNumFramesTotal(0ll),
-      mNumFramesDropped(0ll),
+      mNumInputFramesDropped(0ll),
+      mNumOutputFramesDropped(0ll),
+      mVideoWidth(0),
+      mVideoHeight(0),
       mIsAudio(true),
       mIsVideoAVC(false),
       mIsSecure(false),
@@ -77,11 +80,11 @@
     releaseAndResetMediaBuffers();
 }
 
-void NuPlayer::Decoder::getStats(
-        int64_t *numFramesTotal,
-        int64_t *numFramesDropped) const {
-    *numFramesTotal = mNumFramesTotal;
-    *numFramesDropped = mNumFramesDropped;
+sp<AMessage> NuPlayer::Decoder::getStats() const {
+    mStats->setInt64("frames-total", mNumFramesTotal);
+    mStats->setInt64("frames-dropped-input", mNumInputFramesDropped);
+    mStats->setInt64("frames-dropped-output", mNumOutputFramesDropped);
+    return mStats;
 }
 
 void NuPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) {
@@ -237,6 +240,18 @@
     CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat));
     CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat));
 
+    mStats->setString("mime", mime.c_str());
+    mStats->setString("component-name", mComponentName.c_str());
+
+    if (!mIsAudio) {
+        int32_t width, height;
+        if (mOutputFormat->findInt32("width", &width)
+                && mOutputFormat->findInt32("height", &height)) {
+            mStats->setInt32("width", width);
+            mStats->setInt32("height", height);
+        }
+    }
+
     sp<AMessage> reply = new AMessage(kWhatCodecNotify, this);
     mCodec->setCallback(reply);
 
@@ -520,6 +535,8 @@
         mSkipRenderingUntilMediaTimeUs = -1;
     }
 
+    mNumFramesTotal += !mIsAudio;
+
     // wait until 1st frame comes out to signal resume complete
     notifyResumeCompleteIfNecessary();
 
@@ -536,6 +553,12 @@
 
 void NuPlayer::Decoder::handleOutputFormatChange(const sp<AMessage> &format) {
     if (!mIsAudio) {
+        int32_t width, height;
+        if (format->findInt32("width", &width)
+                && format->findInt32("height", &height)) {
+            mStats->setInt32("width", width);
+            mStats->setInt32("height", height);
+        }
         sp<AMessage> notify = mNotify->dup();
         notify->setInt32("what", kWhatVideoSizeChanged);
         notify->setMessage("format", format);
@@ -654,10 +677,6 @@
             return ERROR_END_OF_STREAM;
         }
 
-        if (!mIsAudio) {
-            ++mNumFramesTotal;
-        }
-
         dropAccessUnit = false;
         if (!mIsAudio
                 && !mIsSecure
@@ -665,7 +684,7 @@
                 && mIsVideoAVC
                 && !IsAVCReferenceFrame(accessUnit)) {
             dropAccessUnit = true;
-            ++mNumFramesDropped;
+            ++mNumInputFramesDropped;
         }
     } while (dropAccessUnit);
 
@@ -833,6 +852,7 @@
         CHECK(msg->findInt64("timestampNs", &timestampNs));
         err = mCodec->renderOutputBufferAndRelease(bufferIx, timestampNs);
     } else {
+        mNumOutputFramesDropped += !mIsAudio;
         err = mCodec->releaseOutputBuffer(bufferIx);
     }
     if (err != OK) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index 070d51a..ceccb7a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -30,9 +30,7 @@
             const sp<Surface> &surface = NULL,
             const sp<CCDecoder> &ccDecoder = NULL);
 
-    virtual void getStats(
-            int64_t *mNumFramesTotal,
-            int64_t *mNumFramesDropped) const;
+    virtual sp<AMessage> getStats() const;
 
 protected:
     virtual ~Decoder();
@@ -77,7 +75,10 @@
 
     int64_t mSkipRenderingUntilMediaTimeUs;
     int64_t mNumFramesTotal;
-    int64_t mNumFramesDropped;
+    int64_t mNumInputFramesDropped;
+    int64_t mNumOutputFramesDropped;
+    int32_t mVideoWidth;
+    int32_t mVideoHeight;
     bool mIsAudio;
     bool mIsVideoAVC;
     bool mIsSecure;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
index 9d509bf..7e76842 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
@@ -31,6 +31,7 @@
 NuPlayer::DecoderBase::DecoderBase(const sp<AMessage> &notify)
     :  mNotify(notify),
        mBufferGeneration(0),
+       mStats(new AMessage),
        mRequestInputBuffersPending(false) {
     // Every decoder has its own looper because MediaCodec operations
     // are blocking, but NuPlayer needs asynchronous operations.
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index b52e7f7..8f030f0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -42,9 +42,9 @@
     void signalResume(bool notifyComplete);
     void initiateShutdown();
 
-    virtual void getStats(
-            int64_t *mNumFramesTotal,
-            int64_t *mNumFramesDropped) const = 0;
+    virtual sp<AMessage> getStats() const {
+        return mStats;
+    }
 
     enum {
         kWhatInputDiscontinuity  = 'inDi',
@@ -76,6 +76,7 @@
 
     sp<AMessage> mNotify;
     int32_t mBufferGeneration;
+    sp<AMessage> mStats;
 
 private:
     enum {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index d7b070e..30146c4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -59,12 +59,6 @@
 NuPlayer::DecoderPassThrough::~DecoderPassThrough() {
 }
 
-void NuPlayer::DecoderPassThrough::getStats(
-        int64_t *numFramesTotal, int64_t *numFramesDropped) const {
-    *numFramesTotal = 0;
-    *numFramesDropped = 0;
-}
-
 void NuPlayer::DecoderPassThrough::onConfigure(const sp<AMessage> &format) {
     ALOGV("[%s] onConfigure", mComponentName.c_str());
     mCachedBytes = 0;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
index 2f6df2c..db33e87 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
@@ -29,10 +29,6 @@
                        const sp<Source> &source,
                        const sp<Renderer> &renderer);
 
-    virtual void getStats(
-            int64_t *mNumFramesTotal,
-            int64_t *mNumFramesDropped) const;
-
 protected:
 
     virtual ~DecoderPassThrough();
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 84ae25e..3882dcd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "NuPlayerDriver"
 #include <inttypes.h>
 #include <utils/Log.h>
+#include <cutils/properties.h>
 
 #include "NuPlayerDriver.h"
 
@@ -241,7 +242,7 @@
 }
 
 status_t NuPlayerDriver::start() {
-    ALOGD("start(%p)", this);
+    ALOGD("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
     Mutex::Autolock autoLock(mLock);
 
     switch (mState) {
@@ -484,6 +485,13 @@
         notifyListener_l(MEDIA_STOPPED);
     }
 
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("persist.debug.sf.stats", value, NULL) &&
+            (!strcmp("1", value) || !strcasecmp("true", value))) {
+        Vector<String16> args;
+        dump(-1, args);
+    }
+
     mState = STATE_RESET_IN_PROGRESS;
     mPlayer->resetAsync();
 
@@ -652,22 +660,59 @@
 
 status_t NuPlayerDriver::dump(
         int fd, const Vector<String16> & /* args */) const {
-    int64_t numFramesTotal;
-    int64_t numFramesDropped;
-    mPlayer->getStats(&numFramesTotal, &numFramesDropped);
 
-    FILE *out = fdopen(dup(fd), "w");
+    Vector<sp<AMessage> > trackStats;
+    mPlayer->getStats(&trackStats);
 
-    fprintf(out, " NuPlayer\n");
-    fprintf(out, "  numFramesTotal(%" PRId64 "), numFramesDropped(%" PRId64 "), "
-                 "percentageDropped(%.2f)\n",
-                 numFramesTotal,
-                 numFramesDropped,
-                 numFramesTotal == 0
-                    ? 0.0 : (double)numFramesDropped / numFramesTotal);
+    AString logString(" NuPlayer\n");
+    char buf[256] = {0};
 
-    fclose(out);
-    out = NULL;
+    for (size_t i = 0; i < trackStats.size(); ++i) {
+        const sp<AMessage> &stats = trackStats.itemAt(i);
+
+        AString mime;
+        if (stats->findString("mime", &mime)) {
+            snprintf(buf, sizeof(buf), "  mime(%s)\n", mime.c_str());
+            logString.append(buf);
+        }
+
+        AString name;
+        if (stats->findString("component-name", &name)) {
+            snprintf(buf, sizeof(buf), "    decoder(%s)\n", name.c_str());
+            logString.append(buf);
+        }
+
+        if (mime.startsWith("video/")) {
+            int32_t width, height;
+            if (stats->findInt32("width", &width)
+                    && stats->findInt32("height", &height)) {
+                snprintf(buf, sizeof(buf), "    resolution(%d x %d)\n", width, height);
+                logString.append(buf);
+            }
+
+            int64_t numFramesTotal = 0;
+            int64_t numFramesDropped = 0;
+
+            stats->findInt64("frames-total", &numFramesTotal);
+            stats->findInt64("frames-dropped-output", &numFramesDropped);
+            snprintf(buf, sizeof(buf), "    numFramesTotal(%lld), numFramesDropped(%lld), "
+                     "percentageDropped(%.2f%%)\n",
+                     (long long)numFramesTotal,
+                     (long long)numFramesDropped,
+                     numFramesTotal == 0
+                            ? 0.0 : (double)(numFramesDropped * 100) / numFramesTotal);
+            logString.append(buf);
+        }
+    }
+
+    ALOGI("%s", logString.c_str());
+
+    if (fd >= 0) {
+        FILE *out = fdopen(dup(fd), "w");
+        fprintf(out, "%s", logString.c_str());
+        fclose(out);
+        out = NULL;
+    }
 
     return OK;
 }
@@ -680,6 +725,7 @@
 
 void NuPlayerDriver::notifyListener_l(
         int msg, int ext1, int ext2, const Parcel *in) {
+    ALOGD("notifyListener_l(%p), (%d, %d, %d)", this, msg, ext1, ext2);
     switch (msg) {
         case MEDIA_PLAYBACK_COMPLETE:
         {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index fb2e767..7e55aac 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -771,6 +771,33 @@
     return sizeCopied;
 }
 
+void NuPlayer::Renderer::drainAudioQueueUntilLastEOS() {
+    List<QueueEntry>::iterator it = mAudioQueue.begin(), itEOS = it;
+    bool foundEOS = false;
+    while (it != mAudioQueue.end()) {
+        int32_t eos;
+        QueueEntry *entry = &*it++;
+        if (entry->mBuffer == NULL
+                || (entry->mNotifyConsumed->findInt32("eos", &eos) && eos != 0)) {
+            itEOS = it;
+            foundEOS = true;
+        }
+    }
+
+    if (foundEOS) {
+        // post all replies before EOS and drop the samples
+        for (it = mAudioQueue.begin(); it != itEOS; it++) {
+            if (it->mBuffer == NULL) {
+                // delay doesn't matter as we don't even have an AudioTrack
+                notifyEOS(true /* audio */, it->mFinalResult);
+            } else {
+                it->mNotifyConsumed->post();
+            }
+        }
+        mAudioQueue.erase(mAudioQueue.begin(), itEOS);
+    }
+}
+
 bool NuPlayer::Renderer::onDrainAudioQueue() {
     // TODO: This call to getPosition checks if AudioTrack has been created
     // in AudioSink before draining audio. If AudioTrack doesn't exist, then
@@ -784,6 +811,13 @@
     // "vorbis_dsp_synthesis returned -135", along with RTSP.
     uint32_t numFramesPlayed;
     if (mAudioSink->getPosition(&numFramesPlayed) != OK) {
+        // When getPosition fails, renderer will not reschedule the draining
+        // unless new samples are queued.
+        // If we have pending EOS (or "eos" marker for discontinuities), we need
+        // to post these now as NuPlayerDecoder might be waiting for it.
+        drainAudioQueueUntilLastEOS();
+
+        ALOGW("onDrainAudioQueue(): audio sink is not ready");
         return false;
     }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index c2fea40..3e65649 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -208,6 +208,7 @@
     size_t fillAudioBuffer(void *buffer, size_t size);
 
     bool onDrainAudioQueue();
+    void drainAudioQueueUntilLastEOS();
     int64_t getPendingAudioPlayoutDurationUs(int64_t nowUs);
     int64_t getPlayedOutAudioDurationUs(int64_t nowUs);
     void postDrainAudioQueue_l(int64_t delayUs = 0);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index a57d4cf..527e9cd 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -110,6 +110,8 @@
 struct MessageList : public RefBase {
     MessageList() {
     }
+    virtual ~MessageList() {
+    }
     std::list<sp<AMessage> > &getList() { return mList; }
 private:
     std::list<sp<AMessage> > mList;
@@ -126,15 +128,19 @@
 
     // from IOMXObserver
     virtual void onMessages(const std::list<omx_message> &messages) {
-        sp<AMessage> notify;
+        if (messages.empty()) {
+            return;
+        }
+
+        sp<AMessage> notify = mNotify->dup();
         bool first = true;
         sp<MessageList> msgList = new MessageList();
         for (std::list<omx_message>::const_iterator it = messages.cbegin();
               it != messages.cend(); ++it) {
             const omx_message &omx_msg = *it;
             if (first) {
-                notify = mNotify->dup();
                 notify->setInt32("node", omx_msg.node);
+                first = false;
             }
 
             sp<AMessage> msg = new AMessage;
@@ -1390,7 +1396,8 @@
 
 status_t ACodec::freeBuffersOnPort(OMX_U32 portIndex) {
     status_t err = OK;
-    for (size_t i = mBuffers[portIndex].size(); i-- > 0;) {
+    for (size_t i = mBuffers[portIndex].size(); i > 0;) {
+        i--;
         status_t err2 = freeBuffer(portIndex, i);
         if (err == OK) {
             err = err2;
@@ -1404,7 +1411,8 @@
 
 status_t ACodec::freeOutputBuffersNotOwnedByComponent() {
     status_t err = OK;
-    for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) {
+    for (size_t i = mBuffers[kPortIndexOutput].size(); i > 0;) {
+        i--;
         BufferInfo *info =
             &mBuffers[kPortIndexOutput].editItemAt(i);
 
@@ -5196,16 +5204,11 @@
 
         int64_t timestampNs = 0;
         if (!msg->findInt64("timestampNs", &timestampNs)) {
-            // TODO: it seems like we should use the timestamp
-            // in the (media)buffer as it potentially came from
-            // an input surface, but we did not propagate it prior to
-            // API 20.  Perhaps check for target SDK version.
-#if 0
+            // use media timestamp if client did not request a specific render timestamp
             if (info->mData->meta()->findInt64("timeUs", &timestampNs)) {
-                ALOGV("using buffer PTS of %" PRId64, timestampNs);
+                ALOGV("using buffer PTS of %lld", (long long)timestampNs);
                 timestampNs *= 1000;
             }
-#endif
         }
 
         status_t err;
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index 41f0175..e17fdf8 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -109,9 +109,26 @@
     }
 
     // Check if the cache satisfies the read.
-    if (offset >= mCachedOffset && offset + size <= mCachedOffset + mCachedSize) {
-        memcpy(data, &mCache[offset - mCachedOffset], size);
-        return size;
+    if (mCachedOffset <= offset
+            && offset < (off64_t) (mCachedOffset + mCachedSize)) {
+        if (offset + size <= mCachedOffset + mCachedSize) {
+            memcpy(data, &mCache[offset - mCachedOffset], size);
+            return size;
+        } else {
+            // If the cache hits only partially, flush the cache and read the
+            // remainder.
+
+            // This value is guaranteed to be greater than 0 because of the
+            // enclosing if statement.
+            const ssize_t remaining = mCachedOffset + mCachedSize - offset;
+            memcpy(data, &mCache[offset - mCachedOffset], remaining);
+            const ssize_t readMore = readAt(offset + remaining,
+                    (uint8_t*)data + remaining, size - remaining);
+            if (readMore < 0) {
+                return readMore;
+            }
+            return remaining + readMore;
+        }
     }
 
     // Fill the cache and copy to the caller.
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
old mode 100644
new mode 100755
index 62612c7..8bf47b1
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1665,7 +1665,18 @@
                     return err;
                 }
             }
+            if (mPath.size() >= 2
+                    && mPath[mPath.size() - 2] == FOURCC('m', 'p', '4', 'v')) {
+                // Check if the video is MPEG2
+                ESDS esds(&buffer[4], chunk_data_size - 4);
 
+                uint8_t objectTypeIndication;
+                if (esds.getObjectTypeIndication(&objectTypeIndication) == OK) {
+                    if (objectTypeIndication >= 0x60 && objectTypeIndication <= 0x65) {
+                        mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
+                    }
+                }
+            }
             break;
         }
 
@@ -2847,6 +2858,7 @@
             return ERROR_MALFORMED;
         }
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
+            || !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG2)
             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
         if (!track->meta->findData(kKeyESDS, &type, &data, &size)
                 || type != kTypeESDS) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 7ee84a8..e5b7202 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2452,18 +2452,12 @@
         info->mData->meta()->findInt64("timeUs", &mediaTimeUs);
 
         int64_t renderTimeNs = 0;
-        if (msg->findInt64("timestampNs", &renderTimeNs)) {
-            info->mNotify->setInt64("timestampNs", renderTimeNs);
-        } else {
-            // TODO: it seems like we should use the timestamp
-            // in the (media)buffer as it potentially came from
-            // an input surface, but we did not propagate it prior to
-            // API 20.  Perhaps check for target SDK version.
-#if 0
-            ALOGV("using buffer PTS of %" PRId64, timestampNs);
+        if (!msg->findInt64("timestampNs", &renderTimeNs)) {
+            // use media timestamp if client did not request a specific render timestamp
+            ALOGV("using buffer PTS of %lld", (long long)mediaTimeUs);
             renderTimeNs = mediaTimeUs * 1000;
-#endif
         }
+        info->mNotify->setInt64("timestampNs", renderTimeNs);
 
         if (mSoftRenderer != NULL) {
             std::list<FrameRenderTracker::Info> doneFrames = mSoftRenderer->render(
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index d48ede9..a47bfc7 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -79,6 +79,8 @@
 // static
 void *MediaCodecList::profilerThreadWrapper(void * /*arg*/) {
     ALOGV("Enter profilerThreadWrapper.");
+    remove(kProfilingResults);  // remove previous result so that it won't be loaded to
+                                // the new MediaCodecList
     MediaCodecList *codecList = new MediaCodecList();
     if (codecList->initCheck() != OK) {
         ALOGW("Failed to create a new MediaCodecList, skipping codec profiling.");
@@ -218,7 +220,8 @@
         }
     }
 
-    for (size_t i = mCodecInfos.size(); i-- > 0;) {
+    for (size_t i = mCodecInfos.size(); i > 0;) {
+        i--;
         const MediaCodecInfo &info = *mCodecInfos.itemAt(i).get();
         if (info.mCaps.size() == 0) {
             // No types supported by this component???
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index e9566f2..7c554db 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -20,22 +20,35 @@
 #include <inttypes.h>
 
 #include <utils/Log.h>
+#include <gui/Surface.h>
 
 #include "include/StagefrightMetadataRetriever.h"
 
+#include <media/ICrypto.h>
 #include <media/IMediaHTTPService.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/ColorConverter.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaExtractor.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OMXCodec.h>
-#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/Utils.h>
+
 #include <CharacterEncodingDetector.h>
 
 namespace android {
 
+static const int64_t kBufferTimeOutUs = 30000ll; // 30 msec
+static const size_t kRetryCount = 20; // must be >0
+
 StagefrightMetadataRetriever::StagefrightMetadataRetriever()
     : mParsedMetaData(false),
       mAlbumArt(NULL) {
@@ -123,73 +136,52 @@
     return OK;
 }
 
-static bool isYUV420PlanarSupported(
-            OMXClient *client,
-            const sp<MetaData> &trackMeta) {
-
-    const char *mime;
-    CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
-
-    Vector<CodecCapabilities> caps;
-    if (QueryCodecs(client->interface(), mime,
-                    true, /* queryDecoders */
-                    true, /* hwCodecOnly */
-                    &caps) == OK) {
-
-        for (size_t j = 0; j < caps.size(); ++j) {
-            CodecCapabilities cap = caps[j];
-            for (size_t i = 0; i < cap.mColorFormats.size(); ++i) {
-                if (cap.mColorFormats[i] == OMX_COLOR_FormatYUV420Planar) {
-                    return true;
-                }
-            }
-        }
-    }
-    return false;
-}
-
-static VideoFrame *extractVideoFrameWithCodecFlags(
-        OMXClient *client,
+static VideoFrame *extractVideoFrame(
+        const char *componentName,
         const sp<MetaData> &trackMeta,
         const sp<MediaSource> &source,
-        uint32_t flags,
         int64_t frameTimeUs,
         int seekMode) {
 
     sp<MetaData> format = source->getFormat();
 
-    // XXX:
-    // Once all vendors support OMX_COLOR_FormatYUV420Planar, we can
-    // remove this check and always set the decoder output color format
-    if (isYUV420PlanarSupported(client, trackMeta)) {
-        format->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
-    }
+    sp<AMessage> videoFormat;
+    convertMetaDataToMessage(trackMeta, &videoFormat);
 
-    sp<MediaSource> decoder =
-        OMXCodec::Create(
-                client->interface(), format, false, source,
-                NULL, flags | OMXCodec::kClientNeedsFramebuffer);
+    // TODO: Use Flexible color instead
+    videoFormat->setInt32("color-format", OMX_COLOR_FormatYUV420Planar);
 
-    if (decoder.get() == NULL) {
-        ALOGV("unable to instantiate video decoder.");
+    status_t err;
+    sp<ALooper> looper = new ALooper;
+    looper->start();
+    sp<MediaCodec> decoder = MediaCodec::CreateByComponentName(
+            looper, componentName, &err);
 
+    if (decoder.get() == NULL || err != OK) {
+        ALOGW("Failed to instantiate decoder [%s]", componentName);
         return NULL;
     }
 
-    status_t err = decoder->start();
+    err = decoder->configure(videoFormat, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
     if (err != OK) {
-        ALOGW("OMXCodec::start returned error %d (0x%08x)\n", err, err);
+        ALOGW("configure returned error %d (%s)", err, asString(err));
+        decoder->release();
         return NULL;
     }
 
-    // Read one output buffer, ignore format change notifications
-    // and spurious empty buffers.
+    err = decoder->start();
+    if (err != OK) {
+        ALOGW("start returned error %d (%s)", err, asString(err));
+        decoder->release();
+        return NULL;
+    }
 
     MediaSource::ReadOptions options;
     if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
         seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {
 
         ALOGE("Unknown seek mode: %d", seekMode);
+        decoder->release();
         return NULL;
     }
 
@@ -208,64 +200,155 @@
         options.setSeekTo(frameTimeUs, mode);
     }
 
-    MediaBuffer *buffer = NULL;
-    do {
-        if (buffer != NULL) {
-            buffer->release();
-            buffer = NULL;
-        }
-        err = decoder->read(&buffer, &options);
-        options.clearSeekTo();
-    } while (err == INFO_FORMAT_CHANGED
-             || (buffer != NULL && buffer->range_length() == 0));
-
+    err = source->start();
     if (err != OK) {
-        CHECK(buffer == NULL);
+        ALOGW("source failed to start: %d (%s)", err, asString(err));
+        decoder->release();
+        return NULL;
+    }
 
-        ALOGV("decoding frame failed.");
+    Vector<sp<ABuffer> > inputBuffers;
+    err = decoder->getInputBuffers(&inputBuffers);
+    if (err != OK) {
+        ALOGW("failed to get input buffers: %d (%s)", err, asString(err));
+        decoder->release();
+        return NULL;
+    }
+
+    Vector<sp<ABuffer> > outputBuffers;
+    err = decoder->getOutputBuffers(&outputBuffers);
+    if (err != OK) {
+        ALOGW("failed to get output buffers: %d (%s)", err, asString(err));
+        decoder->release();
+        return NULL;
+    }
+
+    sp<AMessage> outputFormat = NULL;
+    bool haveMoreInputs = true;
+    size_t index, offset, size;
+    int64_t timeUs;
+    size_t retriesLeft = kRetryCount;
+    bool done = false;
+
+    do {
+        size_t inputIndex = -1;
+        int64_t ptsUs = 0ll;
+        uint32_t flags = 0;
+        sp<ABuffer> codecBuffer = NULL;
+
+        while (haveMoreInputs) {
+            err = decoder->dequeueInputBuffer(&inputIndex, kBufferTimeOutUs);
+            if (err != OK) {
+                ALOGW("Timed out waiting for input");
+                if (retriesLeft) {
+                    err = OK;
+                }
+                break;
+            }
+            codecBuffer = inputBuffers[inputIndex];
+
+            MediaBuffer *mediaBuffer = NULL;
+
+            err = source->read(&mediaBuffer, &options);
+            options.clearSeekTo();
+            if (err != OK) {
+                ALOGW("Input Error or EOS");
+                haveMoreInputs = false;
+                break;
+            }
+
+            if (mediaBuffer->range_length() > codecBuffer->capacity()) {
+                ALOGE("buffer size (%zu) too large for codec input size (%zu)",
+                        mediaBuffer->range_length(), codecBuffer->capacity());
+                err = BAD_VALUE;
+            } else {
+                codecBuffer->setRange(0, mediaBuffer->range_length());
+
+                CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &ptsUs));
+                memcpy(codecBuffer->data(),
+                        (const uint8_t*)mediaBuffer->data() + mediaBuffer->range_offset(),
+                        mediaBuffer->range_length());
+            }
+
+            mediaBuffer->release();
+            break;
+        }
+
+        if (err == OK && inputIndex < inputBuffers.size()) {
+            ALOGV("QueueInput: size=%zu ts=%" PRId64 " us flags=%x",
+                    codecBuffer->size(), ptsUs, flags);
+            err = decoder->queueInputBuffer(
+                    inputIndex,
+                    codecBuffer->offset(),
+                    codecBuffer->size(),
+                    ptsUs,
+                    flags);
+
+            // we don't expect an output from codec config buffer
+            if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG) {
+                continue;
+            }
+        }
+
+        while (err == OK) {
+            // wait for a decoded buffer
+            err = decoder->dequeueOutputBuffer(
+                    &index,
+                    &offset,
+                    &size,
+                    &timeUs,
+                    &flags,
+                    kBufferTimeOutUs);
+
+            if (err == INFO_FORMAT_CHANGED) {
+                ALOGV("Received format change");
+                err = decoder->getOutputFormat(&outputFormat);
+            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
+                ALOGV("Output buffers changed");
+                err = decoder->getOutputBuffers(&outputBuffers);
+            } else {
+                if (err == -EAGAIN /* INFO_TRY_AGAIN_LATER */ && --retriesLeft > 0) {
+                    ALOGV("Timed-out waiting for output.. retries left = %zu", retriesLeft);
+                    err = OK;
+                } else if (err == OK) {
+                    ALOGV("Received an output buffer");
+                    done = true;
+                } else {
+                    ALOGW("Received error %d (%s) instead of output", err, asString(err));
+                    done = true;
+                }
+                break;
+            }
+        }
+    } while (err == OK && !done);
+
+    if (err != OK || size <= 0 || outputFormat == NULL) {
+        ALOGE("Failed to decode thumbnail frame");
+        source->stop();
         decoder->stop();
-
+        decoder->release();
         return NULL;
     }
 
     ALOGV("successfully decoded video frame.");
+    sp<ABuffer> videoFrameBuffer = outputBuffers.itemAt(index);
 
-    int32_t unreadable;
-    if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)
-            && unreadable != 0) {
-        ALOGV("video frame is unreadable, decoder does not give us access "
-             "to the video data.");
-
-        buffer->release();
-        buffer = NULL;
-
-        decoder->stop();
-
-        return NULL;
-    }
-
-    int64_t timeUs;
-    CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
     if (thumbNailTime >= 0) {
         if (timeUs != thumbNailTime) {
-            const char *mime;
-            CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
+            AString mime;
+            CHECK(outputFormat->findString("mime", &mime));
 
-            ALOGV("thumbNailTime = %" PRId64 " us, timeUs = %" PRId64 " us, mime = %s",
-                 thumbNailTime, timeUs, mime);
+            ALOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s",
+                    (long long)thumbNailTime, (long long)timeUs, mime.c_str());
         }
     }
 
-    sp<MetaData> meta = decoder->getFormat();
-
     int32_t width, height;
-    CHECK(meta->findInt32(kKeyWidth, &width));
-    CHECK(meta->findInt32(kKeyHeight, &height));
+    CHECK(outputFormat->findInt32("width", &width));
+    CHECK(outputFormat->findInt32("height", &height));
 
     int32_t crop_left, crop_top, crop_right, crop_bottom;
-    if (!meta->findRect(
-                kKeyCropRect,
-                &crop_left, &crop_top, &crop_right, &crop_bottom)) {
+    if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
         crop_left = crop_top = 0;
         crop_right = width - 1;
         crop_bottom = height - 1;
@@ -285,23 +368,21 @@
     frame->mData = new uint8_t[frame->mSize];
     frame->mRotationAngle = rotationAngle;
 
-    int32_t displayWidth, displayHeight;
-    if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
-        frame->mDisplayWidth = displayWidth;
-    }
-    if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
-        frame->mDisplayHeight = displayHeight;
+    int32_t sarWidth, sarHeight;
+    if (trackMeta->findInt32(kKeySARWidth, &sarWidth)
+            && trackMeta->findInt32(kKeySARHeight, &sarHeight)
+            && sarHeight != 0) {
+        frame->mDisplayWidth = (frame->mDisplayWidth * sarWidth) / sarHeight;
     }
 
     int32_t srcFormat;
-    CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
+    CHECK(outputFormat->findInt32("color-format", &srcFormat));
 
-    ColorConverter converter(
-            (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
+    ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
 
     if (converter.isValid()) {
         err = converter.convert(
-                (const uint8_t *)buffer->data() + buffer->range_offset(),
+                (const uint8_t *)videoFrameBuffer->data(),
                 width, height,
                 crop_left, crop_top, crop_right, crop_bottom,
                 frame->mData,
@@ -309,17 +390,16 @@
                 frame->mHeight,
                 0, 0, frame->mWidth - 1, frame->mHeight - 1);
     } else {
-        ALOGE("Unable to instantiate color conversion from format 0x%08x to "
-              "RGB565",
-              srcFormat);
+        ALOGE("Unable to convert from format 0x%08x to RGB565", srcFormat);
 
         err = ERROR_UNSUPPORTED;
     }
 
-    buffer->release();
-    buffer = NULL;
-
+    videoFrameBuffer.clear();
+    source->stop();
+    decoder->releaseOutputBuffer(index);
     decoder->stop();
+    decoder->release();
 
     if (err != OK) {
         ALOGE("Colorconverter failed to convert frame.");
@@ -390,20 +470,29 @@
         mAlbumArt = MediaAlbumArt::fromData(dataSize, data);
     }
 
-    VideoFrame *frame =
-        extractVideoFrameWithCodecFlags(
-                &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs,
-                timeUs, option);
+    const char *mime;
+    CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
 
-    if (frame == NULL) {
-        ALOGV("Software decoder failed to extract thumbnail, "
-             "trying hardware decoder.");
+    Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs;
+    OMXCodec::findMatchingCodecs(
+            mime,
+            false, /* encoder */
+            NULL, /* matchComponentName */
+            OMXCodec::kPreferSoftwareCodecs,
+            &matchingCodecs);
 
-        frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0,
-                        timeUs, option);
+    for (size_t i = 0; i < matchingCodecs.size(); ++i) {
+        const char *componentName = matchingCodecs[i].mName.string();
+        VideoFrame *frame =
+            extractVideoFrame(componentName, trackMeta, source, timeUs, option);
+
+        if (frame != NULL) {
+            return frame;
+        }
+        ALOGV("%s failed to extract thumbnail, trying next decoder.", componentName);
     }
 
-    return frame;
+    return NULL;
 }
 
 MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
diff --git a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
index 8ac337a..f3af777 100755
--- a/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
+++ b/media/libstagefright/codecs/avcdec/SoftAVCDec.cpp
@@ -787,7 +787,7 @@
             }
 
             if (s_dec_op.u4_output_present) {
-                outHeader->nFilledLen = (mWidth * mHeight * 3) / 2;
+                outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
 
                 outHeader->nTimeStamp = mTimeStamps[s_dec_op.u4_ts];
                 mTimeStampsValid[s_dec_op.u4_ts] = false;
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
index a35909e..e161fb8 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -146,8 +146,8 @@
         }
 
         outHeader->nOffset = 0;
-        outHeader->nFilledLen = (width * height * 3) / 2;
         outHeader->nFlags = 0;
+        outHeader->nFilledLen = (outputBufferWidth() * outputBufferHeight() * 3) / 2;
         outHeader->nTimeStamp = *(OMX_TICKS *)mImg->user_priv;
 
         uint8_t *dst = outHeader->pBuffer;
diff --git a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
index 7ff9ee7..cb10bce 100644
--- a/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
+++ b/media/libstagefright/codecs/opus/dec/SoftOpus.cpp
@@ -34,6 +34,12 @@
 
 static const int kRate = 48000;
 
+// Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
+// mappings for up to 8 channels. This information is part of the Vorbis I
+// Specification:
+// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
+static const int kMaxChannels = 8;
+
 template<class T>
 static void InitOMXParams(T *params) {
     params->nSize = sizeof(T);
@@ -101,7 +107,7 @@
     def.eDir = OMX_DirOutput;
     def.nBufferCountMin = kNumBuffers;
     def.nBufferCountActual = def.nBufferCountMin;
-    def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t);
+    def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t) * kMaxChannels;
     def.bEnabled = OMX_TRUE;
     def.bPopulated = OMX_FALSE;
     def.eDomain = OMX_PortDomainAudio;
@@ -225,12 +231,6 @@
     return val;
 }
 
-// Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
-// mappings for up to 8 channels. This information is part of the Vorbis I
-// Specification:
-// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
-static const int kMaxChannels = 8;
-
 // Maximum packet size used in Xiph's opusdec.
 static const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
 
diff --git a/media/libstagefright/foundation/AHierarchicalStateMachine.cpp b/media/libstagefright/foundation/AHierarchicalStateMachine.cpp
index 5f7c70d..b837f66 100644
--- a/media/libstagefright/foundation/AHierarchicalStateMachine.cpp
+++ b/media/libstagefright/foundation/AHierarchicalStateMachine.cpp
@@ -109,7 +109,8 @@
         A.editItemAt(i)->stateExited();
     }
 
-    for (size_t i = B.size(); i-- > 0;) {
+    for (size_t i = B.size(); i > 0;) {
+        i--;
         B.editItemAt(i)->stateEntered();
     }
 }
diff --git a/media/libstagefright/foundation/ALooperRoster.cpp b/media/libstagefright/foundation/ALooperRoster.cpp
index 473ce1b..9ed53e7 100644
--- a/media/libstagefright/foundation/ALooperRoster.cpp
+++ b/media/libstagefright/foundation/ALooperRoster.cpp
@@ -79,7 +79,8 @@
     {
         Mutex::Autolock autoLock(mLock);
 
-        for (size_t i = mHandlers.size(); i-- > 0;) {
+        for (size_t i = mHandlers.size(); i > 0;) {
+            i--;
             const HandlerInfo &info = mHandlers.valueAt(i);
 
             sp<ALooper> looper = info.mLooper.promote();
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index db429f6..e3c3e80 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -694,7 +694,8 @@
             status_t err = flush(event);
 
             if (err != OK) {
-                return err;
+                ALOGW("Error (%08x) happened while flushing; we simply discard "
+                      "the PES packet and continue.", err);
             }
         }
 
@@ -996,10 +997,6 @@
                 return ERROR_MALFORMED;
             }
 
-            if (br->numBitsLeft() < dataLength * 8) {
-                return ERROR_MALFORMED;
-            }
-
             onPayloadData(
                     PTS_DTS_flags, PTS, DTS, br->data(), dataLength, event);
 
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 692667f..6ee1a77 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -1423,7 +1423,9 @@
         }
     }
 
-    mObserver->onMessages(messages);
+    if (!messages.empty()) {
+        mObserver->onMessages(messages);
+    }
 }
 
 void OMXNodeInstance::onObserverDied(OMXMaster *master) {
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index 78dfbb1..b6de0d9 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -11,8 +11,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	main_mediaserver.cpp \
-	icuutils.cpp
+	main_mediaserver.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libaudioflinger \
@@ -33,6 +32,7 @@
 	libradioservice
 
 LOCAL_STATIC_LIBRARIES := \
+        libicuandroid_utils \
         libregistermsext
 
 LOCAL_C_INCLUDES := \
diff --git a/media/mediaserver/IcuUtils.h b/media/mediaserver/IcuUtils.h
deleted file mode 100644
index 52fab6d..0000000
--- a/media/mediaserver/IcuUtils.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ICU_UTILS_H
-#define ICU_UTILS_H
-
-// Initializes ICU or dies trying. This must be called when the process
-// is single threaded.
-void initializeIcuOrDie();
-
-#endif  // ICU_UTILS_H
-
diff --git a/media/mediaserver/icuutils.cpp b/media/mediaserver/icuutils.cpp
deleted file mode 100644
index 4015849..0000000
--- a/media/mediaserver/icuutils.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "IcuUtils.h"
-
-#include "unicode/putil.h"
-#include "unicode/uclean.h"
-#include "unicode/utypes.h"
-#include "utils/Log.h"
-
-#include <stdlib.h>
-
-void initializeIcuOrDie() {
-    const char* systemPathPrefix = getenv("ANDROID_ROOT");
-    LOG_ALWAYS_FATAL_IF(systemPathPrefix == NULL, "ANDROID_ROOT environment variable not set");
-
-    char buf[256];
-    const int num_written = snprintf(buf, sizeof(buf), "%s/usr/icu/", systemPathPrefix);
-    LOG_ALWAYS_FATAL_IF((num_written < 0 || static_cast<size_t>(num_written) >= sizeof(buf)),
-            "Unable to construct ICU path.");
-
-    u_setDataDirectory(buf);
-    UErrorCode status = U_ZERO_ERROR;
-
-    // u_setDataDirectory doesn't try doing anything with the directory we gave
-    // it, so we'll have to call u_init to make sure it was successful.
-    u_init(&status);
-    LOG_ALWAYS_FATAL_IF(!U_SUCCESS(status), "Failed to initialize ICU %s", u_errorName(status));
-}
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 27a40b2..4a485ed 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -125,7 +125,7 @@
             prctl(PR_SET_PDEATHSIG, SIGKILL);   // if parent media.log dies before me, kill me also
             setpgid(0, 0);                      // but if I die first, don't kill my parent
         }
-        initializeIcuOrDie();
+        InitializeIcuOrDie();
         sp<ProcessState> proc(ProcessState::self());
         sp<IServiceManager> sm = defaultServiceManager();
         ALOGI("ServiceManager: %p", sm.get());
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index ad445a5..489f2d4 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4459,6 +4459,17 @@
     }
 }
 
+void AudioFlinger::DirectOutputThread::onAddNewTrack_l()
+{
+    sp<Track> previousTrack = mPreviousTrack.promote();
+    sp<Track> latestTrack = mLatestActiveTrack.promote();
+
+    if (previousTrack != 0 && latestTrack != 0 &&
+        (previousTrack->sessionId() != latestTrack->sessionId())) {
+        mFlushPending = true;
+    }
+    PlaybackThread::onAddNewTrack_l();
+}
 
 AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prepareTracks_l(
     Vector< sp<Track> > *tracksToRemove
@@ -4468,7 +4479,6 @@
     mixer_state mixerStatus = MIXER_IDLE;
     bool doHwPause = false;
     bool doHwResume = false;
-    bool flushPending = false;
 
     // find out which tracks need to be processed
     for (size_t i = 0; i < count; i++) {
@@ -4478,6 +4488,12 @@
             continue;
         }
 
+        if (t->isInvalid()) {
+            ALOGW("An invalidated track shouldn't be in active list");
+            tracksToRemove->add(t);
+            continue;
+        }
+
         Track* const track = t.get();
         audio_track_cblk_t* cblk = track->cblk();
         // Only consider last track started for volume and mixer state control.
@@ -4497,7 +4513,7 @@
         } else if (track->isFlushPending()) {
             track->flushAck();
             if (last) {
-                flushPending = true;
+                mFlushPending = true;
             }
         } else if (track->isResumePending()) {
             track->resumeAck();
@@ -4538,6 +4554,21 @@
             // compute volume for this track
             processVolume_l(track, last);
             if (last) {
+                sp<Track> previousTrack = mPreviousTrack.promote();
+                if (previousTrack != 0) {
+                    if (track != previousTrack.get()) {
+                        // Flush any data still being written from last track
+                        mBytesRemaining = 0;
+                        // flush data already sent if changing audio session as audio
+                        // comes from a different source. Also invalidate previous track to force a
+                        // seek when resuming.
+                        if (previousTrack->sessionId() != track->sessionId()) {
+                            previousTrack->invalidate();
+                        }
+                    }
+                }
+                mPreviousTrack = track;
+
                 // reset retry count
                 track->mRetryCount = kMaxTrackRetriesDirect;
                 mActiveTrack = t;
@@ -4604,11 +4635,11 @@
     }
 
     // if an active track did not command a flush, check for pending flush on stopped tracks
-    if (!flushPending) {
+    if (!mFlushPending) {
         for (size_t i = 0; i < mTracks.size(); i++) {
             if (mTracks[i]->isFlushPending()) {
                 mTracks[i]->flushAck();
-                flushPending = true;
+                mFlushPending = true;
             }
         }
     }
@@ -4618,10 +4649,10 @@
     // before flush and then resume HW. This can happen in case of pause/flush/resume
     // if resume is received before pause is executed.
     if (mHwSupportsPause && !mStandby &&
-            (doHwPause || (flushPending && !mHwPaused && (count != 0)))) {
+            (doHwPause || (mFlushPending && !mHwPaused && (count != 0)))) {
         mOutput->stream->pause(mOutput->stream);
     }
-    if (flushPending) {
+    if (mFlushPending) {
         flushHw_l();
     }
     if (mHwSupportsPause && !mStandby && doHwResume) {
@@ -4680,14 +4711,13 @@
 {
     {
         Mutex::Autolock _l(mLock);
-        bool flushPending = false;
         for (size_t i = 0; i < mTracks.size(); i++) {
             if (mTracks[i]->isFlushPending()) {
                 mTracks[i]->flushAck();
-                flushPending = true;
+                mFlushPending = true;
             }
         }
-        if (flushPending) {
+        if (mFlushPending) {
             flushHw_l();
         }
     }
@@ -4825,6 +4855,7 @@
 {
     mOutput->flush();
     mHwPaused = false;
+    mFlushPending = false;
 }
 
 // ----------------------------------------------------------------------------
@@ -5146,7 +5177,6 @@
     }
     if (mFlushPending) {
         flushHw_l();
-        mFlushPending = false;
     }
     if (!mStandby && doHwResume) {
         mOutput->stream->resume(mOutput->stream);
@@ -5194,18 +5224,6 @@
     }
 }
 
-void AudioFlinger::OffloadThread::onAddNewTrack_l()
-{
-    sp<Track> previousTrack = mPreviousTrack.promote();
-    sp<Track> latestTrack = mLatestActiveTrack.promote();
-
-    if (previousTrack != 0 && latestTrack != 0 &&
-        (previousTrack->sessionId() != latestTrack->sessionId())) {
-        mFlushPending = true;
-    }
-    PlaybackThread::onAddNewTrack_l();
-}
-
 // ----------------------------------------------------------------------------
 
 AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 7b4fb14..4ebe615 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -941,6 +941,8 @@
     virtual     void        threadLoop_exit();
     virtual     bool        shouldStandby_l();
 
+    virtual     void        onAddNewTrack_l();
+
     // volumes last sent to audio HAL with stream->set_volume()
     float mLeftVolFloat;
     float mRightVolFloat;
@@ -952,6 +954,9 @@
 
     // prepareTracks_l() tells threadLoop_mix() the name of the single active track
     sp<Track>               mActiveTrack;
+
+    wp<Track>               mPreviousTrack;         // used to detect track switch
+
 public:
     virtual     bool        hasFastMixer() const { return false; }
 };
@@ -971,12 +976,10 @@
 
     virtual     bool        waitingAsyncCallback();
     virtual     bool        waitingAsyncCallback_l();
-    virtual     void        onAddNewTrack_l();
 
 private:
     size_t      mPausedWriteLength;     // length in bytes of write interrupted by pause
     size_t      mPausedBytesRemaining;  // bytes still waiting in mixbuffer after resume
-    wp<Track>   mPreviousTrack;         // used to detect track switch
 };
 
 class AsyncCallbackThread : public Thread {
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 1b03060..f7da209 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1951,7 +1951,9 @@
                           ((buffer == NULL) ? ALLOC_LOCAL : ALLOC_NONE),
                   type),
         mOverflow(false),
-        mFramesToDrop(0)
+        mFramesToDrop(0),
+        mResamplerBufferProvider(NULL), // initialize in case of early constructor exit
+        mRecordBufferConverter(NULL)
 {
     if (mCblk == NULL) {
         return;
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index bded309..deebc23 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -789,6 +789,11 @@
     // only allow deep buffering for music stream type
     if (stream != AUDIO_STREAM_MUSIC) {
         flags = (audio_output_flags_t)(flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
+    } else if (/* stream == AUDIO_STREAM_MUSIC && */
+            flags == AUDIO_OUTPUT_FLAG_NONE &&
+            property_get_bool("audio.deep_buffer.media", false /* default_value */)) {
+        // use DEEP_BUFFER as default output for music stream type
+        flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
     }
     if (stream == AUDIO_STREAM_TTS) {
         flags = AUDIO_OUTPUT_FLAG_TTS;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 3bda70c..0f485ca 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -27,8 +27,7 @@
 
 namespace android {
 
-struct CameraDeviceClientBase :
-        public CameraService::BasicClient, public BnCameraDeviceUser
+struct CameraDeviceClientBase : public CameraService::BasicClient, public BnCameraDeviceUser
 {
     typedef ICameraDeviceCallbacks TCamCallbacks;
 
@@ -167,7 +166,7 @@
 
     // Find the closest dimensions for a given format in available stream configurations with
     // a width <= ROUNDING_WIDTH_CAP
-    static const int32_t ROUNDING_WIDTH_CAP = 1080;
+    static const int32_t ROUNDING_WIDTH_CAP = 1920;
     static bool roundBufferDimensionNearest(int32_t width, int32_t height, int32_t format,
             android_dataspace dataSpace, const CameraMetadata& info,
             /*out*/int32_t* outWidth, /*out*/int32_t* outHeight);