Merge "audio policy: add option to use new policy manager"
diff --git a/camera/CameraParameters.cpp b/camera/CameraParameters.cpp
index af091f4..99e5df4 100644
--- a/camera/CameraParameters.cpp
+++ b/camera/CameraParameters.cpp
@@ -16,6 +16,7 @@
 */
 
 #define LOG_TAG "CameraParams"
+// #define LOG_NDEBUG 0
 #include <utils/Log.h>
 
 #include <string.h>
@@ -198,6 +199,8 @@
             flattened += ";";
     }
 
+    ALOGV("%s: Flattened params = %s", __FUNCTION__, flattened.string());
+
     return flattened;
 }
 
@@ -247,7 +250,9 @@
         return;
     }
 
-    mMap.replaceValueFor(String8(key), String8(value));
+    // Replacing a value updates the key's order to be the new largest order
+    ssize_t res = mMap.replaceValueFor(String8(key), String8(value));
+    LOG_ALWAYS_FATAL_IF(res < 0, "replaceValueFor(%s,%s) failed", key, value);
 }
 
 void CameraParameters::set(const char *key, int value)
@@ -266,10 +271,12 @@
 
 const char *CameraParameters::get(const char *key) const
 {
-    String8 v = mMap.valueFor(String8(key));
-    if (v.length() == 0)
-        return 0;
-    return v.string();
+    ssize_t idx = mMap.indexOfKey(String8(key));
+    if (idx < 0) {
+        return NULL;
+    } else {
+        return mMap.valueAt(idx).string();
+    }
 }
 
 int CameraParameters::getInt(const char *key) const
@@ -287,6 +294,36 @@
     return strtof(v, 0);
 }
 
+status_t CameraParameters::compareSetOrder(const char *key1, const char *key2,
+        int *order) const {
+    if (key1 == NULL) {
+        ALOGE("%s: key1 must not be NULL", __FUNCTION__);
+        return BAD_VALUE;
+    } else if (key2 == NULL) {
+        ALOGE("%s: key2 must not be NULL", __FUNCTION__);
+        return BAD_VALUE;
+    } else if (order == NULL) {
+        ALOGE("%s: order must not be NULL", __FUNCTION__);
+        return BAD_VALUE;
+    }
+
+    ssize_t index1 = mMap.indexOfKey(String8(key1));
+    ssize_t index2 = mMap.indexOfKey(String8(key2));
+    if (index1 < 0) {
+        ALOGW("%s: Key1 (%s) was not set", __FUNCTION__, key1);
+        return NAME_NOT_FOUND;
+    } else if (index2 < 0) {
+        ALOGW("%s: Key2 (%s) was not set", __FUNCTION__, key2);
+        return NAME_NOT_FOUND;
+    }
+
+    *order = (index1 == index2) ? 0  :
+             (index1 < index2)  ? -1 :
+             1;
+
+    return OK;
+}
+
 void CameraParameters::remove(const char *key)
 {
     mMap.removeItem(String8(key));
@@ -412,6 +449,12 @@
     parse_pair(p, min_fps, max_fps, ',');
 }
 
+void CameraParameters::setPreviewFpsRange(int min_fps, int max_fps)
+{
+    String8 str = String8::format("%d,%d", min_fps, max_fps);
+    set(KEY_PREVIEW_FPS_RANGE, str.string());
+}
+
 void CameraParameters::setPreviewFormat(const char *format)
 {
     set(KEY_PREVIEW_FORMAT, format);
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index ba5a48c..48f8e8e 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -249,11 +249,14 @@
     sp <IProCameraUser> c = mCamera;
     if (c == 0) return NO_INIT;
 
-    sp<BufferQueue> bq = new BufferQueue();
-    sp<CpuConsumer> cc = new CpuConsumer(bq, heapCount/*, synchronousMode*/);
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    sp<CpuConsumer> cc = new CpuConsumer(consumer, heapCount
+            /*, synchronousMode*/);
     cc->setName(String8("ProCamera::mCpuConsumer"));
 
-    sp<Surface> stc = new Surface(bq);
+    sp<Surface> stc = new Surface(producer);
 
     status_t s = createStream(width, height, format,
                               stc->getIGraphicBufferProducer(),
diff --git a/include/camera/CameraParameters.h b/include/camera/CameraParameters.h
index d521543..833ba76 100644
--- a/include/camera/CameraParameters.h
+++ b/include/camera/CameraParameters.h
@@ -18,6 +18,7 @@
 #define ANDROID_HARDWARE_CAMERA_PARAMETERS_H
 
 #include <utils/KeyedVector.h>
+#include <utils/Vector.h>
 #include <utils/String8.h>
 
 namespace android {
@@ -50,10 +51,26 @@
     void set(const char *key, const char *value);
     void set(const char *key, int value);
     void setFloat(const char *key, float value);
+    // Look up string value by key.
+    // -- The string remains valid until the next set/remove of the same key,
+    //    or until the map gets cleared.
     const char *get(const char *key) const;
     int getInt(const char *key) const;
     float getFloat(const char *key) const;
 
+    // Compare the order that key1 was set vs the order that key2 was set.
+    //
+    // Sets the order parameter to an integer less than, equal to, or greater
+    // than zero if key1's set order was respectively, to be less than, to
+    // match, or to be greater than key2's set order.
+    //
+    // Error codes:
+    //  * NAME_NOT_FOUND - if either key has not been set previously
+    //  * BAD_VALUE - if any of the parameters are NULL
+    status_t compareSetOrder(const char *key1, const char *key2,
+            /*out*/
+            int *order) const;
+
     void remove(const char *key);
 
     void setPreviewSize(int width, int height);
@@ -91,6 +108,7 @@
     void setPreviewFrameRate(int fps);
     int getPreviewFrameRate() const;
     void getPreviewFpsRange(int *min_fps, int *max_fps) const;
+    void setPreviewFpsRange(int min_fps, int max_fps);
     void setPreviewFormat(const char *format);
     const char *getPreviewFormat() const;
     void setPictureSize(int width, int height);
@@ -675,7 +693,91 @@
     static const char LIGHTFX_HDR[];
 
 private:
-    DefaultKeyedVector<String8,String8>    mMap;
+
+    // Quick and dirty map that maintains insertion order
+    template <typename KeyT, typename ValueT>
+    struct OrderedKeyedVector {
+
+        ssize_t add(const KeyT& key, const ValueT& value) {
+            return mList.add(Pair(key, value));
+        }
+
+        size_t size() const {
+            return mList.size();
+        }
+
+        const KeyT& keyAt(size_t idx) const {
+            return mList[idx].mKey;
+        }
+
+        const ValueT& valueAt(size_t idx) const {
+            return mList[idx].mValue;
+        }
+
+        const ValueT& valueFor(const KeyT& key) const {
+            ssize_t i = indexOfKey(key);
+            LOG_ALWAYS_FATAL_IF(i<0, "%s: key not found", __PRETTY_FUNCTION__);
+
+            return valueAt(i);
+        }
+
+        ssize_t indexOfKey(const KeyT& key) const {
+                size_t vectorIdx = 0;
+                for (; vectorIdx < mList.size(); ++vectorIdx) {
+                    if (mList[vectorIdx].mKey == key) {
+                        return (ssize_t) vectorIdx;
+                    }
+                }
+
+                return NAME_NOT_FOUND;
+        }
+
+        ssize_t removeItem(const KeyT& key) {
+            size_t vectorIdx = (size_t) indexOfKey(key);
+
+            if (vectorIdx < 0) {
+                return vectorIdx;
+            }
+
+            return mList.removeAt(vectorIdx);
+        }
+
+        void clear() {
+            mList.clear();
+        }
+
+        // Same as removing and re-adding. The key's index changes to max.
+        ssize_t replaceValueFor(const KeyT& key, const ValueT& value) {
+            removeItem(key);
+            return add(key, value);
+        }
+
+    private:
+
+        struct Pair {
+            Pair() : mKey(), mValue() {}
+            Pair(const KeyT& key, const ValueT& value) :
+                    mKey(key),
+                    mValue(value) {}
+            KeyT   mKey;
+            ValueT mValue;
+        };
+
+        Vector<Pair> mList;
+    };
+
+    /**
+     * Order matters: Keys that are set() later are stored later in the map.
+     *
+     * If two keys have meaning that conflict, then the later-set key
+     * wins.
+     *
+     * For example, preview FPS and preview FPS range conflict since only
+     * we only want to use the FPS range if that's the last thing that was set.
+     * So in that case, only use preview FPS range if it was set later than
+     * the preview FPS.
+     */
+    OrderedKeyedVector<String8,String8>    mMap;
 };
 
 }; // namespace android
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index f8e4e3b..3ca3095 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -223,6 +223,7 @@
             status_t        getDuration(int *msec);
             status_t        reset();
             status_t        setAudioStreamType(audio_stream_type_t type);
+            status_t        getAudioStreamType(audio_stream_type_t *type);
             status_t        setLooping(int loop);
             bool            isLooping();
             status_t        setVolume(float leftVolume, float rightVolume);
diff --git a/include/media/stagefright/MediaCodecList.h b/include/media/stagefright/MediaCodecList.h
index 590623b..01a5daf 100644
--- a/include/media/stagefright/MediaCodecList.h
+++ b/include/media/stagefright/MediaCodecList.h
@@ -60,6 +60,7 @@
         SECTION_DECODER,
         SECTION_ENCODERS,
         SECTION_ENCODER,
+        SECTION_INCLUDE,
     };
 
     struct CodecInfo {
@@ -73,7 +74,9 @@
 
     status_t mInitCheck;
     Section mCurrentSection;
+    Vector<Section> mPastSections;
     int32_t mDepth;
+    AString mHrefBase;
 
     Vector<CodecInfo> mCodecInfos;
     KeyedVector<AString, size_t> mCodecQuirks;
@@ -83,7 +86,8 @@
     ~MediaCodecList();
 
     status_t initCheck() const;
-    void parseXMLFile(FILE *file);
+    void parseXMLFile(const char *path);
+    void parseTopLevelXMLFile(const char *path);
 
     static void StartElementHandlerWrapper(
             void *me, const char *name, const char **attrs);
@@ -93,6 +97,7 @@
     void startElementHandler(const char *name, const char **attrs);
     void endElementHandler(const char *name);
 
+    status_t includeXMLFile(const char **attrs);
     status_t addMediaCodecFromAttributes(bool encoder, const char **attrs);
     void addMediaCodec(bool encoder, const char *name, const char *type = NULL);
 
diff --git a/libvideoeditor/lvpp/Android.mk b/libvideoeditor/lvpp/Android.mk
index 77a21ac..8318d28 100755
--- a/libvideoeditor/lvpp/Android.mk
+++ b/libvideoeditor/lvpp/Android.mk
@@ -46,7 +46,7 @@
 
 
 LOCAL_SHARED_LIBRARIES :=     \
-    libaudioflinger           \
+    libaudioresampler         \
     libaudioutils             \
     libbinder                 \
     libcutils                 \
@@ -80,7 +80,6 @@
     $(TOP)/frameworks/av/services/audioflinger \
     $(TOP)/frameworks/native/include/media/editor \
     $(TOP)/frameworks/native/include/media/openmax \
-    $(TOP)/frameworks/native/services/audioflinger
 
 
 LOCAL_SHARED_LIBRARIES += libdl
@@ -99,8 +98,6 @@
     -DUSE_STAGEFRIGHT_READERS \
     -DUSE_STAGEFRIGHT_3GPP_READER
 
-LOCAL_32_BIT_ONLY := true
-
 include $(BUILD_SHARED_LIBRARY)
 
 #include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/libvideoeditor/vss/src/Android.mk b/libvideoeditor/vss/src/Android.mk
index 8856c41..47627ec 100755
--- a/libvideoeditor/vss/src/Android.mk
+++ b/libvideoeditor/vss/src/Android.mk
@@ -53,7 +53,7 @@
 LOCAL_MODULE_TAGS := optional
 
 LOCAL_SHARED_LIBRARIES :=       \
-    libaudioflinger             \
+    libaudioresampler           \
     libaudioutils               \
     libbinder                   \
     libcutils                   \
@@ -81,7 +81,6 @@
     $(TOP)/frameworks/av/libvideoeditor/vss/stagefrightshells/inc \
     $(TOP)/frameworks/av/services/audioflinger \
     $(TOP)/frameworks/native/include/media/openmax \
-    $(TOP)/frameworks/native/services/audioflinger \
     $(TOP)/system/media/audio_effects/include \
     $(TOP)/system/media/audio_utils/include
 
@@ -96,6 +95,4 @@
     -DM4xVSS_RESERVED_MOOV_DISK_SPACEno \
     -DDECODE_GIF_ON_SAVING
 
-LOCAL_32_BIT_ONLY := true
-
 include $(BUILD_SHARED_LIBRARY)
diff --git a/libvideoeditor/vss/src/VideoEditorResampler.cpp b/libvideoeditor/vss/src/VideoEditorResampler.cpp
index 1129c3c..53537f0 100755
--- a/libvideoeditor/vss/src/VideoEditorResampler.cpp
+++ b/libvideoeditor/vss/src/VideoEditorResampler.cpp
@@ -17,7 +17,7 @@
 #define LOG_NDEBUG 1
 #include <audio_utils/primitives.h>
 #include <utils/Log.h>
-#include "AudioMixer.h"
+#include "AudioResampler.h"
 #include "VideoEditorResampler.h"
 
 namespace android {
diff --git a/libvideoeditor/vss/stagefrightshells/src/Android.mk b/libvideoeditor/vss/stagefrightshells/src/Android.mk
index a060c0d..9188942 100755
--- a/libvideoeditor/vss/stagefrightshells/src/Android.mk
+++ b/libvideoeditor/vss/stagefrightshells/src/Android.mk
@@ -64,6 +64,4 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_32_BIT_ONLY := true
-
 include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp
index eb091ac..5a3bf9d 100644
--- a/media/libmedia/CharacterEncodingDetector.cpp
+++ b/media/libmedia/CharacterEncodingDetector.cpp
@@ -90,6 +90,7 @@
         char buf[1024];
         buf[0] = 0;
         int idx;
+        bool allprintable = true;
         for (int i = 0; i < size; i++) {
             const char *name = mNames.getEntry(i);
             const char *value = mValues.getEntry(i);
@@ -103,18 +104,60 @@
                 strlcat(buf, value, sizeof(buf));
                 // separate tags by space so ICU's ngram detector can do its job
                 strlcat(buf, " ", sizeof(buf));
+                allprintable = false;
             }
         }
-        ucsdet_setText(csd, buf, strlen(buf), &status);
 
-        int32_t matches;
-        const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status);
-        const char *combinedenc = "???";
+        const char *combinedenc = "UTF-8";
+        if (allprintable) {
+            // since 'buf' is empty, ICU would return a UTF-8 matcher with low confidence, so
+            // no need to even call it
+            ALOGV("all tags are printable, assuming ascii (%d)", strlen(buf));
+        } else {
+            ucsdet_setText(csd, buf, strlen(buf), &status);
+            int32_t matches;
+            const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status);
+            bool goodmatch = true;
+            const UCharsetMatch* bestCombinedMatch = getPreferred(buf, strlen(buf),
+                    ucma, matches, &goodmatch);
 
-        const UCharsetMatch* bestCombinedMatch = getPreferred(buf, strlen(buf), ucma, matches);
+            if (!goodmatch && strlen(buf) < 20) {
+                ALOGV("not a good match, trying with more data");
+                // This string might be too short for ICU to do anything useful with.
+                // (real world example: "Björk" in ISO-8859-1 might be detected as GB18030, because
+                //  the ISO detector reports a confidence of 0, while the GB18030 detector reports
+                //  a confidence of 10 with no invalid characters)
+                // Append artist, album and title if they were previously omitted because they
+                // were printable ascii.
+                bool added = false;
+                for (int i = 0; i < size; i++) {
+                    const char *name = mNames.getEntry(i);
+                    const char *value = mValues.getEntry(i);
+                    if (isPrintableAscii(value, strlen(value)) && (
+                                !strcmp(name, "artist") ||
+                                !strcmp(name, "album") ||
+                                !strcmp(name, "title"))) {
+                        strlcat(buf, value, sizeof(buf));
+                        strlcat(buf, " ", sizeof(buf));
+                        added = true;
+                    }
+                }
+                if (added) {
+                    ucsdet_setText(csd, buf, strlen(buf), &status);
+                    ucma = ucsdet_detectAll(csd, &matches, &status);
+                    bestCombinedMatch = getPreferred(buf, strlen(buf),
+                            ucma, matches, &goodmatch);
+                    if (!goodmatch) {
+                        ALOGV("still not a good match after adding printable tags");
+                    }
+                } else {
+                    ALOGV("no printable tags to add");
+                }
+            }
 
-        if (bestCombinedMatch != NULL) {
-            combinedenc = ucsdet_getName(bestCombinedMatch, &status);
+            if (bestCombinedMatch != NULL) {
+                combinedenc = ucsdet_getName(bestCombinedMatch, &status);
+            }
         }
 
         for (int i = 0; i < size; i++) {
@@ -128,7 +171,7 @@
             int32_t inputLength = strlen(s);
             const char *enc;
 
-            if (!strcmp(name, "artist") ||
+            if (!allprintable && !strcmp(name, "artist") ||
                     !strcmp(name, "albumartist") ||
                     !strcmp(name, "composer") ||
                     !strcmp(name, "genre") ||
@@ -137,15 +180,20 @@
                 // use encoding determined from the combination of artist/album/title etc.
                 enc = combinedenc;
             } else {
-                ucsdet_setText(csd, s, inputLength, &status);
-                ucm = ucsdet_detect(csd, &status);
-                if (!ucm) {
-                    mValues.setEntry(i, "???");
-                    continue;
+                if (isPrintableAscii(s, inputLength)) {
+                    enc = "UTF-8";
+                    ALOGV("@@@@ %s is ascii", mNames.getEntry(i));
+                } else {
+                    ucsdet_setText(csd, s, inputLength, &status);
+                    ucm = ucsdet_detect(csd, &status);
+                    if (!ucm) {
+                        mValues.setEntry(i, "???");
+                        continue;
+                    }
+                    enc = ucsdet_getName(ucm, &status);
+                    ALOGV("@@@@ recognized charset: %s for %s confidence %d",
+                            enc, mNames.getEntry(i), ucsdet_getConfidence(ucm, &status));
                 }
-                enc = ucsdet_getName(ucm, &status);
-                ALOGV("@@@@ recognized charset: %s for %s confidence %d",
-                        enc, mNames.getEntry(i), ucsdet_getConfidence(ucm, &status));
             }
 
             if (strcmp(enc,"UTF-8") != 0) {
@@ -207,10 +255,15 @@
  *   algorithm and larger frequent character lists than ICU
  * - devalue encoding where the conversion contains unlikely characters (symbols, reserved, etc)
  * - pick the highest match
+ * - signal to the caller whether this match is considered good: confidence > 15, and confidence
+ *   delta with the next runner up > 15
  */
 const UCharsetMatch *CharacterEncodingDetector::getPreferred(
-        const char *input, size_t len, const UCharsetMatch** ucma, size_t nummatches) {
+        const char *input, size_t len,
+        const UCharsetMatch** ucma, size_t nummatches,
+        bool *goodmatch) {
 
+    *goodmatch = false;
     Vector<const UCharsetMatch*> matches;
     UErrorCode status = U_ZERO_ERROR;
 
@@ -227,6 +280,10 @@
         return NULL;
     }
     if (num == 1) {
+        int confidence = ucsdet_getConfidence(matches[0], &status);
+        if (confidence > 15) {
+            *goodmatch = true;
+        }
         return matches[0];
     }
 
@@ -326,15 +383,35 @@
     // find match with highest confidence after adjusting for unlikely characters
     int highest = newconfidence[0];
     size_t highestidx = 0;
+    int runnerup = -10000;
+    int runnerupidx = -10000;
     num = newconfidence.size();
     for (size_t i = 1; i < num; i++) {
         if (newconfidence[i] > highest) {
+            runnerup = highest;
+            runnerupidx = highestidx;
             highest = newconfidence[i];
             highestidx = i;
+        } else if (newconfidence[i] > runnerup){
+            runnerup = newconfidence[i];
+            runnerupidx = i;
         }
     }
     status = U_ZERO_ERROR;
-    ALOGV("selecting '%s' w/ %d confidence", ucsdet_getName(matches[highestidx], &status), highest);
+    ALOGV("selecting: '%s' w/ %d confidence",
+            ucsdet_getName(matches[highestidx], &status), highest);
+    if (runnerupidx < 0) {
+        ALOGV("no runner up");
+        if (highest > 15) {
+            *goodmatch = true;
+        }
+    } else {
+        ALOGV("runner up: '%s' w/ %d confidence",
+                ucsdet_getName(matches[runnerupidx], &status), runnerup);
+        if ((highest - runnerup) > 15) {
+            *goodmatch = true;
+        }
+    }
     return matches[highestidx];
 }
 
diff --git a/media/libmedia/CharacterEncodingDetector.h b/media/libmedia/CharacterEncodingDetector.h
index 3655a91..7b5ed86 100644
--- a/media/libmedia/CharacterEncodingDetector.h
+++ b/media/libmedia/CharacterEncodingDetector.h
@@ -41,7 +41,9 @@
 
     private:
         const UCharsetMatch *getPreferred(
-                const char *input, size_t len, const UCharsetMatch** ucma, size_t matches);
+                const char *input, size_t len,
+                const UCharsetMatch** ucma, size_t matches,
+                bool *goodmatch);
 
         bool isFrequent(const uint16_t *values, uint32_t c);
 
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index d94c7c5..0be01a9 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -531,6 +531,14 @@
     return OK;
 }
 
+status_t MediaPlayer::getAudioStreamType(audio_stream_type_t *type)
+{
+    ALOGV("getAudioStreamType");
+    Mutex::Autolock _l(mLock);
+    *type = mStreamType;
+    return OK;
+}
+
 status_t MediaPlayer::setLooping(int loop)
 {
     ALOGV("MediaPlayer::setLooping");
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index e9e96d1..9164e5c 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -644,8 +644,8 @@
 
     // FIXME: assume that surface is controlled by app (native window
     // returns the number for the case when surface is not controlled by app)
-    (*minUndequeuedBuffers)++;
-
+    // FIXME2: This means that minUndeqeueudBufs can be 1 larger than reported
+    // For now, try to allocate 1 more buffer, but don't fail if unsuccessful
 
     // Use conservative allocation while also trying to reduce starvation
     //
@@ -653,7 +653,8 @@
     //    minimum needed for the consumer to be able to work
     // 2. try to allocate two (2) additional buffers to reduce starvation from
     //    the consumer
-    for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) {
+    //    plus an extra buffer to account for incorrect minUndequeuedBufs
+    for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) {
         OMX_U32 newBufferCount =
             def.nBufferCountMin + *minUndequeuedBuffers + extraBuffers;
         def.nBufferCountActual = newBufferCount;
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index a9b0c73..714b5e0 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -118,8 +118,6 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_32_BIT_ONLY := true
-
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index 6248e90..8a451c8 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -48,22 +48,43 @@
 
 MediaCodecList::MediaCodecList()
     : mInitCheck(NO_INIT) {
-    FILE *file = fopen("/etc/media_codecs.xml", "r");
+    parseTopLevelXMLFile("/etc/media_codecs.xml");
+}
 
-    if (file == NULL) {
-        ALOGW("unable to open media codecs configuration xml file.");
+void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml) {
+    // get href_base
+    char *href_base_end = strrchr(codecs_xml, '/');
+    if (href_base_end != NULL) {
+        mHrefBase = AString(codecs_xml, href_base_end - codecs_xml + 1);
+    }
+
+    mInitCheck = OK;
+    mCurrentSection = SECTION_TOPLEVEL;
+    mDepth = 0;
+
+    parseXMLFile(codecs_xml);
+
+    if (mInitCheck != OK) {
+        mCodecInfos.clear();
+        mCodecQuirks.clear();
         return;
     }
 
-    parseXMLFile(file);
+    // These are currently still used by the video editing suite.
+    addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm");
+    addMediaCodec(
+            false /* encoder */, "OMX.google.raw.decoder", "audio/raw");
 
-    if (mInitCheck == OK) {
-        // These are currently still used by the video editing suite.
+    for (size_t i = mCodecInfos.size(); i-- > 0;) {
+        CodecInfo *info = &mCodecInfos.editItemAt(i);
 
-        addMediaCodec(true /* encoder */, "AACEncoder", "audio/mp4a-latm");
+        if (info->mTypes == 0) {
+            // No types supported by this component???
+            ALOGW("Component %s does not support any type of media?",
+                  info->mName.c_str());
 
-        addMediaCodec(
-                false /* encoder */, "OMX.google.raw.decoder", "audio/raw");
+            mCodecInfos.removeAt(i);
+        }
     }
 
 #if 0
@@ -84,9 +105,6 @@
         ALOGI("%s", line.c_str());
     }
 #endif
-
-    fclose(file);
-    file = NULL;
 }
 
 MediaCodecList::~MediaCodecList() {
@@ -96,10 +114,14 @@
     return mInitCheck;
 }
 
-void MediaCodecList::parseXMLFile(FILE *file) {
-    mInitCheck = OK;
-    mCurrentSection = SECTION_TOPLEVEL;
-    mDepth = 0;
+void MediaCodecList::parseXMLFile(const char *path) {
+    FILE *file = fopen(path, "r");
+
+    if (file == NULL) {
+        ALOGW("unable to open media codecs configuration xml file: %s", path);
+        mInitCheck = NAME_NOT_FOUND;
+        return;
+    }
 
     XML_Parser parser = ::XML_ParserCreate(NULL);
     CHECK(parser != NULL);
@@ -112,7 +134,7 @@
     while (mInitCheck == OK) {
         void *buff = ::XML_GetBuffer(parser, BUFF_SIZE);
         if (buff == NULL) {
-            ALOGE("failed to in call to XML_GetBuffer()");
+            ALOGE("failed in call to XML_GetBuffer()");
             mInitCheck = UNKNOWN_ERROR;
             break;
         }
@@ -124,8 +146,9 @@
             break;
         }
 
-        if (::XML_ParseBuffer(parser, bytes_read, bytes_read == 0)
-                != XML_STATUS_OK) {
+        XML_Status status = ::XML_ParseBuffer(parser, bytes_read, bytes_read == 0);
+        if (status != XML_STATUS_OK) {
+            ALOGE("malformed (%s)", ::XML_ErrorString(::XML_GetErrorCode(parser)));
             mInitCheck = ERROR_MALFORMED;
             break;
         }
@@ -137,25 +160,8 @@
 
     ::XML_ParserFree(parser);
 
-    if (mInitCheck == OK) {
-        for (size_t i = mCodecInfos.size(); i-- > 0;) {
-            CodecInfo *info = &mCodecInfos.editItemAt(i);
-
-            if (info->mTypes == 0) {
-                // No types supported by this component???
-
-                ALOGW("Component %s does not support any type of media?",
-                      info->mName.c_str());
-
-                mCodecInfos.removeAt(i);
-            }
-        }
-    }
-
-    if (mInitCheck != OK) {
-        mCodecInfos.clear();
-        mCodecQuirks.clear();
-    }
+    fclose(file);
+    file = NULL;
 }
 
 // static
@@ -169,12 +175,63 @@
     static_cast<MediaCodecList *>(me)->endElementHandler(name);
 }
 
+status_t MediaCodecList::includeXMLFile(const char **attrs) {
+    const char *href = NULL;
+    size_t i = 0;
+    while (attrs[i] != NULL) {
+        if (!strcmp(attrs[i], "href")) {
+            if (attrs[i + 1] == NULL) {
+                return -EINVAL;
+            }
+            href = attrs[i + 1];
+            ++i;
+        } else {
+            return -EINVAL;
+        }
+        ++i;
+    }
+
+    // For security reasons and for simplicity, file names can only contain
+    // [a-zA-Z0-9_.] and must start with  media_codecs_ and end with .xml
+    for (i = 0; href[i] != '\0'; i++) {
+        if (href[i] == '.' || href[i] == '_' ||
+                (href[i] >= '0' && href[i] <= '9') ||
+                (href[i] >= 'A' && href[i] <= 'Z') ||
+                (href[i] >= 'a' && href[i] <= 'z')) {
+            continue;
+        }
+        ALOGE("invalid include file name: %s", href);
+        return -EINVAL;
+    }
+
+    AString filename = href;
+    if (!filename.startsWith("media_codecs_") ||
+        !filename.endsWith(".xml")) {
+        ALOGE("invalid include file name: %s", href);
+        return -EINVAL;
+    }
+    filename.insert(mHrefBase, 0);
+
+    parseXMLFile(filename.c_str());
+    return mInitCheck;
+}
+
 void MediaCodecList::startElementHandler(
         const char *name, const char **attrs) {
     if (mInitCheck != OK) {
         return;
     }
 
+    if (!strcmp(name, "Include")) {
+        mInitCheck = includeXMLFile(attrs);
+        if (mInitCheck == OK) {
+            mPastSections.push(mCurrentSection);
+            mCurrentSection = SECTION_INCLUDE;
+        }
+        ++mDepth;
+        return;
+    }
+
     switch (mCurrentSection) {
         case SECTION_TOPLEVEL:
         {
@@ -264,6 +321,15 @@
             break;
         }
 
+        case SECTION_INCLUDE:
+        {
+            if (!strcmp(name, "Include") && mPastSections.size() > 0) {
+                mCurrentSection = mPastSections.top();
+                mPastSections.pop();
+            }
+            break;
+        }
+
         default:
             break;
     }
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 545ca9d..1cfe6c0 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1806,7 +1806,8 @@
     }
     // FIXME: assume that surface is controlled by app (native window
     // returns the number for the case when surface is not controlled by app)
-    minUndequeuedBufs++;
+    // FIXME2: This means that minUndeqeueudBufs can be 1 larger than reported
+    // For now, try to allocate 1 more buffer, but don't fail if unsuccessful
 
     // Use conservative allocation while also trying to reduce starvation
     //
@@ -1814,10 +1815,11 @@
     //    minimum needed for the consumer to be able to work
     // 2. try to allocate two (2) additional buffers to reduce starvation from
     //    the consumer
-    CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d",
+    //    plus an extra buffer to account for incorrect minUndequeuedBufs
+    CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d+1",
             def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs);
 
-    for (OMX_U32 extraBuffers = 2; /* condition inside loop */; extraBuffers--) {
+    for (OMX_U32 extraBuffers = 2 + 1; /* condition inside loop */; extraBuffers--) {
         OMX_U32 newBufferCount =
             def.nBufferCountMin + minUndequeuedBufs + extraBuffers;
         def.nBufferCountActual = newBufferCount;
@@ -1836,7 +1838,7 @@
             return err;
         }
     }
-    CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d",
+    CODEC_LOGI("OMX-buffers: min=%u actual=%u undeq=%d+1",
             def.nBufferCountMin, def.nBufferCountActual, minUndequeuedBufs);
 
     err = native_window_set_buffer_count(
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 04dc487..58ec3ba 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -117,7 +117,6 @@
 
   LOCAL_MODULE := libstagefright_soft_aacenc
   LOCAL_MODULE_TAGS := optional
-  LOCAL_32_BIT_ONLY := true
 
   include $(BUILD_SHARED_LIBRARY)
 
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
index c2e7b81..537ba42 100644
--- a/media/libstagefright/codecs/avc/enc/Android.mk
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -20,7 +20,6 @@
 
 
 LOCAL_MODULE := libstagefright_avcenc
-LOCAL_32_BIT_ONLY := true
 
 LOCAL_C_INCLUDES := \
     $(LOCAL_PATH)/src \
@@ -71,7 +70,6 @@
 
 LOCAL_MODULE := libstagefright_soft_h264enc
 LOCAL_MODULE_TAGS := optional
-LOCAL_32_BIT_ONLY := true
 
 LOCAL_CFLAGS += -Werror
 
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
index 40661e7..0c62ec0 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
@@ -247,7 +247,7 @@
 
             if (defParams->nPortIndex == 0) {
                 if (defParams->nBufferSize > kMaxInputBufferSize) {
-                    ALOGE("Input buffer size must be at most %zu bytes",
+                    ALOGE("Input buffer size must be at most %d bytes",
                         kMaxInputBufferSize);
                     return OMX_ErrorUnsupportedSetting;
                 }
@@ -354,12 +354,12 @@
             size_t bytes, unsigned samples,
             unsigned current_frame) {
     UNUSED_UNLESS_VERBOSE(current_frame);
-    ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%d, samples=%d, curr_frame=%d)",
+    ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%zu, samples=%u, curr_frame=%u)",
             bytes, samples, current_frame);
 
 #ifdef WRITE_FLAC_HEADER_IN_FIRST_BUFFER
     if (samples == 0) {
-        ALOGI(" saving %d bytes of header", bytes);
+        ALOGI(" saving %zu bytes of header", bytes);
         memcpy(mHeader + mHeaderOffset, buffer, bytes);
         mHeaderOffset += bytes;// will contain header size when finished receiving header
         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
@@ -370,7 +370,7 @@
     if ((samples == 0) || !mEncoderWriteData) {
         // called by the encoder because there's header data to save, but it's not the role
         // of this component (unless WRITE_FLAC_HEADER_IN_FIRST_BUFFER is defined)
-        ALOGV("ignoring %d bytes of header data (samples=%d)", bytes, samples);
+        ALOGV("ignoring %zu bytes of header data (samples=%d)", bytes, samples);
         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
     }
 
@@ -391,9 +391,9 @@
 #endif
 
     // write encoded data
-    ALOGV(" writing %d bytes of encoded data on output port", bytes);
+    ALOGV(" writing %zu bytes of encoded data on output port", bytes);
     if (bytes > outHeader->nAllocLen - outHeader->nOffset - outHeader->nFilledLen) {
-        ALOGE(" not enough space left to write encoded data, dropping %u bytes", bytes);
+        ALOGE(" not enough space left to write encoded data, dropping %zu bytes", bytes);
         // a fatal error would stop the encoding
         return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
     }
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index 2c73e57..ee8dcf2 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -33,6 +33,8 @@
 
 #include "SoftMPEG4Encoder.h"
 
+#include <inttypes.h>
+
 namespace android {
 
 template<class T>
@@ -725,7 +727,7 @@
             if (!PVEncodeVideoFrame(mHandle, &vin, &vout,
                     &modTimeMs, outPtr, &dataLength, &nLayer) ||
                 !PVGetHintTrack(mHandle, &hintTrack)) {
-                ALOGE("Failed to encode frame or get hink track at frame %lld",
+                ALOGE("Failed to encode frame or get hink track at frame %" PRId64,
                     mNumInputFrames);
                 mSignalledError = true;
                 notify(OMX_EventError, OMX_ErrorUndefined, 0, 0);
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index 5efe022..b3a6bcc 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -141,9 +141,9 @@
       mWidth(176),
       mHeight(144),
       mBitrate(192000),  // in bps
+      mFramerate(30 << 16), // in Q16 format
       mBitrateUpdated(false),
       mBitrateControlMode(VPX_VBR),  // variable bitrate
-      mFrameDurationUs(33333),  // Defaults to 30 fps
       mDCTPartitions(0),
       mErrorResilience(OMX_FALSE),
       mColorFormat(OMX_COLOR_FormatYUV420Planar),
@@ -180,9 +180,8 @@
     inputPort.format.video.nStride = inputPort.format.video.nFrameWidth;
     inputPort.format.video.nSliceHeight = inputPort.format.video.nFrameHeight;
     inputPort.format.video.nBitrate = 0;
-    // frameRate is reciprocal of frameDuration, which is
-    // in microseconds. It is also in Q16 format.
-    inputPort.format.video.xFramerate = (1000000/mFrameDurationUs) << 16;
+    // frameRate is in Q16 format.
+    inputPort.format.video.xFramerate = mFramerate;
     inputPort.format.video.bFlagErrorConcealment = OMX_FALSE;
     inputPort.nPortIndex = kInputPortIndex;
     inputPort.eDir = OMX_DirInput;
@@ -220,7 +219,7 @@
     outputPort.format.video.eCompressionFormat = OMX_VIDEO_CodingVP8;
     outputPort.format.video.eColorFormat = OMX_COLOR_FormatUnused;
     outputPort.format.video.pNativeWindow = NULL;
-    outputPort.nBufferSize = 256 * 1024;  // arbitrary
+    outputPort.nBufferSize = 1024 * 1024; // arbitrary
 
     addPort(outputPort);
 }
@@ -277,8 +276,39 @@
     mCodecConfiguration->g_timebase.num = 1;
     mCodecConfiguration->g_timebase.den = 1000000;
     // rc_target_bitrate is in kbps, mBitrate in bps
-    mCodecConfiguration->rc_target_bitrate = mBitrate/1000;
+    mCodecConfiguration->rc_target_bitrate = mBitrate / 1000;
     mCodecConfiguration->rc_end_usage = mBitrateControlMode;
+    // Disable frame drop - not allowed in MediaCodec now.
+    mCodecConfiguration->rc_dropframe_thresh = 0;
+    if (mBitrateControlMode == VPX_CBR) {
+        // Disable spatial resizing.
+        mCodecConfiguration->rc_resize_allowed = 0;
+        // Single-pass mode.
+        mCodecConfiguration->g_pass = VPX_RC_ONE_PASS;
+        // Minimum quantization level.
+        mCodecConfiguration->rc_min_quantizer = 2;
+        // Maximum quantization level.
+        mCodecConfiguration->rc_max_quantizer = 63;
+        // Maximum amount of bits that can be subtracted from the target
+        // bitrate - expressed as percentage of the target bitrate.
+        mCodecConfiguration->rc_undershoot_pct = 100;
+        // Maximum amount of bits that can be added to the target
+        // bitrate - expressed as percentage of the target bitrate.
+        mCodecConfiguration->rc_overshoot_pct = 15;
+        // Initial value of the buffer level in ms.
+        mCodecConfiguration->rc_buf_initial_sz = 500;
+        // Amount of data that the encoder should try to maintain in ms.
+        mCodecConfiguration->rc_buf_optimal_sz = 600;
+        // The amount of data that may be buffered by the decoding
+        // application in ms.
+        mCodecConfiguration->rc_buf_sz = 1000;
+        // Enable error resilience - needed for packet loss.
+        mCodecConfiguration->g_error_resilient = 1;
+        // Disable lagged encoding.
+        mCodecConfiguration->g_lag_in_frames = 0;
+        // Encoder determines optimal key frame placement automatically.
+        mCodecConfiguration->kf_mode = VPX_KF_AUTO;
+    }
 
     codec_return = vpx_codec_enc_init(mCodecContext,
                                       mCodecInterface,
@@ -298,6 +328,33 @@
         return UNKNOWN_ERROR;
     }
 
+    // Extra CBR settings
+    if (mBitrateControlMode == VPX_CBR) {
+        codec_return = vpx_codec_control(mCodecContext,
+                                         VP8E_SET_STATIC_THRESHOLD,
+                                         1);
+        if (codec_return == VPX_CODEC_OK) {
+            uint32_t rc_max_intra_target =
+                mCodecConfiguration->rc_buf_optimal_sz * (mFramerate >> 17) / 10;
+            // Don't go below 3 times per frame bandwidth.
+            if (rc_max_intra_target < 300) {
+                rc_max_intra_target = 300;
+            }
+            codec_return = vpx_codec_control(mCodecContext,
+                                             VP8E_SET_MAX_INTRA_BITRATE_PCT,
+                                             rc_max_intra_target);
+        }
+        if (codec_return == VPX_CODEC_OK) {
+            codec_return = vpx_codec_control(mCodecContext,
+                                             VP8E_SET_CPUUSED,
+                                             -8);
+        }
+        if (codec_return != VPX_CODEC_OK) {
+            ALOGE("Error setting cbr parameters for vpx encoder.");
+            return UNKNOWN_ERROR;
+        }
+    }
+
     if (mColorFormat == OMX_COLOR_FormatYUV420SemiPlanar || mInputDataIsMeta) {
         if (mConversionBuffer == NULL) {
             mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
@@ -361,9 +418,7 @@
                 }
 
                 formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
-                // Converting from microseconds
-                // Also converting to Q16 format
-                formatParams->xFramerate = (1000000/mFrameDurationUs) << 16;
+                formatParams->xFramerate = mFramerate;
                 return OMX_ErrorNone;
             } else if (formatParams->nPortIndex == kOutputPortIndex) {
                 formatParams->eCompressionFormat = OMX_VIDEO_CodingVP8;
@@ -660,9 +715,7 @@
         mHeight = port->format.video.nFrameHeight;
 
         // xFramerate comes in Q16 format, in frames per second unit
-        const uint32_t framerate = port->format.video.xFramerate >> 16;
-        // frame duration is in microseconds
-        mFrameDurationUs = (1000000/framerate);
+        mFramerate = port->format.video.xFramerate;
 
         if (port->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar ||
             port->format.video.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar ||
@@ -684,6 +737,13 @@
         return OMX_ErrorNone;
     } else if (port->nPortIndex == kOutputPortIndex) {
         mBitrate = port->format.video.nBitrate;
+        mWidth = port->format.video.nFrameWidth;
+        mHeight = port->format.video.nFrameHeight;
+
+        OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
+        def->format.video.nFrameWidth = mWidth;
+        def->format.video.nFrameHeight = mHeight;
+        def->format.video.nBitrate = mBitrate;
         return OMX_ErrorNone;
     } else {
         return OMX_ErrorBadPortIndex;
@@ -814,11 +874,12 @@
             mBitrateUpdated = false;
         }
 
+        uint32_t frameDuration = (uint32_t)(((uint64_t)1000000 << 16) / mFramerate);
         codec_return = vpx_codec_encode(
                 mCodecContext,
                 &raw_frame,
                 inputBufferHeader->nTimeStamp,  // in timebase units
-                mFrameDurationUs,  // frame duration in timebase units
+                frameDuration,  // frame duration in timebase units
                 flags,  // frame flags
                 VPX_DL_REALTIME);  // encoding deadline
         if (codec_return != VPX_CODEC_OK) {
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
index 076830f..1c983ab 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.h
@@ -130,16 +130,15 @@
     // Target bitrate set for the encoder, in bits per second.
     uint32_t mBitrate;
 
+    // Target framerate set for the encoder.
+    uint32_t mFramerate;
+
     // If a request for a change it bitrate has been received.
     bool mBitrateUpdated;
 
     // Bitrate control mode, either constant or variable
     vpx_rc_mode mBitrateControlMode;
 
-    // Frame duration is the reciprocal of framerate, denoted
-    // in microseconds
-    uint64_t mFrameDurationUs;
-
     // vp8 specific configuration parameter
     // that enables token partitioning of
     // the stream into substreams
diff --git a/media/libstagefright/foundation/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp
index 08c4a87..af5be70 100644
--- a/media/libstagefright/foundation/ANetworkSession.cpp
+++ b/media/libstagefright/foundation/ANetworkSession.cpp
@@ -579,7 +579,7 @@
 
         if (err == -EAGAIN) {
             if (!mOutFragments.empty()) {
-                ALOGI("%d datagrams remain queued.", mOutFragments.size());
+                ALOGI("%zu datagrams remain queued.", mOutFragments.size());
             }
             err = OK;
         }
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 19db6eb..fd42e77 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -43,6 +43,7 @@
 #include <utils/Mutex.h>
 
 #include <ctype.h>
+#include <inttypes.h>
 #include <openssl/aes.h>
 #include <openssl/md5.h>
 
@@ -168,7 +169,7 @@
         if (stream == STREAMTYPE_AUDIO || stream == STREAMTYPE_VIDEO) {
             int64_t timeUs;
             CHECK((*accessUnit)->meta()->findInt64("timeUs",  &timeUs));
-            ALOGV("[%s] read buffer at time %lld us", streamStr, timeUs);
+            ALOGV("[%s] read buffer at time %" PRId64 " us", streamStr, timeUs);
 
             mLastDequeuedTimeUs = timeUs;
             mRealTimeBaseUs = ALooper::GetNowUs() - timeUs;
@@ -622,7 +623,7 @@
  * - block_size == 0 means entire range
  *
  */
-status_t LiveSession::fetchFile(
+ssize_t LiveSession::fetchFile(
         const char *url, sp<ABuffer> *out,
         int64_t range_offset, int64_t range_length,
         uint32_t block_size, /* download block size */
@@ -673,8 +674,9 @@
         buffer->setRange(0, 0);
     }
 
+    ssize_t bytesRead = 0;
     // adjust range_length if only reading partial block
-    if (block_size > 0 && (range_length == -1 || buffer->size() + block_size < range_length)) {
+    if (block_size > 0 && (range_length == -1 || (int64_t)(buffer->size() + block_size) < range_length)) {
         range_length = buffer->size() + block_size;
     }
     for (;;) {
@@ -683,7 +685,7 @@
         if (bufferRemaining == 0 && getSizeErr != OK) {
             bufferRemaining = 32768;
 
-            ALOGV("increasing download buffer to %d bytes",
+            ALOGV("increasing download buffer to %zu bytes",
                  buffer->size() + bufferRemaining);
 
             sp<ABuffer> copy = new ABuffer(buffer->size() + bufferRemaining);
@@ -696,7 +698,7 @@
         size_t maxBytesToRead = bufferRemaining;
         if (range_length >= 0) {
             int64_t bytesLeftInRange = range_length - buffer->size();
-            if (bytesLeftInRange < maxBytesToRead) {
+            if (bytesLeftInRange < (int64_t)maxBytesToRead) {
                 maxBytesToRead = bytesLeftInRange;
 
                 if (bytesLeftInRange == 0) {
@@ -720,6 +722,7 @@
         }
 
         buffer->setRange(0, buffer->size() + (size_t)n);
+        bytesRead += n;
     }
 
     *out = buffer;
@@ -730,7 +733,7 @@
         }
     }
 
-    return OK;
+    return bytesRead;
 }
 
 sp<M3UParser> LiveSession::fetchPlaylist(
@@ -741,9 +744,9 @@
 
     sp<ABuffer> buffer;
     String8 actualUrl;
-    status_t err = fetchFile(url, &buffer, 0, -1, 0, NULL, &actualUrl);
+    ssize_t  err = fetchFile(url, &buffer, 0, -1, 0, NULL, &actualUrl);
 
-    if (err != OK) {
+    if (err <= 0) {
         return NULL;
     }
 
@@ -962,7 +965,7 @@
 
     mPrevBandwidthIndex = bandwidthIndex;
 
-    ALOGV("changeConfiguration => timeUs:%lld us, bwIndex:%d, pickTrack:%d",
+    ALOGV("changeConfiguration => timeUs:%" PRId64 " us, bwIndex:%zu, pickTrack:%d",
           timeUs, bandwidthIndex, pickTrack);
 
     if (pickTrack) {
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index f489ec4..d7ed56f 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -203,7 +203,7 @@
     //
     // For reused HTTP sources, the caller must download a file sequentially without
     // any overlaps or gaps to prevent reconnection.
-    status_t fetchFile(
+    ssize_t fetchFile(
             const char *url, sp<ABuffer> *out,
             /* request/open a file starting at range_offset for range_length bytes */
             int64_t range_offset = 0, int64_t range_length = -1,
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index dacdd40..f22d650 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -163,21 +163,21 @@
 
     if (select) {
         if (index >= mMediaItems.size()) {
-            ALOGE("track %d does not exist", index);
+            ALOGE("track %zu does not exist", index);
             return INVALID_OPERATION;
         }
         if (mSelectedIndex == (ssize_t)index) {
-            ALOGE("track %d already selected", index);
+            ALOGE("track %zu already selected", index);
             return BAD_VALUE;
         }
-        ALOGV("selected track %d", index);
+        ALOGV("selected track %zu", index);
         mSelectedIndex = index;
     } else {
         if (mSelectedIndex != (ssize_t)index) {
-            ALOGE("track %d is not selected", index);
+            ALOGE("track %zu is not selected", index);
             return BAD_VALUE;
         }
-        ALOGV("unselected track %d", index);
+        ALOGV("unselected track %zu", index);
         mSelectedIndex = -1;
     }
 
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 9d7cb99..5011bc1 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -40,6 +40,7 @@
 #include <media/stagefright/Utils.h>
 
 #include <ctype.h>
+#include <inttypes.h>
 #include <openssl/aes.h>
 #include <openssl/md5.h>
 
@@ -48,6 +49,7 @@
 // static
 const int64_t PlaylistFetcher::kMinBufferedDurationUs = 10000000ll;
 const int64_t PlaylistFetcher::kMaxMonitorDelayUs = 3000000ll;
+const int32_t PlaylistFetcher::kDownloadBlockSize = 192;
 const int32_t PlaylistFetcher::kNumSkipFrames = 10;
 
 PlaylistFetcher::PlaylistFetcher(
@@ -216,9 +218,9 @@
     if (index >= 0) {
         key = mAESKeyForURI.valueAt(index);
     } else {
-        status_t err = mSession->fetchFile(keyURI.c_str(), &key);
+        ssize_t err = mSession->fetchFile(keyURI.c_str(), &key);
 
-        if (err != OK) {
+        if (err < 0) {
             ALOGE("failed to fetch cipher key from '%s'.", keyURI.c_str());
             return ERROR_IO;
         } else if (key->size() != 16) {
@@ -315,7 +317,7 @@
         maxDelayUs = minDelayUs;
     }
     if (delayUs > maxDelayUs) {
-        ALOGV("Need to refresh playlist in %lld", maxDelayUs);
+        ALOGV("Need to refresh playlist in %" PRId64 , maxDelayUs);
         delayUs = maxDelayUs;
     }
     sp<AMessage> msg = new AMessage(kWhatMonitorQueue, id());
@@ -626,7 +628,7 @@
 
             int64_t bufferedStreamDurationUs =
                 mPacketSources.valueAt(i)->getBufferedDurationUs(&finalResult);
-            ALOGV("buffered %lld for stream %d",
+            ALOGV("buffered %" PRId64 " for stream %d",
                     bufferedStreamDurationUs, mPacketSources.keyAt(i));
             if (bufferedStreamDurationUs > bufferedDurationUs) {
                 bufferedDurationUs = bufferedStreamDurationUs;
@@ -639,7 +641,7 @@
     if (!mPrepared && bufferedDurationUs > targetDurationUs && downloadMore) {
         mPrepared = true;
 
-        ALOGV("prepared, buffered=%lld > %lld",
+        ALOGV("prepared, buffered=%" PRId64 " > %" PRId64 "",
                 bufferedDurationUs, targetDurationUs);
         sp<AMessage> msg = mNotify->dup();
         msg->setInt32("what", kWhatTemporarilyDoneFetching);
@@ -647,7 +649,7 @@
     }
 
     if (finalResult == OK && downloadMore) {
-        ALOGV("monitoring, buffered=%lld < %lld",
+        ALOGV("monitoring, buffered=%" PRId64 " < %" PRId64 "",
                 bufferedDurationUs, durationToBufferUs);
         // delay the next download slightly; hopefully this gives other concurrent fetchers
         // a better chance to run.
@@ -663,7 +665,7 @@
         msg->post();
 
         int64_t delayUs = mPrepared ? kMaxMonitorDelayUs : targetDurationUs / 2;
-        ALOGV("pausing for %lld, buffered=%lld > %lld",
+        ALOGV("pausing for %" PRId64 ", buffered=%" PRId64 " > %" PRId64 "",
                 delayUs, bufferedDurationUs, durationToBufferUs);
         // :TRICKY: need to enforce minimum delay because the delay to
         // refresh the playlist will become 0
@@ -704,6 +706,11 @@
     return OK;
 }
 
+// static
+bool PlaylistFetcher::bufferStartsWithTsSyncByte(const sp<ABuffer>& buffer) {
+    return buffer->size() > 0 && buffer->data()[0] == 0x47;
+}
+
 void PlaylistFetcher::onDownloadNext() {
     if (refreshPlaylist() != OK) {
         return;
@@ -732,7 +739,7 @@
 
         if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
             mSeqNumber = getSeqNumberForTime(mStartTimeUs);
-            ALOGV("Initial sequence number for time %lld is %d from (%d .. %d)",
+            ALOGV("Initial sequence number for time %" PRId64 " is %d from (%d .. %d)",
                     mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist,
                     lastSeqNumberInPlaylist);
         } else {
@@ -766,7 +773,7 @@
                     delayUs = kMaxMonitorDelayUs;
                 }
                 ALOGV("sequence number high: %d from (%d .. %d), "
-                      "monitor in %lld (retry=%d)",
+                      "monitor in %" PRId64 " (retry=%d)",
                         mSeqNumber, firstSeqNumberInPlaylist,
                         lastSeqNumberInPlaylist, delayUs, mNumRetries);
                 postMonitorQueue(delayUs);
@@ -791,7 +798,7 @@
             ALOGE("Cannot find sequence number %d in playlist "
                  "(contains %d - %d)",
                  mSeqNumber, firstSeqNumberInPlaylist,
-                 firstSeqNumberInPlaylist + mPlaylist->size() - 1);
+                  firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1);
 
             notifyError(ERROR_END_OF_STREAM);
             return;
@@ -824,64 +831,159 @@
 
     ALOGV("fetching '%s'", uri.c_str());
 
-    sp<ABuffer> buffer;
-    status_t err = mSession->fetchFile(
-            uri.c_str(), &buffer, range_offset, range_length);
-
-    if (err != OK) {
-        ALOGE("failed to fetch .ts segment at url '%s'", uri.c_str());
-        notifyError(err);
-        return;
-    }
-
-    CHECK(buffer != NULL);
-
-    err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer);
-    if (err == OK) {
-        err = checkDecryptPadding(buffer);
-    }
-
-    if (err != OK) {
-        ALOGE("decryptBuffer failed w/ error %d", err);
-
-        notifyError(err);
-        return;
-    }
-
-    if (mStartup || seekDiscontinuity || explicitDiscontinuity) {
-        // Signal discontinuity.
-
-        if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
-            // If this was a live event this made no sense since
-            // we don't have access to all the segment before the current
-            // one.
-            mNextPTSTimeUs = getSegmentStartTimeUs(mSeqNumber);
-        }
-
-        if (seekDiscontinuity || explicitDiscontinuity) {
-            ALOGI("queueing discontinuity (seek=%d, explicit=%d)",
-                 seekDiscontinuity, explicitDiscontinuity);
-
-            queueDiscontinuity(
-                    explicitDiscontinuity
-                        ? ATSParser::DISCONTINUITY_FORMATCHANGE
-                        : ATSParser::DISCONTINUITY_SEEK,
-                    NULL /* extra */);
+    sp<DataSource> source;
+    sp<ABuffer> buffer, tsBuffer;
+    // decrypt a junk buffer to prefetch key; since a session uses only one http connection,
+    // this avoids interleaved connections to the key and segment file.
+    {
+        sp<ABuffer> junk = new ABuffer(16);
+        junk->setRange(0, 16);
+        status_t err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, junk,
+                true /* first */);
+        if (err != OK) {
+            notifyError(err);
+            return;
         }
     }
 
-    err = extractAndQueueAccessUnits(buffer, itemMeta);
+    // block-wise download
+    ssize_t bytesRead;
+    do {
+        bytesRead = mSession->fetchFile(
+                uri.c_str(), &buffer, range_offset, range_length, kDownloadBlockSize, &source);
 
-    if (err == -EAGAIN) {
-        // bad starting sequence number hint
-        postMonitorQueue();
+        if (bytesRead < 0) {
+            status_t err = bytesRead;
+            ALOGE("failed to fetch .ts segment at url '%s'", uri.c_str());
+            notifyError(err);
+            return;
+        }
+
+        CHECK(buffer != NULL);
+
+        size_t size = buffer->size();
+        // Set decryption range.
+        buffer->setRange(size - bytesRead, bytesRead);
+        status_t err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer,
+                buffer->offset() == 0 /* first */);
+        // Unset decryption range.
+        buffer->setRange(0, size);
+
+        if (err != OK) {
+            ALOGE("decryptBuffer failed w/ error %d", err);
+
+            notifyError(err);
+            return;
+        }
+
+        if (mStartup || seekDiscontinuity || explicitDiscontinuity) {
+            // Signal discontinuity.
+
+            if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
+                // If this was a live event this made no sense since
+                // we don't have access to all the segment before the current
+                // one.
+                mNextPTSTimeUs = getSegmentStartTimeUs(mSeqNumber);
+            }
+
+            if (seekDiscontinuity || explicitDiscontinuity) {
+                ALOGI("queueing discontinuity (seek=%d, explicit=%d)",
+                     seekDiscontinuity, explicitDiscontinuity);
+
+                queueDiscontinuity(
+                        explicitDiscontinuity
+                            ? ATSParser::DISCONTINUITY_FORMATCHANGE
+                            : ATSParser::DISCONTINUITY_SEEK,
+                        NULL /* extra */);
+            }
+        }
+
+        err = OK;
+        if (bufferStartsWithTsSyncByte(buffer)) {
+            // Incremental extraction is only supported for MPEG2 transport streams.
+            if (tsBuffer == NULL) {
+                tsBuffer = new ABuffer(buffer->data(), buffer->capacity());
+                tsBuffer->setRange(0, 0);
+            } else if (tsBuffer->capacity() != buffer->capacity()) {
+                size_t tsOff = tsBuffer->offset(), tsSize = tsBuffer->size();
+                tsBuffer = new ABuffer(buffer->data(), buffer->capacity());
+                tsBuffer->setRange(tsOff, tsSize);
+            }
+            tsBuffer->setRange(tsBuffer->offset(), tsBuffer->size() + bytesRead);
+
+            err = extractAndQueueAccessUnitsFromTs(tsBuffer);
+        }
+
+        if (err == -EAGAIN) {
+            // bad starting sequence number hint
+            postMonitorQueue();
+            return;
+        }
+
+        if (err == ERROR_OUT_OF_RANGE) {
+            // reached stopping point
+            stopAsync(/* selfTriggered = */ true);
+            return;
+        }
+
+        if (err != OK) {
+            notifyError(err);
+            return;
+        }
+
+        mStartup = false;
+    } while (bytesRead != 0);
+
+    if (bufferStartsWithTsSyncByte(buffer)) {
+        // If we still don't see a stream after fetching a full ts segment mark it as
+        // nonexistent.
+        const size_t kNumTypes = ATSParser::NUM_SOURCE_TYPES;
+        ATSParser::SourceType srcTypes[kNumTypes] =
+                { ATSParser::VIDEO, ATSParser::AUDIO };
+        LiveSession::StreamType streamTypes[kNumTypes] =
+                { LiveSession::STREAMTYPE_VIDEO, LiveSession::STREAMTYPE_AUDIO };
+
+        for (size_t i = 0; i < kNumTypes; i++) {
+            ATSParser::SourceType srcType = srcTypes[i];
+            LiveSession::StreamType streamType = streamTypes[i];
+
+            sp<AnotherPacketSource> source =
+                static_cast<AnotherPacketSource *>(
+                    mTSParser->getSource(srcType).get());
+
+            if (source == NULL) {
+                ALOGW("MPEG2 Transport stream does not contain %s data.",
+                      srcType == ATSParser::VIDEO ? "video" : "audio");
+
+                mStreamTypeMask &= ~streamType;
+                mPacketSources.removeItem(streamType);
+            }
+        }
+
+    }
+
+    if (checkDecryptPadding(buffer) != OK) {
+        ALOGE("Incorrect padding bytes after decryption.");
+        notifyError(ERROR_MALFORMED);
         return;
     }
 
-    if (err == ERROR_OUT_OF_RANGE) {
-        // reached stopping point
-        stopAsync(/* selfTriggered = */ true);
-        return;
+    status_t err = OK;
+    if (tsBuffer != NULL) {
+        AString method;
+        CHECK(buffer->meta()->findString("cipher-method", &method));
+        if ((tsBuffer->size() > 0 && method == "NONE")
+                || tsBuffer->size() > 16) {
+            ALOGE("MPEG2 transport stream is not an even multiple of 188 "
+                    "bytes in length.");
+            notifyError(ERROR_MALFORMED);
+            return;
+        }
+    }
+
+    // bulk extract non-ts files
+    if (tsBuffer == NULL) {
+      err = extractAndQueueAccessUnits(buffer, itemMeta);
     }
 
     if (err != OK) {
@@ -892,8 +994,6 @@
     ++mSeqNumber;
 
     postMonitorQueue();
-
-    mStartup = false;
 }
 
 int32_t PlaylistFetcher::getSeqNumberForTime(int64_t timeUs) const {
@@ -928,173 +1028,163 @@
     return firstSeqNumberInPlaylist + index;
 }
 
-status_t PlaylistFetcher::extractAndQueueAccessUnits(
-        const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta) {
-    if (buffer->size() > 0 && buffer->data()[0] == 0x47) {
-        // Let's assume this is an MPEG2 transport stream.
+status_t PlaylistFetcher::extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &buffer) {
+    if (mTSParser == NULL) {
+        // Use TS_TIMESTAMPS_ARE_ABSOLUTE so pts carry over between fetchers.
+        mTSParser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE);
+    }
 
-        if ((buffer->size() % 188) != 0) {
-            ALOGE("MPEG2 transport stream is not an even multiple of 188 "
-                  "bytes in length.");
-            return ERROR_MALFORMED;
-        }
+    if (mNextPTSTimeUs >= 0ll) {
+        sp<AMessage> extra = new AMessage;
+        // Since we are using absolute timestamps, signal an offset of 0 to prevent
+        // ATSParser from skewing the timestamps of access units.
+        extra->setInt64(IStreamListener::kKeyMediaTimeUs, 0);
 
-        if (mTSParser == NULL) {
-            // Use TS_TIMESTAMPS_ARE_ABSOLUTE so pts carry over between fetchers.
-            mTSParser = new ATSParser(ATSParser::TS_TIMESTAMPS_ARE_ABSOLUTE);
-        }
+        mTSParser->signalDiscontinuity(
+                ATSParser::DISCONTINUITY_SEEK, extra);
 
-        if (mNextPTSTimeUs >= 0ll) {
-            sp<AMessage> extra = new AMessage;
-            // Since we are using absolute timestamps, signal an offset of 0 to prevent
-            // ATSParser from skewing the timestamps of access units.
-            extra->setInt64(IStreamListener::kKeyMediaTimeUs, 0);
+        mNextPTSTimeUs = -1ll;
+    }
 
-            mTSParser->signalDiscontinuity(
-                    ATSParser::DISCONTINUITY_SEEK, extra);
-
-            mNextPTSTimeUs = -1ll;
-        }
-
-        size_t offset = 0;
-        while (offset < buffer->size()) {
-            status_t err = mTSParser->feedTSPacket(buffer->data() + offset, 188);
-
-            if (err != OK) {
-                return err;
-            }
-
-            offset += 188;
-        }
-
-        status_t err = OK;
-        for (size_t i = mPacketSources.size(); i-- > 0;) {
-            sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
-
-            const char *key;
-            ATSParser::SourceType type;
-            const LiveSession::StreamType stream = mPacketSources.keyAt(i);
-            switch (stream) {
-
-                case LiveSession::STREAMTYPE_VIDEO:
-                    type = ATSParser::VIDEO;
-                    key = "timeUsVideo";
-                    break;
-
-                case LiveSession::STREAMTYPE_AUDIO:
-                    type = ATSParser::AUDIO;
-                    key = "timeUsAudio";
-                    break;
-
-                case LiveSession::STREAMTYPE_SUBTITLES:
-                {
-                    ALOGE("MPEG2 Transport streams do not contain subtitles.");
-                    return ERROR_MALFORMED;
-                    break;
-                }
-
-                default:
-                    TRESPASS();
-            }
-
-            sp<AnotherPacketSource> source =
-                static_cast<AnotherPacketSource *>(
-                        mTSParser->getSource(type).get());
-
-            if (source == NULL) {
-                ALOGW("MPEG2 Transport stream does not contain %s data.",
-                      type == ATSParser::VIDEO ? "video" : "audio");
-
-                mStreamTypeMask &= ~mPacketSources.keyAt(i);
-                mPacketSources.removeItemsAt(i);
-                continue;
-            }
-
-            int64_t timeUs;
-            sp<ABuffer> accessUnit;
-            status_t finalResult;
-            while (source->hasBufferAvailable(&finalResult)
-                    && source->dequeueAccessUnit(&accessUnit) == OK) {
-
-                CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-                if (mMinStartTimeUs > 0) {
-                    if (timeUs < mMinStartTimeUs) {
-                        // TODO untested path
-                        // try a later ts
-                        int32_t targetDuration;
-                        mPlaylist->meta()->findInt32("target-duration", &targetDuration);
-                        int32_t incr = (mMinStartTimeUs - timeUs) / 1000000 / targetDuration;
-                        if (incr == 0) {
-                            // increment mSeqNumber by at least one
-                            incr = 1;
-                        }
-                        mSeqNumber += incr;
-                        err = -EAGAIN;
-                        break;
-                    } else {
-                        int64_t startTimeUs;
-                        if (mStartTimeUsNotify != NULL
-                                && !mStartTimeUsNotify->findInt64(key, &startTimeUs)) {
-                            mStartTimeUsNotify->setInt64(key, timeUs);
-
-                            uint32_t streamMask = 0;
-                            mStartTimeUsNotify->findInt32("streamMask", (int32_t *) &streamMask);
-                            streamMask |= mPacketSources.keyAt(i);
-                            mStartTimeUsNotify->setInt32("streamMask", streamMask);
-
-                            if (streamMask == mStreamTypeMask) {
-                                mStartTimeUsNotify->post();
-                                mStartTimeUsNotify.clear();
-                            }
-                        }
-                    }
-                }
-
-                if (mStopParams != NULL) {
-                    // Queue discontinuity in original stream.
-                    int64_t stopTimeUs;
-                    if (!mStopParams->findInt64(key, &stopTimeUs) || timeUs >= stopTimeUs) {
-                        packetSource->queueAccessUnit(mSession->createFormatChangeBuffer());
-                        mStreamTypeMask &= ~stream;
-                        mPacketSources.removeItemsAt(i);
-                        break;
-                    }
-                }
-
-                // Note that we do NOT dequeue any discontinuities except for format change.
-
-                // for simplicity, store a reference to the format in each unit
-                sp<MetaData> format = source->getFormat();
-                if (format != NULL) {
-                    accessUnit->meta()->setObject("format", format);
-                }
-
-                // Stash the sequence number so we can hint future fetchers where to start at.
-                accessUnit->meta()->setInt32("seq", mSeqNumber);
-                packetSource->queueAccessUnit(accessUnit);
-            }
-
-            if (err != OK) {
-                break;
-            }
-        }
+    size_t offset = 0;
+    while (offset + 188 <= buffer->size()) {
+        status_t err = mTSParser->feedTSPacket(buffer->data() + offset, 188);
 
         if (err != OK) {
-            for (size_t i = mPacketSources.size(); i-- > 0;) {
-                sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
-                packetSource->clear();
-            }
             return err;
         }
 
-        if (!mStreamTypeMask) {
-            // Signal gap is filled between original and new stream.
-            ALOGV("ERROR OUT OF RANGE");
-            return ERROR_OUT_OF_RANGE;
+        offset += 188;
+    }
+    // setRange to indicate consumed bytes.
+    buffer->setRange(buffer->offset() + offset, buffer->size() - offset);
+
+    status_t err = OK;
+    for (size_t i = mPacketSources.size(); i-- > 0;) {
+        sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
+
+        const char *key;
+        ATSParser::SourceType type;
+        const LiveSession::StreamType stream = mPacketSources.keyAt(i);
+        switch (stream) {
+            case LiveSession::STREAMTYPE_VIDEO:
+                type = ATSParser::VIDEO;
+                key = "timeUsVideo";
+                break;
+
+            case LiveSession::STREAMTYPE_AUDIO:
+                type = ATSParser::AUDIO;
+                key = "timeUsAudio";
+                break;
+
+            case LiveSession::STREAMTYPE_SUBTITLES:
+            {
+                ALOGE("MPEG2 Transport streams do not contain subtitles.");
+                return ERROR_MALFORMED;
+                break;
+            }
+
+            default:
+                TRESPASS();
         }
 
-        return OK;
-    } else if (buffer->size() >= 7 && !memcmp("WEBVTT\n", buffer->data(), 7)) {
+        sp<AnotherPacketSource> source =
+            static_cast<AnotherPacketSource *>(
+                    mTSParser->getSource(type).get());
+
+        if (source == NULL) {
+            continue;
+        }
+
+        int64_t timeUs;
+        sp<ABuffer> accessUnit;
+        status_t finalResult;
+        while (source->hasBufferAvailable(&finalResult)
+                && source->dequeueAccessUnit(&accessUnit) == OK) {
+
+            CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+            if (mMinStartTimeUs > 0) {
+                if (timeUs < mMinStartTimeUs) {
+                    // TODO untested path
+                    // try a later ts
+                    int32_t targetDuration;
+                    mPlaylist->meta()->findInt32("target-duration", &targetDuration);
+                    int32_t incr = (mMinStartTimeUs - timeUs) / 1000000 / targetDuration;
+                    if (incr == 0) {
+                        // increment mSeqNumber by at least one
+                        incr = 1;
+                    }
+                    mSeqNumber += incr;
+                    err = -EAGAIN;
+                    break;
+                } else {
+                    int64_t startTimeUs;
+                    if (mStartTimeUsNotify != NULL
+                            && !mStartTimeUsNotify->findInt64(key, &startTimeUs)) {
+                        mStartTimeUsNotify->setInt64(key, timeUs);
+
+                        uint32_t streamMask = 0;
+                        mStartTimeUsNotify->findInt32("streamMask", (int32_t *) &streamMask);
+                        streamMask |= mPacketSources.keyAt(i);
+                        mStartTimeUsNotify->setInt32("streamMask", streamMask);
+
+                        if (streamMask == mStreamTypeMask) {
+                            mStartTimeUsNotify->post();
+                            mStartTimeUsNotify.clear();
+                        }
+                    }
+                }
+            }
+
+            if (mStopParams != NULL) {
+                // Queue discontinuity in original stream.
+                int64_t stopTimeUs;
+                if (!mStopParams->findInt64(key, &stopTimeUs) || timeUs >= stopTimeUs) {
+                    packetSource->queueAccessUnit(mSession->createFormatChangeBuffer());
+                    mStreamTypeMask &= ~stream;
+                    mPacketSources.removeItemsAt(i);
+                    break;
+                }
+            }
+
+            // Note that we do NOT dequeue any discontinuities except for format change.
+
+            // for simplicity, store a reference to the format in each unit
+            sp<MetaData> format = source->getFormat();
+            if (format != NULL) {
+                accessUnit->meta()->setObject("format", format);
+            }
+
+            // Stash the sequence number so we can hint future playlist where to start at.
+            accessUnit->meta()->setInt32("seq", mSeqNumber);
+            packetSource->queueAccessUnit(accessUnit);
+        }
+
+        if (err != OK) {
+            break;
+        }
+    }
+
+    if (err != OK) {
+        for (size_t i = mPacketSources.size(); i-- > 0;) {
+            sp<AnotherPacketSource> packetSource = mPacketSources.valueAt(i);
+            packetSource->clear();
+        }
+        return err;
+    }
+
+    if (!mStreamTypeMask) {
+        // Signal gap is filled between original and new stream.
+        ALOGV("ERROR OUT OF RANGE");
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    return OK;
+}
+
+status_t PlaylistFetcher::extractAndQueueAccessUnits(
+        const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta) {
+    if (buffer->size() >= 7 && !memcmp("WEBVTT\n", buffer->data(), 7)) {
         if (mStreamTypeMask != LiveSession::STREAMTYPE_SUBTITLES) {
             ALOGE("This stream only contains subtitles.");
             return ERROR_MALFORMED;
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index 8404b8d..7e21523 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -87,8 +87,11 @@
 
     static const int64_t kMinBufferedDurationUs;
     static const int64_t kMaxMonitorDelayUs;
+    static const int32_t kDownloadBlockSize;
     static const int32_t kNumSkipFrames;
 
+    static bool bufferStartsWithTsSyncByte(const sp<ABuffer>& buffer);
+
     // notifications to mSession
     sp<AMessage> mNotify;
     sp<AMessage> mStartTimeUsNotify;
@@ -169,6 +172,8 @@
     // Resume a fetcher to continue until the stopping point stored in msg.
     status_t onResumeUntil(const sp<AMessage> &msg);
 
+    status_t extractAndQueueAccessUnitsFromTs(const sp<ABuffer> &buffer);
+
     status_t extractAndQueueAccessUnits(
             const sp<ABuffer> &buffer, const sp<AMessage> &itemMeta);
 
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index f0f203c..7f221a0 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -41,9 +41,9 @@
     }
 
     virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
-        off64_t available = (offset >= mSize) ? 0ll : mSize - offset;
+        off64_t available = (offset >= (off64_t)mSize) ? 0ll : mSize - offset;
 
-        size_t copy = (available > size) ? size : available;
+        size_t copy = (available > (off64_t)size) ? size : available;
         memcpy(data, mData + offset, copy);
 
         return copy;
@@ -172,7 +172,7 @@
     }
 
     if (size > kMaxMetadataSize) {
-        ALOGE("skipping huge ID3 metadata of size %d", size);
+        ALOGE("skipping huge ID3 metadata of size %zu", size);
         return false;
     }
 
@@ -633,8 +633,8 @@
             mFrameSize += 6;
 
             if (mOffset + mFrameSize > mParent.mSize) {
-                ALOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)",
-                     mOffset, mFrameSize, mParent.mSize - mOffset - 6);
+                ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)",
+                    mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)6);
                 return;
             }
 
@@ -674,8 +674,8 @@
             mFrameSize = 10 + baseSize;
 
             if (mOffset + mFrameSize > mParent.mSize) {
-                ALOGV("partial frame at offset %d (size = %d, bytes-remaining = %d)",
-                     mOffset, mFrameSize, mParent.mSize - mOffset - 10);
+                ALOGV("partial frame at offset %zu (size = %zu, bytes-remaining = %zu)",
+                    mOffset, mFrameSize, mParent.mSize - mOffset - (size_t)10);
                 return;
             }
 
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 6ec9263..d4a7c7f 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -33,6 +33,8 @@
 #include <media/stagefright/Utils.h>
 #include <utils/String8.h>
 
+#include <inttypes.h>
+
 namespace android {
 
 struct DataSourceReader : public mkvparser::IMkvReader {
@@ -103,7 +105,7 @@
 
 private:
     MatroskaExtractor *mExtractor;
-    unsigned long mTrackNum;
+    long long mTrackNum;
 
     const mkvparser::Cluster *mCluster;
     const mkvparser::BlockEntry *mBlockEntry;
@@ -183,7 +185,7 @@
         CHECK_GE(avccSize, 5u);
 
         mNALSizeLen = 1 + (avcc[4] & 3);
-        ALOGV("mNALSizeLen = %d", mNALSizeLen);
+        ALOGV("mNALSizeLen = %zu", mNALSizeLen);
     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
         mType = AAC;
     }
@@ -320,7 +322,7 @@
     // Special case the 0 seek to avoid loading Cues when the application
     // extraneously seeks to 0 before playing.
     if (seekTimeNs <= 0) {
-        ALOGV("Seek to beginning: %lld", seekTimeUs);
+        ALOGV("Seek to beginning: %" PRId64, seekTimeUs);
         mCluster = pSegment->GetFirst();
         mBlockEntryIndex = 0;
         do {
@@ -329,7 +331,7 @@
         return;
     }
 
-    ALOGV("Seeking to: %lld", seekTimeUs);
+    ALOGV("Seeking to: %" PRId64, seekTimeUs);
 
     // If the Cues have not been located then find them.
     const mkvparser::Cues* pCues = pSegment->GetCues();
@@ -378,7 +380,7 @@
     for (size_t index = 0; index < pTracks->GetTracksCount(); ++index) {
         pTrack = pTracks->GetTrackByIndex(index);
         if (pTrack && pTrack->GetType() == 1) { // VIDEO_TRACK
-            ALOGV("Video track located at %d", index);
+            ALOGV("Video track located at %zu", index);
             break;
         }
     }
@@ -409,7 +411,7 @@
         if (isAudio || block()->IsKey()) {
             // Accept the first key frame
             *actualFrameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL;
-            ALOGV("Requested seek point: %lld actual: %lld",
+            ALOGV("Requested seek point: %" PRId64 " actual: %" PRId64,
                   seekTimeUs, *actualFrameTimeUs);
             break;
         }
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index d039f7d..d1afd8b 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -36,6 +36,8 @@
 #include <media/IStreamSource.h>
 #include <utils/KeyedVector.h>
 
+#include <inttypes.h>
+
 namespace android {
 
 // I want the expression "y" evaluated even if verbose logging is off.
@@ -586,7 +588,7 @@
         // Increment in multiples of 64K.
         neededSize = (neededSize + 65535) & ~65535;
 
-        ALOGI("resizing buffer to %d bytes", neededSize);
+        ALOGI("resizing buffer to %zu bytes", neededSize);
 
         sp<ABuffer> newBuffer = new ABuffer(neededSize);
         memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
@@ -748,7 +750,7 @@
             PTS |= br->getBits(15);
             CHECK_EQ(br->getBits(1), 1u);
 
-            ALOGV("PTS = 0x%016llx (%.2f)", PTS, PTS / 90000.0);
+            ALOGV("PTS = 0x%016" PRIx64 " (%.2f)", PTS, PTS / 90000.0);
 
             optional_bytes_remaining -= 5;
 
@@ -764,7 +766,7 @@
                 DTS |= br->getBits(15);
                 CHECK_EQ(br->getBits(1), 1u);
 
-                ALOGV("DTS = %llu", DTS);
+                ALOGV("DTS = %" PRIu64, DTS);
 
                 optional_bytes_remaining -= 5;
             }
@@ -782,7 +784,7 @@
             ESCR |= br->getBits(15);
             CHECK_EQ(br->getBits(1), 1u);
 
-            ALOGV("ESCR = %llu", ESCR);
+            ALOGV("ESCR = %" PRIu64, ESCR);
             MY_LOGV("ESCR_extension = %u", br->getBits(9));
 
             CHECK_EQ(br->getBits(1), 1u);
@@ -812,7 +814,7 @@
 
             if (br->numBitsLeft() < dataLength * 8) {
                 ALOGE("PES packet does not carry enough data to contain "
-                     "payload. (numBitsLeft = %d, required = %d)",
+                     "payload. (numBitsLeft = %zu, required = %u)",
                      br->numBitsLeft(), dataLength * 8);
 
                 return ERROR_MALFORMED;
@@ -832,7 +834,7 @@
             size_t payloadSizeBits = br->numBitsLeft();
             CHECK_EQ(payloadSizeBits % 8, 0u);
 
-            ALOGV("There's %d bytes of payload.", payloadSizeBits / 8);
+            ALOGV("There's %zu bytes of payload.", payloadSizeBits / 8);
         }
     } else if (stream_id == 0xbe) {  // padding_stream
         CHECK_NE(PES_packet_length, 0u);
@@ -850,7 +852,7 @@
         return OK;
     }
 
-    ALOGV("flushing stream 0x%04x size = %d", mElementaryPID, mBuffer->size());
+    ALOGV("flushing stream 0x%04x size = %zu", mElementaryPID, mBuffer->size());
 
     ABitReader br(mBuffer->data(), mBuffer->size());
 
@@ -1172,7 +1174,7 @@
 
             uint64_t PCR = PCR_base * 300 + PCR_ext;
 
-            ALOGV("PID 0x%04x: PCR = 0x%016llx (%.2f)",
+            ALOGV("PID 0x%04x: PCR = 0x%016" PRIx64 " (%.2f)",
                   PID, PCR, PCR / 27E6);
 
             // The number of bytes received by this parser up to and
@@ -1268,7 +1270,7 @@
 
 void ATSParser::updatePCR(
         unsigned /* PID */, uint64_t PCR, size_t byteOffsetFromStart) {
-    ALOGV("PCR 0x%016llx @ %d", PCR, byteOffsetFromStart);
+    ALOGV("PCR 0x%016" PRIx64 " @ %zu", PCR, byteOffsetFromStart);
 
     if (mNumPCRs == 2) {
         mPCR[0] = mPCR[1];
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index d4e30b4..86b025f 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -71,8 +71,9 @@
     void signalEOS(status_t finalResult);
 
     enum SourceType {
-        VIDEO,
-        AUDIO
+        VIDEO = 0,
+        AUDIO = 1,
+        NUM_SOURCE_TYPES = 2
     };
     sp<MediaSource> getSource(SourceType type);
 
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 6dfaa94..021b640 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -26,6 +26,8 @@
 #include <media/stagefright/MetaData.h>
 #include <utils/Vector.h>
 
+#include <inttypes.h>
+
 namespace android {
 
 const int64_t kNearEOSMarkUs = 2000000ll; // 2 secs
@@ -186,7 +188,7 @@
     int64_t lastQueuedTimeUs;
     CHECK(buffer->meta()->findInt64("timeUs", &lastQueuedTimeUs));
     mLastQueuedTimeUs = lastQueuedTimeUs;
-    ALOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6);
+    ALOGV("queueAccessUnit timeUs=%" PRIi64 " us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6);
 
     Mutex::Autolock autoLock(mLock);
     mBuffers.push_back(buffer);
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index c0c9717..f7abf01 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -31,6 +31,7 @@
 
 #include "include/avc_utils.h"
 
+#include <inttypes.h>
 #include <netinet/in.h>
 
 namespace android {
@@ -264,7 +265,7 @@
 
                 if (startOffset > 0) {
                     ALOGI("found something resembling an H.264/MPEG syncword "
-                          "at offset %d",
+                          "at offset %zd",
                           startOffset);
                 }
 
@@ -297,7 +298,7 @@
 
                 if (startOffset > 0) {
                     ALOGI("found something resembling an H.264/MPEG syncword "
-                          "at offset %d",
+                          "at offset %zd",
                           startOffset);
                 }
 
@@ -330,7 +331,7 @@
 
                 if (startOffset > 0) {
                     ALOGI("found something resembling an AAC syncword at "
-                          "offset %d",
+                          "offset %zd",
                           startOffset);
                 }
 
@@ -358,7 +359,7 @@
 
                 if (startOffset > 0) {
                     ALOGI("found something resembling an AC3 syncword at "
-                          "offset %d",
+                          "offset %zd",
                           startOffset);
                 }
 
@@ -385,7 +386,7 @@
 
                 if (startOffset > 0) {
                     ALOGI("found something resembling an MPEG audio "
-                          "syncword at offset %d",
+                          "syncword at offset %zd",
                           startOffset);
                 }
 
@@ -409,7 +410,7 @@
     if (mBuffer == NULL || neededSize > mBuffer->capacity()) {
         neededSize = (neededSize + 65535) & ~65535;
 
-        ALOGV("resizing buffer to size %d", neededSize);
+        ALOGV("resizing buffer to size %zu", neededSize);
 
         sp<ABuffer> buffer = new ABuffer(neededSize);
         if (mBuffer != NULL) {
@@ -432,7 +433,7 @@
 
 #if 0
     if (mMode == AAC) {
-        ALOGI("size = %d, timeUs = %.2f secs", size, timeUs / 1E6);
+        ALOGI("size = %zu, timeUs = %.2f secs", size, timeUs / 1E6);
         hexdump(data, size);
     }
 #endif
@@ -1027,7 +1028,7 @@
 
                 accessUnit->meta()->setInt64("timeUs", timeUs);
 
-                ALOGV("returning MPEG video access unit at time %lld us",
+                ALOGV("returning MPEG video access unit at time %" PRId64 " us",
                       timeUs);
 
                 // hexdump(accessUnit->data(), accessUnit->size());
@@ -1186,7 +1187,7 @@
 
                     accessUnit->meta()->setInt64("timeUs", timeUs);
 
-                    ALOGV("returning MPEG4 video access unit at time %lld us",
+                    ALOGV("returning MPEG4 video access unit at time %" PRId64 " us",
                          timeUs);
 
                     // hexdump(accessUnit->data(), accessUnit->size());
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
index bc2a16d..85859f7 100644
--- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -36,6 +36,8 @@
 #include <media/stagefright/Utils.h>
 #include <utils/String8.h>
 
+#include <inttypes.h>
+
 namespace android {
 
 struct MPEG2PSExtractor::Track : public MediaSource {
@@ -409,7 +411,7 @@
             PTS |= br.getBits(15);
             CHECK_EQ(br.getBits(1), 1u);
 
-            ALOGV("PTS = %llu", PTS);
+            ALOGV("PTS = %" PRIu64, PTS);
             // ALOGI("PTS = %.2f secs", PTS / 90000.0f);
 
             optional_bytes_remaining -= 5;
@@ -426,7 +428,7 @@
                 DTS |= br.getBits(15);
                 CHECK_EQ(br.getBits(1), 1u);
 
-                ALOGV("DTS = %llu", DTS);
+                ALOGV("DTS = %" PRIu64, DTS);
 
                 optional_bytes_remaining -= 5;
             }
@@ -444,7 +446,7 @@
             ESCR |= br.getBits(15);
             CHECK_EQ(br.getBits(1), 1u);
 
-            ALOGV("ESCR = %llu", ESCR);
+            ALOGV("ESCR = %" PRIu64, ESCR);
             /* unsigned ESCR_extension = */br.getBits(9);
 
             CHECK_EQ(br.getBits(1), 1u);
@@ -473,7 +475,7 @@
 
         if (br.numBitsLeft() < dataLength * 8) {
             ALOGE("PES packet does not carry enough data to contain "
-                 "payload. (numBitsLeft = %d, required = %d)",
+                 "payload. (numBitsLeft = %zu, required = %u)",
                  br.numBitsLeft(), dataLength * 8);
 
             return ERROR_MALFORMED;
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 8b79af4..447b29e 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -17,4 +17,6 @@
 
 LOCAL_MODULE_TAGS := tests
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp
index a6825eb..4bc67e8 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AAVCAssembler.cpp
@@ -124,7 +124,7 @@
 }
 
 void AAVCAssembler::addSingleNALUnit(const sp<ABuffer> &buffer) {
-    ALOGV("addSingleNALUnit of size %d", buffer->size());
+    ALOGV("addSingleNALUnit of size %zu", buffer->size());
 #if !LOG_NDEBUG
     hexdump(buffer->data(), buffer->size());
 #endif
@@ -191,7 +191,7 @@
     CHECK((indicator & 0x1f) == 28);
 
     if (size < 2) {
-        ALOGV("Ignoring malformed FU buffer (size = %d)", size);
+        ALOGV("Ignoring malformed FU buffer (size = %zu)", size);
 
         queue->erase(queue->begin());
         ++mNextExpectedSeqNo;
@@ -225,7 +225,7 @@
     } else {
         List<sp<ABuffer> >::iterator it = ++queue->begin();
         while (it != queue->end()) {
-            ALOGV("sequence length %d", totalCount);
+            ALOGV("sequence length %zu", totalCount);
 
             const sp<ABuffer> &buffer = *it;
 
@@ -294,7 +294,7 @@
     for (size_t i = 0; i < totalCount; ++i) {
         const sp<ABuffer> &buffer = *it;
 
-        ALOGV("piece #%d/%d", i + 1, totalCount);
+        ALOGV("piece #%zu/%zu", i + 1, totalCount);
 #if !LOG_NDEBUG
         hexdump(buffer->data(), buffer->size());
 #endif
@@ -317,7 +317,7 @@
 void AAVCAssembler::submitAccessUnit() {
     CHECK(!mNALUnits.empty());
 
-    ALOGV("Access unit complete (%d nal units)", mNALUnits.size());
+    ALOGV("Access unit complete (%zu nal units)", mNALUnits.size());
 
     size_t totalSize = 0;
     for (List<sp<ABuffer> >::iterator it = mNALUnits.begin();
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
index eefceba..98b50dd 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -365,7 +365,7 @@
 void AMPEG4ElementaryAssembler::submitAccessUnit() {
     CHECK(!mPackets.empty());
 
-    ALOGV("Access unit complete (%d nal units)", mPackets.size());
+    ALOGV("Access unit complete (%zu nal units)", mPackets.size());
 
     sp<ABuffer> accessUnit;
 
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index af369b5..372fbe9 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -563,7 +563,7 @@
 
             default:
             {
-                ALOGW("Unknown RTCP packet type %u of size %d",
+                ALOGW("Unknown RTCP packet type %u of size %zu",
                      (unsigned)data[1], headerLength);
                 break;
             }
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index c46d16f..793d116 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -277,7 +277,7 @@
     }
 
     if (mediaBuf->range_length() > 0) {
-        ALOGV("read buffer of size %d", mediaBuf->range_length());
+        ALOGV("read buffer of size %zu", mediaBuf->range_length());
 
         if (mMode == H264) {
             StripStartcode(mediaBuf);
diff --git a/media/libstagefright/rtsp/SDPLoader.cpp b/media/libstagefright/rtsp/SDPLoader.cpp
index 13e8da3..09f7eee 100644
--- a/media/libstagefright/rtsp/SDPLoader.cpp
+++ b/media/libstagefright/rtsp/SDPLoader.cpp
@@ -125,7 +125,7 @@
         ssize_t readSize = mHTTPDataSource->readAt(0, buffer->data(), sdpSize);
 
         if (readSize < 0) {
-            ALOGE("Failed to read SDP, error code = %d", readSize);
+            ALOGE("Failed to read SDP, error code = %zu", readSize);
             err = UNKNOWN_ERROR;
         } else {
             desc = new ASessionDescription;
diff --git a/media/libstagefright/tests/Android.mk b/media/libstagefright/tests/Android.mk
index 06ce16b..903af49 100644
--- a/media/libstagefright/tests/Android.mk
+++ b/media/libstagefright/tests/Android.mk
@@ -41,6 +41,8 @@
 	frameworks/av/media/libstagefright/include \
 	$(TOP)/frameworks/native/include/media/openmax \
 
+LOCAL_32_BIT_ONLY := true
+
 include $(BUILD_EXECUTABLE)
 
 endif
diff --git a/media/libstagefright/timedtext/TimedTextPlayer.cpp b/media/libstagefright/timedtext/TimedTextPlayer.cpp
index 9fb0afe..a070487 100644
--- a/media/libstagefright/timedtext/TimedTextPlayer.cpp
+++ b/media/libstagefright/timedtext/TimedTextPlayer.cpp
@@ -18,6 +18,7 @@
 #define LOG_TAG "TimedTextPlayer"
 #include <utils/Log.h>
 
+#include <inttypes.h>
 #include <limits.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -271,7 +272,7 @@
     sp<MediaPlayerBase> listener = mListener.promote();
     if (listener == NULL) {
         // TODO: it may be better to return kInvalidTimeUs
-        ALOGE("%s: Listener is NULL. (fireTimeUs = %lld)",
+        ALOGE("%s: Listener is NULL. (fireTimeUs = %" PRId64" )",
               __FUNCTION__, fireTimeUs);
         return 0;
     }
diff --git a/media/libstagefright/webm/WebmElement.cpp b/media/libstagefright/webm/WebmElement.cpp
index c978966..a008cab 100644
--- a/media/libstagefright/webm/WebmElement.cpp
+++ b/media/libstagefright/webm/WebmElement.cpp
@@ -119,7 +119,7 @@
     off64_t mapSize = curOff - alignedOff;
     off64_t pageOff = off - alignedOff;
     void *dst = ::mmap64(NULL, mapSize, PROT_WRITE, MAP_SHARED, fd, alignedOff);
-    if ((int) dst == -1) {
+    if (dst == MAP_FAILED) {
         ALOGE("mmap64 failed; errno = %d", errno);
         ALOGE("fd %d; flags: %o", fd, ::fcntl(fd, F_GETFL, 0));
         return errno;
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index 5addd3c..a4b8a42 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -48,7 +48,7 @@
 status_t WebmFrameThread::stop() {
     void *status;
     pthread_join(mThread, &status);
-    return (status_t) status;
+    return (status_t)(intptr_t)status;
 }
 
 //=================================================================================================
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index de7e3c3..6cb0299 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -29,10 +29,6 @@
     Tracks.cpp                  \
     Effects.cpp                 \
     AudioMixer.cpp.arm          \
-    AudioResampler.cpp.arm      \
-    AudioResamplerCubic.cpp.arm \
-    AudioResamplerSinc.cpp.arm  \
-    AudioResamplerDyn.cpp.arm
 
 LOCAL_SRC_FILES += StateQueue.cpp
 
@@ -42,6 +38,7 @@
     $(call include-path-for, audio-utils)
 
 LOCAL_SHARED_LIBRARIES := \
+    libaudioresampler \
     libaudioutils \
     libcommon_time_client \
     libcutils \
@@ -53,7 +50,6 @@
     libhardware \
     libhardware_legacy \
     libeffects \
-    libdl \
     libpowermanager
 
 LOCAL_STATIC_LIBRARIES := \
@@ -87,10 +83,6 @@
 
 LOCAL_SRC_FILES:=               \
     test-resample.cpp           \
-    AudioResampler.cpp.arm      \
-    AudioResamplerCubic.cpp.arm \
-    AudioResamplerSinc.cpp.arm  \
-    AudioResamplerDyn.cpp.arm
 
 LOCAL_C_INCLUDES := \
     $(call include-path-for, audio-utils)
@@ -99,6 +91,7 @@
     libsndfile
 
 LOCAL_SHARED_LIBRARIES := \
+    libaudioresampler \
     libaudioutils \
     libdl \
     libcutils \
@@ -111,4 +104,21 @@
 
 include $(BUILD_EXECUTABLE)
 
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    AudioResampler.cpp.arm \
+    AudioResamplerCubic.cpp.arm \
+    AudioResamplerSinc.cpp.arm \
+    AudioResamplerDyn.cpp.arm
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libdl \
+    liblog
+
+LOCAL_MODULE := libaudioresampler
+
+include $(BUILD_SHARED_LIBRARY)
+
 include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index b5e763d..e9c6834 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -96,6 +96,8 @@
     void reset();
     bool isFlushPending() const { return mFlushHwPending; }
     void flushAck();
+    bool isResumePending();
+    void resumeAck();
 
     bool isOutputTrack() const {
         return (mStreamType == AUDIO_STREAM_CNT);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 12d453e..e046e03 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -4223,32 +4223,34 @@
             if (last) {
                 mFlushPending = true;
             }
-        } else if (track->framesReady() && track->isReady() &&
+        } else if (track->isResumePending()){
+            track->resumeAck();
+            if (last) {
+                if (mPausedBytesRemaining) {
+                    // Need to continue write that was interrupted
+                    mCurrentWriteLength = mPausedWriteLength;
+                    mBytesRemaining = mPausedBytesRemaining;
+                    mPausedBytesRemaining = 0;
+                }
+                if (mHwPaused) {
+                    doHwResume = true;
+                    mHwPaused = false;
+                    // threadLoop_mix() will handle the case that we need to
+                    // resume an interrupted write
+                }
+                // enable write to audio HAL
+                sleepTime = 0;
+
+                // Do not handle new data in this iteration even if track->framesReady()
+                mixerStatus = MIXER_TRACKS_ENABLED;
+            }
+        }  else if (track->framesReady() && track->isReady() &&
                 !track->isPaused() && !track->isTerminated() && !track->isStopping_2()) {
             ALOGVV("OffloadThread: track %d s=%08x [OK]", track->name(), cblk->mServer);
             if (track->mFillingUpStatus == Track::FS_FILLED) {
                 track->mFillingUpStatus = Track::FS_ACTIVE;
                 // make sure processVolume_l() will apply new volume even if 0
                 mLeftVolFloat = mRightVolFloat = -1.0;
-                if (track->mState == TrackBase::RESUMING) {
-                    track->mState = TrackBase::ACTIVE;
-                    if (last) {
-                        if (mPausedBytesRemaining) {
-                            // Need to continue write that was interrupted
-                            mCurrentWriteLength = mPausedWriteLength;
-                            mBytesRemaining = mPausedBytesRemaining;
-                            mPausedBytesRemaining = 0;
-                        }
-                        if (mHwPaused) {
-                            doHwResume = true;
-                            mHwPaused = false;
-                            // threadLoop_mix() will handle the case that we need to
-                            // resume an interrupted write
-                        }
-                        // enable write to audio HAL
-                        sleepTime = 0;
-                    }
-                }
             }
 
             if (last) {
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index f19cd88..9fe459b 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -567,7 +567,14 @@
 
 // Don't call for fast tracks; the framesReady() could result in priority inversion
 bool AudioFlinger::PlaybackThread::Track::isReady() const {
-    if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing() || isStopping()) {
+    if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) {
+        return true;
+    }
+
+    if (isStopping()) {
+        if (framesReady() > 0) {
+            mFillingUpStatus = FS_FILLED;
+        }
         return true;
     }
 
@@ -604,7 +611,10 @@
         // here the track could be either new, or restarted
         // in both cases "unstop" the track
 
-        if (state == PAUSED) {
+        // initial state-stopping. next state-pausing.
+        // What if resume is called ?
+
+        if (state == PAUSED || state == PAUSING) {
             if (mResumeToStopping) {
                 // happened we need to resume to STOPPING_1
                 mState = TrackBase::STOPPING_1;
@@ -991,6 +1001,33 @@
     }
 }
 
+//To be called with thread lock held
+bool AudioFlinger::PlaybackThread::Track::isResumePending() {
+
+    if (mState == RESUMING)
+        return true;
+    /* Resume is pending if track was stopping before pause was called */
+    if (mState == STOPPING_1 &&
+        mResumeToStopping)
+        return true;
+
+    return false;
+}
+
+//To be called with thread lock held
+void AudioFlinger::PlaybackThread::Track::resumeAck() {
+
+
+    if (mState == RESUMING)
+        mState = ACTIVE;
+
+    // Other possibility of  pending resume is stopping_1 state
+    // Do not update the state from stopping as this prevents
+    // drain being called.
+    if (mState == STOPPING_1) {
+        mResumeToStopping = false;
+    }
+}
 // ----------------------------------------------------------------------------
 
 sp<AudioFlinger::PlaybackThread::TimedTrack>
diff --git a/services/audiopolicy/AudioPolicyService.cpp b/services/audiopolicy/AudioPolicyService.cpp
index 037faa7..4a708a0 100644
--- a/services/audiopolicy/AudioPolicyService.cpp
+++ b/services/audiopolicy/AudioPolicyService.cpp
@@ -880,7 +880,7 @@
     return fx_param;
 
 error:
-    delete fx_param;
+    free(fx_param);
     return NULL;
 }
 
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
index d2ac79c..c266213 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp
@@ -110,11 +110,13 @@
     if (!mCallbackToApp && mCallbackConsumer == 0) {
         // Create CPU buffer queue endpoint, since app hasn't given us one
         // Make it async to avoid disconnect deadlocks
-        sp<BufferQueue> bq = new BufferQueue();
-        mCallbackConsumer = new CpuConsumer(bq, kCallbackHeapCount);
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        mCallbackConsumer = new CpuConsumer(consumer, kCallbackHeapCount);
         mCallbackConsumer->setFrameAvailableListener(this);
         mCallbackConsumer->setName(String8("Camera2Client::CallbackConsumer"));
-        mCallbackWindow = new Surface(bq);
+        mCallbackWindow = new Surface(producer);
     }
 
     if (mCallbackStreamId != NO_STREAM) {
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index ec81456..fb8bd27 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -83,11 +83,13 @@
 
     if (mCaptureConsumer == 0) {
         // Create CPU buffer queue endpoint
-        sp<BufferQueue> bq = new BufferQueue();
-        mCaptureConsumer = new CpuConsumer(bq, 1);
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        mCaptureConsumer = new CpuConsumer(consumer, 1);
         mCaptureConsumer->setFrameAvailableListener(this);
         mCaptureConsumer->setName(String8("Camera2Client::CaptureConsumer"));
-        mCaptureWindow = new Surface(bq);
+        mCaptureWindow = new Surface(producer);
         // Create memory for API consumption
         mCaptureHeap = new MemoryHeapBase(maxJpegSize.data.i32[0], 0,
                                        "Camera2Client::CaptureHeap");
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 2cf0d29..75ec426 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "Camera2-Parameters"
 #define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 
 #include <utils/Log.h>
 #include <utils/Trace.h>
@@ -92,26 +92,6 @@
         staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
     if (!availableFpsRanges.count) return NO_INIT;
 
-    previewFpsRange[0] = availableFpsRanges.data.i32[0];
-    previewFpsRange[1] = availableFpsRanges.data.i32[1];
-
-    params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
-            String8::format("%d,%d",
-                    previewFpsRange[0] * kFpsToApiScale,
-                    previewFpsRange[1] * kFpsToApiScale));
-
-    {
-        String8 supportedPreviewFpsRange;
-        for (size_t i=0; i < availableFpsRanges.count; i += 2) {
-            if (i != 0) supportedPreviewFpsRange += ",";
-            supportedPreviewFpsRange += String8::format("(%d,%d)",
-                    availableFpsRanges.data.i32[i] * kFpsToApiScale,
-                    availableFpsRanges.data.i32[i+1] * kFpsToApiScale);
-        }
-        params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE,
-                supportedPreviewFpsRange);
-    }
-
     previewFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP;
     params.set(CameraParameters::KEY_PREVIEW_FORMAT,
             formatEnumToString(previewFormat)); // NV21
@@ -179,6 +159,9 @@
                 supportedPreviewFormats);
     }
 
+    previewFpsRange[0] = availableFpsRanges.data.i32[0];
+    previewFpsRange[1] = availableFpsRanges.data.i32[1];
+
     // PREVIEW_FRAME_RATE / SUPPORTED_PREVIEW_FRAME_RATES are deprecated, but
     // still have to do something sane for them
 
@@ -187,6 +170,27 @@
     params.set(CameraParameters::KEY_PREVIEW_FRAME_RATE,
             previewFps);
 
+    // PREVIEW_FPS_RANGE
+    // -- Order matters. Set range after single value to so that a roundtrip
+    //    of setParameters(getParameters()) would keep the FPS range in higher
+    //    order.
+    params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
+            String8::format("%d,%d",
+                    previewFpsRange[0] * kFpsToApiScale,
+                    previewFpsRange[1] * kFpsToApiScale));
+
+    {
+        String8 supportedPreviewFpsRange;
+        for (size_t i=0; i < availableFpsRanges.count; i += 2) {
+            if (i != 0) supportedPreviewFpsRange += ",";
+            supportedPreviewFpsRange += String8::format("(%d,%d)",
+                    availableFpsRanges.data.i32[i] * kFpsToApiScale,
+                    availableFpsRanges.data.i32[i+1] * kFpsToApiScale);
+        }
+        params.set(CameraParameters::KEY_SUPPORTED_PREVIEW_FPS_RANGE,
+                supportedPreviewFpsRange);
+    }
+
     {
         SortedVector<int32_t> sortedPreviewFrameRates;
 
@@ -1127,29 +1131,72 @@
     // RECORDING_HINT (always supported)
     validatedParams.recordingHint = boolFromString(
         newParams.get(CameraParameters::KEY_RECORDING_HINT) );
-    bool recordingHintChanged = validatedParams.recordingHint != recordingHint;
-    ALOGV_IF(recordingHintChanged, "%s: Recording hint changed to %d",
-            __FUNCTION__, recordingHintChanged);
+    IF_ALOGV() { // Avoid unused variable warning
+        bool recordingHintChanged =
+                validatedParams.recordingHint != recordingHint;
+        if (recordingHintChanged) {
+            ALOGV("%s: Recording hint changed to %d",
+                  __FUNCTION__, validatedParams.recordingHint);
+        }
+    }
 
     // PREVIEW_FPS_RANGE
-    bool fpsRangeChanged = false;
-    int32_t lastSetFpsRange[2];
 
-    params.getPreviewFpsRange(&lastSetFpsRange[0], &lastSetFpsRange[1]);
-    lastSetFpsRange[0] /= kFpsToApiScale;
-    lastSetFpsRange[1] /= kFpsToApiScale;
+    /**
+     * Use the single FPS value if it was set later than the range.
+     * Otherwise, use the range value.
+     */
+    bool fpsUseSingleValue;
+    {
+        const char *fpsRange, *fpsSingle;
 
+        fpsRange = params.get(CameraParameters::KEY_PREVIEW_FRAME_RATE);
+        fpsSingle = params.get(CameraParameters::KEY_PREVIEW_FPS_RANGE);
+
+        /**
+         * Pick either the range or the single key if only one was set.
+         *
+         * If both are set, pick the one that has greater set order.
+         */
+        if (fpsRange == NULL && fpsSingle == NULL) {
+            ALOGE("%s: FPS was not set. One of %s or %s must be set.",
+                  __FUNCTION__, CameraParameters::KEY_PREVIEW_FRAME_RATE,
+                  CameraParameters::KEY_PREVIEW_FPS_RANGE);
+            return BAD_VALUE;
+        } else if (fpsRange == NULL) {
+            fpsUseSingleValue = true;
+            ALOGV("%s: FPS range not set, using FPS single value",
+                  __FUNCTION__);
+        } else if (fpsSingle == NULL) {
+            fpsUseSingleValue = false;
+            ALOGV("%s: FPS single not set, using FPS range value",
+                  __FUNCTION__);
+        } else {
+            int fpsKeyOrder;
+            res = params.compareSetOrder(
+                    CameraParameters::KEY_PREVIEW_FRAME_RATE,
+                    CameraParameters::KEY_PREVIEW_FPS_RANGE,
+                    &fpsKeyOrder);
+            LOG_ALWAYS_FATAL_IF(res != OK, "Impossibly bad FPS keys");
+
+            fpsUseSingleValue = (fpsKeyOrder > 0);
+
+        }
+
+        ALOGV("%s: Preview FPS value is used from '%s'",
+              __FUNCTION__, fpsUseSingleValue ? "single" : "range");
+    }
     newParams.getPreviewFpsRange(&validatedParams.previewFpsRange[0],
             &validatedParams.previewFpsRange[1]);
     validatedParams.previewFpsRange[0] /= kFpsToApiScale;
     validatedParams.previewFpsRange[1] /= kFpsToApiScale;
 
-    // Compare the FPS range value from the last set() to the current set()
-    // to determine if the client has changed it
-    if (validatedParams.previewFpsRange[0] != lastSetFpsRange[0] ||
-            validatedParams.previewFpsRange[1] != lastSetFpsRange[1]) {
+    // Ignore the FPS range if the FPS single has higher precedence
+    if (!fpsUseSingleValue) {
+        ALOGV("%s: Preview FPS range (%d, %d)", __FUNCTION__,
+                validatedParams.previewFpsRange[0],
+                validatedParams.previewFpsRange[1]);
 
-        fpsRangeChanged = true;
         camera_metadata_ro_entry_t availablePreviewFpsRanges =
             staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
         for (i = 0; i < availablePreviewFpsRanges.count; i += 2) {
@@ -1200,14 +1247,13 @@
         }
     }
 
-    // PREVIEW_FRAME_RATE Deprecated, only use if the preview fps range is
-    // unchanged this time.  The single-value FPS is the same as the minimum of
-    // the range.  To detect whether the application has changed the value of
-    // previewFps, compare against their last-set preview FPS.
-    if (!fpsRangeChanged) {
+    // PREVIEW_FRAME_RATE Deprecated
+    // - Use only if the single FPS value was set later than the FPS range
+    if (fpsUseSingleValue) {
         int previewFps = newParams.getPreviewFrameRate();
-        int lastSetPreviewFps = params.getPreviewFrameRate();
-        if (previewFps != lastSetPreviewFps || recordingHintChanged) {
+        ALOGV("%s: Preview FPS single value requested: %d",
+              __FUNCTION__, previewFps);
+        {
             camera_metadata_ro_entry_t availableFrameRates =
                 staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
             /**
@@ -1276,6 +1322,35 @@
         }
     }
 
+    /**
+     * Update Preview FPS and Preview FPS ranges based on
+     * what we actually set.
+     *
+     * This updates the API-visible (Camera.Parameters#getParameters) values of
+     * the FPS fields, not only the internal versions.
+     *
+     * Order matters: The value that was set last takes precedence.
+     * - If the client does a setParameters(getParameters()) we retain
+     *   the same order for preview FPS.
+     */
+    if (!fpsUseSingleValue) {
+        // Set fps single, then fps range (range wins)
+        validatedParams.params.setPreviewFrameRate(
+                fpsFromRange(/*min*/validatedParams.previewFpsRange[0],
+                             /*max*/validatedParams.previewFpsRange[1]));
+        validatedParams.params.setPreviewFpsRange(
+                validatedParams.previewFpsRange[0],
+                validatedParams.previewFpsRange[1]);
+    } else {
+        // Set fps range, then fps single (single wins)
+        validatedParams.params.setPreviewFpsRange(
+                validatedParams.previewFpsRange[0],
+                validatedParams.previewFpsRange[1]);
+        validatedParams.params.setPreviewFrameRate(
+                fpsFromRange(/*min*/validatedParams.previewFpsRange[0],
+                             /*max*/validatedParams.previewFpsRange[1]));
+    }
+
     // PICTURE_SIZE
     newParams.getPictureSize(&validatedParams.pictureWidth,
             &validatedParams.pictureHeight);
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index 6076dae..1844ea3 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -319,13 +319,15 @@
         // Create CPU buffer queue endpoint. We need one more buffer here so that we can
         // always acquire and free a buffer when the heap is full; otherwise the consumer
         // will have buffers in flight we'll never clear out.
-        sp<BufferQueue> bq = new BufferQueue();
-        mRecordingConsumer = new BufferItemConsumer(bq,
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        mRecordingConsumer = new BufferItemConsumer(consumer,
                 GRALLOC_USAGE_HW_VIDEO_ENCODER,
                 mRecordingHeapCount + 1);
         mRecordingConsumer->setFrameAvailableListener(this);
         mRecordingConsumer->setName(String8("Camera2-RecordingConsumer"));
-        mRecordingWindow = new Surface(bq);
+        mRecordingWindow = new Surface(producer);
         newConsumer = true;
         // Allocate memory later, since we don't know buffer size until receipt
     }
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 453d54c..07381ae 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -128,13 +128,15 @@
 
     if (mZslConsumer == 0) {
         // Create CPU buffer queue endpoint
-        sp<BufferQueue> bq = new BufferQueue();
-        mZslConsumer = new BufferItemConsumer(bq,
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
+        mZslConsumer = new BufferItemConsumer(consumer,
             GRALLOC_USAGE_HW_CAMERA_ZSL,
             kZslBufferDepth);
         mZslConsumer->setFrameAvailableListener(this);
         mZslConsumer->setName(String8("Camera2Client::ZslConsumer"));
-        mZslWindow = new Surface(bq);
+        mZslWindow = new Surface(producer);
     }
 
     if (mZslStreamId != NO_STREAM) {
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index e1c492b..dd7fb6c 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -203,10 +203,12 @@
     mFrameCount = 0;
 
     if (mConsumer.get() == 0) {
-        sp<BufferQueue> bq = new BufferQueue();
+        sp<IGraphicBufferProducer> producer;
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&producer, &consumer);
 
         int minUndequeuedBuffers = 0;
-        res = bq->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
+        res = producer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
         if (res != OK || minUndequeuedBuffers < 0) {
             ALOGE("%s: Stream %d: Could not query min undequeued buffers (error %d, bufCount %d)",
                   __FUNCTION__, mId, res, minUndequeuedBuffers);
@@ -226,7 +228,7 @@
             camera3_stream::max_buffers : minBufs;
         // TODO: somehow set the total buffer count when producer connects?
 
-        mConsumer = new BufferItemConsumer(bq, camera3_stream::usage,
+        mConsumer = new BufferItemConsumer(consumer, camera3_stream::usage,
                                            mTotalBufferCount);
         mConsumer->setName(String8::format("Camera3-InputStream-%d", mId));
     }
diff --git a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
index e509350..04deac5 100644
--- a/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3ZslStream.cpp
@@ -115,9 +115,11 @@
                             HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED),
         mDepth(bufferCount) {
 
-    sp<BufferQueue> bq = new BufferQueue();
-    mProducer = new RingBufferConsumer(bq, GRALLOC_USAGE_HW_CAMERA_ZSL, bufferCount);
-    mConsumer = new Surface(bq);
+    sp<IGraphicBufferProducer> producer;
+    sp<IGraphicBufferConsumer> consumer;
+    BufferQueue::createBufferQueue(&producer, &consumer);
+    mProducer = new RingBufferConsumer(consumer, GRALLOC_USAGE_HW_CAMERA_ZSL, bufferCount);
+    mConsumer = new Surface(producer);
 }
 
 Camera3ZslStream::~Camera3ZslStream() {