Merge "support for time lapse/slow motion when using SURFACE source"
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index 14b4306..587077a 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -24,7 +24,7 @@
     }
 }
 
-status_t SineSource::start(MetaData *params) {
+status_t SineSource::start(MetaData * /* params */) {
     CHECK(!mStarted);
 
     mGroup = new MediaBufferGroup;
@@ -58,7 +58,7 @@
 }
 
 status_t SineSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBuffer **out, const ReadOptions * /* options */) {
     *out = NULL;
 
     MediaBuffer *buffer;
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index b7a40c2..fdc352e 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -296,7 +296,7 @@
 }
 #else
 
-int main(int argc, char **argv) {
+int main(int /* argc */, char ** /* argv */) {
     android::ProcessState::self()->startThreadPool();
 
     OMXClient client;
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index dfc2066..fd86737 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -141,8 +141,8 @@
     static uint32_t getInputFramesLost(audio_io_handle_t ioHandle);
 
     static int newAudioSessionId();
-    static void acquireAudioSessionId(int audioSession);
-    static void releaseAudioSessionId(int audioSession);
+    static void acquireAudioSessionId(int audioSession, pid_t pid);
+    static void releaseAudioSessionId(int audioSession, pid_t pid);
 
     // types of io configuration change events received with ioConfigChanged()
     enum io_config_event {
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 5a50280..d0df710 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -190,7 +190,8 @@
                                     int sessionId        = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     const audio_offload_info_t *offloadInfo = NULL,
-                                    int uid = -1);
+                                    int uid = -1,
+                                    pid_t pid = -1);
 
     /* Creates an audio track and registers it with AudioFlinger.
      * With this constructor, the track is configured for static buffer mode.
@@ -215,7 +216,8 @@
                                     int sessionId       = AUDIO_SESSION_ALLOCATE,
                                     transfer_type transferType = TRANSFER_DEFAULT,
                                     const audio_offload_info_t *offloadInfo = NULL,
-                                    int uid = -1);
+                                    int uid = -1,
+                                    pid_t pid = -1);
 
     /* Terminates the AudioTrack and unregisters it from AudioFlinger.
      * Also destroys all resources associated with the AudioTrack.
@@ -253,7 +255,8 @@
                             int sessionId       = AUDIO_SESSION_ALLOCATE,
                             transfer_type transferType = TRANSFER_DEFAULT,
                             const audio_offload_info_t *offloadInfo = NULL,
-                            int uid = -1);
+                            int uid = -1,
+                            pid_t pid = -1);
 
     /* Result of constructing the AudioTrack. This must be checked for successful initialization
      * before using any AudioTrack API (except for set()), because using
@@ -757,6 +760,7 @@
     sp<DeathNotifier>       mDeathNotifier;
     uint32_t                mSequence;              // incremented for each new IAudioTrack attempt
     int                     mClientUid;
+    pid_t                   mClientPid;
 };
 
 class TimedAudioTrack : public AudioTrack
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index ea225ac..7f53bfc 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -180,8 +180,8 @@
 
     virtual int newAudioSessionId() = 0;
 
-    virtual void acquireAudioSessionId(int audioSession) = 0;
-    virtual void releaseAudioSessionId(int audioSession) = 0;
+    virtual void acquireAudioSessionId(int audioSession, pid_t pid) = 0;
+    virtual void releaseAudioSessionId(int audioSession, pid_t pid) = 0;
 
     virtual status_t queryNumberEffects(uint32_t *numEffects) const = 0;
 
diff --git a/include/media/nbaio/NBLog.h b/include/media/nbaio/NBLog.h
index 6d59ea7..bcbbc04 100644
--- a/include/media/nbaio/NBLog.h
+++ b/include/media/nbaio/NBLog.h
@@ -25,6 +25,8 @@
 
 namespace android {
 
+class String8;
+
 class NBLog {
 
 public:
@@ -187,6 +189,10 @@
     const Shared* const mShared; // raw pointer to shared memory
     const sp<IMemory> mIMemory; // ref-counted version
     int32_t     mFront;         // index of oldest acknowledged Entry
+    int     mFd;                // file descriptor
+    int     mIndent;            // indentation level
+
+    void    dumpLine(const String8& timestamp, String8& body);
 
     static const size_t kSquashTimestamp = 5; // squash this many or more adjacent timestamps
 };
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 69cfbd0..dd0a106 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -172,7 +172,7 @@
                  const sp<IGraphicBufferProducer>& surface,
                  bool storeMetaDataInVideoBuffers);
 
-    virtual void startCameraRecording();
+    virtual status_t startCameraRecording();
     virtual void releaseRecordingFrame(const sp<IMemory>& frame);
 
     // Returns true if need to skip the current frame.
diff --git a/include/media/stagefright/DataURISource.h b/include/media/stagefright/DataURISource.h
new file mode 100644
index 0000000..693562e
--- /dev/null
+++ b/include/media/stagefright/DataURISource.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef DATA_URI_SOURCE_H_
+
+#define DATA_URI_SOURCE_H_
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct ABuffer;
+
+struct DataURISource : public DataSource {
+    static sp<DataURISource> Create(const char *uri);
+
+    virtual status_t initCheck() const;
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+    virtual status_t getSize(off64_t *size);
+
+protected:
+    virtual ~DataURISource();
+
+private:
+    sp<ABuffer> mBuffer;
+
+    DataURISource(const sp<ABuffer> &buffer);
+
+    DISALLOW_EVIL_CONSTRUCTORS(DataURISource);
+};
+
+}  // namespace android
+
+#endif  // DATA_URI_SOURCE_H_
+
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
index 3818e63..204d1c6 100644
--- a/include/media/stagefright/MediaSource.h
+++ b/include/media/stagefright/MediaSource.h
@@ -105,7 +105,7 @@
     // This will be called after a successful start() and before the
     // first read() call.
     // Callee assumes ownership of the buffers if no error is returned.
-    virtual status_t setBuffers(const Vector<MediaBuffer *> &buffers) {
+    virtual status_t setBuffers(const Vector<MediaBuffer *> & /* buffers */) {
         return ERROR_UNSUPPORTED;
     }
 
diff --git a/media/libeffects/factory/Android.mk b/media/libeffects/factory/Android.mk
index 60a6ce5..a932af7 100644
--- a/media/libeffects/factory/Android.mk
+++ b/media/libeffects/factory/Android.mk
@@ -9,7 +9,6 @@
 LOCAL_SHARED_LIBRARIES := \
 	libcutils liblog
 
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
 LOCAL_MODULE:= libeffects
 
 LOCAL_SHARED_LIBRARIES += libdl
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index fc4b2a5..e0acae6 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -60,16 +60,12 @@
 
 LOCAL_SRC_FILES += ../libnbaio/roundup.c
 
-# for <cutils/atomic-inline.h>
-LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0)
-LOCAL_SRC_FILES += SingleStateQueue.cpp
-LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"'
-# Consider a separate a library for SingleStateQueueInstantiations.
-
 LOCAL_SHARED_LIBRARIES := \
 	libui liblog libcutils libutils libbinder libsonivox libicuuc libicui18n libexpat \
         libcamera_client libstagefright_foundation \
-        libgui libdl libaudioutils
+        libgui libdl libaudioutils libnbaio
+
+LOCAL_STATIC_LIBRARIES += libinstantssq
 
 LOCAL_WHOLE_STATIC_LIBRARY := libmedia_helper
 
@@ -84,3 +80,15 @@
     $(call include-path-for, audio-utils)
 
 include $(BUILD_SHARED_LIBRARY)
+
+include $(CLEAR_VARS)
+
+# for <cutils/atomic-inline.h>
+LOCAL_CFLAGS += -DANDROID_SMP=$(if $(findstring true,$(TARGET_CPU_SMP)),1,0)
+LOCAL_SRC_FILES += SingleStateQueue.cpp
+LOCAL_CFLAGS += -DSINGLE_STATE_QUEUE_INSTANTIATIONS='"SingleStateQueueInstantiations.cpp"'
+
+LOCAL_MODULE := libinstantssq
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 541cb51..700718d 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -115,7 +115,7 @@
             mAudioRecord.clear();
         }
         IPCThreadState::self()->flushCommands();
-        AudioSystem::releaseAudioSessionId(mSessionId);
+        AudioSystem::releaseAudioSessionId(mSessionId, -1);
     }
 }
 
@@ -266,7 +266,7 @@
     mMarkerReached = false;
     mNewPosition = 0;
     mUpdatePeriod = 0;
-    AudioSystem::acquireAudioSessionId(mSessionId);
+    AudioSystem::acquireAudioSessionId(mSessionId, -1);
     mSequence = 1;
     mObservedSequence = mSequence;
     mInOverrun = false;
@@ -462,7 +462,9 @@
     audio_io_handle_t input = AudioSystem::getInput(mInputSource, mSampleRate, mFormat,
             mChannelMask, mSessionId);
     if (input == 0) {
-        ALOGE("Could not get audio input for record source %d", mInputSource);
+        ALOGE("Could not get audio input for record source %d, sample rate %u, format %#x, "
+              "channel mask %#x, session %d",
+              mInputSource, mSampleRate, mFormat, mChannelMask, mSessionId);
         return BAD_VALUE;
     }
     {
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 87f4b4c..140fb66 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -435,19 +435,19 @@
     return af->newAudioSessionId();
 }
 
-void AudioSystem::acquireAudioSessionId(int audioSession)
+void AudioSystem::acquireAudioSessionId(int audioSession, pid_t pid)
 {
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af != 0) {
-        af->acquireAudioSessionId(audioSession);
+        af->acquireAudioSessionId(audioSession, pid);
     }
 }
 
-void AudioSystem::releaseAudioSessionId(int audioSession)
+void AudioSystem::releaseAudioSessionId(int audioSession, pid_t pid)
 {
     const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
     if (af != 0) {
-        af->releaseAudioSessionId(audioSession);
+        af->releaseAudioSessionId(audioSession, pid);
     }
 }
 
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 63eaf1a..5c62260 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -116,7 +116,8 @@
         int sessionId,
         transfer_type transferType,
         const audio_offload_info_t *offloadInfo,
-        int uid)
+        int uid,
+        pid_t pid)
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
@@ -125,7 +126,7 @@
     mStatus = set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
             0 /*sharedBuffer*/, false /*threadCanCallJava*/, sessionId, transferType,
-            offloadInfo, uid);
+            offloadInfo, uid, pid);
 }
 
 AudioTrack::AudioTrack(
@@ -141,7 +142,8 @@
         int sessionId,
         transfer_type transferType,
         const audio_offload_info_t *offloadInfo,
-        int uid)
+        int uid,
+        pid_t pid)
     : mStatus(NO_INIT),
       mIsTimed(false),
       mPreviousPriority(ANDROID_PRIORITY_NORMAL),
@@ -149,7 +151,8 @@
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             0 /*frameCount*/, flags, cbf, user, notificationFrames,
-            sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo, uid);
+            sharedBuffer, false /*threadCanCallJava*/, sessionId, transferType, offloadInfo,
+            uid, pid);
 }
 
 AudioTrack::~AudioTrack()
@@ -168,7 +171,9 @@
         mAudioTrack->asBinder()->unlinkToDeath(mDeathNotifier, this);
         mAudioTrack.clear();
         IPCThreadState::self()->flushCommands();
-        AudioSystem::releaseAudioSessionId(mSessionId);
+        ALOGV("~AudioTrack, releasing session id from %d on behalf of %d",
+                IPCThreadState::self()->getCallingPid(), mClientPid);
+        AudioSystem::releaseAudioSessionId(mSessionId, mClientPid);
     }
 }
 
@@ -187,7 +192,8 @@
         int sessionId,
         transfer_type transferType,
         const audio_offload_info_t *offloadInfo,
-        int uid)
+        int uid,
+        pid_t pid)
 {
     switch (transferType) {
     case TRANSFER_DEFAULT:
@@ -335,11 +341,18 @@
     mNotificationFramesReq = notificationFrames;
     mNotificationFramesAct = 0;
     mSessionId = sessionId;
-    if (uid == -1 || (IPCThreadState::self()->getCallingPid() != getpid())) {
+    int callingpid = IPCThreadState::self()->getCallingPid();
+    int mypid = getpid();
+    if (uid == -1 || (callingpid != mypid)) {
         mClientUid = IPCThreadState::self()->getCallingUid();
     } else {
         mClientUid = uid;
     }
+    if (pid == -1 || (callingpid != mypid)) {
+        mClientPid = callingpid;
+    } else {
+        mClientPid = pid;
+    }
     mAuxEffectId = 0;
     mFlags = flags;
     mCbf = cbf;
@@ -379,7 +392,7 @@
     mMarkerReached = false;
     mNewPosition = 0;
     mUpdatePeriod = 0;
-    AudioSystem::acquireAudioSessionId(mSessionId);
+    AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
     mSequence = 1;
     mObservedSequence = mSequence;
     mInUnderrun = false;
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index eef6a3d..e696323 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -609,19 +609,21 @@
         return id;
     }
 
-    virtual void acquireAudioSessionId(int audioSession)
+    virtual void acquireAudioSessionId(int audioSession, int pid)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(audioSession);
+        data.writeInt32(pid);
         remote()->transact(ACQUIRE_AUDIO_SESSION_ID, data, &reply);
     }
 
-    virtual void releaseAudioSessionId(int audioSession)
+    virtual void releaseAudioSessionId(int audioSession, int pid)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
         data.writeInt32(audioSession);
+        data.writeInt32(pid);
         remote()->transact(RELEASE_AUDIO_SESSION_ID, data, &reply);
     }
 
@@ -986,7 +988,7 @@
                                                  &latency,
                                                  flags,
                                                  hasOffloadInfo ? &offloadInfo : NULL);
-            ALOGV("OPEN_OUTPUT output, %p", output);
+            ALOGV("OPEN_OUTPUT output, %d", output);
             reply->writeInt32((int32_t) output);
             reply->writeInt32(devices);
             reply->writeInt32(samplingRate);
@@ -1082,13 +1084,15 @@
         case ACQUIRE_AUDIO_SESSION_ID: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int audioSession = data.readInt32();
-            acquireAudioSessionId(audioSession);
+            int pid = data.readInt32();
+            acquireAudioSessionId(audioSession, pid);
             return NO_ERROR;
         } break;
         case RELEASE_AUDIO_SESSION_ID: {
             CHECK_INTERFACE(IAudioFlinger, data, reply);
             int audioSession = data.readInt32();
-            releaseAudioSessionId(audioSession);
+            int pid = data.readInt32();
+            releaseAudioSessionId(audioSession, pid);
             return NO_ERROR;
         } break;
         case QUERY_NUM_EFFECTS: {
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 24663ad..d94c7c5 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -58,7 +58,7 @@
     mVideoWidth = mVideoHeight = 0;
     mLockThreadId = 0;
     mAudioSessionId = AudioSystem::newAudioSessionId();
-    AudioSystem::acquireAudioSessionId(mAudioSessionId);
+    AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
     mSendLevel = 0;
     mRetransmitEndpointValid = false;
 }
@@ -66,7 +66,7 @@
 MediaPlayer::~MediaPlayer()
 {
     ALOGV("destructor");
-    AudioSystem::releaseAudioSessionId(mAudioSessionId);
+    AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
     disconnect();
     IPCThreadState::self()->flushCommands();
 }
@@ -576,8 +576,8 @@
         return BAD_VALUE;
     }
     if (sessionId != mAudioSessionId) {
-        AudioSystem::acquireAudioSessionId(sessionId);
-        AudioSystem::releaseAudioSessionId(mAudioSessionId);
+        AudioSystem::acquireAudioSessionId(sessionId, -1);
+        AudioSystem::releaseAudioSessionId(mAudioSessionId, -1);
         mAudioSessionId = sessionId;
     }
     return NO_ERROR;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 1f70620..142788d 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -586,7 +586,8 @@
     }
 
     if (!p->hardwareOutput()) {
-        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid());
+        mAudioOutput = new AudioOutput(mAudioSessionId, IPCThreadState::self()->getCallingUid(),
+                mPid);
         static_cast<MediaPlayerInterface*>(p.get())->setAudioSink(mAudioOutput);
     }
 
@@ -1299,13 +1300,14 @@
 
 #undef LOG_TAG
 #define LOG_TAG "AudioSink"
-MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid)
+MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid)
     : mCallback(NULL),
       mCallbackCookie(NULL),
       mCallbackData(NULL),
       mBytesWritten(0),
       mSessionId(sessionId),
       mUid(uid),
+      mPid(pid),
       mFlags(AUDIO_OUTPUT_FLAG_NONE) {
     ALOGV("AudioOutput(%d)", sessionId);
     mStreamType = AUDIO_STREAM_MUSIC;
@@ -1554,7 +1556,8 @@
                     mSessionId,
                     AudioTrack::TRANSFER_CALLBACK,
                     offloadInfo,
-                    mUid);
+                    mUid,
+                    mPid);
         } else {
             t = new AudioTrack(
                     mStreamType,
@@ -1569,7 +1572,8 @@
                     mSessionId,
                     AudioTrack::TRANSFER_DEFAULT,
                     NULL, // offload info
-                    mUid);
+                    mUid,
+                    mPid);
         }
 
         if ((t == 0) || (t->initCheck() != NO_ERROR)) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index fc355b0..448f27a 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -72,7 +72,7 @@
         class CallbackData;
 
      public:
-                                AudioOutput(int sessionId, int uid);
+                                AudioOutput(int sessionId, int uid, int pid);
         virtual                 ~AudioOutput();
 
         virtual bool            ready() const { return mTrack != 0; }
@@ -140,6 +140,7 @@
         float                   mMsecsPerFrame;
         int                     mSessionId;
         int                     mUid;
+        int                     mPid;
         float                   mSendLevel;
         int                     mAuxEffectId;
         static bool             mIsOnEmulator;
diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp
index b19e8bf..b37aee3 100644
--- a/media/libmediaplayerservice/StagefrightPlayer.cpp
+++ b/media/libmediaplayerservice/StagefrightPlayer.cpp
@@ -189,7 +189,7 @@
 }
 
 status_t StagefrightPlayer::getMetadata(
-        const media::Metadata::Filter& ids, Parcel *records) {
+        const media::Metadata::Filter& /* ids */, Parcel *records) {
     using media::Metadata;
 
     uint32_t flags = mPlayer->flags();
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index a20c1d2..845a589 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -243,7 +243,7 @@
     return OK;
 }
 
-status_t StagefrightRecorder::setOutputFile(const char *path) {
+status_t StagefrightRecorder::setOutputFile(const char * /* path */) {
     ALOGE("setOutputFile(const char*) must not be called");
     // We don't actually support this at all, as the media_server process
     // no longer has permissions to create files.
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index f946c1c..f97ba57 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -11,7 +11,6 @@
         NuPlayerStreamListener.cpp      \
         RTSPSource.cpp                  \
         StreamingSource.cpp             \
-        mp4/MP4Source.cpp               \
 
 LOCAL_C_INCLUDES := \
 	$(TOP)/frameworks/av/media/libstagefright/httplive            \
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index ac2aab8..cbedf5c 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -139,7 +139,7 @@
     // LiveSession::selectTrack returns BAD_VALUE when selecting the currently
     // selected track, or unselecting a non-selected track. In this case it's an
     // no-op so we return OK.
-    return (err == OK || err == BAD_VALUE) ? OK : err;
+    return (err == OK || err == BAD_VALUE) ? (status_t)OK : err;
 }
 
 status_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 817395a..d47ac98 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -28,13 +28,11 @@
 #include "RTSPSource.h"
 #include "StreamingSource.h"
 #include "GenericSource.h"
-#include "mp4/MP4Source.h"
 
 #include "ATSParser.h"
 
 #include "SoftwareRenderer.h"
 
-#include <cutils/properties.h> // for property_get
 #include <media/stagefright/foundation/hexdump.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -183,14 +181,7 @@
 
     sp<AMessage> notify = new AMessage(kWhatSourceNotify, id());
 
-    char prop[PROPERTY_VALUE_MAX];
-    if (property_get("media.stagefright.use-mp4source", prop, NULL)
-            && (!strcmp(prop, "1") || !strcasecmp(prop, "true"))) {
-        msg->setObject("source", new MP4Source(notify, source));
-    } else {
-        msg->setObject("source", new StreamingSource(notify, source));
-    }
-
+    msg->setObject("source", new StreamingSource(notify, source));
     msg->post();
 }
 
@@ -1528,7 +1519,7 @@
     notify->post();
 }
 
-void NuPlayer::Source::onMessageReceived(const sp<AMessage> &msg) {
+void NuPlayer::Source::onMessageReceived(const sp<AMessage> & /* msg */) {
     TRESPASS();
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 9ef8dbd..e4850f0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -367,7 +367,7 @@
     return OK;
 }
 
-status_t NuPlayerDriver::setLooping(int loop) {
+status_t NuPlayerDriver::setLooping(int /* loop */) {
     return INVALID_OPERATION;
 }
 
@@ -423,16 +423,17 @@
     mPlayer->setAudioSink(audioSink);
 }
 
-status_t NuPlayerDriver::setParameter(int key, const Parcel &request) {
+status_t NuPlayerDriver::setParameter(
+        int /* key */, const Parcel & /* request */) {
     return INVALID_OPERATION;
 }
 
-status_t NuPlayerDriver::getParameter(int key, Parcel *reply) {
+status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) {
     return INVALID_OPERATION;
 }
 
 status_t NuPlayerDriver::getMetadata(
-        const media::Metadata::Filter& ids, Parcel *records) {
+        const media::Metadata::Filter& /* ids */, Parcel *records) {
     Mutex::Autolock autoLock(mLock);
 
     using media::Metadata;
@@ -496,7 +497,8 @@
     mNumFramesDropped = numFramesDropped;
 }
 
-status_t NuPlayerDriver::dump(int fd, const Vector<String16> &args) const {
+status_t NuPlayerDriver::dump(
+        int fd, const Vector<String16> & /* args */) const {
     Mutex::Autolock autoLock(mLock);
 
     FILE *out = fdopen(dup(fd), "w");
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index e50533a..11279fc 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -68,19 +68,19 @@
     virtual status_t dequeueAccessUnit(
             bool audio, sp<ABuffer> *accessUnit) = 0;
 
-    virtual status_t getDuration(int64_t *durationUs) {
+    virtual status_t getDuration(int64_t * /* durationUs */) {
         return INVALID_OPERATION;
     }
 
-    virtual status_t getTrackInfo(Parcel* reply) const {
+    virtual status_t getTrackInfo(Parcel* /* reply */) const {
         return INVALID_OPERATION;
     }
 
-    virtual status_t selectTrack(size_t trackIndex, bool select) {
+    virtual status_t selectTrack(size_t /* trackIndex */, bool /* select */) {
         return INVALID_OPERATION;
     }
 
-    virtual status_t seekTo(int64_t seekTimeUs) {
+    virtual status_t seekTo(int64_t /* seekTimeUs */) {
         return INVALID_OPERATION;
     }
 
@@ -93,7 +93,7 @@
 
     virtual void onMessageReceived(const sp<AMessage> &msg);
 
-    virtual sp<MetaData> getFormatMeta(bool audio) { return NULL; }
+    virtual sp<MetaData> getFormatMeta(bool /* audio */) { return NULL; }
 
     sp<AMessage> dupNotify() const { return mNotify->dup(); }
 
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
deleted file mode 100644
index 2aae4dd..0000000
--- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "MP4Source.h"
-
-#include "FragmentedMP4Parser.h"
-#include "../NuPlayerStreamListener.h"
-
-#include <media/IStreamSource.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
-
-namespace android {
-
-struct StreamSource : public FragmentedMP4Parser::Source {
-    StreamSource(const sp<IStreamSource> &source)
-        : mListener(new NuPlayer::NuPlayerStreamListener(source, 0)),
-          mPosition(0) {
-        mListener->start();
-    }
-
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
-        if (offset < mPosition) {
-            return -EPIPE;
-        }
-
-        while (offset > mPosition) {
-            char buffer[1024];
-            off64_t skipBytes = offset - mPosition;
-            if (skipBytes > sizeof(buffer)) {
-                skipBytes = sizeof(buffer);
-            }
-
-            sp<AMessage> extra;
-            ssize_t n;
-            for (;;) {
-                n = mListener->read(buffer, skipBytes, &extra);
-
-                if (n == -EWOULDBLOCK) {
-                    usleep(10000);
-                    continue;
-                }
-
-                break;
-            }
-
-            ALOGV("skipped %ld bytes at offset %lld", n, mPosition);
-
-            if (n < 0) {
-                return n;
-            }
-
-            mPosition += n;
-        }
-
-        sp<AMessage> extra;
-        size_t total = 0;
-        while (total < size) {
-            ssize_t n = mListener->read(
-                    (uint8_t *)data + total, size - total, &extra);
-
-            if (n == -EWOULDBLOCK) {
-                usleep(10000);
-                continue;
-            } else if (n == 0) {
-                break;
-            } else if (n < 0) {
-                mPosition += total;
-                return n;
-            }
-
-            total += n;
-        }
-
-        ALOGV("read %ld bytes at offset %lld", total, mPosition);
-
-        mPosition += total;
-
-        return total;
-    }
-
-    bool isSeekable() {
-        return false;
-    }
-
-private:
-    sp<NuPlayer::NuPlayerStreamListener> mListener;
-    off64_t mPosition;
-
-    DISALLOW_EVIL_CONSTRUCTORS(StreamSource);
-};
-
-MP4Source::MP4Source(
-        const sp<AMessage> &notify, const sp<IStreamSource> &source)
-    : Source(notify),
-      mSource(source),
-      mLooper(new ALooper),
-      mParser(new FragmentedMP4Parser),
-      mEOS(false) {
-    mLooper->registerHandler(mParser);
-}
-
-MP4Source::~MP4Source() {
-}
-
-void MP4Source::prepareAsync() {
-    notifyVideoSizeChanged(0, 0);
-    notifyFlagsChanged(0);
-    notifyPrepared();
-}
-
-void MP4Source::start() {
-    mLooper->start(false /* runOnCallingThread */);
-    mParser->start(new StreamSource(mSource));
-}
-
-status_t MP4Source::feedMoreTSData() {
-    return mEOS ? ERROR_END_OF_STREAM : (status_t)OK;
-}
-
-sp<AMessage> MP4Source::getFormat(bool audio) {
-    return mParser->getFormat(audio);
-}
-
-status_t MP4Source::dequeueAccessUnit(
-        bool audio, sp<ABuffer> *accessUnit) {
-    return mParser->dequeueAccessUnit(audio, accessUnit);
-}
-
-}  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
deleted file mode 100644
index a6ef622..0000000
--- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef MP4_SOURCE_H
-#define MP4_SOURCE_H
-
-#include "NuPlayerSource.h"
-
-namespace android {
-
-struct FragmentedMP4Parser;
-
-struct MP4Source : public NuPlayer::Source {
-    MP4Source(const sp<AMessage> &notify, const sp<IStreamSource> &source);
-
-    virtual void prepareAsync();
-    virtual void start();
-
-    virtual status_t feedMoreTSData();
-
-    virtual sp<AMessage> getFormat(bool audio);
-
-    virtual status_t dequeueAccessUnit(
-            bool audio, sp<ABuffer> *accessUnit);
-
-protected:
-    virtual ~MP4Source();
-
-private:
-    sp<IStreamSource> mSource;
-    sp<ALooper> mLooper;
-    sp<FragmentedMP4Parser> mParser;
-    bool mEOS;
-
-    DISALLOW_EVIL_CONSTRUCTORS(MP4Source);
-};
-
-}  // namespace android
-
-#endif // MP4_SOURCE_H
diff --git a/media/libnbaio/Android.mk b/media/libnbaio/Android.mk
index 69c75b8..9707c4a 100644
--- a/media/libnbaio/Android.mk
+++ b/media/libnbaio/Android.mk
@@ -31,9 +31,8 @@
     libcommon_time_client \
     libcutils \
     libutils \
-    liblog \
-    libmedia
-# This dependency on libmedia is for SingleStateQueueInstantiations.
-# Consider a separate a library for SingleStateQueueInstantiations.
+    liblog
+
+LOCAL_STATIC_LIBRARIES += libinstantssq
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libnbaio/NBLog.cpp b/media/libnbaio/NBLog.cpp
index 190824d..96738a7 100644
--- a/media/libnbaio/NBLog.cpp
+++ b/media/libnbaio/NBLog.cpp
@@ -26,6 +26,7 @@
 #include <cutils/atomic.h>
 #include <media/nbaio/NBLog.h>
 #include <utils/Log.h>
+#include <utils/String8.h>
 
 namespace android {
 
@@ -337,25 +338,25 @@
         }
         i -= length + 3;
     }
-    if (i > 0) {
-        lost += i;
-        if (fd >= 0) {
-            fdprintf(fd, "%*swarning: lost %zu bytes worth of events\n", indent, "", lost);
-        } else {
-            ALOGI("%*swarning: lost %u bytes worth of events\n", indent, "", lost);
-        }
+    mFd = fd;
+    mIndent = indent;
+    String8 timestamp, body;
+    lost += i;
+    if (lost > 0) {
+        body.appendFormat("warning: lost %u bytes worth of events", lost);
+        // TODO timestamp empty here, only other choice to wait for the first timestamp event in the
+        //      log to push it out.  Consider keeping the timestamp/body between calls to readAt().
+        dumpLine(timestamp, body);
     }
     size_t width = 1;
     while (maxSec >= 10) {
         ++width;
         maxSec /= 10;
     }
-    char prefix[32];
     if (maxSec >= 0) {
-        snprintf(prefix, sizeof(prefix), "[%*s] ", width + 4, "");
-    } else {
-        prefix[0] = '\0';
+        timestamp.appendFormat("[%*s]", width + 4, "");
     }
+    bool deferredTimestamp = false;
     while (i < avail) {
         event = (Event) copy[i];
         length = copy[i + 1];
@@ -363,11 +364,8 @@
         size_t advance = length + 3;
         switch (event) {
         case EVENT_STRING:
-            if (fd >= 0) {
-                fdprintf(fd, "%*s%s%.*s\n", indent, "", prefix, length, (const char *) data);
-            } else {
-                ALOGI("%*s%s%.*s", indent, "", prefix, length, (const char *) data);
-            } break;
+            body.appendFormat("%.*s", length, (const char *) data);
+            break;
         case EVENT_TIMESTAMP: {
             // already checked that length == sizeof(struct timespec);
             memcpy(&ts, data, sizeof(struct timespec));
@@ -400,45 +398,53 @@
                 prevNsec = tsNext.tv_nsec;
             }
             size_t n = (j - i) / (sizeof(struct timespec) + 3);
+            if (deferredTimestamp) {
+                dumpLine(timestamp, body);
+                deferredTimestamp = false;
+            }
+            timestamp.clear();
             if (n >= kSquashTimestamp) {
-                if (fd >= 0) {
-                    fdprintf(fd, "%*s[%d.%03d to .%.03d by .%.03d to .%.03d]\n", indent, "",
-                            (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
-                            (int) ((ts.tv_nsec + deltaTotal) / 1000000),
-                            (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
-                } else {
-                    ALOGI("%*s[%d.%03d to .%.03d by .%.03d to .%.03d]\n", indent, "",
-                            (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
-                            (int) ((ts.tv_nsec + deltaTotal) / 1000000),
-                            (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
-                }
+                timestamp.appendFormat("[%d.%03d to .%.03d by .%.03d to .%.03d]",
+                        (int) ts.tv_sec, (int) (ts.tv_nsec / 1000000),
+                        (int) ((ts.tv_nsec + deltaTotal) / 1000000),
+                        (int) (deltaMin / 1000000), (int) (deltaMax / 1000000));
                 i = j;
                 advance = 0;
                 break;
             }
-            if (fd >= 0) {
-                fdprintf(fd, "%*s[%d.%03d]\n", indent, "", (int) ts.tv_sec,
-                        (int) (ts.tv_nsec / 1000000));
-            } else {
-                ALOGI("%*s[%d.%03d]", indent, "", (int) ts.tv_sec,
-                        (int) (ts.tv_nsec / 1000000));
-            }
+            timestamp.appendFormat("[%d.%03d]", (int) ts.tv_sec,
+                    (int) (ts.tv_nsec / 1000000));
+            deferredTimestamp = true;
             } break;
         case EVENT_RESERVED:
         default:
-            if (fd >= 0) {
-                fdprintf(fd, "%*s%swarning: unknown event %d\n", indent, "", prefix, event);
-            } else {
-                ALOGI("%*s%swarning: unknown event %d", indent, "", prefix, event);
-            }
+            body.appendFormat("warning: unknown event %d", event);
             break;
         }
         i += advance;
+
+        if (!body.isEmpty()) {
+            dumpLine(timestamp, body);
+            deferredTimestamp = false;
+        }
+    }
+    if (deferredTimestamp) {
+        dumpLine(timestamp, body);
     }
     // FIXME it would be more efficient to put a char mCopy[256] as a member variable of the dumper
     delete[] copy;
 }
 
+void NBLog::Reader::dumpLine(const String8& timestamp, String8& body)
+{
+    if (mFd >= 0) {
+        fdprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
+    } else {
+        ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
+    }
+    body.clear();
+}
+
 bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
 {
     return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 4d1072f..196f6ee 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -219,7 +219,7 @@
     return new AACSource(mDataSource, mMeta, mOffsetVector, mFrameDurationUs);
 }
 
-sp<MetaData> AACExtractor::getTrackMetaData(size_t index, uint32_t flags) {
+sp<MetaData> AACExtractor::getTrackMetaData(size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -252,7 +252,7 @@
     }
 }
 
-status_t AACSource::start(MetaData *params) {
+status_t AACSource::start(MetaData * /* params */) {
     CHECK(!mStarted);
 
     if (mOffsetVector.empty()) {
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index c9bcaba..deee8e7 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -111,7 +111,7 @@
     return OK;
 }
 
-status_t AACWriter::start(MetaData *params) {
+status_t AACWriter::start(MetaData * /* params */) {
     if (mInitCheck != OK) {
         return mInitCheck;
     }
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 3d5b3b3..4450d62 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1177,7 +1177,7 @@
             if (canDoAdaptivePlayback &&
                 msg->findInt32("max-width", &maxWidth) &&
                 msg->findInt32("max-height", &maxHeight)) {
-                ALOGV("[%s] prepareForAdaptivePlayback(%ldx%ld)",
+                ALOGV("[%s] prepareForAdaptivePlayback(%dx%d)",
                       mComponentName.c_str(), maxWidth, maxHeight);
 
                 err = mOMX->prepareForAdaptivePlayback(
@@ -2974,7 +2974,8 @@
       mCodec(codec) {
 }
 
-ACodec::BaseState::PortMode ACodec::BaseState::getPortMode(OMX_U32 portIndex) {
+ACodec::BaseState::PortMode ACodec::BaseState::getPortMode(
+        OMX_U32 /* portIndex */) {
     return KEEP_BUFFERS;
 }
 
@@ -3383,8 +3384,8 @@
         size_t rangeOffset, size_t rangeLength,
         OMX_U32 flags,
         int64_t timeUs,
-        void *platformPrivate,
-        void *dataPtr) {
+        void * /* platformPrivate */,
+        void * /* dataPtr */) {
     ALOGV("[%s] onOMXFillBufferDone %p time %lld us, flags = 0x%08lx",
          mCodec->mComponentName.c_str(), bufferID, timeUs, flags);
 
@@ -3917,7 +3918,7 @@
 }
 
 void ACodec::LoadedState::onCreateInputSurface(
-        const sp<AMessage> &msg) {
+        const sp<AMessage> & /* msg */) {
     ALOGV("onCreateInputSurface");
 
     sp<AMessage> notify = mCodec->mNotify->dup();
@@ -4180,7 +4181,7 @@
 }
 
 ACodec::BaseState::PortMode ACodec::ExecutingState::getPortMode(
-        OMX_U32 portIndex) {
+        OMX_U32 /* portIndex */) {
     return RESUBMIT_BUFFERS;
 }
 
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index 03dcbf9..3f592ed 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -189,7 +189,7 @@
             mOffsetTable, mOffsetTableLength);
 }
 
-sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t flags) {
+sp<MetaData> AMRExtractor::getTrackMetaData(size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
@@ -221,7 +221,7 @@
     }
 }
 
-status_t AMRSource::start(MetaData *params) {
+status_t AMRSource::start(MetaData * /* params */) {
     CHECK(!mStarted);
 
     mOffset = mIsWide ? 9 : 6;
@@ -258,7 +258,7 @@
         int64_t seekFrame = seekTimeUs / 20000ll;  // 20ms per frame.
         mCurrentTimeUs = seekFrame * 20000ll;
 
-        int index = seekFrame / 50;
+        size_t index = seekFrame < 0 ? 0 : seekFrame / 50;
         if (index >= mOffsetTableLength) {
             index = mOffsetTableLength - 1;
         }
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index 3fe247a..653ca36 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -105,7 +105,7 @@
     return OK;
 }
 
-status_t AMRWriter::start(MetaData *params) {
+status_t AMRWriter::start(MetaData * /* params */) {
     if (mInitCheck != OK) {
         return mInitCheck;
     }
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 63f9399..0636dcc 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -15,6 +15,7 @@
         CameraSource.cpp                  \
         CameraSourceTimeLapse.cpp         \
         DataSource.cpp                    \
+        DataURISource.cpp                 \
         DRMExtractor.cpp                  \
         ESDS.cpp                          \
         FileSource.cpp                    \
@@ -57,8 +58,6 @@
         WVMExtractor.cpp                  \
         XINGSeeker.cpp                    \
         avc_utils.cpp                     \
-        mp4/FragmentedMP4Parser.cpp       \
-        mp4/TrackFragment.cpp             \
 
 LOCAL_C_INCLUDES:= \
         $(TOP)/frameworks/av/include/media/stagefright/timedtext \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index 05ee34e..8623100 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -410,7 +410,7 @@
 
 // static
 size_t AudioPlayer::AudioSinkCallback(
-        MediaPlayerBase::AudioSink *audioSink,
+        MediaPlayerBase::AudioSink * /* audioSink */,
         void *buffer, size_t size, void *cookie,
         MediaPlayerBase::AudioSink::cb_event_t event) {
     AudioPlayer *me = (AudioPlayer *)cookie;
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 6fdee6b..df7da0a 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -68,7 +68,7 @@
         int frameCount = kMaxBufferSize / sizeof(int16_t) / channelCount;
 
         // make sure that the AudioRecord total buffer size is large enough
-        int bufCount = 2;
+        size_t bufCount = 2;
         while ((bufCount * frameCount) < minFrameCount) {
             bufCount++;
         }
@@ -208,7 +208,7 @@
 }
 
 status_t AudioSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
+        MediaBuffer **out, const ReadOptions * /* options */) {
     Mutex::Autolock autoLock(mLock);
     *out = NULL;
 
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index f57ee25..e83ec62 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -86,7 +86,7 @@
 protected:
     virtual ~AwesomeEvent() {}
 
-    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+    virtual void fire(TimedEventQueue * /* queue */, int64_t /* now_us */) {
         (mPlayer->*mMethod)();
     }
 
@@ -2813,7 +2813,8 @@
     return mCachedSource != NULL || mWVMExtractor != NULL;
 }
 
-status_t AwesomePlayer::dump(int fd, const Vector<String16> &args) const {
+status_t AwesomePlayer::dump(
+        int fd, const Vector<String16> & /* args */) const {
     Mutex::Autolock autoLock(mStatsLock);
 
     FILE *out = fdopen(dup(fd), "w");
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 3017fe7..b31e9e8 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -31,6 +31,12 @@
 #include <utils/String8.h>
 #include <cutils/properties.h>
 
+#if LOG_NDEBUG
+#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
+#else
+#define UNUSED_UNLESS_VERBOSE(x)
+#endif
+
 namespace android {
 
 static const int64_t CAMERA_SOURCE_TIMEOUT_NS = 3000000000LL;
@@ -63,11 +69,14 @@
 }
 
 void CameraSourceListener::notify(int32_t msgType, int32_t ext1, int32_t ext2) {
+    UNUSED_UNLESS_VERBOSE(msgType);
+    UNUSED_UNLESS_VERBOSE(ext1);
+    UNUSED_UNLESS_VERBOSE(ext2);
     ALOGV("notify(%d, %d, %d)", msgType, ext1, ext2);
 }
 
 void CameraSourceListener::postData(int32_t msgType, const sp<IMemory> &dataPtr,
-                                    camera_frame_metadata_t *metadata) {
+                                    camera_frame_metadata_t * /* metadata */) {
     ALOGV("postData(%d, ptr:%p, size:%d)",
          msgType, dataPtr->pointer(), dataPtr->size());
 
@@ -577,14 +586,15 @@
     }
 }
 
-void CameraSource::startCameraRecording() {
+status_t CameraSource::startCameraRecording() {
     ALOGV("startCameraRecording");
     // Reset the identity to the current thread because media server owns the
     // camera and recording is started by the applications. The applications
     // will connect to the camera in ICameraRecordingProxy::startRecording.
     int64_t token = IPCThreadState::self()->clearCallingIdentity();
+    status_t err;
     if (mNumInputBuffers > 0) {
-        status_t err = mCamera->sendCommand(
+        err = mCamera->sendCommand(
             CAMERA_CMD_SET_VIDEO_BUFFER_COUNT, mNumInputBuffers, 0);
 
         // This could happen for CameraHAL1 clients; thus the failure is
@@ -595,17 +605,25 @@
         }
     }
 
+    err = OK;
     if (mCameraFlags & FLAGS_HOT_CAMERA) {
         mCamera->unlock();
         mCamera.clear();
-        CHECK_EQ((status_t)OK,
-            mCameraRecordingProxy->startRecording(new ProxyListener(this)));
+        if ((err = mCameraRecordingProxy->startRecording(
+                new ProxyListener(this))) != OK) {
+            ALOGE("Failed to start recording, received error: %s (%d)",
+                    strerror(-err), err);
+        }
     } else {
         mCamera->setListener(new CameraSourceListener(this));
         mCamera->startRecording();
-        CHECK(mCamera->recordingEnabled());
+        if (!mCamera->recordingEnabled()) {
+            err = -EINVAL;
+            ALOGE("Failed to start recording");
+        }
     }
     IPCThreadState::self()->restoreCallingIdentity(token);
+    return err;
 }
 
 status_t CameraSource::start(MetaData *meta) {
@@ -637,10 +655,12 @@
         }
     }
 
-    startCameraRecording();
+    status_t err;
+    if ((err = startCameraRecording()) == OK) {
+        mStarted = true;
+    }
 
-    mStarted = true;
-    return OK;
+    return err;
 }
 
 void CameraSource::stopCameraRecording() {
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 86844b8..60cdf66 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -232,7 +232,7 @@
     return newMemory;
 }
 
-bool CameraSourceTimeLapse::skipCurrentFrame(int64_t timestampUs) {
+bool CameraSourceTimeLapse::skipCurrentFrame(int64_t /* timestampUs */) {
     ALOGV("skipCurrentFrame");
     if (mSkipCurrentFrame) {
         mSkipCurrentFrame = false;
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 2704b74..6e0f37a 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -35,6 +35,7 @@
 #include <media/IMediaHTTPService.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
+#include <media/stagefright/DataURISource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MediaHTTP.h>
@@ -221,6 +222,8 @@
             // in the widevine:// case.
             source = httpSource;
         }
+    } else if (!strncasecmp("data:", uri, 5)) {
+        source = DataURISource::Create(uri);
     } else {
         // Assume it's a filename.
         source = new FileSource(uri);
diff --git a/media/libstagefright/DataURISource.cpp b/media/libstagefright/DataURISource.cpp
new file mode 100644
index 0000000..377bc85
--- /dev/null
+++ b/media/libstagefright/DataURISource.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <media/stagefright/DataURISource.h>
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+
+namespace android {
+
+// static
+sp<DataURISource> DataURISource::Create(const char *uri) {
+    if (strncasecmp("data:", uri, 5)) {
+        return NULL;
+    }
+
+    char *commaPos = strrchr(uri, ',');
+
+    if (commaPos == NULL) {
+        return NULL;
+    }
+
+    sp<ABuffer> buffer;
+
+    AString tmp(&uri[5], commaPos - &uri[5]);
+
+    if (tmp.endsWith(";base64")) {
+        AString encoded(commaPos + 1);
+
+        // Strip CR and LF...
+        for (size_t i = encoded.size(); i-- > 0;) {
+            if (encoded.c_str()[i] == '\r' || encoded.c_str()[i] == '\n') {
+                encoded.erase(i, 1);
+            }
+        }
+
+        buffer = decodeBase64(encoded);
+
+        if (buffer == NULL) {
+            ALOGE("Malformed base64 encoded content found.");
+            return NULL;
+        }
+    } else {
+#if 0
+        size_t dataLen = strlen(uri) - tmp.size() - 6;
+        buffer = new ABuffer(dataLen);
+        memcpy(buffer->data(), commaPos + 1, dataLen);
+
+        // unescape
+#else
+        // MediaPlayer doesn't care for this right now as we don't
+        // play any text-based media.
+        return NULL;
+#endif
+    }
+
+    // We don't really care about charset or mime type.
+
+    return new DataURISource(buffer);
+}
+
+DataURISource::DataURISource(const sp<ABuffer> &buffer)
+    : mBuffer(buffer) {
+}
+
+DataURISource::~DataURISource() {
+}
+
+status_t DataURISource::initCheck() const {
+    return OK;
+}
+
+ssize_t DataURISource::readAt(off64_t offset, void *data, size_t size) {
+    if (offset >= mBuffer->size()) {
+        return 0;
+    }
+
+    size_t copy = mBuffer->size() - offset;
+    if (copy > size) {
+        copy = size;
+    }
+
+    memcpy(data, mBuffer->data() + offset, copy);
+
+    return copy;
+}
+
+status_t DataURISource::getSize(off64_t *size) {
+    *size = mBuffer->size();
+
+    return OK;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp
index 098fcf9..fa7251c 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/libstagefright/FLACExtractor.cpp
@@ -208,55 +208,55 @@
 // with the same parameter list, but discard redundant information.
 
 FLAC__StreamDecoderReadStatus FLACParser::read_callback(
-        const FLAC__StreamDecoder *decoder, FLAC__byte buffer[],
+        const FLAC__StreamDecoder * /* decoder */, FLAC__byte buffer[],
         size_t *bytes, void *client_data)
 {
     return ((FLACParser *) client_data)->readCallback(buffer, bytes);
 }
 
 FLAC__StreamDecoderSeekStatus FLACParser::seek_callback(
-        const FLAC__StreamDecoder *decoder,
+        const FLAC__StreamDecoder * /* decoder */,
         FLAC__uint64 absolute_byte_offset, void *client_data)
 {
     return ((FLACParser *) client_data)->seekCallback(absolute_byte_offset);
 }
 
 FLAC__StreamDecoderTellStatus FLACParser::tell_callback(
-        const FLAC__StreamDecoder *decoder,
+        const FLAC__StreamDecoder * /* decoder */,
         FLAC__uint64 *absolute_byte_offset, void *client_data)
 {
     return ((FLACParser *) client_data)->tellCallback(absolute_byte_offset);
 }
 
 FLAC__StreamDecoderLengthStatus FLACParser::length_callback(
-        const FLAC__StreamDecoder *decoder,
+        const FLAC__StreamDecoder * /* decoder */,
         FLAC__uint64 *stream_length, void *client_data)
 {
     return ((FLACParser *) client_data)->lengthCallback(stream_length);
 }
 
 FLAC__bool FLACParser::eof_callback(
-        const FLAC__StreamDecoder *decoder, void *client_data)
+        const FLAC__StreamDecoder * /* decoder */, void *client_data)
 {
     return ((FLACParser *) client_data)->eofCallback();
 }
 
 FLAC__StreamDecoderWriteStatus FLACParser::write_callback(
-        const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame,
+        const FLAC__StreamDecoder * /* decoder */, const FLAC__Frame *frame,
         const FLAC__int32 * const buffer[], void *client_data)
 {
     return ((FLACParser *) client_data)->writeCallback(frame, buffer);
 }
 
 void FLACParser::metadata_callback(
-        const FLAC__StreamDecoder *decoder,
+        const FLAC__StreamDecoder * /* decoder */,
         const FLAC__StreamMetadata *metadata, void *client_data)
 {
     ((FLACParser *) client_data)->metadataCallback(metadata);
 }
 
 void FLACParser::error_callback(
-        const FLAC__StreamDecoder *decoder,
+        const FLAC__StreamDecoder * /* decoder */,
         FLAC__StreamDecoderErrorStatus status, void *client_data)
 {
     ((FLACParser *) client_data)->errorCallback(status);
@@ -380,15 +380,21 @@
 // Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved.
 // These are candidates for optimization if needed.
 
-static void copyMono8(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyMono8(
+        short *dst,
+        const int *const *src,
+        unsigned nSamples,
+        unsigned /* nChannels */) {
     for (unsigned i = 0; i < nSamples; ++i) {
         *dst++ = src[0][i] << 8;
     }
 }
 
-static void copyStereo8(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyStereo8(
+        short *dst,
+        const int *const *src,
+        unsigned nSamples,
+        unsigned /* nChannels */) {
     for (unsigned i = 0; i < nSamples; ++i) {
         *dst++ = src[0][i] << 8;
         *dst++ = src[1][i] << 8;
@@ -404,15 +410,21 @@
     }
 }
 
-static void copyMono16(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyMono16(
+        short *dst,
+        const int *const *src,
+        unsigned nSamples,
+        unsigned /* nChannels */) {
     for (unsigned i = 0; i < nSamples; ++i) {
         *dst++ = src[0][i];
     }
 }
 
-static void copyStereo16(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyStereo16(
+        short *dst,
+        const int *const *src,
+        unsigned nSamples,
+        unsigned /* nChannels */) {
     for (unsigned i = 0; i < nSamples; ++i) {
         *dst++ = src[0][i];
         *dst++ = src[1][i];
@@ -430,15 +442,21 @@
 
 // 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
 
-static void copyMono24(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyMono24(
+        short *dst,
+        const int *const *src,
+        unsigned nSamples,
+        unsigned /* nChannels */) {
     for (unsigned i = 0; i < nSamples; ++i) {
         *dst++ = src[0][i] >> 8;
     }
 }
 
-static void copyStereo24(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyStereo24(
+        short *dst,
+        const int *const *src,
+        unsigned nSamples,
+        unsigned /* nChannels */) {
     for (unsigned i = 0; i < nSamples; ++i) {
         *dst++ = src[0][i] >> 8;
         *dst++ = src[1][i] >> 8;
@@ -454,8 +472,11 @@
     }
 }
 
-static void copyTrespass(short *dst, const int *const *src, unsigned nSamples, unsigned nChannels)
-{
+static void copyTrespass(
+        short * /* dst */,
+        const int *const * /* src */,
+        unsigned /* nSamples */,
+        unsigned /* nChannels */) {
     TRESPASS();
 }
 
@@ -700,7 +721,7 @@
     }
 }
 
-status_t FLACSource::start(MetaData *params)
+status_t FLACSource::start(MetaData * /* params */)
 {
     ALOGV("FLACSource::start");
 
@@ -792,8 +813,7 @@
 }
 
 sp<MetaData> FLACExtractor::getTrackMetaData(
-        size_t index, uint32_t flags)
-{
+        size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index > 0) {
         return NULL;
     }
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 380dab4..4a63152 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -398,7 +398,8 @@
             mSeeker);
 }
 
-sp<MetaData> MP3Extractor::getTrackMetaData(size_t index, uint32_t flags) {
+sp<MetaData> MP3Extractor::getTrackMetaData(
+        size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index != 0) {
         return NULL;
     }
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index c9ed5bb..78c12e1 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -555,7 +555,7 @@
     return OK;
 }
 
-status_t MPEG2TSWriter::start(MetaData *param) {
+status_t MPEG2TSWriter::start(MetaData * /* param */) {
     CHECK(!mStarted);
 
     mStarted = true;
@@ -596,7 +596,8 @@
     return !mStarted || (mNumSourcesDone == mSources.size() ? true : false);
 }
 
-status_t MPEG2TSWriter::dump(int fd, const Vector<String16> &args) {
+status_t MPEG2TSWriter::dump(
+        int /* fd */, const Vector<String16> & /* args */) {
     return OK;
 }
 
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index e6312c1..f80772a 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -488,12 +488,12 @@
             break;
         }
         uint32_t chunk_type = ntohl(hdr[1]);
-        if (chunk_type == FOURCC('s', 'i', 'd', 'x')) {
-            // parse the sidx box too
-            continue;
-        } else if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
+        if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
             // store the offset of the first segment
             mMoofOffset = offset;
+        } else if (chunk_type != FOURCC('m', 'd', 'a', 't')) {
+            // keep parsing until we get to the data
+            continue;
         }
         break;
     }
@@ -571,7 +571,8 @@
     return size;
 }
 
-status_t MPEG4Extractor::parseDrmSINF(off64_t *offset, off64_t data_offset) {
+status_t MPEG4Extractor::parseDrmSINF(
+        off64_t * /* offset */, off64_t data_offset) {
     uint8_t updateIdTag;
     if (mDataSource->readAt(data_offset, &updateIdTag, 1) < 1) {
         return ERROR_IO;
@@ -1920,9 +1921,10 @@
             ALOGW("sub-sidx boxes not supported yet");
         }
         bool sap = d3 & 0x80000000;
-        bool saptype = d3 >> 28;
-        if (!sap || saptype > 2) {
-            ALOGW("not a stream access point, or unsupported type");
+        uint32_t saptype = (d3 >> 28) & 7;
+        if (!sap || (saptype != 1 && saptype != 2)) {
+            // type 1 and 2 are sync samples
+            ALOGW("not a stream access point, or unsupported type: %08x", d3);
         }
         total_duration += d2;
         offset += 12;
@@ -2898,9 +2900,20 @@
                 }
             }
             if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
-                // *offset points to the mdat box following this moof
-                parseChunk(offset); // doesn't actually parse it, just updates offset
-                mNextMoofOffset = *offset;
+                // *offset points to the box following this moof. Find the next moof from there.
+
+                while (true) {
+                    if (mDataSource->readAt(*offset, hdr, 8) < 8) {
+                        return ERROR_END_OF_STREAM;
+                    }
+                    chunk_size = ntohl(hdr[0]);
+                    chunk_type = ntohl(hdr[1]);
+                    if (chunk_type == FOURCC('m', 'o', 'o', 'f')) {
+                        mNextMoofOffset = *offset;
+                        break;
+                    }
+                    *offset += chunk_size;
+                }
             }
             break;
         }
@@ -2959,7 +2972,8 @@
     return OK;
 }
 
-status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(off64_t offset, off64_t size) {
+status_t MPEG4Source::parseSampleAuxiliaryInformationSizes(
+        off64_t offset, off64_t /* size */) {
     ALOGV("parseSampleAuxiliaryInformationSizes");
     // 14496-12 8.7.12
     uint8_t version;
@@ -3021,7 +3035,8 @@
     return OK;
 }
 
-status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(off64_t offset, off64_t size) {
+status_t MPEG4Source::parseSampleAuxiliaryInformationOffsets(
+        off64_t offset, off64_t /* size */) {
     ALOGV("parseSampleAuxiliaryInformationOffsets");
     // 14496-12 8.7.13
     uint8_t version;
@@ -3703,7 +3718,7 @@
                 const SidxEntry *se = &mSegments[i];
                 if (totalTime + se->mDurationUs > seekTimeUs) {
                     // The requested time is somewhere in this segment
-                    if ((mode == ReadOptions::SEEK_NEXT_SYNC) ||
+                    if ((mode == ReadOptions::SEEK_NEXT_SYNC && seekTimeUs > totalTime) ||
                         (mode == ReadOptions::SEEK_CLOSEST_SYNC &&
                         (seekTimeUs - totalTime) > (totalTime + se->mDurationUs - seekTimeUs))) {
                         // requested next sync, or closest sync and it was closer to the end of
@@ -3716,11 +3731,19 @@
                 totalTime += se->mDurationUs;
                 totalOffset += se->mSize;
             }
-        mCurrentMoofOffset = totalOffset;
-        mCurrentSamples.clear();
-        mCurrentSampleIndex = 0;
-        parseChunk(&totalOffset);
-        mCurrentTime = totalTime * mTimescale / 1000000ll;
+            mCurrentMoofOffset = totalOffset;
+            mCurrentSamples.clear();
+            mCurrentSampleIndex = 0;
+            parseChunk(&totalOffset);
+            mCurrentTime = totalTime * mTimescale / 1000000ll;
+        } else {
+            // without sidx boxes, we can only seek to 0
+            mCurrentMoofOffset = mFirstMoofOffset;
+            mCurrentSamples.clear();
+            mCurrentSampleIndex = 0;
+            off64_t tmp = mCurrentMoofOffset;
+            parseChunk(&tmp);
+            mCurrentTime = 0;
         }
 
         if (mBuffer != NULL) {
@@ -3732,7 +3755,7 @@
     }
 
     off64_t offset = 0;
-    size_t size;
+    size_t size = 0;
     uint32_t cts = 0;
     bool isSyncSample = false;
     bool newBuffer = false;
@@ -3740,16 +3763,18 @@
         newBuffer = true;
 
         if (mCurrentSampleIndex >= mCurrentSamples.size()) {
-            // move to next fragment
-            Sample lastSample = mCurrentSamples[mCurrentSamples.size() - 1];
-            off64_t nextMoof = mNextMoofOffset; // lastSample.offset + lastSample.size;
+            // move to next fragment if there is one
+            if (mNextMoofOffset <= mCurrentMoofOffset) {
+                return ERROR_END_OF_STREAM;
+            }
+            off64_t nextMoof = mNextMoofOffset;
             mCurrentMoofOffset = nextMoof;
             mCurrentSamples.clear();
             mCurrentSampleIndex = 0;
             parseChunk(&nextMoof);
-                if (mCurrentSampleIndex >= mCurrentSamples.size()) {
-                    return ERROR_END_OF_STREAM;
-                }
+            if (mCurrentSampleIndex >= mCurrentSamples.size()) {
+                return ERROR_END_OF_STREAM;
+            }
         }
 
         const Sample *smpl = &mCurrentSamples[mCurrentSampleIndex];
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index ff6feb9..c839560 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -44,7 +44,9 @@
 namespace android {
 
 static const int64_t kMinStreamableFileSizeInBytes = 5 * 1024 * 1024;
-static const int64_t kMax32BitFileSize = 0x007fffffffLL;
+static const int64_t kMax32BitFileSize = 0x00ffffffffLL; // 2^32-1 : max FAT32
+                                                         // filesystem file size
+                                                         // used by most SD cards
 static const uint8_t kNalUnitTypeSeqParamSet = 0x07;
 static const uint8_t kNalUnitTypePicParamSet = 0x08;
 static const int64_t kInitialDelayTimeUs     = 700000LL;
@@ -407,7 +409,7 @@
 }
 
 status_t MPEG4Writer::Track::dump(
-        int fd, const Vector<String16>& args) const {
+        int fd, const Vector<String16>& /* args */) const {
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
@@ -861,11 +863,11 @@
     // Fix up the size of the 'mdat' chunk.
     if (mUse32BitOffset) {
         lseek64(mFd, mMdatOffset, SEEK_SET);
-        int32_t size = htonl(static_cast<int32_t>(mOffset - mMdatOffset));
+        uint32_t size = htonl(static_cast<uint32_t>(mOffset - mMdatOffset));
         ::write(mFd, &size, 4);
     } else {
         lseek64(mFd, mMdatOffset + 8, SEEK_SET);
-        int64_t size = mOffset - mMdatOffset;
+        uint64_t size = mOffset - mMdatOffset;
         size = hton64(size);
         ::write(mFd, &size, 8);
     }
@@ -2278,6 +2280,22 @@
             return UNKNOWN_ERROR;
         }
 
+        // if the duration is different for this sample, see if it is close enough to the previous
+        // duration that we can fudge it and use the same value, to avoid filling the stts table
+        // with lots of near-identical entries.
+        // "close enough" here means that the current duration needs to be adjusted by less
+        // than 0.1 milliseconds
+        if (lastDurationTicks && (currDurationTicks != lastDurationTicks)) {
+            int64_t deltaUs = ((lastDurationTicks - currDurationTicks) * 1000000LL
+                    + (mTimeScale / 2)) / mTimeScale;
+            if (deltaUs > -100 && deltaUs < 100) {
+                // use previous ticks, and adjust timestamp as if it was actually that number
+                // of ticks
+                currDurationTicks = lastDurationTicks;
+                timestampUs += deltaUs;
+            }
+        }
+
         mStszTableEntries->add(htonl(sampleSize));
         if (mStszTableEntries->count() > 2) {
 
diff --git a/media/libstagefright/MediaAdapter.cpp b/media/libstagefright/MediaAdapter.cpp
index 2484212..d680e0c 100644
--- a/media/libstagefright/MediaAdapter.cpp
+++ b/media/libstagefright/MediaAdapter.cpp
@@ -36,7 +36,7 @@
     CHECK(mCurrentMediaBuffer == NULL);
 }
 
-status_t MediaAdapter::start(MetaData *params) {
+status_t MediaAdapter::start(MetaData * /* params */) {
     Mutex::Autolock autoLock(mAdapterLock);
     if (!mStarted) {
         mStarted = true;
@@ -75,7 +75,7 @@
 }
 
 status_t MediaAdapter::read(
-            MediaBuffer **buffer, const ReadOptions *options) {
+            MediaBuffer **buffer, const ReadOptions * /* options */) {
     Mutex::Autolock autoLock(mAdapterLock);
     if (!mStarted) {
         ALOGV("Read before even started!");
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index c4c47b3..fe21296 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -115,7 +115,7 @@
         if (codecIdx >= 0) {
             Vector<AString> types;
             if (mcl->getSupportedTypes(codecIdx, &types) == OK) {
-                for (int i = 0; i < types.size(); i++) {
+                for (size_t i = 0; i < types.size(); i++) {
                     if (types[i].startsWith("video/")) {
                         needDedicatedLooper = true;
                         break;
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 2c20d62..924173c 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -293,8 +293,8 @@
     return mGraphicBufferProducer;
 }
 
-status_t MediaCodecSource::read(MediaBuffer** buffer,
-        const ReadOptions* options) {
+status_t MediaCodecSource::read(
+        MediaBuffer** buffer, const ReadOptions* /* options */) {
     Mutex::Autolock autolock(mOutputBufferLock);
 
     *buffer = NULL;
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 1287fb1..72ea32d 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -333,7 +333,7 @@
             mNumRetriesLeft = 0;
         }
 
-        ALOGE("source returned error %ld, %d retries left", n, mNumRetriesLeft);
+        ALOGE("source returned error %d, %d retries left", n, mNumRetriesLeft);
         mCache->releasePage(page);
     } else if (n == 0) {
         ALOGI("ERROR_END_OF_STREAM");
@@ -648,7 +648,7 @@
     ssize_t lowwaterMarkKb, highwaterMarkKb;
     int keepAliveSecs;
 
-    if (sscanf(s, "%ld/%ld/%d",
+    if (sscanf(s, "%d/%d/%d",
                &lowwaterMarkKb, &highwaterMarkKb, &keepAliveSecs) != 3) {
         ALOGE("Failed to parse cache parameters from '%s'.", s);
         return;
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 5e79e78..f3eeb03 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -151,7 +151,7 @@
     return mExtractor->mImpl->getFormat();
 }
 
-status_t OggSource::start(MetaData *params) {
+status_t OggSource::start(MetaData * /* params */) {
     if (mStarted) {
         return INVALID_OPERATION;
     }
@@ -381,7 +381,7 @@
     ssize_t n;
     if ((n = mSource->readAt(offset, header, sizeof(header)))
             < (ssize_t)sizeof(header)) {
-        ALOGV("failed to read %d bytes at offset 0x%016llx, got %ld bytes",
+        ALOGV("failed to read %zu bytes at offset 0x%016llx, got %d bytes",
              sizeof(header), offset, n);
 
         if (n < 0) {
@@ -505,7 +505,7 @@
                     packetSize);
 
             if (n < (ssize_t)packetSize) {
-                ALOGV("failed to read %d bytes at 0x%016llx, got %ld bytes",
+                ALOGV("failed to read %zu bytes at 0x%016llx, got %d bytes",
                      packetSize, dataOffset, n);
                 return ERROR_IO;
             }
@@ -546,7 +546,7 @@
                 buffer = NULL;
             }
 
-            ALOGV("readPage returned %ld", n);
+            ALOGV("readPage returned %d", n);
 
             return n < 0 ? n : (status_t)ERROR_END_OF_STREAM;
         }
@@ -998,7 +998,7 @@
 }
 
 sp<MetaData> OggExtractor::getTrackMetaData(
-        size_t index, uint32_t flags) {
+        size_t index, uint32_t /* flags */) {
     if (index >= 1) {
         return NULL;
     }
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index edd12fc..fe20835 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -118,7 +118,7 @@
 }
 
 MediaScanResult StagefrightMediaScanner::processFileInternal(
-        const char *path, const char *mimeType,
+        const char *path, const char * /* mimeType */,
         MediaScannerClient &client) {
     const char *extension = strrchr(path, '.');
 
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 94c0a1e..10c00f4 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -99,8 +99,11 @@
     dump(result, "", buffer, 1024);
 }
 
-void SurfaceMediaSource::dump(String8& result, const char* prefix,
-        char* buffer, size_t SIZE) const
+void SurfaceMediaSource::dump(
+        String8& result,
+        const char* /* prefix */,
+        char* buffer,
+        size_t /* SIZE */) const
 {
     Mutex::Autolock lock(mMutex);
 
@@ -270,9 +273,8 @@
             bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset());
 }
 
-status_t SurfaceMediaSource::read( MediaBuffer **buffer,
-                                    const ReadOptions *options)
-{
+status_t SurfaceMediaSource::read(
+        MediaBuffer **buffer, const ReadOptions * /* options */) {
     ALOGV("read");
     Mutex::Autolock lock(mMutex);
 
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index 0afac69..3d2eb1f 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -376,8 +376,8 @@
     mPowerManager.clear();
 }
 
-void TimedEventQueue::PMDeathRecipient::binderDied(const wp<IBinder>& who)
-{
+void TimedEventQueue::PMDeathRecipient::binderDied(
+        const wp<IBinder>& /* who */) {
     mQueue->clearPowerManager();
 }
 
diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp
index a245f2c..af858b9 100644
--- a/media/libstagefright/VBRISeeker.cpp
+++ b/media/libstagefright/VBRISeeker.cpp
@@ -119,7 +119,7 @@
 
         seeker->mSegments.push(numBytes);
 
-        ALOGV("entry #%d: %d offset 0x%08lx", i, numBytes, offset);
+        ALOGV("entry #%d: %u offset 0x%016llx", i, numBytes, offset);
         offset += numBytes;
     }
 
@@ -160,7 +160,7 @@
         *pos += mSegments.itemAt(segmentIndex++);
     }
 
-    ALOGV("getOffsetForTime %lld us => 0x%08lx", *timeUs, *pos);
+    ALOGV("getOffsetForTime %lld us => 0x%016llx", *timeUs, *pos);
 
     *timeUs = nowUs;
 
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 22af6fb..fe9058b 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -127,7 +127,7 @@
 }
 
 sp<MetaData> WAVExtractor::getTrackMetaData(
-        size_t index, uint32_t flags) {
+        size_t index, uint32_t /* flags */) {
     if (mInitCheck != OK || index > 0) {
         return NULL;
     }
@@ -358,7 +358,7 @@
     }
 }
 
-status_t WAVSource::start(MetaData *params) {
+status_t WAVSource::start(MetaData * /* params */) {
     ALOGV("WAVSource::start");
 
     CHECK(!mStarted);
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index b822868..38a1f6b 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -40,6 +40,25 @@
     return x + (1u << numZeroes) - 1;
 }
 
+signed parseSE(ABitReader *br) {
+    unsigned codeNum = parseUE(br);
+
+    return (codeNum & 1) ? (codeNum + 1) / 2 : -(codeNum / 2);
+}
+
+static void skipScalingList(ABitReader *br, size_t sizeOfScalingList) {
+    size_t lastScale = 8;
+    size_t nextScale = 8;
+    for (size_t j = 0; j < sizeOfScalingList; ++j) {
+        if (nextScale != 0) {
+            signed delta_scale = parseSE(br);
+            nextScale = (lastScale + delta_scale + 256) % 256;
+        }
+
+        lastScale = (nextScale == 0) ? lastScale : nextScale;
+    }
+}
+
 // Determine video dimensions from the sequence parameterset.
 void FindAVCDimensions(
         const sp<ABuffer> &seqParamSet,
@@ -63,7 +82,24 @@
         parseUE(&br);  // bit_depth_luma_minus8
         parseUE(&br);  // bit_depth_chroma_minus8
         br.skipBits(1);  // qpprime_y_zero_transform_bypass_flag
-        CHECK_EQ(br.getBits(1), 0u);  // seq_scaling_matrix_present_flag
+
+        if (br.getBits(1)) {  // seq_scaling_matrix_present_flag
+            for (size_t i = 0; i < 8; ++i) {
+                if (br.getBits(1)) {  // seq_scaling_list_present_flag[i]
+
+                    // WARNING: the code below has not ever been exercised...
+                    // need a real-world example.
+
+                    if (i < 6) {
+                        // ScalingList4x4[i],16,...
+                        skipScalingList(&br, 16);
+                    } else {
+                        // ScalingList8x8[i-6],64,...
+                        skipScalingList(&br, 64);
+                    }
+                }
+            }
+        }
     }
 
     parseUE(&br);  // log2_max_frame_num_minus4
@@ -251,9 +287,7 @@
     return OK;
 }
 
-static sp<ABuffer> FindNAL(
-        const uint8_t *data, size_t size, unsigned nalType,
-        size_t *stopOffset) {
+static sp<ABuffer> FindNAL(const uint8_t *data, size_t size, unsigned nalType) {
     const uint8_t *nalStart;
     size_t nalSize;
     while (getNextNALUnit(&data, &size, &nalStart, &nalSize, true) == OK) {
@@ -293,7 +327,7 @@
     const uint8_t *data = accessUnit->data();
     size_t size = accessUnit->size();
 
-    sp<ABuffer> seqParamSet = FindNAL(data, size, 7, NULL);
+    sp<ABuffer> seqParamSet = FindNAL(data, size, 7);
     if (seqParamSet == NULL) {
         return NULL;
     }
@@ -303,8 +337,7 @@
     FindAVCDimensions(
             seqParamSet, &width, &height, &sarWidth, &sarHeight);
 
-    size_t stopOffset;
-    sp<ABuffer> picParamSet = FindNAL(data, size, 8, &stopOffset);
+    sp<ABuffer> picParamSet = FindNAL(data, size, 8);
     CHECK(picParamSet != NULL);
 
     size_t csdSize =
diff --git a/media/libstagefright/codecs/aacdec/Android.mk b/media/libstagefright/codecs/aacdec/Android.mk
index ffa64f9..49ff238 100644
--- a/media/libstagefright/codecs/aacdec/Android.mk
+++ b/media/libstagefright/codecs/aacdec/Android.mk
@@ -17,6 +17,8 @@
 
 LOCAL_CFLAGS :=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_STATIC_LIBRARIES := libFraunhoferAAC
 
 LOCAL_SHARED_LIBRARIES := \
diff --git a/media/libstagefright/codecs/aacenc/Android.mk b/media/libstagefright/codecs/aacenc/Android.mk
index 057c69b..58ec3ba 100644
--- a/media/libstagefright/codecs/aacenc/Android.mk
+++ b/media/libstagefright/codecs/aacenc/Android.mk
@@ -82,6 +82,8 @@
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7
 endif
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 ################################################################################
@@ -106,6 +108,8 @@
 
   LOCAL_CFLAGS :=
 
+  LOCAL_CFLAGS += -Werror
+
   LOCAL_STATIC_LIBRARIES := libFraunhoferAAC
 
   LOCAL_SHARED_LIBRARIES := \
@@ -128,6 +132,8 @@
 
   LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
 
+  LOCAL_CFLAGS += -Werror
+
   LOCAL_STATIC_LIBRARIES := \
           libstagefright_aacenc
 
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index ff2b503..9a91579 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -338,7 +338,7 @@
     return OK;
 }
 
-void SoftAACEncoder2::onQueueFilled(OMX_U32 portIndex) {
+void SoftAACEncoder2::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError) {
         return;
     }
diff --git a/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c b/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
index cc01927..1d029fc 100644
--- a/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
+++ b/media/libstagefright/codecs/aacenc/basic_op/oper_32b.c
@@ -24,6 +24,8 @@
 #include "basic_op.h"
 #include "oper_32b.h"
 
+#define UNUSED(x) (void)(x)
+
 /*****************************************************************************
  *                                                                           *
  *  Function L_Extract()                                                     *
@@ -243,6 +245,8 @@
 Word32 rsqrt(Word32 value,     /*!< Operand to square root (0.0 ... 1) */
              Word32 accuracy)  /*!< Number of valid bits that will be calculated */
 {
+    UNUSED(accuracy);
+
     Word32 root = 0;
 	Word32 scale;
 
diff --git a/media/libstagefright/codecs/aacenc/src/aacenc.c b/media/libstagefright/codecs/aacenc/src/aacenc.c
index d1c8621..40db92c 100644
--- a/media/libstagefright/codecs/aacenc/src/aacenc.c
+++ b/media/libstagefright/codecs/aacenc/src/aacenc.c
@@ -27,6 +27,8 @@
 #include "cmnMemory.h"
 #include "memalign.h"
 
+#define UNUSED(x) (void)(x)
+
 /**
 * Init the audio codec module and return codec handle
 * \param phCodec [OUT] Return the video codec handle
@@ -46,6 +48,8 @@
 	VO_MEM_OPERATOR *pMemOP;
 	int interMem;
 
+        UNUSED(vType);
+
 	interMem = 0;
 	error = 0;
 
@@ -471,6 +475,10 @@
 */
 VO_U32 VO_API voAACEncGetParam(VO_HANDLE hCodec, VO_S32 uParamID, VO_PTR pData)
 {
+        UNUSED(hCodec);
+        UNUSED(uParamID);
+        UNUSED(pData);
+
 	return VO_ERR_NONE;
 }
 
diff --git a/media/libstagefright/codecs/aacenc/src/adj_thr.c b/media/libstagefright/codecs/aacenc/src/adj_thr.c
index ccfe883..471631c 100644
--- a/media/libstagefright/codecs/aacenc/src/adj_thr.c
+++ b/media/libstagefright/codecs/aacenc/src/adj_thr.c
@@ -72,7 +72,7 @@
                           const Word16 nChannels)
 {
   Word16 ch, sfb, sfbGrp;
-  Word32 *pthrExp, *psfbThre;
+  Word32 *pthrExp = NULL, *psfbThre;
   for (ch=0; ch<nChannels; ch++) {
     PSY_OUT_CHANNEL *psyOutChan = &psyOutChannel[ch];
 	 for(sfbGrp = 0; sfbGrp < psyOutChan->sfbCnt; sfbGrp+= psyOutChan->sfbPerGroup)
diff --git a/media/libstagefright/codecs/aacenc/src/bitenc.c b/media/libstagefright/codecs/aacenc/src/bitenc.c
index fcc12dd..d1fd647 100644
--- a/media/libstagefright/codecs/aacenc/src/bitenc.c
+++ b/media/libstagefright/codecs/aacenc/src/bitenc.c
@@ -26,6 +26,7 @@
 #include "qc_data.h"
 #include "interface.h"
 
+#define UNUSED(x) (void)(x)
 
 static const  Word16 globalGainOffset = 100;
 static const  Word16 icsReservedBit   = 0;
@@ -585,6 +586,8 @@
   Word16 elementUsedBits;
   Word16 frameBits=0;
 
+  UNUSED(ancBytes);
+
   /*   struct bitbuffer bsWriteCopy; */
   bitMarkUp = GetBitsAvail(hBitStream);
   if(qcOut->qcElement.adtsUsed)  /*  write adts header*/
diff --git a/media/libstagefright/codecs/aacenc/src/dyn_bits.c b/media/libstagefright/codecs/aacenc/src/dyn_bits.c
index 7769188..4d763d0 100644
--- a/media/libstagefright/codecs/aacenc/src/dyn_bits.c
+++ b/media/libstagefright/codecs/aacenc/src/dyn_bits.c
@@ -25,7 +25,6 @@
 #include "bit_cnt.h"
 #include "psy_const.h"
 
-
 /*****************************************************************************
 *
 * function name: buildBitLookUp
@@ -226,7 +225,7 @@
   }
 
   while (TRUE) {
-    Word16 maxMergeGain, maxNdx, maxNdxNext, maxNdxLast;
+    Word16 maxMergeGain, maxNdx = 0, maxNdxNext, maxNdxLast;
 
     maxMergeGain = findMaxMerge(mergeGainLookUp, sectionInfo, maxSfb, &maxNdx);
 
diff --git a/media/libstagefright/codecs/aacenc/src/psy_main.c b/media/libstagefright/codecs/aacenc/src/psy_main.c
index 4e9218c..6f0679c 100644
--- a/media/libstagefright/codecs/aacenc/src/psy_main.c
+++ b/media/libstagefright/codecs/aacenc/src/psy_main.c
@@ -38,6 +38,8 @@
 #include "tns_func.h"
 #include "memalign.h"
 
+#define UNUSED(x) (void)(x)
+
 /*                                    long       start       short       stop */
 static Word16 blockType2windowShape[] = {KBD_WINDOW,SINE_WINDOW,SINE_WINDOW,KBD_WINDOW};
 
@@ -170,7 +172,9 @@
 *****************************************************************************/
 Word16 PsyOutDelete(PSY_OUT *hPsyOut, VO_MEM_OPERATOR *pMemOP)
 {
-  hPsyOut=NULL;
+  UNUSED(hPsyOut);
+  UNUSED(pMemOP);
+
   return 0;
 }
 
diff --git a/media/libstagefright/codecs/aacenc/src/qc_main.c b/media/libstagefright/codecs/aacenc/src/qc_main.c
index 48ff300..e5d78aa 100644
--- a/media/libstagefright/codecs/aacenc/src/qc_main.c
+++ b/media/libstagefright/codecs/aacenc/src/qc_main.c
@@ -33,6 +33,7 @@
 #include "channel_map.h"
 #include "memalign.h"
 
+#define UNUSED(x) (void)(x)
 
 typedef enum{
   FRAME_LEN_BYTES_MODULO =  1,
@@ -204,11 +205,8 @@
 **********************************************************************************/
 void QCDelete(QC_STATE *hQC, VO_MEM_OPERATOR *pMemOP)
 {
-
-  /*
-     nothing to do
-  */
-  hQC=NULL;
+  UNUSED(hQC);
+  UNUSED(pMemOP);
 }
 
 /*********************************************************************************
diff --git a/media/libstagefright/codecs/aacenc/src/tns.c b/media/libstagefright/codecs/aacenc/src/tns.c
index 455a864..5172612 100644
--- a/media/libstagefright/codecs/aacenc/src/tns.c
+++ b/media/libstagefright/codecs/aacenc/src/tns.c
@@ -30,6 +30,8 @@
 #include "psy_configuration.h"
 #include "tns_func.h"
 
+#define UNUSED(x) (void)(x)
+
 #define TNS_MODIFY_BEGIN         2600  /* Hz */
 #define RATIO_PATCH_LOWER_BORDER 380   /* Hz */
 #define TNS_GAIN_THRESH			 141   /* 1.41*100 */
@@ -643,6 +645,8 @@
   Word32 i;
   Word32 tnsOrderPlus1 = tnsOrder + 1;
 
+  UNUSED(window);
+
   assert(tnsOrder <= TNS_MAX_ORDER);      /* remove asserts later? (btg) */
 
   for(i=0;i<tnsOrder;i++) {
diff --git a/media/libstagefright/codecs/amrnb/common/Android.mk b/media/libstagefright/codecs/amrnb/common/Android.mk
index 30ce29c..a2b3c8f 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.mk
+++ b/media/libstagefright/codecs/amrnb/common/Android.mk
@@ -69,6 +69,8 @@
 LOCAL_CFLAGS := \
         -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF= -DOSCL_EXPORT_REF=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := libstagefright_amrnb_common
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index 8d6c6f8..b067456 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -47,6 +47,8 @@
 LOCAL_CFLAGS := \
         -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := libstagefright_amrnbdec
 
 include $(BUILD_STATIC_LIBRARY)
@@ -68,6 +70,8 @@
 
 LOCAL_CFLAGS := -DOSCL_IMPORT_REF=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_amrnbdec libstagefright_amrwbdec
 
diff --git a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
index 3320688..d1b0f76 100644
--- a/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
+++ b/media/libstagefright/codecs/amrnb/dec/SoftAMR.cpp
@@ -274,7 +274,7 @@
     return frameSize;
 }
 
-void SoftAMR::onQueueFilled(OMX_U32 portIndex) {
+void SoftAMR::onQueueFilled(OMX_U32 /* portIndex */) {
     List<BufferInfo *> &inQueue = getPortQueue(0);
     List<BufferInfo *> &outQueue = getPortQueue(1);
 
@@ -428,7 +428,7 @@
     }
 }
 
-void SoftAMR::onPortFlushCompleted(OMX_U32 portIndex) {
+void SoftAMR::onPortFlushCompleted(OMX_U32 /* portIndex */) {
 }
 
 void SoftAMR::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index f4e467a..afc0b89 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -69,6 +69,8 @@
 LOCAL_CFLAGS := \
         -DOSCL_UNUSED_ARG=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := libstagefright_amrnbenc
 
 include $(BUILD_STATIC_LIBRARY)
@@ -88,6 +90,8 @@
         $(LOCAL_PATH)/../common/include \
         $(LOCAL_PATH)/../common
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_amrnbenc
 
diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
index 50b739c..9489457 100644
--- a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
@@ -270,7 +270,7 @@
     }
 }
 
-void SoftAMRNBEncoder::onQueueFilled(OMX_U32 portIndex) {
+void SoftAMRNBEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError) {
         return;
     }
diff --git a/media/libstagefright/codecs/amrwb/Android.mk b/media/libstagefright/codecs/amrwb/Android.mk
index 677107f..efdf988 100644
--- a/media/libstagefright/codecs/amrwb/Android.mk
+++ b/media/libstagefright/codecs/amrwb/Android.mk
@@ -50,6 +50,8 @@
 LOCAL_CFLAGS := \
         -DOSCL_UNUSED_ARG= -DOSCL_IMPORT_REF=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := libstagefright_amrwbdec
 
 include $(BUILD_STATIC_LIBRARY)
diff --git a/media/libstagefright/codecs/amrwbenc/Android.mk b/media/libstagefright/codecs/amrwbenc/Android.mk
index c5b8e0c..64fe8d1 100644
--- a/media/libstagefright/codecs/amrwbenc/Android.mk
+++ b/media/libstagefright/codecs/amrwbenc/Android.mk
@@ -112,6 +112,8 @@
 LOCAL_C_INCLUDES += $(LOCAL_PATH)/src/asm/ARMV7
 endif
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 ################################################################################
@@ -126,6 +128,8 @@
 	frameworks/av/media/libstagefright/codecs/common/include \
 	frameworks/native/include/media/openmax
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_amrwbenc
 
diff --git a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
index 9ccb49c..91a512d 100644
--- a/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
+++ b/media/libstagefright/codecs/amrwbenc/SoftAMRWBEncoder.cpp
@@ -317,7 +317,7 @@
     }
 }
 
-void SoftAMRWBEncoder::onQueueFilled(OMX_U32 portIndex) {
+void SoftAMRWBEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError) {
         return;
     }
diff --git a/media/libstagefright/codecs/amrwbenc/src/autocorr.c b/media/libstagefright/codecs/amrwbenc/src/autocorr.c
index 8c477ca..0b2ea89 100644
--- a/media/libstagefright/codecs/amrwbenc/src/autocorr.c
+++ b/media/libstagefright/codecs/amrwbenc/src/autocorr.c
@@ -28,6 +28,8 @@
 #include "acelp.h"
 #include "ham_wind.tab"
 
+#define UNUSED(x) (void)(x)
+
 void Autocorr(
 		Word16 x[],                           /* (i)    : Input signal                      */
 		Word16 m,                             /* (i)    : LPC order                         */
@@ -40,6 +42,8 @@
 	Word32 L_sum, L_sum1, L_tmp, F_LEN;
 	Word16 *p1,*p2,*p3;
 	const Word16 *p4;
+        UNUSED(m);
+
 	/* Windowing of signal */
 	p1 = x;
 	p4 = vo_window;
diff --git a/media/libstagefright/codecs/amrwbenc/src/convolve.c b/media/libstagefright/codecs/amrwbenc/src/convolve.c
index acba532..4c1f7d4 100644
--- a/media/libstagefright/codecs/amrwbenc/src/convolve.c
+++ b/media/libstagefright/codecs/amrwbenc/src/convolve.c
@@ -25,6 +25,8 @@
 #include "typedef.h"
 #include "basic_op.h"
 
+#define UNUSED(x) (void)(x)
+
 void Convolve (
 		Word16 x[],        /* (i)     : input vector                           */
 		Word16 h[],        /* (i)     : impulse response                       */
@@ -35,6 +37,8 @@
 	Word32  i, n;
 	Word16 *tmpH,*tmpX;
 	Word32 s;
+        UNUSED(L);
+
 	for (n = 0; n < 64;)
 	{
 		tmpH = h+n;
diff --git a/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c b/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c
index 0d66c31..b66b55e 100644
--- a/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c
+++ b/media/libstagefright/codecs/amrwbenc/src/pitch_f4.c
@@ -31,6 +31,8 @@
 #define UP_SAMP      4
 #define L_INTERPOL1  4
 
+#define UNUSED(x) (void)(x)
+
 /* Local functions */
 
 #ifdef ASM_OPT
@@ -171,6 +173,7 @@
 	Word32 corr, exp_corr, norm, exp, scale;
 	Word16 exp_norm, excf[L_SUBFR], tmp;
 	Word32 L_tmp, L_tmp1, L_tmp2;
+        UNUSED(L_subfr);
 
 	/* compute the filtered excitation for the first delay t_min */
 	k = -t_min;
diff --git a/media/libstagefright/codecs/amrwbenc/src/syn_filt.c b/media/libstagefright/codecs/amrwbenc/src/syn_filt.c
index 1bda05a..961aadc 100644
--- a/media/libstagefright/codecs/amrwbenc/src/syn_filt.c
+++ b/media/libstagefright/codecs/amrwbenc/src/syn_filt.c
@@ -26,6 +26,8 @@
 #include "math_op.h"
 #include "cnst.h"
 
+#define UNUSED(x) (void)(x)
+
 void Syn_filt(
 		Word16 a[],                           /* (i) Q12 : a[m+1] prediction coefficients           */
 		Word16 x[],                           /* (i)     : input signal                             */
@@ -95,6 +97,8 @@
 	Word32 i,a0;
 	Word32 L_tmp, L_tmp1;
 	Word16 *p1, *p2, *p3;
+        UNUSED(m);
+
 	a0 = a[0] >> (4 + Qnew);          /* input / 16 and >>Qnew */
 	/* Do the filtering. */
 	for (i = 0; i < lg; i++)
diff --git a/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c b/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c
index ea9da52..df7b9b3 100644
--- a/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c
+++ b/media/libstagefright/codecs/amrwbenc/src/voAMRWBEnc.c
@@ -39,6 +39,8 @@
 #include "mem_align.h"
 #include "cmnMemory.h"
 
+#define UNUSED(x) (void)(x)
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -1602,6 +1604,8 @@
 	VO_MEM_OPERATOR voMemoprator;
 #endif
 	VO_MEM_OPERATOR *pMemOP;
+        UNUSED(vType);
+
 	int interMem = 0;
 
 	if(pUserData == NULL || pUserData->memflag != VO_IMF_USERMEMOPERATOR || pUserData->memData == NULL )
diff --git a/media/libstagefright/codecs/avc/common/Android.mk b/media/libstagefright/codecs/avc/common/Android.mk
index 22dee15..844ef0a 100644
--- a/media/libstagefright/codecs/avc/common/Android.mk
+++ b/media/libstagefright/codecs/avc/common/Android.mk
@@ -16,4 +16,6 @@
 	$(LOCAL_PATH)/src \
  	$(LOCAL_PATH)/include
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/avc/enc/Android.mk b/media/libstagefright/codecs/avc/enc/Android.mk
index 7d17c2a..537ba42 100644
--- a/media/libstagefright/codecs/avc/enc/Android.mk
+++ b/media/libstagefright/codecs/avc/enc/Android.mk
@@ -30,6 +30,8 @@
 LOCAL_CFLAGS := \
     -DOSCL_IMPORT_REF= -DOSCL_UNUSED_ARG= -DOSCL_EXPORT_REF=
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 ################################################################################
@@ -69,4 +71,6 @@
 LOCAL_MODULE := libstagefright_soft_h264enc
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
index 1d398fb..a15b040 100644
--- a/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
+++ b/media/libstagefright/codecs/avc/enc/SoftAVCEncoder.cpp
@@ -34,6 +34,12 @@
 
 #include "SoftAVCEncoder.h"
 
+#if LOG_NDEBUG
+#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
+#else
+#define UNUSED_UNLESS_VERBOSE(x)
+#endif
+
 namespace android {
 
 template<class T>
@@ -136,14 +142,14 @@
 }
 
 static void* MallocWrapper(
-        void *userData, int32_t size, int32_t attrs) {
+        void * /* userData */, int32_t size, int32_t /* attrs */) {
     void *ptr = malloc(size);
     if (ptr)
         memset(ptr, 0, size);
     return ptr;
 }
 
-static void FreeWrapper(void *userData, void* ptr) {
+static void FreeWrapper(void * /* userData */, void* ptr) {
     free(ptr);
 }
 
@@ -217,7 +223,7 @@
     mHandle->CBAVC_Free = FreeWrapper;
 
     CHECK(mEncParams != NULL);
-    memset(mEncParams, 0, sizeof(mEncParams));
+    memset(mEncParams, 0, sizeof(*mEncParams));
     mEncParams->rate_control = AVC_ON;
     mEncParams->initQP = 0;
     mEncParams->init_CBP_removal_delay = 1600;
@@ -722,7 +728,7 @@
     }
 }
 
-void SoftAVCEncoder::onQueueFilled(OMX_U32 portIndex) {
+void SoftAVCEncoder::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError || mSawInputEOS) {
         return;
     }
@@ -795,7 +801,7 @@
             }
         }
 
-        buffer_handle_t srcBuffer; // for MetaDataMode only
+        buffer_handle_t srcBuffer = NULL; // for MetaDataMode only
 
         // Get next input video frame
         if (mReadyForNextFrame) {
@@ -964,6 +970,7 @@
 }
 
 void SoftAVCEncoder::signalBufferReturned(MediaBuffer *buffer) {
+    UNUSED_UNLESS_VERBOSE(buffer);
     ALOGV("signalBufferReturned: %p", buffer);
 }
 
diff --git a/media/libstagefright/codecs/avc/enc/src/bitstream_io.cpp b/media/libstagefright/codecs/avc/enc/src/bitstream_io.cpp
index 0e3037f..d71c327 100644
--- a/media/libstagefright/codecs/avc/enc/src/bitstream_io.cpp
+++ b/media/libstagefright/codecs/avc/enc/src/bitstream_io.cpp
@@ -103,6 +103,15 @@
     {
         num_bits -= 8;
         byte = (current_word >> num_bits) & 0xFF;
+        if (stream->count_zeros == 2)
+        {   /* for num_bits = 32, this can add 2 more bytes extra for EPBS */
+            if (byte <= 3)
+            {
+                *write_pnt++ = 0x3;
+                stream->write_pos++;
+                stream->count_zeros = 0;
+            }
+        }
         if (byte != 0)
         {
             *write_pnt++ = byte;
@@ -114,12 +123,6 @@
             stream->count_zeros++;
             *write_pnt++ = byte;
             stream->write_pos++;
-            if (stream->count_zeros == 2)
-            {   /* for num_bits = 32, this can add 2 more bytes extra for EPBS */
-                *write_pnt++ = 0x3;
-                stream->write_pos++;
-                stream->count_zeros = 0;
-            }
         }
     }
 
diff --git a/media/libstagefright/codecs/common/Android.mk b/media/libstagefright/codecs/common/Android.mk
index a33cb92..b0010ff 100644
--- a/media/libstagefright/codecs/common/Android.mk
+++ b/media/libstagefright/codecs/common/Android.mk
@@ -14,6 +14,8 @@
 LOCAL_C_INCLUDES := \
 	$(LOCAL_PATH)/include
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
 
 
diff --git a/media/libstagefright/codecs/common/cmnMemory.c b/media/libstagefright/codecs/common/cmnMemory.c
index aa52bd9..5bb6cc4 100644
--- a/media/libstagefright/codecs/common/cmnMemory.c
+++ b/media/libstagefright/codecs/common/cmnMemory.c
@@ -26,8 +26,12 @@
 
 //VO_MEM_OPERATOR		g_memOP;
 
+#define UNUSED(x) (void)(x)
+
 VO_U32 cmnMemAlloc (VO_S32 uID,  VO_MEM_INFO * pMemInfo)
 {
+        UNUSED(uID);
+
 	if (!pMemInfo)
 		return VO_ERR_INVALID_ARG;
 
@@ -37,34 +41,48 @@
 
 VO_U32 cmnMemFree (VO_S32 uID, VO_PTR pMem)
 {
+        UNUSED(uID);
+
 	free (pMem);
 	return 0;
 }
 
 VO_U32	cmnMemSet (VO_S32 uID, VO_PTR pBuff, VO_U8 uValue, VO_U32 uSize)
 {
+        UNUSED(uID);
+
 	memset (pBuff, uValue, uSize);
 	return 0;
 }
 
 VO_U32	cmnMemCopy (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize)
 {
+        UNUSED(uID);
+
 	memcpy (pDest, pSource, uSize);
 	return 0;
 }
 
 VO_U32	cmnMemCheck (VO_S32 uID, VO_PTR pBuffer, VO_U32 uSize)
 {
+        UNUSED(uID);
+        UNUSED(pBuffer);
+        UNUSED(uSize);
+
 	return 0;
 }
 
 VO_S32 cmnMemCompare (VO_S32 uID, VO_PTR pBuffer1, VO_PTR pBuffer2, VO_U32 uSize)
 {
+        UNUSED(uID);
+
 	return memcmp(pBuffer1, pBuffer2, uSize);
 }
 
 VO_U32	cmnMemMove (VO_S32 uID, VO_PTR pDest, VO_PTR pSource, VO_U32 uSize)
 {
+        UNUSED(uID);
+
 	memmove (pDest, pSource, uSize);
 	return 0;
 }
diff --git a/media/libstagefright/codecs/flac/enc/Android.mk b/media/libstagefright/codecs/flac/enc/Android.mk
index f01d605..59a11de 100644
--- a/media/libstagefright/codecs/flac/enc/Android.mk
+++ b/media/libstagefright/codecs/flac/enc/Android.mk
@@ -9,6 +9,8 @@
         frameworks/native/include/media/openmax \
         external/flac/include
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
index e64fe72..40661e7 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
@@ -27,6 +27,12 @@
 #define FLAC_COMPRESSION_LEVEL_DEFAULT 5
 #define FLAC_COMPRESSION_LEVEL_MAX     8
 
+#if LOG_NDEBUG
+#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
+#else
+#define UNUSED_UNLESS_VERBOSE(x)
+#endif
+
 namespace android {
 
 template<class T>
@@ -257,7 +263,7 @@
 }
 
 void SoftFlacEncoder::onQueueFilled(OMX_U32 portIndex) {
-
+    UNUSED_UNLESS_VERBOSE(portIndex);
     ALOGV("SoftFlacEncoder::onQueueFilled(portIndex=%ld)", portIndex);
 
     if (mSignalledError) {
@@ -343,10 +349,11 @@
     }
 }
 
-
 FLAC__StreamEncoderWriteStatus SoftFlacEncoder::onEncodedFlacAvailable(
             const FLAC__byte buffer[],
-            size_t bytes, unsigned samples, unsigned current_frame) {
+            size_t bytes, unsigned samples,
+            unsigned current_frame) {
+    UNUSED_UNLESS_VERBOSE(current_frame);
     ALOGV("SoftFlacEncoder::onEncodedFlacAvailable(bytes=%d, samples=%d, curr_frame=%d)",
             bytes, samples, current_frame);
 
@@ -444,8 +451,12 @@
 
 // static
 FLAC__StreamEncoderWriteStatus SoftFlacEncoder::flacEncoderWriteCallback(
-            const FLAC__StreamEncoder *encoder, const FLAC__byte buffer[],
-            size_t bytes, unsigned samples, unsigned current_frame, void *client_data) {
+            const FLAC__StreamEncoder * /* encoder */,
+            const FLAC__byte buffer[],
+            size_t bytes,
+            unsigned samples,
+            unsigned current_frame,
+            void *client_data) {
     return ((SoftFlacEncoder*) client_data)->onEncodedFlacAvailable(
             buffer, bytes, samples, current_frame);
 }
diff --git a/media/libstagefright/codecs/g711/dec/Android.mk b/media/libstagefright/codecs/g711/dec/Android.mk
index 4c80da6..a0112e1 100644
--- a/media/libstagefright/codecs/g711/dec/Android.mk
+++ b/media/libstagefright/codecs/g711/dec/Android.mk
@@ -14,4 +14,6 @@
 LOCAL_MODULE := libstagefright_soft_g711dec
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/g711/dec/SoftG711.cpp b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
index bcdd3c7..160ada0 100644
--- a/media/libstagefright/codecs/g711/dec/SoftG711.cpp
+++ b/media/libstagefright/codecs/g711/dec/SoftG711.cpp
@@ -182,7 +182,7 @@
     }
 }
 
-void SoftG711::onQueueFilled(OMX_U32 portIndex) {
+void SoftG711::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError) {
         return;
     }
diff --git a/media/libstagefright/codecs/gsm/dec/Android.mk b/media/libstagefright/codecs/gsm/dec/Android.mk
index 71613d2..30868d5 100644
--- a/media/libstagefright/codecs/gsm/dec/Android.mk
+++ b/media/libstagefright/codecs/gsm/dec/Android.mk
@@ -9,6 +9,8 @@
         frameworks/native/include/media/openmax \
         external/libgsm/inc
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
diff --git a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
index 00e0c85..18f7d29 100644
--- a/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
+++ b/media/libstagefright/codecs/gsm/dec/SoftGSM.cpp
@@ -172,7 +172,7 @@
     }
 }
 
-void SoftGSM::onQueueFilled(OMX_U32 portIndex) {
+void SoftGSM::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError) {
         return;
     }
diff --git a/media/libstagefright/codecs/m4v_h263/dec/Android.mk b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
index a3d5779..1d232c6 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/dec/Android.mk
@@ -46,6 +46,8 @@
 
 LOCAL_CFLAGS := -DOSCL_EXPORT_REF= -DOSCL_IMPORT_REF=
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 ################################################################################
@@ -72,4 +74,6 @@
 LOCAL_MODULE := libstagefright_soft_mpeg4dec
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
index fb2a430..0d1ab71 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/SoftMPEG4.cpp
@@ -91,7 +91,7 @@
     return OK;
 }
 
-void SoftMPEG4::onQueueFilled(OMX_U32 portIndex) {
+void SoftMPEG4::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError || mOutputPortSettingsChange != NONE) {
         return;
     }
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.mk b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
index 83a2dd2..c9006d9 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.mk
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.mk
@@ -33,6 +33,8 @@
     $(TOP)/frameworks/av/media/libstagefright/include \
     $(TOP)/frameworks/native/include/media/openmax
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 ################################################################################
@@ -72,4 +74,6 @@
 LOCAL_MODULE := libstagefright_soft_mpeg4enc
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
index e02af90..2c73e57 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
+++ b/media/libstagefright/codecs/m4v_h263/enc/SoftMPEG4Encoder.cpp
@@ -620,7 +620,7 @@
     }
 }
 
-void SoftMPEG4Encoder::onQueueFilled(OMX_U32 portIndex) {
+void SoftMPEG4Encoder::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError || mSawInputEOS) {
         return;
     }
@@ -677,7 +677,7 @@
             mSawInputEOS = true;
         }
 
-        buffer_handle_t srcBuffer; // for MetaDataMode only
+        buffer_handle_t srcBuffer = NULL; // for MetaDataMode only
         if (inHeader->nFilledLen > 0) {
             uint8_t *inputData = NULL;
             if (mStoreMetaDataInBuffers) {
diff --git a/media/libstagefright/codecs/mp3dec/Android.mk b/media/libstagefright/codecs/mp3dec/Android.mk
index 135c715..8284490 100644
--- a/media/libstagefright/codecs/mp3dec/Android.mk
+++ b/media/libstagefright/codecs/mp3dec/Android.mk
@@ -50,6 +50,8 @@
 LOCAL_CFLAGS := \
         -DOSCL_UNUSED_ARG=
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := libstagefright_mp3dec
 
 LOCAL_ARM_MODE := arm
@@ -69,6 +71,8 @@
         $(LOCAL_PATH)/src \
         $(LOCAL_PATH)/include
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_SHARED_LIBRARIES := \
         libstagefright libstagefright_omx libstagefright_foundation libutils liblog
 
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 61df65e..a09ab7c 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -188,7 +188,7 @@
     }
 }
 
-void SoftMP3::onQueueFilled(OMX_U32 portIndex) {
+void SoftMP3::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError || mOutputPortSettingsChange != NONE) {
         return;
     }
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp
index ee42dc5..499672b 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_mpeg2_get_scale_data.cpp
@@ -139,7 +139,7 @@
     int16 blocknumber = 0;
 
     granuleInfo *gr_info = &(si->ch[ch].gran[gr]);
-    uint32 scalefac_comp, int_scalefac_comp, new_slen[4];
+    uint32 scalefac_comp, int_scalefac_comp, new_slen[4] = { 0,0,0,0 };
 
     scalefac_comp =  gr_info->scalefac_compress;
 
diff --git a/media/libstagefright/codecs/on2/dec/Android.mk b/media/libstagefright/codecs/on2/dec/Android.mk
index 7f2c46d..93ff64c 100644
--- a/media/libstagefright/codecs/on2/dec/Android.mk
+++ b/media/libstagefright/codecs/on2/dec/Android.mk
@@ -20,4 +20,6 @@
 LOCAL_MODULE := libstagefright_soft_vpxdec
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
index 476e986..423a057 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -85,7 +85,7 @@
     return OK;
 }
 
-void SoftVPX::onQueueFilled(OMX_U32 portIndex) {
+void SoftVPX::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mOutputPortSettingsChange != NONE) {
         return;
     }
diff --git a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
index 7ddb13c..a7bde97 100644
--- a/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
+++ b/media/libstagefright/codecs/on2/h264dec/SoftAVC.cpp
@@ -98,7 +98,7 @@
     return UNKNOWN_ERROR;
 }
 
-void SoftAVC::onQueueFilled(OMX_U32 portIndex) {
+void SoftAVC::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError || mOutputPortSettingsChange != NONE) {
         return;
     }
diff --git a/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c b/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c
index 2bb4c4d..524a3f0 100644
--- a/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c
+++ b/media/libstagefright/codecs/on2/h264dec/source/H264SwDecApi.c
@@ -42,6 +42,8 @@
 #include "h264bsd_decoder.h"
 #include "h264bsd_util.h"
 
+#define UNUSED(x) (void)(x)
+
 /*------------------------------------------------------------------------------
        Version Information
 ------------------------------------------------------------------------------*/
@@ -73,6 +75,7 @@
 #endif
 
 void H264SwDecTrace(char *string) {
+    UNUSED(string);
 }
 
 void* H264SwDecMalloc(u32 size) {
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c
index 493fb9e..7a262ed 100755
--- a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c
+++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_conceal.c
@@ -267,7 +267,7 @@
     i32 firstPhase[16];
     i32 *pTmp;
     /* neighbours above, below, left and right */
-    i32 a[4], b[4], l[4], r[4];
+    i32 a[4] = { 0,0,0,0 }, b[4], l[4] = { 0,0,0,0 }, r[4];
     u32 A, B, L, R;
 #ifdef H264DEC_OMXDL
     u8 fillBuff[32*21 + 15 + 32];
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c
index c948776..b409a06 100755
--- a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c
+++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_reconstruct.c
@@ -42,6 +42,8 @@
 #include "armVC.h"
 #endif /* H264DEC_OMXDL */
 
+#define UNUSED(x) (void)(x)
+
 /*------------------------------------------------------------------------------
     2. External compiler flags
 --------------------------------------------------------------------------------
@@ -2136,7 +2138,8 @@
   i32 center,
   i32 right)
 {
-
+    UNUSED(left);
+    UNUSED(right);
     ASSERT(ref);
     ASSERT(fill);
 
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c
index a7c6f64..23401c6 100755
--- a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c
+++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_slice_header.c
@@ -47,6 +47,8 @@
 #include "h264bsd_nal_unit.h"
 #include "h264bsd_dpb.h"
 
+#define UNUSED(x) (void)(x)
+
 /*------------------------------------------------------------------------------
     2. External compiler flags
 --------------------------------------------------------------------------------
@@ -1407,6 +1409,7 @@
     u32 tmp, value, i;
     i32 ivalue;
     strmData_t tmpStrmData[1];
+    UNUSED(nalUnitType);
 
 /* Code */
 
diff --git a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c
index cc838fd..fb97a28 100755
--- a/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c
+++ b/media/libstagefright/codecs/on2/h264dec/source/h264bsd_util.c
@@ -186,7 +186,7 @@
         return(HANTRO_FALSE);
 
     if ( (bits > 8) ||
-         ((h264bsdShowBits32(pStrmData)>>(32-bits)) != (1 << (bits-1))) )
+         ((h264bsdShowBits32(pStrmData)>>(32-bits)) != (1ul << (bits-1))) )
         return(HANTRO_TRUE);
     else
         return(HANTRO_FALSE);
diff --git a/media/libstagefright/codecs/raw/Android.mk b/media/libstagefright/codecs/raw/Android.mk
index fe90a03..87080e7 100644
--- a/media/libstagefright/codecs/raw/Android.mk
+++ b/media/libstagefright/codecs/raw/Android.mk
@@ -8,6 +8,8 @@
         frameworks/av/media/libstagefright/include \
         frameworks/native/include/media/openmax
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_SHARED_LIBRARIES := \
         libstagefright_omx libstagefright_foundation libutils liblog
 
diff --git a/media/libstagefright/codecs/raw/SoftRaw.cpp b/media/libstagefright/codecs/raw/SoftRaw.cpp
index 19d6f13..9d514a6 100644
--- a/media/libstagefright/codecs/raw/SoftRaw.cpp
+++ b/media/libstagefright/codecs/raw/SoftRaw.cpp
@@ -163,7 +163,7 @@
     }
 }
 
-void SoftRaw::onQueueFilled(OMX_U32 portIndex) {
+void SoftRaw::onQueueFilled(OMX_U32 /* portIndex */) {
     if (mSignalledError) {
         return;
     }
diff --git a/media/libstagefright/codecs/vorbis/dec/Android.mk b/media/libstagefright/codecs/vorbis/dec/Android.mk
index 2232353..217a6d2 100644
--- a/media/libstagefright/codecs/vorbis/dec/Android.mk
+++ b/media/libstagefright/codecs/vorbis/dec/Android.mk
@@ -16,4 +16,6 @@
 LOCAL_MODULE := libstagefright_soft_vorbisdec
 LOCAL_MODULE_TAGS := optional
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/foundation/ANetworkSession.cpp b/media/libstagefright/foundation/ANetworkSession.cpp
index e629588..08c4a87 100644
--- a/media/libstagefright/foundation/ANetworkSession.cpp
+++ b/media/libstagefright/foundation/ANetworkSession.cpp
@@ -521,7 +521,7 @@
     return err;
 }
 
-void ANetworkSession::Session::dumpFragmentStats(const Fragment &frag) {
+void ANetworkSession::Session::dumpFragmentStats(const Fragment & /* frag */) {
 #if 0
     int64_t nowUs = ALooper::GetNowUs();
     int64_t delayMs = (nowUs - frag.mTimeUs) / 1000ll;
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index ad2dab5..90a6a23 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -24,7 +24,7 @@
         libutils          \
         liblog
 
-LOCAL_CFLAGS += -Wno-multichar
+LOCAL_CFLAGS += -Wno-multichar -Werror
 
 LOCAL_MODULE:= libstagefright_foundation
 
diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
index d5fb4e0..dcf5bef 100644
--- a/media/libstagefright/foundation/base64.cpp
+++ b/media/libstagefright/foundation/base64.cpp
@@ -33,6 +33,10 @@
 
         if (n >= 2 && s.c_str()[n - 2] == '=') {
             padding = 2;
+
+            if (n >= 3 && s.c_str()[n - 3] == '=') {
+                padding = 3;
+            }
         }
     }
 
@@ -71,7 +75,7 @@
         if (((i + 1) % 4) == 0) {
             out[j++] = (accum >> 16);
 
-            if (j < outLen) { out[j++] = (accum >> 8) & 0xff; } 
+            if (j < outLen) { out[j++] = (accum >> 8) & 0xff; }
             if (j < outLen) { out[j++] = accum & 0xff; }
 
             accum = 0;
diff --git a/media/libstagefright/http/Android.mk b/media/libstagefright/http/Android.mk
index a6b481f..7f3307d 100644
--- a/media/libstagefright/http/Android.mk
+++ b/media/libstagefright/http/Android.mk
@@ -21,6 +21,8 @@
 
 LOCAL_CFLAGS += -Wno-multichar
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_SHARED_LIBRARY)
 
 endif
diff --git a/media/libstagefright/httplive/Android.mk b/media/libstagefright/httplive/Android.mk
index f3529f9..e8d558c 100644
--- a/media/libstagefright/httplive/Android.mk
+++ b/media/libstagefright/httplive/Android.mk
@@ -13,6 +13,8 @@
 	$(TOP)/frameworks/native/include/media/openmax \
 	$(TOP)/external/openssl/include
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_SHARED_LIBRARIES := \
         libbinder \
         libcrypto \
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 149a817..bc26de1 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -61,14 +61,14 @@
       mRealTimeBaseUs(0ll),
       mReconfigurationInProgress(false),
       mDisconnectReplyID(0) {
-    mPacketSources.add(
-            STREAMTYPE_AUDIO, new AnotherPacketSource(NULL /* meta */));
 
-    mPacketSources.add(
-            STREAMTYPE_VIDEO, new AnotherPacketSource(NULL /* meta */));
+    mStreams[kAudioIndex] = StreamItem("audio");
+    mStreams[kVideoIndex] = StreamItem("video");
+    mStreams[kSubtitleIndex] = StreamItem("subtitle");
 
-    mPacketSources.add(
-            STREAMTYPE_SUBTITLES, new AnotherPacketSource(NULL /* meta */));
+    for (size_t i = 0; i < kMaxStreams; ++i) {
+        mPacketSources.add(indexToType(i), new AnotherPacketSource(NULL /* meta */));
+    }
 }
 
 LiveSession::~LiveSession() {
@@ -369,6 +369,12 @@
     return 1;
 }
 
+// static
+LiveSession::StreamType LiveSession::indexToType(int idx) {
+    CHECK(idx >= 0 && idx < kMaxStreams);
+    return (StreamType)(1 << idx);
+}
+
 void LiveSession::onConnect(const sp<AMessage> &msg) {
     AString url;
     CHECK(msg->findString("url", &url));
@@ -507,53 +513,81 @@
     return info.mFetcher;
 }
 
+/*
+ * Illustration of parameters:
+ *
+ * 0      `range_offset`
+ * +------------+-------------------------------------------------------+--+--+
+ * |            |                                 | next block to fetch |  |  |
+ * |            | `source` handle => `out` buffer |                     |  |  |
+ * | `url` file |<--------- buffer size --------->|<--- `block_size` -->|  |  |
+ * |            |<----------- `range_length` / buffer capacity ----------->|  |
+ * |<------------------------------ file_size ------------------------------->|
+ *
+ * Special parameter values:
+ * - range_length == -1 means entire file
+ * - block_size == 0 means entire range
+ *
+ */
 status_t LiveSession::fetchFile(
         const char *url, sp<ABuffer> *out,
-        int64_t range_offset, int64_t range_length) {
-    *out = NULL;
-
-    sp<DataSource> source;
-
-    if (!strncasecmp(url, "file://", 7)) {
-        source = new FileSource(url + 7);
-    } else if (strncasecmp(url, "http://", 7)
-            && strncasecmp(url, "https://", 8)) {
-        return ERROR_UNSUPPORTED;
-    } else {
-        KeyedVector<String8, String8> headers = mExtraHeaders;
-        if (range_offset > 0 || range_length >= 0) {
-            headers.add(
-                    String8("Range"),
-                    String8(
-                        StringPrintf(
-                            "bytes=%lld-%s",
-                            range_offset,
-                            range_length < 0
-                                ? "" : StringPrintf("%lld", range_offset + range_length - 1).c_str()).c_str()));
-        }
-        status_t err = mHTTPDataSource->connect(url, &headers);
-
-        if (err != OK) {
-            return err;
-        }
-
-        source = mHTTPDataSource;
+        int64_t range_offset, int64_t range_length,
+        uint32_t block_size, /* download block size */
+        sp<DataSource> *source, /* to return and reuse source */
+        String8 *actualUrl) {
+    off64_t size;
+    sp<DataSource> temp_source;
+    if (source == NULL) {
+        source = &temp_source;
     }
 
-    off64_t size;
-    status_t err = source->getSize(&size);
+    if (*source == NULL) {
+        if (!strncasecmp(url, "file://", 7)) {
+            *source = new FileSource(url + 7);
+        } else if (strncasecmp(url, "http://", 7)
+                && strncasecmp(url, "https://", 8)) {
+            return ERROR_UNSUPPORTED;
+        } else {
+            KeyedVector<String8, String8> headers = mExtraHeaders;
+            if (range_offset > 0 || range_length >= 0) {
+                headers.add(
+                        String8("Range"),
+                        String8(
+                            StringPrintf(
+                                "bytes=%lld-%s",
+                                range_offset,
+                                range_length < 0
+                                    ? "" : StringPrintf("%lld",
+                                            range_offset + range_length - 1).c_str()).c_str()));
+            }
+            status_t err = mHTTPDataSource->connect(url, &headers);
 
-    if (err != OK) {
+            if (err != OK) {
+                return err;
+            }
+
+            *source = mHTTPDataSource;
+        }
+    }
+
+    status_t getSizeErr = (*source)->getSize(&size);
+    if (getSizeErr != OK) {
         size = 65536;
     }
 
-    sp<ABuffer> buffer = new ABuffer(size);
-    buffer->setRange(0, 0);
+    sp<ABuffer> buffer = *out != NULL ? *out : new ABuffer(size);
+    if (*out == NULL) {
+        buffer->setRange(0, 0);
+    }
 
+    // adjust range_length if only reading partial block
+    if (block_size > 0 && (range_length == -1 || buffer->size() + block_size < range_length)) {
+        range_length = buffer->size() + block_size;
+    }
     for (;;) {
+        // Only resize when we don't know the size.
         size_t bufferRemaining = buffer->capacity() - buffer->size();
-
-        if (bufferRemaining == 0) {
+        if (bufferRemaining == 0 && getSizeErr != OK) {
             bufferRemaining = 32768;
 
             ALOGV("increasing download buffer to %d bytes",
@@ -578,7 +612,9 @@
             }
         }
 
-        ssize_t n = source->readAt(
+        // The DataSource is responsible for informing us of error (n < 0) or eof (n == 0)
+        // to help us break out of the loop.
+        ssize_t n = (*source)->readAt(
                 buffer->size(), buffer->data() + buffer->size(),
                 maxBytesToRead);
 
@@ -594,6 +630,12 @@
     }
 
     *out = buffer;
+    if (actualUrl != NULL) {
+        *actualUrl = (*source)->getUri();
+        if (actualUrl->isEmpty()) {
+            *actualUrl = url;
+        }
+    }
 
     return OK;
 }
@@ -605,7 +647,8 @@
     *unchanged = false;
 
     sp<ABuffer> buffer;
-    status_t err = fetchFile(url, &buffer);
+    String8 actualUrl;
+    status_t err = fetchFile(url, &buffer, 0, -1, 0, NULL, &actualUrl);
 
     if (err != OK) {
         return NULL;
@@ -636,7 +679,7 @@
 #endif
 
     sp<M3UParser> playlist =
-        new M3UParser(url, buffer->data(), buffer->size());
+        new M3UParser(actualUrl.string(), buffer->data(), buffer->size());
 
     if (playlist->initCheck() != OK) {
         ALOGE("failed to parse .m3u8 playlist");
@@ -821,19 +864,11 @@
 
     uint32_t streamMask = 0;
 
-    AString audioURI;
-    if (mPlaylist->getAudioURI(item.mPlaylistIndex, &audioURI)) {
-        streamMask |= STREAMTYPE_AUDIO;
-    }
-
-    AString videoURI;
-    if (mPlaylist->getVideoURI(item.mPlaylistIndex, &videoURI)) {
-        streamMask |= STREAMTYPE_VIDEO;
-    }
-
-    AString subtitleURI;
-    if (mPlaylist->getSubtitleURI(item.mPlaylistIndex, &subtitleURI)) {
-        streamMask |= STREAMTYPE_SUBTITLES;
+    AString URIs[kMaxStreams];
+    for (size_t i = 0; i < kMaxStreams; ++i) {
+        if (mPlaylist->getTypeURI(item.mPlaylistIndex, mStreams[i].mType, &URIs[i])) {
+            streamMask |= indexToType(i);
+        }
     }
 
     // Step 1, stop and discard fetchers that are no longer needed.
@@ -845,10 +880,10 @@
 
         // If we're seeking all current fetchers are discarded.
         if (timeUs < 0ll) {
-            if (((streamMask & STREAMTYPE_AUDIO) && uri == audioURI)
-                    || ((streamMask & STREAMTYPE_VIDEO) && uri == videoURI)
-                    || ((streamMask & STREAMTYPE_SUBTITLES) && uri == subtitleURI)) {
-                discardFetcher = false;
+            for (size_t j = 0; j < kMaxStreams; ++j) {
+                if ((streamMask & indexToType(j)) && uri == URIs[j]) {
+                    discardFetcher = false;
+                }
             }
         }
 
@@ -862,14 +897,10 @@
     sp<AMessage> msg = new AMessage(kWhatChangeConfiguration2, id());
     msg->setInt32("streamMask", streamMask);
     msg->setInt64("timeUs", timeUs);
-    if (streamMask & STREAMTYPE_AUDIO) {
-        msg->setString("audioURI", audioURI.c_str());
-    }
-    if (streamMask & STREAMTYPE_VIDEO) {
-        msg->setString("videoURI", videoURI.c_str());
-    }
-    if (streamMask & STREAMTYPE_SUBTITLES) {
-        msg->setString("subtitleURI", subtitleURI.c_str());
+    for (size_t i = 0; i < kMaxStreams; ++i) {
+        if (streamMask & indexToType(i)) {
+            msg->setString(mStreams[i].uriKey().c_str(), URIs[i].c_str());
+        }
     }
 
     // Every time a fetcher acknowledges the stopAsync or pauseAsync request
@@ -900,18 +931,13 @@
     uint32_t streamMask;
     CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask));
 
-    AString audioURI, videoURI, subtitleURI;
-    if (streamMask & STREAMTYPE_AUDIO) {
-        CHECK(msg->findString("audioURI", &audioURI));
-        ALOGV("audioURI = '%s'", audioURI.c_str());
-    }
-    if (streamMask & STREAMTYPE_VIDEO) {
-        CHECK(msg->findString("videoURI", &videoURI));
-        ALOGV("videoURI = '%s'", videoURI.c_str());
-    }
-    if (streamMask & STREAMTYPE_SUBTITLES) {
-        CHECK(msg->findString("subtitleURI", &subtitleURI));
-        ALOGV("subtitleURI = '%s'", subtitleURI.c_str());
+    AString URIs[kMaxStreams];
+    for (size_t i = 0; i < kMaxStreams; ++i) {
+        if (streamMask & indexToType(i)) {
+            const AString &uriKey = mStreams[i].uriKey();
+            CHECK(msg->findString(uriKey.c_str(), &URIs[i]));
+            ALOGV("%s = '%s'", uriKey.c_str(), URIs[i].c_str());
+        }
     }
 
     // Determine which decoders to shutdown on the player side,
@@ -921,15 +947,12 @@
     // 2) its streamtype was already active and still is but the URI
     //    has changed.
     uint32_t changedMask = 0;
-    if (((mStreamMask & streamMask & STREAMTYPE_AUDIO)
-                && !(audioURI == mAudioURI))
-        || (mStreamMask & ~streamMask & STREAMTYPE_AUDIO)) {
-        changedMask |= STREAMTYPE_AUDIO;
-    }
-    if (((mStreamMask & streamMask & STREAMTYPE_VIDEO)
-                && !(videoURI == mVideoURI))
-        || (mStreamMask & ~streamMask & STREAMTYPE_VIDEO)) {
-        changedMask |= STREAMTYPE_VIDEO;
+    for (size_t i = 0; i < kMaxStreams && i != kSubtitleIndex; ++i) {
+        if (((mStreamMask & streamMask & indexToType(i))
+                && !(URIs[i] == mStreams[i].mUri))
+                || (mStreamMask & ~streamMask & indexToType(i))) {
+            changedMask |= indexToType(i);
+        }
     }
 
     if (changedMask == 0) {
@@ -961,15 +984,10 @@
     uint32_t streamMask;
     CHECK(msg->findInt32("streamMask", (int32_t *)&streamMask));
 
-    AString audioURI, videoURI, subtitleURI;
-    if (streamMask & STREAMTYPE_AUDIO) {
-        CHECK(msg->findString("audioURI", &audioURI));
-    }
-    if (streamMask & STREAMTYPE_VIDEO) {
-        CHECK(msg->findString("videoURI", &videoURI));
-    }
-    if (streamMask & STREAMTYPE_SUBTITLES) {
-        CHECK(msg->findString("subtitleURI", &subtitleURI));
+    for (size_t i = 0; i < kMaxStreams; ++i) {
+        if (streamMask & indexToType(i)) {
+            CHECK(msg->findString(mStreams[i].uriKey().c_str(), &mStreams[i].mUri));
+        }
     }
 
     int64_t timeUs;
@@ -981,9 +999,6 @@
     mRealTimeBaseUs = ALooper::GetNowUs() - timeUs;
 
     mStreamMask = streamMask;
-    mAudioURI = audioURI;
-    mVideoURI = videoURI;
-    mSubtitleURI = subtitleURI;
 
     // Resume all existing fetchers and assign them packet sources.
     for (size_t i = 0; i < mFetcherInfos.size(); ++i) {
@@ -991,22 +1006,13 @@
 
         uint32_t resumeMask = 0;
 
-        sp<AnotherPacketSource> audioSource;
-        if ((streamMask & STREAMTYPE_AUDIO) && uri == audioURI) {
-            audioSource = mPacketSources.valueFor(STREAMTYPE_AUDIO);
-            resumeMask |= STREAMTYPE_AUDIO;
-        }
-
-        sp<AnotherPacketSource> videoSource;
-        if ((streamMask & STREAMTYPE_VIDEO) && uri == videoURI) {
-            videoSource = mPacketSources.valueFor(STREAMTYPE_VIDEO);
-            resumeMask |= STREAMTYPE_VIDEO;
-        }
-
-        sp<AnotherPacketSource> subtitleSource;
-        if ((streamMask & STREAMTYPE_SUBTITLES) && uri == subtitleURI) {
-            subtitleSource = mPacketSources.valueFor(STREAMTYPE_SUBTITLES);
-            resumeMask |= STREAMTYPE_SUBTITLES;
+        sp<AnotherPacketSource> sources[kMaxStreams];
+        // TRICKY: looping from i as earlier streams are already removed from streamMask
+        for (size_t j = i; j < kMaxStreams; ++j) {
+            if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) {
+                sources[j] = mPacketSources.valueFor(indexToType(j));
+                resumeMask |= indexToType(j);
+            }
         }
 
         CHECK_NE(resumeMask, 0u);
@@ -1016,7 +1022,7 @@
         streamMask &= ~resumeMask;
 
         mFetcherInfos.valueAt(i).mFetcher->startAsync(
-                audioSource, videoSource, subtitleSource);
+                sources[kAudioIndex], sources[kVideoIndex], sources[kSubtitleIndex]);
     }
 
     // streamMask now only contains the types that need a new fetcher created.
@@ -1025,52 +1031,33 @@
         ALOGV("creating new fetchers for mask 0x%08x", streamMask);
     }
 
-    while (streamMask != 0) {
-        StreamType streamType = (StreamType)(streamMask & ~(streamMask - 1));
+    for (size_t i = 0; i < kMaxStreams; i++) {
+        if (!(indexToType(i) & streamMask)) {
+            continue;
+        }
 
         AString uri;
-        switch (streamType) {
-            case STREAMTYPE_AUDIO:
-                uri = audioURI;
-                break;
-            case STREAMTYPE_VIDEO:
-                uri = videoURI;
-                break;
-            case STREAMTYPE_SUBTITLES:
-                uri = subtitleURI;
-                break;
-            default:
-                TRESPASS();
-        }
+        uri = mStreams[i].mUri;
 
         sp<PlaylistFetcher> fetcher = addFetcher(uri.c_str());
         CHECK(fetcher != NULL);
 
-        sp<AnotherPacketSource> audioSource;
-        if ((streamMask & STREAMTYPE_AUDIO) && uri == audioURI) {
-            audioSource = mPacketSources.valueFor(STREAMTYPE_AUDIO);
-            audioSource->clear();
+        sp<AnotherPacketSource> sources[kMaxStreams];
+        // TRICKY: looping from i as earlier streams are already removed from streamMask
+        for (size_t j = i; j < kMaxStreams; ++j) {
+            if ((streamMask & indexToType(j)) && uri == mStreams[j].mUri) {
+                sources[j] = mPacketSources.valueFor(indexToType(j));
+                sources[j]->clear();
 
-            streamMask &= ~STREAMTYPE_AUDIO;
+                streamMask &= ~indexToType(j);
+            }
         }
 
-        sp<AnotherPacketSource> videoSource;
-        if ((streamMask & STREAMTYPE_VIDEO) && uri == videoURI) {
-            videoSource = mPacketSources.valueFor(STREAMTYPE_VIDEO);
-            videoSource->clear();
-
-            streamMask &= ~STREAMTYPE_VIDEO;
-        }
-
-        sp<AnotherPacketSource> subtitleSource;
-        if ((streamMask & STREAMTYPE_SUBTITLES) && uri == subtitleURI) {
-            subtitleSource = mPacketSources.valueFor(STREAMTYPE_SUBTITLES);
-            subtitleSource->clear();
-
-            streamMask &= ~STREAMTYPE_SUBTITLES;
-        }
-
-        fetcher->startAsync(audioSource, videoSource, subtitleSource, timeUs);
+        fetcher->startAsync(
+                sources[kAudioIndex],
+                sources[kVideoIndex],
+                sources[kSubtitleIndex],
+                timeUs);
     }
 
     // All fetchers have now been started, the configuration change
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index ee10e70..c4d125c 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -44,10 +44,17 @@
             uint32_t flags,
             const sp<IMediaHTTPService> &httpService);
 
+    enum StreamIndex {
+        kAudioIndex    = 0,
+        kVideoIndex    = 1,
+        kSubtitleIndex = 2,
+        kMaxStreams    = 3,
+    };
+
     enum StreamType {
-        STREAMTYPE_AUDIO        = 1,
-        STREAMTYPE_VIDEO        = 2,
-        STREAMTYPE_SUBTITLES    = 4,
+        STREAMTYPE_AUDIO        = 1 << kAudioIndex,
+        STREAMTYPE_VIDEO        = 1 << kVideoIndex,
+        STREAMTYPE_SUBTITLES    = 1 << kSubtitleIndex,
     };
     status_t dequeueAccessUnit(StreamType stream, sp<ABuffer> *accessUnit);
 
@@ -107,6 +114,19 @@
         bool mIsPrepared;
     };
 
+    struct StreamItem {
+        const char *mType;
+        AString mUri;
+        StreamItem() : mType("") {}
+        StreamItem(const char *type) : mType(type) {}
+        AString uriKey() {
+            AString key(mType);
+            key.append("URI");
+            return key;
+        }
+    };
+    StreamItem mStreams[kMaxStreams];
+
     sp<AMessage> mNotify;
     uint32_t mFlags;
     sp<IMediaHTTPService> mHTTPService;
@@ -124,7 +144,6 @@
     sp<M3UParser> mPlaylist;
 
     KeyedVector<AString, FetcherInfo> mFetcherInfos;
-    AString mAudioURI, mVideoURI, mSubtitleURI;
     uint32_t mStreamMask;
 
     KeyedVector<StreamType, sp<AnotherPacketSource> > mPacketSources;
@@ -146,9 +165,26 @@
     status_t onSeek(const sp<AMessage> &msg);
     void onFinishDisconnect2();
 
+    // If given a non-zero block_size (default 0), it is used to cap the number of
+    // bytes read in from the DataSource. If given a non-NULL buffer, new content
+    // is read into the end.
+    //
+    // The DataSource we read from is responsible for signaling error or EOF to help us
+    // break out of the read loop. The DataSource can be returned to the caller, so
+    // that the caller can reuse it for subsequent fetches (within the initially
+    // requested range).
+    //
+    // For reused HTTP sources, the caller must download a file sequentially without
+    // any overlaps or gaps to prevent reconnection.
     status_t fetchFile(
             const char *url, sp<ABuffer> *out,
-            int64_t range_offset = 0, int64_t range_length = -1);
+            /* request/open a file starting at range_offset for range_length bytes */
+            int64_t range_offset = 0, int64_t range_length = -1,
+            /* download block size */
+            uint32_t block_size = 0,
+            /* reuse DataSource if doing partial fetch */
+            sp<DataSource> *source = NULL,
+            String8 *actualUrl = NULL);
 
     sp<M3UParser> fetchPlaylist(
             const char *url, uint8_t *curPlaylistHash, bool *unchanged);
@@ -156,6 +192,7 @@
     size_t getBandwidthIndex();
 
     static int SortByBandwidth(const BandwidthItem *, const BandwidthItem *);
+    static StreamType indexToType(int idx);
 
     void changeConfiguration(
             int64_t timeUs, size_t bandwidthIndex, bool pickTrack = false);
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 5ef7c0f..4dc5db0 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -125,7 +125,7 @@
                 mSelectedIndex = strtoul(value, &end, 10);
                 CHECK(end > value && *end == '\0');
 
-                if (mSelectedIndex >= mMediaItems.size()) {
+                if (mSelectedIndex >= (ssize_t)mMediaItems.size()) {
                     mSelectedIndex = mMediaItems.size() - 1;
                 }
             } else {
@@ -165,14 +165,14 @@
             ALOGE("track %d does not exist", index);
             return INVALID_OPERATION;
         }
-        if (mSelectedIndex == index) {
+        if (mSelectedIndex == (ssize_t)index) {
             ALOGE("track %d already selected", index);
             return BAD_VALUE;
         }
         ALOGV("selected track %d", index);
         mSelectedIndex = index;
     } else {
-        if (mSelectedIndex != index) {
+        if (mSelectedIndex != (ssize_t)index) {
             ALOGE("track %d is not selected", index);
             return BAD_VALUE;
         }
@@ -369,18 +369,6 @@
     return true;
 }
 
-bool M3UParser::getAudioURI(size_t index, AString *uri) const {
-    return getTypeURI(index, "audio", uri);
-}
-
-bool M3UParser::getVideoURI(size_t index, AString *uri) const {
-    return getTypeURI(index, "video", uri);
-}
-
-bool M3UParser::getSubtitleURI(size_t index, AString *uri) const {
-    return getTypeURI(index, "subtitles", uri);
-}
-
 static bool MakeURL(const char *baseURL, const char *url, AString *out) {
     out->clear();
 
diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h
index 5248004..2051e41 100644
--- a/media/libstagefright/httplive/M3UParser.h
+++ b/media/libstagefright/httplive/M3UParser.h
@@ -45,9 +45,7 @@
     status_t getTrackInfo(Parcel* reply) const;
     ssize_t getSelectedIndex() const;
 
-    bool getAudioURI(size_t index, AString *uri) const;
-    bool getVideoURI(size_t index, AString *uri) const;
-    bool getSubtitleURI(size_t index, AString *uri) const;
+    bool getTypeURI(size_t index, const char *key, AString *uri) const;
 
 protected:
     virtual ~M3UParser();
@@ -95,8 +93,6 @@
 
     status_t parseMedia(const AString &line);
 
-    bool getTypeURI(size_t index, const char *key, AString *uri) const;
-
     static status_t ParseInt32(const char *s, int32_t *x);
     static status_t ParseDouble(const char *s, double *x);
 
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index f095987..030cbde 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -170,7 +170,8 @@
 }
 
 status_t PlaylistFetcher::decryptBuffer(
-        size_t playlistIndex, const sp<ABuffer> &buffer) {
+        size_t playlistIndex, const sp<ABuffer> &buffer,
+        bool first) {
     sp<AMessage> itemMeta;
     bool found = false;
     AString method;
@@ -188,6 +189,7 @@
     if (!found) {
         method = "NONE";
     }
+    buffer->meta()->setString("cipher-method", method.c_str());
 
     if (method == "NONE") {
         return OK;
@@ -227,59 +229,77 @@
         return UNKNOWN_ERROR;
     }
 
-    unsigned char aes_ivec[16];
+    size_t n = buffer->size();
+    if (!n) {
+        return OK;
+    }
+    CHECK(n % 16 == 0);
 
-    AString iv;
-    if (itemMeta->findString("cipher-iv", &iv)) {
-        if ((!iv.startsWith("0x") && !iv.startsWith("0X"))
-                || iv.size() != 16 * 2 + 2) {
-            ALOGE("malformed cipher IV '%s'.", iv.c_str());
-            return ERROR_MALFORMED;
-        }
+    if (first) {
+        // If decrypting the first block in a file, read the iv from the manifest
+        // or derive the iv from the file's sequence number.
 
-        memset(aes_ivec, 0, sizeof(aes_ivec));
-        for (size_t i = 0; i < 16; ++i) {
-            char c1 = tolower(iv.c_str()[2 + 2 * i]);
-            char c2 = tolower(iv.c_str()[3 + 2 * i]);
-            if (!isxdigit(c1) || !isxdigit(c2)) {
+        AString iv;
+        if (itemMeta->findString("cipher-iv", &iv)) {
+            if ((!iv.startsWith("0x") && !iv.startsWith("0X"))
+                    || iv.size() != 16 * 2 + 2) {
                 ALOGE("malformed cipher IV '%s'.", iv.c_str());
                 return ERROR_MALFORMED;
             }
-            uint8_t nibble1 = isdigit(c1) ? c1 - '0' : c1 - 'a' + 10;
-            uint8_t nibble2 = isdigit(c2) ? c2 - '0' : c2 - 'a' + 10;
 
-            aes_ivec[i] = nibble1 << 4 | nibble2;
+            memset(mAESInitVec, 0, sizeof(mAESInitVec));
+            for (size_t i = 0; i < 16; ++i) {
+                char c1 = tolower(iv.c_str()[2 + 2 * i]);
+                char c2 = tolower(iv.c_str()[3 + 2 * i]);
+                if (!isxdigit(c1) || !isxdigit(c2)) {
+                    ALOGE("malformed cipher IV '%s'.", iv.c_str());
+                    return ERROR_MALFORMED;
+                }
+                uint8_t nibble1 = isdigit(c1) ? c1 - '0' : c1 - 'a' + 10;
+                uint8_t nibble2 = isdigit(c2) ? c2 - '0' : c2 - 'a' + 10;
+
+                mAESInitVec[i] = nibble1 << 4 | nibble2;
+            }
+        } else {
+            memset(mAESInitVec, 0, sizeof(mAESInitVec));
+            mAESInitVec[15] = mSeqNumber & 0xff;
+            mAESInitVec[14] = (mSeqNumber >> 8) & 0xff;
+            mAESInitVec[13] = (mSeqNumber >> 16) & 0xff;
+            mAESInitVec[12] = (mSeqNumber >> 24) & 0xff;
         }
-    } else {
-        memset(aes_ivec, 0, sizeof(aes_ivec));
-        aes_ivec[15] = mSeqNumber & 0xff;
-        aes_ivec[14] = (mSeqNumber >> 8) & 0xff;
-        aes_ivec[13] = (mSeqNumber >> 16) & 0xff;
-        aes_ivec[12] = (mSeqNumber >> 24) & 0xff;
     }
 
     AES_cbc_encrypt(
             buffer->data(), buffer->data(), buffer->size(),
-            &aes_key, aes_ivec, AES_DECRYPT);
+            &aes_key, mAESInitVec, AES_DECRYPT);
 
-    // hexdump(buffer->data(), buffer->size());
+    return OK;
+}
 
-    size_t n = buffer->size();
-    CHECK_GT(n, 0u);
-
-    size_t pad = buffer->data()[n - 1];
-
-    CHECK_GT(pad, 0u);
-    CHECK_LE(pad, 16u);
-    CHECK_GE((size_t)n, pad);
-    for (size_t i = 0; i < pad; ++i) {
-        CHECK_EQ((unsigned)buffer->data()[n - 1 - i], pad);
+status_t PlaylistFetcher::checkDecryptPadding(const sp<ABuffer> &buffer) {
+    status_t err;
+    AString method;
+    CHECK(buffer->meta()->findString("cipher-method", &method));
+    if (method == "NONE") {
+        return OK;
     }
 
-    n -= pad;
+    uint8_t padding = 0;
+    if (buffer->size() > 0) {
+        padding = buffer->data()[buffer->size() - 1];
+    }
 
-    buffer->setRange(buffer->offset(), n);
+    if (padding > 16) {
+        return ERROR_MALFORMED;
+    }
 
+    for (size_t i = buffer->size() - padding; i < padding; i++) {
+        if (buffer->data()[i] != padding) {
+            return ERROR_MALFORMED;
+        }
+    }
+
+    buffer->setRange(buffer->offset(), buffer->size() - padding);
     return OK;
 }
 
@@ -602,7 +622,7 @@
 
         if (mPlaylist->isComplete() || mPlaylist->isEvent()) {
             mSeqNumber = getSeqNumberForTime(mStartTimeUs);
-            ALOGV("Initial sequence number for time %lld is %ld from (%ld .. %ld)",
+            ALOGV("Initial sequence number for time %lld is %d from (%d .. %d)",
                     mStartTimeUs, mSeqNumber, firstSeqNumberInPlaylist,
                     lastSeqNumberInPlaylist);
         } else {
@@ -611,7 +631,7 @@
             if (mSeqNumber < firstSeqNumberInPlaylist) {
                 mSeqNumber = firstSeqNumberInPlaylist;
             }
-            ALOGV("Initial sequence number for live event %ld from (%ld .. %ld)",
+            ALOGV("Initial sequence number for live event %d from (%d .. %d)",
                     mSeqNumber, firstSeqNumberInPlaylist,
                     lastSeqNumberInPlaylist);
         }
@@ -635,7 +655,8 @@
                 if (delayUs > kMaxMonitorDelayUs) {
                     delayUs = kMaxMonitorDelayUs;
                 }
-                ALOGV("sequence number high: %ld from (%ld .. %ld), monitor in %lld (retry=%d)",
+                ALOGV("sequence number high: %d from (%d .. %d), "
+                      "monitor in %lld (retry=%d)",
                         mSeqNumber, firstSeqNumberInPlaylist,
                         lastSeqNumberInPlaylist, delayUs, mNumRetries);
                 postMonitorQueue(delayUs);
@@ -706,6 +727,9 @@
     CHECK(buffer != NULL);
 
     err = decryptBuffer(mSeqNumber - firstSeqNumberInPlaylist, buffer);
+    if (err == OK) {
+        err = checkDecryptPadding(buffer);
+    }
 
     if (err != OK) {
         ALOGE("decryptBuffer failed w/ error %d", err);
diff --git a/media/libstagefright/httplive/PlaylistFetcher.h b/media/libstagefright/httplive/PlaylistFetcher.h
index 78dea20..ac04a77 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.h
+++ b/media/libstagefright/httplive/PlaylistFetcher.h
@@ -119,8 +119,23 @@
     uint64_t mFirstPTS;
     int64_t mAbsoluteTimeAnchorUs;
 
+    // Stores the initialization vector to decrypt the next block of cipher text, which can
+    // either be derived from the sequence number, read from the manifest, or copied from
+    // the last block of cipher text (cipher-block chaining).
+    unsigned char mAESInitVec[16];
+
+    // Set first to true if decrypting the first segment of a playlist segment. When
+    // first is true, reset the initialization vector based on the available
+    // information in the manifest; otherwise, use the initialization vector as
+    // updated by the last call to AES_cbc_encrypt.
+    //
+    // For the input to decrypt correctly, decryptBuffer must be called on
+    // consecutive byte ranges on block boundaries, e.g. 0..15, 16..47, 48..63,
+    // and so on.
     status_t decryptBuffer(
-            size_t playlistIndex, const sp<ABuffer> &buffer);
+            size_t playlistIndex, const sp<ABuffer> &buffer,
+            bool first = true);
+    status_t checkDecryptPadding(const sp<ABuffer> &buffer);
 
     void postMonitorQueue(int64_t delayUs = 0, int64_t minDelayUs = 0);
     void cancelMonitorQueue();
diff --git a/media/libstagefright/id3/Android.mk b/media/libstagefright/id3/Android.mk
index bf6f7bb..2194c38 100644
--- a/media/libstagefright/id3/Android.mk
+++ b/media/libstagefright/id3/Android.mk
@@ -4,6 +4,8 @@
 LOCAL_SRC_FILES := \
 	ID3.cpp
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := libstagefright_id3
 
 include $(BUILD_STATIC_LIBRARY)
@@ -15,6 +17,8 @@
 LOCAL_SRC_FILES := \
 	testid3.cpp
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_SHARED_LIBRARIES := \
 	libstagefright libutils liblog libbinder libstagefright_foundation
 
diff --git a/media/libstagefright/include/FragmentedMP4Parser.h b/media/libstagefright/include/FragmentedMP4Parser.h
deleted file mode 100644
index dbe02b8..0000000
--- a/media/libstagefright/include/FragmentedMP4Parser.h
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef PARSER_H_
-
-#define PARSER_H_
-
-#include <media/stagefright/foundation/AHandler.h>
-#include <media/stagefright/DataSource.h>
-#include <utils/Vector.h>
-
-namespace android {
-
-struct ABuffer;
-
-struct FragmentedMP4Parser : public AHandler {
-    struct Source : public RefBase {
-        Source() {}
-
-        virtual ssize_t readAt(off64_t offset, void *data, size_t size) = 0;
-        virtual bool isSeekable() = 0;
-
-        protected:
-        virtual ~Source() {}
-
-        private:
-        DISALLOW_EVIL_CONSTRUCTORS(Source);
-    };
-
-    FragmentedMP4Parser();
-
-    void start(const char *filename);
-    void start(const sp<Source> &source);
-    void start(sp<DataSource> &source);
-
-    sp<AMessage> getFormat(bool audio, bool synchronous = false);
-    status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit, bool synchronous = false);
-    status_t seekTo(bool audio, int64_t timeUs);
-    bool isSeekable() const;
-
-    virtual void onMessageReceived(const sp<AMessage> &msg);
-
-protected:
-    virtual ~FragmentedMP4Parser();
-
-private:
-    enum {
-        kWhatStart,
-        kWhatProceed,
-        kWhatReadMore,
-        kWhatGetFormat,
-        kWhatDequeueAccessUnit,
-        kWhatSeekTo,
-    };
-
-    struct TrackFragment;
-    struct DynamicTrackFragment;
-    struct StaticTrackFragment;
-
-    struct DispatchEntry {
-        uint32_t mType;
-        uint32_t mParentType;
-        status_t (FragmentedMP4Parser::*mHandler)(uint32_t, size_t, uint64_t);
-    };
-
-    struct Container {
-        uint64_t mOffset;
-        uint64_t mBytesRemaining;
-        uint32_t mType;
-        bool mExtendsToEOF;
-    };
-
-    struct SampleDescription {
-        uint32_t mType;
-        uint16_t mDataRefIndex;
-
-        sp<AMessage> mFormat;
-    };
-
-    struct SampleInfo {
-        off64_t mOffset;
-        size_t mSize;
-        uint32_t mPresentationTime;
-        size_t mSampleDescIndex;
-        uint32_t mFlags;
-    };
-
-    struct MediaDataInfo {
-        sp<ABuffer> mBuffer;
-        off64_t mOffset;
-    };
-
-    struct SidxEntry {
-        size_t mSize;
-        uint32_t mDurationUs;
-    };
-
-    struct TrackInfo {
-        enum Flags {
-            kTrackEnabled     = 0x01,
-            kTrackInMovie     = 0x02,
-            kTrackInPreview   = 0x04,
-        };
-
-        uint32_t mTrackID;
-        uint32_t mFlags;
-        uint32_t mDuration;  // This is the duration in terms of movie timescale!
-        uint64_t mSidxDuration; // usec, from sidx box, which can use a different timescale
-
-        uint32_t mMediaTimeScale;
-
-        uint32_t mMediaHandlerType;
-        Vector<SampleDescription> mSampleDescs;
-
-        // from track extends:
-        uint32_t mDefaultSampleDescriptionIndex;
-        uint32_t mDefaultSampleDuration;
-        uint32_t mDefaultSampleSize;
-        uint32_t mDefaultSampleFlags;
-
-        uint32_t mDecodingTime;
-
-        Vector<SidxEntry> mSidx;
-        sp<StaticTrackFragment> mStaticFragment;
-        List<sp<TrackFragment> > mFragments;
-    };
-
-    struct TrackFragmentHeaderInfo {
-        enum Flags {
-            kBaseDataOffsetPresent         = 0x01,
-            kSampleDescriptionIndexPresent = 0x02,
-            kDefaultSampleDurationPresent  = 0x08,
-            kDefaultSampleSizePresent      = 0x10,
-            kDefaultSampleFlagsPresent     = 0x20,
-            kDurationIsEmpty               = 0x10000,
-        };
-
-        uint32_t mTrackID;
-        uint32_t mFlags;
-        uint64_t mBaseDataOffset;
-        uint32_t mSampleDescriptionIndex;
-        uint32_t mDefaultSampleDuration;
-        uint32_t mDefaultSampleSize;
-        uint32_t mDefaultSampleFlags;
-
-        uint64_t mDataOffset;
-    };
-
-    static const DispatchEntry kDispatchTable[];
-
-    sp<Source> mSource;
-    off_t mBufferPos;
-    bool mSuspended;
-    bool mDoneWithMoov;
-    off_t mFirstMoofOffset; // used as the starting point for offsets calculated from the sidx box
-    sp<ABuffer> mBuffer;
-    Vector<Container> mStack;
-    KeyedVector<uint32_t, TrackInfo> mTracks;  // TrackInfo by trackID
-    Vector<MediaDataInfo> mMediaData;
-
-    uint32_t mCurrentTrackID;
-
-    status_t mFinalResult;
-
-    TrackFragmentHeaderInfo mTrackFragmentHeaderInfo;
-
-    status_t onProceed();
-    status_t onDequeueAccessUnit(size_t trackIndex, sp<ABuffer> *accessUnit);
-    status_t onSeekTo(bool wantAudio, int64_t position);
-
-    void enter(off64_t offset, uint32_t type, uint64_t size);
-
-    uint16_t readU16(size_t offset);
-    uint32_t readU32(size_t offset);
-    uint64_t readU64(size_t offset);
-    void skip(off_t distance);
-    status_t need(size_t size);
-    bool fitsContainer(uint64_t size) const;
-
-    status_t parseTrackHeader(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseMediaHeader(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseMediaHandler(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseTrackExtends(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseTrackFragmentHeader(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseTrackFragmentRun(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseVisualSampleEntry(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseAudioSampleEntry(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseSampleSizes(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseCompactSampleSizes(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseSampleToChunk(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseChunkOffsets(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseChunkOffsets64(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseAVCCodecSpecificData(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseESDSCodecSpecificData(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseMediaData(
-            uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseSegmentIndex(
-            uint32_t type, size_t offset, uint64_t size);
-
-    TrackInfo *editTrack(uint32_t trackID, bool createIfNecessary = false);
-
-    ssize_t findTrack(bool wantAudio) const;
-
-    status_t makeAccessUnit(
-            TrackInfo *info,
-            const SampleInfo &sample,
-            const MediaDataInfo &mdatInfo,
-            sp<ABuffer> *accessUnit);
-
-    status_t getSample(
-            TrackInfo *info,
-            sp<TrackFragment> *fragment,
-            SampleInfo *sampleInfo);
-
-    static int CompareSampleLocation(
-        const SampleInfo &sample, const MediaDataInfo &mdatInfo);
-
-    void resumeIfNecessary();
-
-    void copyBuffer(
-            sp<ABuffer> *dst,
-            size_t offset, uint64_t size) const;
-
-    DISALLOW_EVIL_CONSTRUCTORS(FragmentedMP4Parser);
-};
-
-}  // namespace android
-
-#endif  // PARSER_H_
-
diff --git a/media/libstagefright/include/TimedEventQueue.h b/media/libstagefright/include/TimedEventQueue.h
index 3e84256..2963150 100644
--- a/media/libstagefright/include/TimedEventQueue.h
+++ b/media/libstagefright/include/TimedEventQueue.h
@@ -122,7 +122,7 @@
     };
 
     struct StopEvent : public TimedEventQueue::Event {
-        virtual void fire(TimedEventQueue *queue, int64_t now_us) {
+        virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
             queue->mStopped = true;
         }
     };
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index 2d8c1e1..446ff8c 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -8,7 +8,7 @@
         $(TOP)/external/libvpx/libwebm \
         $(TOP)/frameworks/native/include/media/openmax \
 
-LOCAL_CFLAGS += -Wno-multichar
+LOCAL_CFLAGS += -Wno-multichar -Werror
 
 LOCAL_MODULE:= libstagefright_matroska
 
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index dcb1cda..6f69d0b 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -193,7 +193,7 @@
     clearPendingFrames();
 }
 
-status_t MatroskaSource::start(MetaData *params) {
+status_t MatroskaSource::start(MetaData * /* params */) {
     mBlockIter.reset();
 
     return OK;
@@ -410,7 +410,7 @@
             // Accept the first key frame
             *actualFrameTimeUs = (block()->GetTime(mCluster) + 500LL) / 1000LL;
             ALOGV("Requested seek point: %lld actual: %lld",
-                  seekTimeUs, actualFrameTimeUs);
+                  seekTimeUs, *actualFrameTimeUs);
             break;
         }
     }
diff --git a/media/libstagefright/mp4/FragmentedMP4Parser.cpp b/media/libstagefright/mp4/FragmentedMP4Parser.cpp
deleted file mode 100644
index 0102656..0000000
--- a/media/libstagefright/mp4/FragmentedMP4Parser.cpp
+++ /dev/null
@@ -1,1993 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "FragmentedMP4Parser"
-#include <utils/Log.h>
-
-#include "include/avc_utils.h"
-#include "include/ESDS.h"
-#include "include/FragmentedMP4Parser.h"
-#include "TrackFragment.h"
-
-
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-
-
-namespace android {
-
-static const char *Fourcc2String(uint32_t fourcc) {
-    static char buffer[5];
-    buffer[4] = '\0';
-    buffer[0] = fourcc >> 24;
-    buffer[1] = (fourcc >> 16) & 0xff;
-    buffer[2] = (fourcc >> 8) & 0xff;
-    buffer[3] = fourcc & 0xff;
-
-    return buffer;
-}
-
-static const char *IndentString(size_t n) {
-    static const char kSpace[] = "                              ";
-    return kSpace + sizeof(kSpace) - 2 * n - 1;
-}
-
-// static
-const FragmentedMP4Parser::DispatchEntry FragmentedMP4Parser::kDispatchTable[] = {
-    { FOURCC('m', 'o', 'o', 'v'), 0, NULL },
-    { FOURCC('t', 'r', 'a', 'k'), FOURCC('m', 'o', 'o', 'v'), NULL },
-    { FOURCC('u', 'd', 't', 'a'), FOURCC('t', 'r', 'a', 'k'), NULL },
-    { FOURCC('u', 'd', 't', 'a'), FOURCC('m', 'o', 'o', 'v'), NULL },
-    { FOURCC('m', 'e', 't', 'a'), FOURCC('u', 'd', 't', 'a'), NULL },
-    { FOURCC('i', 'l', 's', 't'), FOURCC('m', 'e', 't', 'a'), NULL },
-
-    { FOURCC('t', 'k', 'h', 'd'), FOURCC('t', 'r', 'a', 'k'),
-        &FragmentedMP4Parser::parseTrackHeader
-    },
-
-    { FOURCC('m', 'v', 'e', 'x'), FOURCC('m', 'o', 'o', 'v'), NULL },
-
-    { FOURCC('t', 'r', 'e', 'x'), FOURCC('m', 'v', 'e', 'x'),
-        &FragmentedMP4Parser::parseTrackExtends
-    },
-
-    { FOURCC('e', 'd', 't', 's'), FOURCC('t', 'r', 'a', 'k'), NULL },
-    { FOURCC('m', 'd', 'i', 'a'), FOURCC('t', 'r', 'a', 'k'), NULL },
-
-    { FOURCC('m', 'd', 'h', 'd'), FOURCC('m', 'd', 'i', 'a'),
-        &FragmentedMP4Parser::parseMediaHeader
-    },
-
-    { FOURCC('h', 'd', 'l', 'r'), FOURCC('m', 'd', 'i', 'a'),
-        &FragmentedMP4Parser::parseMediaHandler
-    },
-
-    { FOURCC('m', 'i', 'n', 'f'), FOURCC('m', 'd', 'i', 'a'), NULL },
-    { FOURCC('d', 'i', 'n', 'f'), FOURCC('m', 'i', 'n', 'f'), NULL },
-    { FOURCC('s', 't', 'b', 'l'), FOURCC('m', 'i', 'n', 'f'), NULL },
-    { FOURCC('s', 't', 's', 'd'), FOURCC('s', 't', 'b', 'l'), NULL },
-
-    { FOURCC('s', 't', 's', 'z'), FOURCC('s', 't', 'b', 'l'),
-        &FragmentedMP4Parser::parseSampleSizes },
-
-    { FOURCC('s', 't', 'z', '2'), FOURCC('s', 't', 'b', 'l'),
-        &FragmentedMP4Parser::parseCompactSampleSizes },
-
-    { FOURCC('s', 't', 's', 'c'), FOURCC('s', 't', 'b', 'l'),
-        &FragmentedMP4Parser::parseSampleToChunk },
-
-    { FOURCC('s', 't', 'c', 'o'), FOURCC('s', 't', 'b', 'l'),
-        &FragmentedMP4Parser::parseChunkOffsets },
-
-    { FOURCC('c', 'o', '6', '4'), FOURCC('s', 't', 'b', 'l'),
-        &FragmentedMP4Parser::parseChunkOffsets64 },
-
-    { FOURCC('a', 'v', 'c', 'C'), FOURCC('a', 'v', 'c', '1'),
-        &FragmentedMP4Parser::parseAVCCodecSpecificData },
-
-    { FOURCC('e', 's', 'd', 's'), FOURCC('m', 'p', '4', 'a'),
-        &FragmentedMP4Parser::parseESDSCodecSpecificData },
-
-    { FOURCC('e', 's', 'd', 's'), FOURCC('m', 'p', '4', 'v'),
-        &FragmentedMP4Parser::parseESDSCodecSpecificData },
-
-    { FOURCC('m', 'd', 'a', 't'), 0, &FragmentedMP4Parser::parseMediaData },
-
-    { FOURCC('m', 'o', 'o', 'f'), 0, NULL },
-    { FOURCC('t', 'r', 'a', 'f'), FOURCC('m', 'o', 'o', 'f'), NULL },
-
-    { FOURCC('t', 'f', 'h', 'd'), FOURCC('t', 'r', 'a', 'f'),
-        &FragmentedMP4Parser::parseTrackFragmentHeader
-    },
-    { FOURCC('t', 'r', 'u', 'n'), FOURCC('t', 'r', 'a', 'f'),
-        &FragmentedMP4Parser::parseTrackFragmentRun
-    },
-
-    { FOURCC('m', 'f', 'r', 'a'), 0, NULL },
-
-    { FOURCC('s', 'i', 'd', 'x'), 0, &FragmentedMP4Parser::parseSegmentIndex },
-};
-
-struct FileSource : public FragmentedMP4Parser::Source {
-    FileSource(const char *filename)
-        : mFile(fopen(filename, "rb")) {
-            CHECK(mFile != NULL);
-        }
-
-    virtual ~FileSource() {
-        fclose(mFile);
-    }
-
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
-        fseek(mFile, offset, SEEK_SET);
-        return fread(data, 1, size, mFile);
-    }
-
-    virtual bool isSeekable() {
-        return true;
-    }
-
-    private:
-    FILE *mFile;
-
-    DISALLOW_EVIL_CONSTRUCTORS(FileSource);
-};
-
-struct ReadTracker : public RefBase {
-    ReadTracker(off64_t size) {
-        allocSize = 1 + size / 8192; // 1 bit per kilobyte
-        bitmap = (char*) calloc(1, allocSize);
-    }
-    virtual ~ReadTracker() {
-        dumpToLog();
-        free(bitmap);
-    }
-    void mark(off64_t offset, size_t size) {
-        int firstbit = offset / 1024;
-        int lastbit = (offset + size - 1) / 1024;
-        for (int i = firstbit; i <= lastbit; i++) {
-            bitmap[i/8] |= (0x80 >> (i & 7));
-        }
-    }
-
- private:
-    void dumpToLog() {
-        // 96 chars per line, each char represents one kilobyte, 1 kb per bit
-        int numlines = allocSize / 12;
-        char buf[97];
-        char *cur = bitmap;
-        for (int i = 0; i < numlines; i++ && cur) {
-            for (int j = 0; j < 12; j++) {
-                for (int k = 0; k < 8; k++) {
-                    buf[(j * 8) + k] = (*cur & (0x80 >> k)) ? 'X' : '.';
-                }
-                cur++;
-            }
-            buf[96] = '\0';
-            ALOGI("%5dk: %s", i * 96, buf);
-        }
-    }
-
-    size_t allocSize;
-    char *bitmap;
-};
-
-struct DataSourceSource : public FragmentedMP4Parser::Source {
-    DataSourceSource(sp<DataSource> &source)
-        : mDataSource(source) {
-            CHECK(mDataSource != NULL);
-#if 0
-            off64_t size;
-            if (source->getSize(&size) == OK) {
-                mReadTracker = new ReadTracker(size);
-            } else {
-                ALOGE("couldn't get data source size");
-            }
-#endif
-        }
-
-    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
-        if (mReadTracker != NULL) {
-            mReadTracker->mark(offset, size);
-        }
-        return mDataSource->readAt(offset, data, size);
-    }
-
-    virtual bool isSeekable() {
-        return true;
-    }
-
-    private:
-    sp<DataSource> mDataSource;
-    sp<ReadTracker> mReadTracker;
-
-    DISALLOW_EVIL_CONSTRUCTORS(DataSourceSource);
-};
-
-FragmentedMP4Parser::FragmentedMP4Parser()
-    : mBufferPos(0),
-      mSuspended(false),
-      mDoneWithMoov(false),
-      mFirstMoofOffset(0),
-      mFinalResult(OK) {
-}
-
-FragmentedMP4Parser::~FragmentedMP4Parser() {
-}
-
-void FragmentedMP4Parser::start(const char *filename) {
-    sp<AMessage> msg = new AMessage(kWhatStart, id());
-    msg->setObject("source", new FileSource(filename));
-    msg->post();
-    ALOGV("Parser::start(%s)", filename);
-}
-
-void FragmentedMP4Parser::start(const sp<Source> &source) {
-    sp<AMessage> msg = new AMessage(kWhatStart, id());
-    msg->setObject("source", source);
-    msg->post();
-    ALOGV("Parser::start(Source)");
-}
-
-void FragmentedMP4Parser::start(sp<DataSource> &source) {
-    sp<AMessage> msg = new AMessage(kWhatStart, id());
-    msg->setObject("source", new DataSourceSource(source));
-    msg->post();
-    ALOGV("Parser::start(DataSource)");
-}
-
-sp<AMessage> FragmentedMP4Parser::getFormat(bool audio, bool synchronous) {
-
-    while (true) {
-        bool moovDone = mDoneWithMoov;
-        sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
-        msg->setInt32("audio", audio);
-
-        sp<AMessage> response;
-        status_t err = msg->postAndAwaitResponse(&response);
-
-        if (err != OK) {
-            ALOGV("getFormat post failed: %d", err);
-            return NULL;
-        }
-
-        if (response->findInt32("err", &err) && err != OK) {
-            if (synchronous && err == -EWOULDBLOCK && !moovDone) {
-                resumeIfNecessary();
-                ALOGV("@getFormat parser not ready yet, retrying");
-                usleep(10000);
-                continue;
-            }
-            ALOGV("getFormat failed: %d", err);
-            return NULL;
-        }
-
-        sp<AMessage> format;
-        CHECK(response->findMessage("format", &format));
-
-        ALOGV("returning format %s", format->debugString().c_str());
-        return format;
-    }
-}
-
-status_t FragmentedMP4Parser::seekTo(bool wantAudio, int64_t timeUs) {
-    sp<AMessage> msg = new AMessage(kWhatSeekTo, id());
-    msg->setInt32("audio", wantAudio);
-    msg->setInt64("position", timeUs);
-
-    sp<AMessage> response;
-    status_t err = msg->postAndAwaitResponse(&response);
-    return err;
-}
-
-bool FragmentedMP4Parser::isSeekable() const {
-    while (mFirstMoofOffset == 0 && mFinalResult == OK) {
-        usleep(10000);
-    }
-    bool seekable = mSource->isSeekable();
-    for (size_t i = 0; seekable && i < mTracks.size(); i++) {
-        const TrackInfo *info = &mTracks.valueAt(i);
-        seekable &= !info->mSidx.empty();
-    }
-    return seekable;
-}
-
-status_t FragmentedMP4Parser::onSeekTo(bool wantAudio, int64_t position) {
-    status_t err = -EINVAL;
-    ssize_t trackIndex = findTrack(wantAudio);
-    if (trackIndex < 0) {
-        err = trackIndex;
-    } else {
-        TrackInfo *info = &mTracks.editValueAt(trackIndex);
-
-        int numSidxEntries = info->mSidx.size();
-        int64_t totalTime = 0;
-        off_t totalOffset = mFirstMoofOffset;
-        for (int i = 0; i < numSidxEntries; i++) {
-            const SidxEntry *se = &info->mSidx[i];
-            if (totalTime + se->mDurationUs > position) {
-                mBuffer->setRange(0,0);
-                mBufferPos = totalOffset;
-                if (mFinalResult == ERROR_END_OF_STREAM) {
-                    mFinalResult = OK;
-                    mSuspended = true; // force resume
-                    resumeIfNecessary();
-                }
-                info->mFragments.clear();
-                info->mDecodingTime = totalTime * info->mMediaTimeScale / 1000000ll;
-                return OK;
-            }
-            totalTime += se->mDurationUs;
-            totalOffset += se->mSize;
-        }
-    }
-    ALOGV("seekTo out of range");
-    return err;
-}
-
-status_t FragmentedMP4Parser::dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit,
-                                                bool synchronous) {
-
-    while (true) {
-        sp<AMessage> msg = new AMessage(kWhatDequeueAccessUnit, id());
-        msg->setInt32("audio", audio);
-
-        sp<AMessage> response;
-        status_t err = msg->postAndAwaitResponse(&response);
-
-        if (err != OK) {
-            ALOGV("dequeue fail 1: %d", err);
-            return err;
-        }
-
-        if (response->findInt32("err", &err) && err != OK) {
-            if (synchronous && err == -EWOULDBLOCK) {
-                resumeIfNecessary();
-                ALOGV("Parser not ready yet, retrying");
-                usleep(10000);
-                continue;
-            }
-            ALOGV("dequeue fail 2: %d, %d", err, synchronous);
-            return err;
-        }
-
-        CHECK(response->findBuffer("accessUnit", accessUnit));
-
-        return OK;
-    }
-}
-
-ssize_t FragmentedMP4Parser::findTrack(bool wantAudio) const {
-    for (size_t i = 0; i < mTracks.size(); ++i) {
-        const TrackInfo *info = &mTracks.valueAt(i);
-
-        bool isAudio =
-            info->mMediaHandlerType == FOURCC('s', 'o', 'u', 'n');
-
-        bool isVideo =
-            info->mMediaHandlerType == FOURCC('v', 'i', 'd', 'e');
-
-        if ((wantAudio && isAudio) || (!wantAudio && !isAudio)) {
-            if (info->mSampleDescs.empty()) {
-                break;
-            }
-
-            return i;
-        }
-    }
-
-    return -EWOULDBLOCK;
-}
-
-void FragmentedMP4Parser::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-        case kWhatStart:
-        {
-            sp<RefBase> obj;
-            CHECK(msg->findObject("source", &obj));
-
-            mSource = static_cast<Source *>(obj.get());
-
-            mBuffer = new ABuffer(512 * 1024);
-            mBuffer->setRange(0, 0);
-
-            enter(0ll, 0, 0);
-
-            (new AMessage(kWhatProceed, id()))->post();
-            break;
-        }
-
-        case kWhatProceed:
-        {
-            CHECK(!mSuspended);
-
-            status_t err = onProceed();
-
-            if (err == OK) {
-                if (!mSuspended) {
-                    msg->post();
-                }
-            } else if (err != -EAGAIN) {
-                ALOGE("onProceed returned error %d", err);
-            }
-
-            break;
-        }
-
-        case kWhatReadMore:
-        {
-            size_t needed;
-            CHECK(msg->findSize("needed", &needed));
-
-            memmove(mBuffer->base(), mBuffer->data(), mBuffer->size());
-            mBufferPos += mBuffer->offset();
-            mBuffer->setRange(0, mBuffer->size());
-
-            size_t maxBytesToRead = mBuffer->capacity() - mBuffer->size();
-
-            if (maxBytesToRead < needed) {
-                ALOGV("resizing buffer.");
-
-                sp<ABuffer> newBuffer =
-                    new ABuffer((mBuffer->size() + needed + 1023) & ~1023);
-                memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
-                newBuffer->setRange(0, mBuffer->size());
-
-                mBuffer = newBuffer;
-                maxBytesToRead = mBuffer->capacity() - mBuffer->size();
-            }
-
-            CHECK_GE(maxBytesToRead, needed);
-
-            ssize_t n = mSource->readAt(
-                    mBufferPos + mBuffer->size(),
-                    mBuffer->data() + mBuffer->size(), needed);
-
-            if (n < (ssize_t)needed) {
-                ALOGV("Reached EOF when reading %d @ %d + %d", needed, mBufferPos, mBuffer->size());
-                if (n < 0) {
-                    mFinalResult = n;
-                } else if (n == 0) {
-                    mFinalResult = ERROR_END_OF_STREAM;
-                } else {
-                    mFinalResult = ERROR_IO;
-                }
-            } else {
-                mBuffer->setRange(0, mBuffer->size() + n);
-                (new AMessage(kWhatProceed, id()))->post();
-            }
-
-            break;
-        }
-
-        case kWhatGetFormat:
-        {
-            int32_t wantAudio;
-            CHECK(msg->findInt32("audio", &wantAudio));
-
-            status_t err = -EWOULDBLOCK;
-            sp<AMessage> response = new AMessage;
-
-            ssize_t trackIndex = findTrack(wantAudio);
-
-            if (trackIndex < 0) {
-                err = trackIndex;
-            } else {
-                TrackInfo *info = &mTracks.editValueAt(trackIndex);
-
-                sp<AMessage> format = info->mSampleDescs.itemAt(0).mFormat;
-                if (info->mSidxDuration) {
-                    format->setInt64("durationUs", info->mSidxDuration);
-                } else {
-                    // this is probably going to be zero. Oh well...
-                    format->setInt64("durationUs",
-                                     1000000ll * info->mDuration / info->mMediaTimeScale);
-                }
-                response->setMessage(
-                        "format", format);
-
-                err = OK;
-            }
-
-            response->setInt32("err", err);
-
-            uint32_t replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
-            response->postReply(replyID);
-            break;
-        }
-
-        case kWhatDequeueAccessUnit:
-        {
-            int32_t wantAudio;
-            CHECK(msg->findInt32("audio", &wantAudio));
-
-            status_t err = -EWOULDBLOCK;
-            sp<AMessage> response = new AMessage;
-
-            ssize_t trackIndex = findTrack(wantAudio);
-
-            if (trackIndex < 0) {
-                err = trackIndex;
-            } else {
-                sp<ABuffer> accessUnit;
-                err = onDequeueAccessUnit(trackIndex, &accessUnit);
-
-                if (err == OK) {
-                    response->setBuffer("accessUnit", accessUnit);
-                }
-            }
-
-            response->setInt32("err", err);
-
-            uint32_t replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-
-            response->postReply(replyID);
-            break;
-        }
-
-        case kWhatSeekTo:
-        {
-            ALOGV("kWhatSeekTo");
-            int32_t wantAudio;
-            CHECK(msg->findInt32("audio", &wantAudio));
-            int64_t position;
-            CHECK(msg->findInt64("position", &position));
-
-            status_t err = -EWOULDBLOCK;
-            sp<AMessage> response = new AMessage;
-
-            ssize_t trackIndex = findTrack(wantAudio);
-
-            if (trackIndex < 0) {
-                err = trackIndex;
-            } else {
-                err = onSeekTo(wantAudio, position);
-            }
-            response->setInt32("err", err);
-            uint32_t replyID;
-            CHECK(msg->senderAwaitsResponse(&replyID));
-            response->postReply(replyID);
-            break;
-        }
-        default:
-            TRESPASS();
-    }
-}
-
-status_t FragmentedMP4Parser::onProceed() {
-    status_t err;
-
-    if ((err = need(8)) != OK) {
-        return err;
-    }
-
-    uint64_t size = readU32(0);
-    uint32_t type = readU32(4);
-
-    size_t offset = 8;
-
-    if (size == 1) {
-        if ((err = need(16)) != OK) {
-            return err;
-        }
-
-        size = readU64(offset);
-        offset += 8;
-    }
-
-    uint8_t userType[16];
-
-    if (type == FOURCC('u', 'u', 'i', 'd')) {
-        if ((err = need(offset + 16)) != OK) {
-            return err;
-        }
-
-        memcpy(userType, mBuffer->data() + offset, 16);
-        offset += 16;
-    }
-
-    CHECK(!mStack.isEmpty());
-    uint32_t ptype = mStack.itemAt(mStack.size() - 1).mType;
-
-    static const size_t kNumDispatchers =
-        sizeof(kDispatchTable) / sizeof(kDispatchTable[0]);
-
-    size_t i;
-    for (i = 0; i < kNumDispatchers; ++i) {
-        if (kDispatchTable[i].mType == type
-                && kDispatchTable[i].mParentType == ptype) {
-            break;
-        }
-    }
-
-    // SampleEntry boxes are container boxes that start with a variable
-    // amount of data depending on the media handler type.
-    // We don't look inside 'hint' type SampleEntry boxes.
-
-    bool isSampleEntryBox =
-        (ptype == FOURCC('s', 't', 's', 'd'))
-        && editTrack(mCurrentTrackID)->mMediaHandlerType
-        != FOURCC('h', 'i', 'n', 't');
-
-    if ((i < kNumDispatchers && kDispatchTable[i].mHandler == 0)
-            || isSampleEntryBox || ptype == FOURCC('i', 'l', 's', 't')) {
-        // This is a container box.
-        if (type == FOURCC('m', 'o', 'o', 'f')) {
-            if (mFirstMoofOffset == 0) {
-                ALOGV("first moof @ %08x", mBufferPos + offset);
-                mFirstMoofOffset = mBufferPos + offset - 8; // point at the size
-            }
-        }
-        if (type == FOURCC('m', 'e', 't', 'a')) {
-            if ((err = need(offset + 4)) < OK) {
-                return err;
-            }
-
-            if (readU32(offset) != 0) {
-                return -EINVAL;
-            }
-
-            offset += 4;
-        } else if (type == FOURCC('s', 't', 's', 'd')) {
-            if ((err = need(offset + 8)) < OK) {
-                return err;
-            }
-
-            if (readU32(offset) != 0) {
-                return -EINVAL;
-            }
-
-            if (readU32(offset + 4) == 0) {
-                // We need at least some entries.
-                return -EINVAL;
-            }
-
-            offset += 8;
-        } else if (isSampleEntryBox) {
-            size_t headerSize;
-
-            switch (editTrack(mCurrentTrackID)->mMediaHandlerType) {
-                case FOURCC('v', 'i', 'd', 'e'):
-                {
-                    // 8 bytes SampleEntry + 70 bytes VisualSampleEntry
-                    headerSize = 78;
-                    break;
-                }
-
-                case FOURCC('s', 'o', 'u', 'n'):
-                {
-                    // 8 bytes SampleEntry + 20 bytes AudioSampleEntry
-                    headerSize = 28;
-                    break;
-                }
-
-                case FOURCC('m', 'e', 't', 'a'):
-                {
-                    headerSize = 8;  // 8 bytes SampleEntry
-                    break;
-                }
-
-                default:
-                    TRESPASS();
-            }
-
-            if (offset + headerSize > size) {
-                return -EINVAL;
-            }
-
-            if ((err = need(offset + headerSize)) != OK) {
-                return err;
-            }
-
-            switch (editTrack(mCurrentTrackID)->mMediaHandlerType) {
-                case FOURCC('v', 'i', 'd', 'e'):
-                {
-                    err = parseVisualSampleEntry(
-                            type, offset, offset + headerSize);
-                    break;
-                }
-
-                case FOURCC('s', 'o', 'u', 'n'):
-                {
-                    err = parseAudioSampleEntry(
-                            type, offset, offset + headerSize);
-                    break;
-                }
-
-                case FOURCC('m', 'e', 't', 'a'):
-                {
-                    err = OK;
-                    break;
-                }
-
-                default:
-                    TRESPASS();
-            }
-
-            if (err != OK) {
-                return err;
-            }
-
-            offset += headerSize;
-        }
-
-        skip(offset);
-
-        ALOGV("%sentering box of type '%s'",
-                IndentString(mStack.size()), Fourcc2String(type));
-
-        enter(mBufferPos - offset, type, size - offset);
-    } else {
-        if (!fitsContainer(size)) {
-            return -EINVAL;
-        }
-
-        if (i < kNumDispatchers && kDispatchTable[i].mHandler != 0) {
-            // We have a handler for this box type.
-
-            if ((err = need(size)) != OK) {
-                return err;
-            }
-
-            ALOGV("%sparsing box of type '%s'",
-                    IndentString(mStack.size()), Fourcc2String(type));
-
-            if ((err = (this->*kDispatchTable[i].mHandler)(
-                            type, offset, size)) != OK) {
-                return err;
-            }
-        } else {
-            // Unknown box type
-
-            ALOGV("%sskipping box of type '%s', size %llu",
-                    IndentString(mStack.size()),
-                    Fourcc2String(type), size);
-
-        }
-
-        skip(size);
-    }
-
-    return OK;
-}
-
-// static
-int FragmentedMP4Parser::CompareSampleLocation(
-        const SampleInfo &sample, const MediaDataInfo &mdatInfo) {
-    if (sample.mOffset + sample.mSize < mdatInfo.mOffset) {
-        return -1;
-    }
-
-    if (sample.mOffset >= mdatInfo.mOffset + mdatInfo.mBuffer->size()) {
-        return 1;
-    }
-
-    // Otherwise make sure the sample is completely contained within this
-    // media data block.
-
-    CHECK_GE(sample.mOffset, mdatInfo.mOffset);
-
-    CHECK_LE(sample.mOffset + sample.mSize,
-             mdatInfo.mOffset + mdatInfo.mBuffer->size());
-
-    return 0;
-}
-
-void FragmentedMP4Parser::resumeIfNecessary() {
-    if (!mSuspended) {
-        return;
-    }
-
-    ALOGV("resuming.");
-
-    mSuspended = false;
-    (new AMessage(kWhatProceed, id()))->post();
-}
-
-status_t FragmentedMP4Parser::getSample(
-        TrackInfo *info, sp<TrackFragment> *fragment, SampleInfo *sampleInfo) {
-    for (;;) {
-        if (info->mFragments.empty()) {
-            if (mFinalResult != OK) {
-                return mFinalResult;
-            }
-
-            resumeIfNecessary();
-            return -EWOULDBLOCK;
-        }
-
-        *fragment = *info->mFragments.begin();
-
-        status_t err = (*fragment)->getSample(sampleInfo);
-
-        if (err == OK) {
-            return OK;
-        } else if (err != ERROR_END_OF_STREAM) {
-            return err;
-        }
-
-        // Really, end of this fragment...
-
-        info->mFragments.erase(info->mFragments.begin());
-    }
-}
-
-status_t FragmentedMP4Parser::onDequeueAccessUnit(
-        size_t trackIndex, sp<ABuffer> *accessUnit) {
-    TrackInfo *info = &mTracks.editValueAt(trackIndex);
-
-    sp<TrackFragment> fragment;
-    SampleInfo sampleInfo;
-    status_t err = getSample(info, &fragment, &sampleInfo);
-
-    if (err == -EWOULDBLOCK) {
-        resumeIfNecessary();
-        return err;
-    } else if (err != OK) {
-        return err;
-    }
-
-    err = -EWOULDBLOCK;
-
-    bool checkDroppable = false;
-
-    for (size_t i = 0; i < mMediaData.size(); ++i) {
-        const MediaDataInfo &mdatInfo = mMediaData.itemAt(i);
-
-        int cmp = CompareSampleLocation(sampleInfo, mdatInfo);
-
-        if (cmp < 0 && !mSource->isSeekable()) {
-            return -EPIPE;
-        } else if (cmp == 0) {
-            if (i > 0) {
-                checkDroppable = true;
-            }
-
-            err = makeAccessUnit(info, sampleInfo, mdatInfo, accessUnit);
-            break;
-        }
-    }
-
-    if (err != OK) {
-        return err;
-    }
-
-    fragment->advance();
-
-    if (!mMediaData.empty() && checkDroppable) {
-        size_t numDroppable = 0;
-        bool done = false;
-
-        // XXX FIXME: if one of the tracks is not advanced (e.g. if you play an audio+video
-        // file with sf2), then mMediaData will not be pruned and keeps growing
-        for (size_t i = 0; !done && i < mMediaData.size(); ++i) {
-            const MediaDataInfo &mdatInfo = mMediaData.itemAt(i);
-
-            for (size_t j = 0; j < mTracks.size(); ++j) {
-                TrackInfo *info = &mTracks.editValueAt(j);
-
-                sp<TrackFragment> fragment;
-                SampleInfo sampleInfo;
-                err = getSample(info, &fragment, &sampleInfo);
-
-                if (err != OK) {
-                    done = true;
-                    break;
-                }
-
-                int cmp = CompareSampleLocation(sampleInfo, mdatInfo);
-
-                if (cmp <= 0) {
-                    done = true;
-                    break;
-                }
-            }
-
-            if (!done) {
-                ++numDroppable;
-            }
-        }
-
-        if (numDroppable > 0) {
-            mMediaData.removeItemsAt(0, numDroppable);
-
-            if (mMediaData.size() < 5) {
-                resumeIfNecessary();
-            }
-        }
-    }
-
-    return err;
-}
-
-static size_t parseNALSize(size_t nalLengthSize, const uint8_t *data) {
-    switch (nalLengthSize) {
-        case 1:
-            return *data;
-        case 2:
-            return U16_AT(data);
-        case 3:
-            return ((size_t)data[0] << 16) | U16_AT(&data[1]);
-        case 4:
-            return U32_AT(data);
-    }
-
-    // This cannot happen, mNALLengthSize springs to life by adding 1 to
-    // a 2-bit integer.
-    TRESPASS();
-
-    return 0;
-}
-
-status_t FragmentedMP4Parser::makeAccessUnit(
-        TrackInfo *info,
-        const SampleInfo &sample,
-        const MediaDataInfo &mdatInfo,
-        sp<ABuffer> *accessUnit) {
-    if (sample.mSampleDescIndex < 1
-            || sample.mSampleDescIndex > info->mSampleDescs.size()) {
-        return ERROR_MALFORMED;
-    }
-
-    int64_t presentationTimeUs =
-        1000000ll * sample.mPresentationTime / info->mMediaTimeScale;
-
-    const SampleDescription &sampleDesc =
-        info->mSampleDescs.itemAt(sample.mSampleDescIndex - 1);
-
-    size_t nalLengthSize;
-    if (!sampleDesc.mFormat->findSize("nal-length-size", &nalLengthSize)) {
-        *accessUnit = new ABuffer(sample.mSize);
-
-        memcpy((*accessUnit)->data(),
-               mdatInfo.mBuffer->data() + (sample.mOffset - mdatInfo.mOffset),
-               sample.mSize);
-
-        (*accessUnit)->meta()->setInt64("timeUs", presentationTimeUs);
-        if (IsIDR(*accessUnit)) {
-            (*accessUnit)->meta()->setInt32("is-sync-frame", 1);
-        }
-
-        return OK;
-    }
-
-    const uint8_t *srcPtr =
-        mdatInfo.mBuffer->data() + (sample.mOffset - mdatInfo.mOffset);
-
-    for (int i = 0; i < 2 ; ++i) {
-        size_t srcOffset = 0;
-        size_t dstOffset = 0;
-
-        while (srcOffset < sample.mSize) {
-            if (srcOffset + nalLengthSize > sample.mSize) {
-                return ERROR_MALFORMED;
-            }
-
-            size_t nalSize = parseNALSize(nalLengthSize, &srcPtr[srcOffset]);
-            srcOffset += nalLengthSize;
-
-            if (srcOffset + nalSize > sample.mSize) {
-                return ERROR_MALFORMED;
-            }
-
-            if (i == 1) {
-                memcpy((*accessUnit)->data() + dstOffset,
-                       "\x00\x00\x00\x01",
-                       4);
-
-                memcpy((*accessUnit)->data() + dstOffset + 4,
-                       srcPtr + srcOffset,
-                       nalSize);
-            }
-
-            srcOffset += nalSize;
-            dstOffset += nalSize + 4;
-        }
-
-        if (i == 0) {
-            (*accessUnit) = new ABuffer(dstOffset);
-            (*accessUnit)->meta()->setInt64(
-                    "timeUs", presentationTimeUs);
-        }
-    }
-    if (IsIDR(*accessUnit)) {
-        (*accessUnit)->meta()->setInt32("is-sync-frame", 1);
-    }
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::need(size_t size) {
-    if (!fitsContainer(size)) {
-        return -EINVAL;
-    }
-
-    if (size <= mBuffer->size()) {
-        return OK;
-    }
-
-    sp<AMessage> msg = new AMessage(kWhatReadMore, id());
-    msg->setSize("needed", size - mBuffer->size());
-    msg->post();
-
-    // ALOGV("need(%d) returning -EAGAIN, only have %d", size, mBuffer->size());
-
-    return -EAGAIN;
-}
-
-void FragmentedMP4Parser::enter(off64_t offset, uint32_t type, uint64_t size) {
-    Container container;
-    container.mOffset = offset;
-    container.mType = type;
-    container.mExtendsToEOF = (size == 0);
-    container.mBytesRemaining = size;
-
-    mStack.push(container);
-}
-
-bool FragmentedMP4Parser::fitsContainer(uint64_t size) const {
-    CHECK(!mStack.isEmpty());
-    const Container &container = mStack.itemAt(mStack.size() - 1);
-
-    return container.mExtendsToEOF || size <= container.mBytesRemaining;
-}
-
-uint16_t FragmentedMP4Parser::readU16(size_t offset) {
-    CHECK_LE(offset + 2, mBuffer->size());
-
-    const uint8_t *ptr = mBuffer->data() + offset;
-    return (ptr[0] << 8) | ptr[1];
-}
-
-uint32_t FragmentedMP4Parser::readU32(size_t offset) {
-    CHECK_LE(offset + 4, mBuffer->size());
-
-    const uint8_t *ptr = mBuffer->data() + offset;
-    return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
-}
-
-uint64_t FragmentedMP4Parser::readU64(size_t offset) {
-    return (((uint64_t)readU32(offset)) << 32) | readU32(offset + 4);
-}
-
-void FragmentedMP4Parser::skip(off_t distance) {
-    CHECK(!mStack.isEmpty());
-    for (size_t i = mStack.size(); i-- > 0;) {
-        Container *container = &mStack.editItemAt(i);
-        if (!container->mExtendsToEOF) {
-            CHECK_LE(distance, (off_t)container->mBytesRemaining);
-
-            container->mBytesRemaining -= distance;
-
-            if (container->mBytesRemaining == 0) {
-                ALOGV("%sleaving box of type '%s'",
-                        IndentString(mStack.size() - 1),
-                        Fourcc2String(container->mType));
-
-#if 0
-                if (container->mType == FOURCC('s', 't', 's', 'd')) {
-                    TrackInfo *trackInfo = editTrack(mCurrentTrackID);
-                    for (size_t i = 0;
-                            i < trackInfo->mSampleDescs.size(); ++i) {
-                        ALOGI("format #%d: %s",
-                              i,
-                              trackInfo->mSampleDescs.itemAt(i)
-                                .mFormat->debugString().c_str());
-                    }
-                }
-#endif
-
-                if (container->mType == FOURCC('s', 't', 'b', 'l')) {
-                    TrackInfo *trackInfo = editTrack(mCurrentTrackID);
-
-                    trackInfo->mStaticFragment->signalCompletion();
-
-                    CHECK(trackInfo->mFragments.empty());
-                    trackInfo->mFragments.push_back(trackInfo->mStaticFragment);
-                    trackInfo->mStaticFragment.clear();
-                } else if (container->mType == FOURCC('t', 'r', 'a', 'f')) {
-                    TrackInfo *trackInfo =
-                        editTrack(mTrackFragmentHeaderInfo.mTrackID);
-
-                    const sp<TrackFragment> &fragment =
-                        *--trackInfo->mFragments.end();
-
-                    static_cast<DynamicTrackFragment *>(
-                            fragment.get())->signalCompletion();
-                } else if (container->mType == FOURCC('m', 'o', 'o', 'v')) {
-                    mDoneWithMoov = true;
-                }
-
-                container = NULL;
-                mStack.removeItemsAt(i);
-            }
-        }
-    }
-
-    if (distance < (off_t)mBuffer->size()) {
-        mBuffer->setRange(mBuffer->offset() + distance, mBuffer->size() - distance);
-        mBufferPos += distance;
-        return;
-    }
-
-    mBuffer->setRange(0, 0);
-    mBufferPos += distance;
-}
-
-status_t FragmentedMP4Parser::parseTrackHeader(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 4 > size) {
-        return -EINVAL;
-    }
-
-    uint32_t flags = readU32(offset);
-
-    uint32_t version = flags >> 24;
-    flags &= 0xffffff;
-
-    uint32_t trackID;
-    uint64_t duration;
-
-    if (version == 1) {
-        if (offset + 36 > size) {
-            return -EINVAL;
-        }
-
-        trackID = readU32(offset + 20);
-        duration = readU64(offset + 28);
-
-        offset += 36;
-    } else if (version == 0) {
-        if (offset + 24 > size) {
-            return -EINVAL;
-        }
-
-        trackID = readU32(offset + 12);
-        duration = readU32(offset + 20);
-
-        offset += 24;
-    } else {
-        return -EINVAL;
-    }
-
-    TrackInfo *info = editTrack(trackID, true /* createIfNecessary */);
-    info->mFlags = flags;
-    info->mDuration = duration;
-    if (info->mDuration == 0xffffffff) {
-        // ffmpeg sets this to -1, which is incorrect.
-        info->mDuration = 0;
-    }
-
-    info->mStaticFragment = new StaticTrackFragment;
-
-    mCurrentTrackID = trackID;
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseMediaHeader(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 4 > size) {
-        return -EINVAL;
-    }
-
-    uint32_t versionAndFlags = readU32(offset);
-
-    if (versionAndFlags & 0xffffff) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t version = versionAndFlags >> 24;
-
-    TrackInfo *info = editTrack(mCurrentTrackID);
-
-    if (version == 1) {
-        if (offset + 4 + 32 > size) {
-            return -EINVAL;
-        }
-        info->mMediaTimeScale = U32_AT(mBuffer->data() + offset + 20);
-    } else if (version == 0) {
-        if (offset + 4 + 20 > size) {
-            return -EINVAL;
-        }
-        info->mMediaTimeScale = U32_AT(mBuffer->data() + offset + 12);
-    } else {
-        return ERROR_MALFORMED;
-    }
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseMediaHandler(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 12 > size) {
-        return -EINVAL;
-    }
-
-    if (readU32(offset) != 0) {
-        return -EINVAL;
-    }
-
-    uint32_t handlerType = readU32(offset + 8);
-
-    switch (handlerType) {
-        case FOURCC('v', 'i', 'd', 'e'):
-        case FOURCC('s', 'o', 'u', 'n'):
-        case FOURCC('h', 'i', 'n', 't'):
-        case FOURCC('m', 'e', 't', 'a'):
-            break;
-
-        default:
-            return -EINVAL;
-    }
-
-    editTrack(mCurrentTrackID)->mMediaHandlerType = handlerType;
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseVisualSampleEntry(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 78 > size) {
-        return -EINVAL;
-    }
-
-    TrackInfo *trackInfo = editTrack(mCurrentTrackID);
-
-    trackInfo->mSampleDescs.push();
-    SampleDescription *sampleDesc =
-        &trackInfo->mSampleDescs.editItemAt(
-                trackInfo->mSampleDescs.size() - 1);
-
-    sampleDesc->mType = type;
-    sampleDesc->mDataRefIndex = readU16(offset + 6);
-
-    sp<AMessage> format = new AMessage;
-
-    switch (type) {
-        case FOURCC('a', 'v', 'c', '1'):
-            format->setString("mime", MEDIA_MIMETYPE_VIDEO_AVC);
-            break;
-        case FOURCC('m', 'p', '4', 'v'):
-            format->setString("mime", MEDIA_MIMETYPE_VIDEO_MPEG4);
-            break;
-        case FOURCC('s', '2', '6', '3'):
-        case FOURCC('h', '2', '6', '3'):
-        case FOURCC('H', '2', '6', '3'):
-            format->setString("mime", MEDIA_MIMETYPE_VIDEO_H263);
-            break;
-        default:
-            format->setString("mime", "application/octet-stream");
-            break;
-    }
-
-    format->setInt32("width", readU16(offset + 8 + 16));
-    format->setInt32("height", readU16(offset + 8 + 18));
-
-    sampleDesc->mFormat = format;
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseAudioSampleEntry(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 28 > size) {
-        return -EINVAL;
-    }
-
-    TrackInfo *trackInfo = editTrack(mCurrentTrackID);
-
-    trackInfo->mSampleDescs.push();
-    SampleDescription *sampleDesc =
-        &trackInfo->mSampleDescs.editItemAt(
-                trackInfo->mSampleDescs.size() - 1);
-
-    sampleDesc->mType = type;
-    sampleDesc->mDataRefIndex = readU16(offset + 6);
-
-    sp<AMessage> format = new AMessage;
-
-    format->setInt32("channel-count", readU16(offset + 8 + 8));
-    format->setInt32("sample-size", readU16(offset + 8 + 10));
-    format->setInt32("sample-rate", readU32(offset + 8 + 16) / 65536.0f);
-
-    switch (type) {
-        case FOURCC('m', 'p', '4', 'a'):
-            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
-            break;
-
-        case FOURCC('s', 'a', 'm', 'r'):
-            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_NB);
-            format->setInt32("channel-count", 1);
-            format->setInt32("sample-rate", 8000);
-            break;
-
-        case FOURCC('s', 'a', 'w', 'b'):
-            format->setString("mime", MEDIA_MIMETYPE_AUDIO_AMR_WB);
-            format->setInt32("channel-count", 1);
-            format->setInt32("sample-rate", 16000);
-            break;
-        default:
-            format->setString("mime", "application/octet-stream");
-            break;
-    }
-
-    sampleDesc->mFormat = format;
-
-    return OK;
-}
-
-static void addCodecSpecificData(
-        const sp<AMessage> &format, int32_t index,
-        const void *data, size_t size,
-        bool insertStartCode = false) {
-    sp<ABuffer> csd = new ABuffer(insertStartCode ? size + 4 : size);
-
-    memcpy(csd->data() + (insertStartCode ? 4 : 0), data, size);
-
-    if (insertStartCode) {
-        memcpy(csd->data(), "\x00\x00\x00\x01", 4);
-    }
-
-    csd->meta()->setInt32("csd", true);
-    csd->meta()->setInt64("timeUs", 0ll);
-
-    format->setBuffer(StringPrintf("csd-%d", index).c_str(), csd);
-}
-
-status_t FragmentedMP4Parser::parseSampleSizes(
-        uint32_t type, size_t offset, uint64_t size) {
-    return editTrack(mCurrentTrackID)->mStaticFragment->parseSampleSizes(
-            this, type, offset, size);
-}
-
-status_t FragmentedMP4Parser::parseCompactSampleSizes(
-        uint32_t type, size_t offset, uint64_t size) {
-    return editTrack(mCurrentTrackID)->mStaticFragment->parseCompactSampleSizes(
-            this, type, offset, size);
-}
-
-status_t FragmentedMP4Parser::parseSampleToChunk(
-        uint32_t type, size_t offset, uint64_t size) {
-    return editTrack(mCurrentTrackID)->mStaticFragment->parseSampleToChunk(
-            this, type, offset, size);
-}
-
-status_t FragmentedMP4Parser::parseChunkOffsets(
-        uint32_t type, size_t offset, uint64_t size) {
-    return editTrack(mCurrentTrackID)->mStaticFragment->parseChunkOffsets(
-            this, type, offset, size);
-}
-
-status_t FragmentedMP4Parser::parseChunkOffsets64(
-        uint32_t type, size_t offset, uint64_t size) {
-    return editTrack(mCurrentTrackID)->mStaticFragment->parseChunkOffsets64(
-            this, type, offset, size);
-}
-
-status_t FragmentedMP4Parser::parseAVCCodecSpecificData(
-        uint32_t type, size_t offset, uint64_t size) {
-    TrackInfo *trackInfo = editTrack(mCurrentTrackID);
-
-    SampleDescription *sampleDesc =
-        &trackInfo->mSampleDescs.editItemAt(
-                trackInfo->mSampleDescs.size() - 1);
-
-    if (sampleDesc->mType != FOURCC('a', 'v', 'c', '1')) {
-        return -EINVAL;
-    }
-
-    const uint8_t *ptr = mBuffer->data() + offset;
-
-    size -= offset;
-    offset = 0;
-
-    if (size < 7 || ptr[0] != 0x01) {
-        return ERROR_MALFORMED;
-    }
-
-    sampleDesc->mFormat->setSize("nal-length-size", 1 + (ptr[4] & 3));
-
-    size_t numSPS = ptr[5] & 31;
-
-    ptr += 6;
-    size -= 6;
-
-    for (size_t i = 0; i < numSPS; ++i) {
-        if (size < 2) {
-            return ERROR_MALFORMED;
-        }
-
-        size_t length = U16_AT(ptr);
-
-        ptr += 2;
-        size -= 2;
-
-        if (size < length) {
-            return ERROR_MALFORMED;
-        }
-
-        addCodecSpecificData(
-                sampleDesc->mFormat, i, ptr, length,
-                true /* insertStartCode */);
-
-        ptr += length;
-        size -= length;
-    }
-
-    if (size < 1) {
-        return ERROR_MALFORMED;
-    }
-
-    size_t numPPS = *ptr;
-    ++ptr;
-    --size;
-
-    for (size_t i = 0; i < numPPS; ++i) {
-        if (size < 2) {
-            return ERROR_MALFORMED;
-        }
-
-        size_t length = U16_AT(ptr);
-
-        ptr += 2;
-        size -= 2;
-
-        if (size < length) {
-            return ERROR_MALFORMED;
-        }
-
-        addCodecSpecificData(
-                sampleDesc->mFormat, numSPS + i, ptr, length,
-                true /* insertStartCode */);
-
-        ptr += length;
-        size -= length;
-    }
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseESDSCodecSpecificData(
-        uint32_t type, size_t offset, uint64_t size) {
-    TrackInfo *trackInfo = editTrack(mCurrentTrackID);
-
-    SampleDescription *sampleDesc =
-        &trackInfo->mSampleDescs.editItemAt(
-                trackInfo->mSampleDescs.size() - 1);
-
-    if (sampleDesc->mType != FOURCC('m', 'p', '4', 'a')
-            && sampleDesc->mType != FOURCC('m', 'p', '4', 'v')) {
-        return -EINVAL;
-    }
-
-    const uint8_t *ptr = mBuffer->data() + offset;
-
-    size -= offset;
-    offset = 0;
-
-    if (size < 4) {
-        return -EINVAL;
-    }
-
-    if (U32_AT(ptr) != 0) {
-        return -EINVAL;
-    }
-
-    ptr += 4;
-    size -=4;
-
-    ESDS esds(ptr, size);
-
-    uint8_t objectTypeIndication;
-    if (esds.getObjectTypeIndication(&objectTypeIndication) != OK) {
-        return ERROR_MALFORMED;
-    }
-
-    const uint8_t *csd;
-    size_t csd_size;
-    if (esds.getCodecSpecificInfo(
-                (const void **)&csd, &csd_size) != OK) {
-        return ERROR_MALFORMED;
-    }
-
-    addCodecSpecificData(sampleDesc->mFormat, 0, csd, csd_size);
-
-    if (sampleDesc->mType != FOURCC('m', 'p', '4', 'a')) {
-        return OK;
-    }
-
-    if (csd_size == 0) {
-        // There's no further information, i.e. no codec specific data
-        // Let's assume that the information provided in the mpeg4 headers
-        // is accurate and hope for the best.
-
-        return OK;
-    }
-
-    if (csd_size < 2) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t objectType = csd[0] >> 3;
-
-    if (objectType == 31) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    uint32_t freqIndex = (csd[0] & 7) << 1 | (csd[1] >> 7);
-    int32_t sampleRate = 0;
-    int32_t numChannels = 0;
-    if (freqIndex == 15) {
-        if (csd_size < 5) {
-            return ERROR_MALFORMED;
-        }
-
-        sampleRate = (csd[1] & 0x7f) << 17
-                        | csd[2] << 9
-                        | csd[3] << 1
-                        | (csd[4] >> 7);
-
-        numChannels = (csd[4] >> 3) & 15;
-    } else {
-        static uint32_t kSamplingRate[] = {
-            96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
-            16000, 12000, 11025, 8000, 7350
-        };
-
-        if (freqIndex == 13 || freqIndex == 14) {
-            return ERROR_MALFORMED;
-        }
-
-        sampleRate = kSamplingRate[freqIndex];
-        numChannels = (csd[1] >> 3) & 15;
-    }
-
-    if (numChannels == 0) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    sampleDesc->mFormat->setInt32("sample-rate", sampleRate);
-    sampleDesc->mFormat->setInt32("channel-count", numChannels);
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseMediaData(
-        uint32_t type, size_t offset, uint64_t size) {
-    ALOGV("skipping 'mdat' chunk at offsets 0x%08lx-0x%08llx.",
-          mBufferPos + offset, mBufferPos + size);
-
-    sp<ABuffer> buffer = new ABuffer(size - offset);
-    memcpy(buffer->data(), mBuffer->data() + offset, size - offset);
-
-    mMediaData.push();
-    MediaDataInfo *info = &mMediaData.editItemAt(mMediaData.size() - 1);
-    info->mBuffer = buffer;
-    info->mOffset = mBufferPos + offset;
-
-    if (mMediaData.size() > 10) {
-        ALOGV("suspending for now.");
-        mSuspended = true;
-    }
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseSegmentIndex(
-        uint32_t type, size_t offset, uint64_t size) {
-    ALOGV("sidx box type %d, offset %d, size %d", type, int(offset), int(size));
-//    AString sidxstr;
-//    hexdump(mBuffer->data() + offset, size, 0 /* indent */, &sidxstr);
-//    ALOGV("raw sidx:");
-//    ALOGV("%s", sidxstr.c_str());
-    if (offset + 12 > size) {
-        return -EINVAL;
-    }
-
-    uint32_t flags = readU32(offset);
-
-    uint32_t version = flags >> 24;
-    flags &= 0xffffff;
-
-    ALOGV("sidx version %d", version);
-
-    uint32_t referenceId = readU32(offset + 4);
-    uint32_t timeScale = readU32(offset + 8);
-    ALOGV("sidx refid/timescale: %d/%d", referenceId, timeScale);
-
-    uint64_t earliestPresentationTime;
-    uint64_t firstOffset;
-
-    offset += 12;
-
-    if (version == 0) {
-        if (offset + 8 > size) {
-            return -EINVAL;
-        }
-        earliestPresentationTime = readU32(offset);
-        firstOffset = readU32(offset + 4);
-        offset += 8;
-    } else {
-        if (offset + 16 > size) {
-            return -EINVAL;
-        }
-        earliestPresentationTime = readU64(offset);
-        firstOffset = readU64(offset + 8);
-        offset += 16;
-    }
-    ALOGV("sidx pres/off: %Ld/%Ld", earliestPresentationTime, firstOffset);
-
-    if (offset + 4 > size) {
-        return -EINVAL;
-    }
-    if (readU16(offset) != 0) { // reserved
-        return -EINVAL;
-    }
-    int32_t referenceCount = readU16(offset + 2);
-    offset += 4;
-    ALOGV("refcount: %d", referenceCount);
-
-    if (offset + referenceCount * 12 > size) {
-        return -EINVAL;
-    }
-
-    TrackInfo *info = editTrack(mCurrentTrackID);
-    uint64_t total_duration = 0;
-    for (int i = 0; i < referenceCount; i++) {
-        uint32_t d1 = readU32(offset);
-        uint32_t d2 = readU32(offset + 4);
-        uint32_t d3 = readU32(offset + 8);
-
-        if (d1 & 0x80000000) {
-            ALOGW("sub-sidx boxes not supported yet");
-        }
-        bool sap = d3 & 0x80000000;
-        bool saptype = d3 >> 28;
-        if (!sap || saptype > 2) {
-            ALOGW("not a stream access point, or unsupported type");
-        }
-        total_duration += d2;
-        offset += 12;
-        ALOGV(" item %d, %08x %08x %08x", i, d1, d2, d3);
-        SidxEntry se;
-        se.mSize = d1 & 0x7fffffff;
-        se.mDurationUs = 1000000LL * d2 / timeScale;
-        info->mSidx.add(se);
-    }
-
-    info->mSidxDuration = total_duration * 1000000 / timeScale;
-    ALOGV("duration: %lld", info->mSidxDuration);
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseTrackExtends(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 24 > size) {
-        return -EINVAL;
-    }
-
-    if (readU32(offset) != 0) {
-        return -EINVAL;
-    }
-
-    uint32_t trackID = readU32(offset + 4);
-
-    TrackInfo *info = editTrack(trackID, true /* createIfNecessary */);
-    info->mDefaultSampleDescriptionIndex = readU32(offset + 8);
-    info->mDefaultSampleDuration = readU32(offset + 12);
-    info->mDefaultSampleSize = readU32(offset + 16);
-    info->mDefaultSampleFlags = readU32(offset + 20);
-
-    return OK;
-}
-
-FragmentedMP4Parser::TrackInfo *FragmentedMP4Parser::editTrack(
-        uint32_t trackID, bool createIfNecessary) {
-    ssize_t i = mTracks.indexOfKey(trackID);
-
-    if (i >= 0) {
-        return &mTracks.editValueAt(i);
-    }
-
-    if (!createIfNecessary) {
-        return NULL;
-    }
-
-    TrackInfo info;
-    info.mTrackID = trackID;
-    info.mFlags = 0;
-    info.mDuration = 0xffffffff;
-    info.mSidxDuration = 0;
-    info.mMediaTimeScale = 0;
-    info.mMediaHandlerType = 0;
-    info.mDefaultSampleDescriptionIndex = 0;
-    info.mDefaultSampleDuration = 0;
-    info.mDefaultSampleSize = 0;
-    info.mDefaultSampleFlags = 0;
-
-    info.mDecodingTime = 0;
-
-    mTracks.add(trackID, info);
-    return &mTracks.editValueAt(mTracks.indexOfKey(trackID));
-}
-
-status_t FragmentedMP4Parser::parseTrackFragmentHeader(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 8 > size) {
-        return -EINVAL;
-    }
-
-    uint32_t flags = readU32(offset);
-
-    if (flags & 0xff000000) {
-        return -EINVAL;
-    }
-
-    mTrackFragmentHeaderInfo.mFlags = flags;
-
-    mTrackFragmentHeaderInfo.mTrackID = readU32(offset + 4);
-    offset += 8;
-
-    if (flags & TrackFragmentHeaderInfo::kBaseDataOffsetPresent) {
-        if (offset + 8 > size) {
-            return -EINVAL;
-        }
-
-        mTrackFragmentHeaderInfo.mBaseDataOffset = readU64(offset);
-        offset += 8;
-    }
-
-    if (flags & TrackFragmentHeaderInfo::kSampleDescriptionIndexPresent) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        mTrackFragmentHeaderInfo.mSampleDescriptionIndex = readU32(offset);
-        offset += 4;
-    }
-
-    if (flags & TrackFragmentHeaderInfo::kDefaultSampleDurationPresent) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        mTrackFragmentHeaderInfo.mDefaultSampleDuration = readU32(offset);
-        offset += 4;
-    }
-
-    if (flags & TrackFragmentHeaderInfo::kDefaultSampleSizePresent) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        mTrackFragmentHeaderInfo.mDefaultSampleSize = readU32(offset);
-        offset += 4;
-    }
-
-    if (flags & TrackFragmentHeaderInfo::kDefaultSampleFlagsPresent) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        mTrackFragmentHeaderInfo.mDefaultSampleFlags = readU32(offset);
-        offset += 4;
-    }
-
-    if (!(flags & TrackFragmentHeaderInfo::kBaseDataOffsetPresent)) {
-        // This should point to the position of the first byte of the
-        // enclosing 'moof' container for the first track and
-        // the end of the data of the preceding fragment for subsequent
-        // tracks.
-
-        CHECK_GE(mStack.size(), 2u);
-
-        mTrackFragmentHeaderInfo.mBaseDataOffset =
-            mStack.itemAt(mStack.size() - 2).mOffset;
-
-        // XXX TODO: This does not do the right thing for the 2nd and
-        // subsequent tracks yet.
-    }
-
-    mTrackFragmentHeaderInfo.mDataOffset =
-        mTrackFragmentHeaderInfo.mBaseDataOffset;
-
-    TrackInfo *trackInfo = editTrack(mTrackFragmentHeaderInfo.mTrackID);
-
-    if (trackInfo->mFragments.empty()
-            || (*trackInfo->mFragments.begin())->complete()) {
-        trackInfo->mFragments.push_back(new DynamicTrackFragment);
-    }
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::parseTrackFragmentRun(
-        uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 8 > size) {
-        return -EINVAL;
-    }
-
-    enum {
-        kDataOffsetPresent                  = 0x01,
-        kFirstSampleFlagsPresent            = 0x04,
-        kSampleDurationPresent              = 0x100,
-        kSampleSizePresent                  = 0x200,
-        kSampleFlagsPresent                 = 0x400,
-        kSampleCompositionTimeOffsetPresent = 0x800,
-    };
-
-    uint32_t flags = readU32(offset);
-
-    if (flags & 0xff000000) {
-        return -EINVAL;
-    }
-
-    if ((flags & kFirstSampleFlagsPresent) && (flags & kSampleFlagsPresent)) {
-        // These two shall not be used together.
-        return -EINVAL;
-    }
-
-    uint32_t sampleCount = readU32(offset + 4);
-    offset += 8;
-
-    uint64_t dataOffset = mTrackFragmentHeaderInfo.mDataOffset;
-
-    uint32_t firstSampleFlags = 0;
-
-    if (flags & kDataOffsetPresent) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        int32_t dataOffsetDelta = (int32_t)readU32(offset);
-
-        dataOffset = mTrackFragmentHeaderInfo.mBaseDataOffset + dataOffsetDelta;
-
-        offset += 4;
-    }
-
-    if (flags & kFirstSampleFlagsPresent) {
-        if (offset + 4 > size) {
-            return -EINVAL;
-        }
-
-        firstSampleFlags = readU32(offset);
-        offset += 4;
-    }
-
-    TrackInfo *info = editTrack(mTrackFragmentHeaderInfo.mTrackID);
-
-    if (info == NULL) {
-        return -EINVAL;
-    }
-
-    uint32_t sampleDuration = 0, sampleSize = 0, sampleFlags = 0,
-             sampleCtsOffset = 0;
-
-    size_t bytesPerSample = 0;
-    if (flags & kSampleDurationPresent) {
-        bytesPerSample += 4;
-    } else if (mTrackFragmentHeaderInfo.mFlags
-            & TrackFragmentHeaderInfo::kDefaultSampleDurationPresent) {
-        sampleDuration = mTrackFragmentHeaderInfo.mDefaultSampleDuration;
-    } else {
-        sampleDuration = info->mDefaultSampleDuration;
-    }
-
-    if (flags & kSampleSizePresent) {
-        bytesPerSample += 4;
-    } else if (mTrackFragmentHeaderInfo.mFlags
-            & TrackFragmentHeaderInfo::kDefaultSampleSizePresent) {
-        sampleSize = mTrackFragmentHeaderInfo.mDefaultSampleSize;
-    } else {
-        sampleSize = info->mDefaultSampleSize;
-    }
-
-    if (flags & kSampleFlagsPresent) {
-        bytesPerSample += 4;
-    } else if (mTrackFragmentHeaderInfo.mFlags
-            & TrackFragmentHeaderInfo::kDefaultSampleFlagsPresent) {
-        sampleFlags = mTrackFragmentHeaderInfo.mDefaultSampleFlags;
-    } else {
-        sampleFlags = info->mDefaultSampleFlags;
-    }
-
-    if (flags & kSampleCompositionTimeOffsetPresent) {
-        bytesPerSample += 4;
-    } else {
-        sampleCtsOffset = 0;
-    }
-
-    if (offset + sampleCount * bytesPerSample > size) {
-        return -EINVAL;
-    }
-
-    uint32_t sampleDescIndex =
-        (mTrackFragmentHeaderInfo.mFlags
-            & TrackFragmentHeaderInfo::kSampleDescriptionIndexPresent)
-            ? mTrackFragmentHeaderInfo.mSampleDescriptionIndex
-            : info->mDefaultSampleDescriptionIndex;
-
-    for (uint32_t i = 0; i < sampleCount; ++i) {
-        if (flags & kSampleDurationPresent) {
-            sampleDuration = readU32(offset);
-            offset += 4;
-        }
-
-        if (flags & kSampleSizePresent) {
-            sampleSize = readU32(offset);
-            offset += 4;
-        }
-
-        if (flags & kSampleFlagsPresent) {
-            sampleFlags = readU32(offset);
-            offset += 4;
-        }
-
-        if (flags & kSampleCompositionTimeOffsetPresent) {
-            sampleCtsOffset = readU32(offset);
-            offset += 4;
-        }
-
-        ALOGV("adding sample at offset 0x%08llx, size %u, duration %u, "
-              "sampleDescIndex=%u, flags 0x%08x",
-                dataOffset, sampleSize, sampleDuration,
-                sampleDescIndex,
-                (flags & kFirstSampleFlagsPresent) && i == 0
-                    ? firstSampleFlags : sampleFlags);
-
-        const sp<TrackFragment> &fragment = *--info->mFragments.end();
-
-        uint32_t decodingTime = info->mDecodingTime;
-        info->mDecodingTime += sampleDuration;
-        uint32_t presentationTime = decodingTime + sampleCtsOffset;
-
-        static_cast<DynamicTrackFragment *>(
-                fragment.get())->addSample(
-                    dataOffset,
-                    sampleSize,
-                    presentationTime,
-                    sampleDescIndex,
-                    ((flags & kFirstSampleFlagsPresent) && i == 0)
-                        ? firstSampleFlags : sampleFlags);
-
-        dataOffset += sampleSize;
-    }
-
-    mTrackFragmentHeaderInfo.mDataOffset = dataOffset;
-
-    return OK;
-}
-
-void FragmentedMP4Parser::copyBuffer(
-        sp<ABuffer> *dst, size_t offset, uint64_t size) const {
-    sp<ABuffer> buf = new ABuffer(size);
-    memcpy(buf->data(), mBuffer->data() + offset, size);
-
-    *dst = buf;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/mp4/TrackFragment.cpp b/media/libstagefright/mp4/TrackFragment.cpp
deleted file mode 100644
index 3699038..0000000
--- a/media/libstagefright/mp4/TrackFragment.cpp
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "TrackFragment"
-#include <utils/Log.h>
-
-#include "TrackFragment.h"
-
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/Utils.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/hexdump.h>
-
-namespace android {
-
-FragmentedMP4Parser::DynamicTrackFragment::DynamicTrackFragment()
-    : mComplete(false),
-      mSampleIndex(0) {
-}
-
-FragmentedMP4Parser::DynamicTrackFragment::~DynamicTrackFragment() {
-}
-
-status_t FragmentedMP4Parser::DynamicTrackFragment::getSample(SampleInfo *info) {
-    if (mSampleIndex >= mSamples.size()) {
-        return mComplete ? ERROR_END_OF_STREAM : -EWOULDBLOCK;
-    }
-
-    *info = mSamples.itemAt(mSampleIndex);
-
-    return OK;
-}
-
-void FragmentedMP4Parser::DynamicTrackFragment::advance() {
-    ++mSampleIndex;
-}
-
-void FragmentedMP4Parser::DynamicTrackFragment::addSample(
-        off64_t dataOffset, size_t sampleSize,
-        uint32_t presentationTime,
-        size_t sampleDescIndex,
-        uint32_t flags) {
-    mSamples.push();
-    SampleInfo *sampleInfo = &mSamples.editItemAt(mSamples.size() - 1);
-
-    sampleInfo->mOffset = dataOffset;
-    sampleInfo->mSize = sampleSize;
-    sampleInfo->mPresentationTime = presentationTime;
-    sampleInfo->mSampleDescIndex = sampleDescIndex;
-    sampleInfo->mFlags = flags;
-}
-
-status_t FragmentedMP4Parser::DynamicTrackFragment::signalCompletion() {
-    mComplete = true;
-
-    return OK;
-}
-
-bool FragmentedMP4Parser::DynamicTrackFragment::complete() const {
-    return mComplete;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-FragmentedMP4Parser::StaticTrackFragment::StaticTrackFragment()
-    : mSampleIndex(0),
-      mSampleCount(0),
-      mChunkIndex(0),
-      mSampleToChunkIndex(-1),
-      mSampleToChunkRemaining(0),
-      mPrevChunkIndex(0xffffffff),
-      mNextSampleOffset(0) {
-}
-
-FragmentedMP4Parser::StaticTrackFragment::~StaticTrackFragment() {
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::getSample(SampleInfo *info) {
-    if (mSampleIndex >= mSampleCount) {
-        return ERROR_END_OF_STREAM;
-    }
-
-    *info = mSampleInfo;
-
-    ALOGV("returning sample %d at [0x%08llx, 0x%08llx)",
-          mSampleIndex,
-          info->mOffset, info->mOffset + info->mSize);
-
-    return OK;
-}
-
-void FragmentedMP4Parser::StaticTrackFragment::updateSampleInfo() {
-    if (mSampleIndex >= mSampleCount) {
-        return;
-    }
-
-    if (mSampleSizes != NULL) {
-        uint32_t defaultSampleSize = U32_AT(mSampleSizes->data() + 4);
-        if (defaultSampleSize > 0) {
-            mSampleInfo.mSize = defaultSampleSize;
-        } else {
-            mSampleInfo.mSize= U32_AT(mSampleSizes->data() + 12 + 4 * mSampleIndex);
-        }
-    } else {
-        CHECK(mCompactSampleSizes != NULL);
-
-        uint32_t fieldSize = U32_AT(mCompactSampleSizes->data() + 4);
-
-        switch (fieldSize) {
-            case 4:
-            {
-                unsigned byte = mCompactSampleSizes->data()[12 + mSampleIndex / 2];
-                mSampleInfo.mSize = (mSampleIndex & 1) ? byte & 0x0f : byte >> 4;
-                break;
-            }
-
-            case 8:
-            {
-                mSampleInfo.mSize = mCompactSampleSizes->data()[12 + mSampleIndex];
-                break;
-            }
-
-            default:
-            {
-                CHECK_EQ(fieldSize, 16);
-                mSampleInfo.mSize =
-                    U16_AT(mCompactSampleSizes->data() + 12 + mSampleIndex * 2);
-                break;
-            }
-        }
-    }
-
-    CHECK_GT(mSampleToChunkRemaining, 0);
-
-    // The sample desc index is 1-based... XXX
-    mSampleInfo.mSampleDescIndex =
-        U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 8);
-
-    if (mChunkIndex != mPrevChunkIndex) {
-        mPrevChunkIndex = mChunkIndex;
-
-        if (mChunkOffsets != NULL) {
-            uint32_t entryCount = U32_AT(mChunkOffsets->data() + 4);
-
-            if (mChunkIndex >= entryCount) {
-                mSampleIndex = mSampleCount;
-                return;
-            }
-
-            mNextSampleOffset =
-                U32_AT(mChunkOffsets->data() + 8 + 4 * mChunkIndex);
-        } else {
-            CHECK(mChunkOffsets64 != NULL);
-
-            uint32_t entryCount = U32_AT(mChunkOffsets64->data() + 4);
-
-            if (mChunkIndex >= entryCount) {
-                mSampleIndex = mSampleCount;
-                return;
-            }
-
-            mNextSampleOffset =
-                U64_AT(mChunkOffsets64->data() + 8 + 8 * mChunkIndex);
-        }
-    }
-
-    mSampleInfo.mOffset = mNextSampleOffset;
-
-    mSampleInfo.mPresentationTime = 0;
-    mSampleInfo.mFlags = 0;
-}
-
-void FragmentedMP4Parser::StaticTrackFragment::advance() {
-    mNextSampleOffset += mSampleInfo.mSize;
-
-    ++mSampleIndex;
-    if (--mSampleToChunkRemaining == 0) {
-        ++mChunkIndex;
-
-        uint32_t entryCount = U32_AT(mSampleToChunk->data() + 4);
-
-        // If this is the last entry in the sample to chunk table, we will
-        // stay on this entry.
-        if ((uint32_t)(mSampleToChunkIndex + 1) < entryCount) {
-            uint32_t nextChunkIndex =
-                U32_AT(mSampleToChunk->data() + 8 + 12 * (mSampleToChunkIndex + 1));
-
-            CHECK_GE(nextChunkIndex, 1u);
-            --nextChunkIndex;
-
-            if (mChunkIndex >= nextChunkIndex) {
-                CHECK_EQ(mChunkIndex, nextChunkIndex);
-                ++mSampleToChunkIndex;
-            }
-        }
-
-        mSampleToChunkRemaining =
-            U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 4);
-    }
-
-    updateSampleInfo();
-}
-
-static void setU32At(uint8_t *ptr, uint32_t x) {
-    ptr[0] = x >> 24;
-    ptr[1] = (x >> 16) & 0xff;
-    ptr[2] = (x >> 8) & 0xff;
-    ptr[3] = x & 0xff;
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::signalCompletion() {
-    mSampleToChunkIndex = 0;
-
-    mSampleToChunkRemaining =
-        (mSampleToChunk == NULL)
-            ? 0
-            : U32_AT(mSampleToChunk->data() + 8 + 12 * mSampleToChunkIndex + 4);
-
-    updateSampleInfo();
-
-    return OK;
-}
-
-bool FragmentedMP4Parser::StaticTrackFragment::complete() const {
-    return true;
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleSizes(
-        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 12 > size) {
-        return ERROR_MALFORMED;
-    }
-
-    if (parser->readU32(offset) != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t sampleSize = parser->readU32(offset + 4);
-    uint32_t sampleCount = parser->readU32(offset + 8);
-
-    if (sampleSize == 0 && offset + 12 + sampleCount * 4 != size) {
-        return ERROR_MALFORMED;
-    }
-
-    parser->copyBuffer(&mSampleSizes, offset, size);
-
-    mSampleCount = sampleCount;
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::parseCompactSampleSizes(
-        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 12 > size) {
-        return ERROR_MALFORMED;
-    }
-
-    if (parser->readU32(offset) != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t fieldSize = parser->readU32(offset + 4);
-
-    if (fieldSize != 4 && fieldSize != 8 && fieldSize != 16) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t sampleCount = parser->readU32(offset + 8);
-
-    if (offset + 12 + (sampleCount * fieldSize + 4) / 8 != size) {
-        return ERROR_MALFORMED;
-    }
-
-    parser->copyBuffer(&mCompactSampleSizes, offset, size);
-
-    mSampleCount = sampleCount;
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleToChunk(
-        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 8 > size) {
-        return ERROR_MALFORMED;
-    }
-
-    if (parser->readU32(offset) != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t entryCount = parser->readU32(offset + 4);
-
-    if (entryCount == 0) {
-        return OK;
-    }
-
-    if (offset + 8 + entryCount * 12 != size) {
-        return ERROR_MALFORMED;
-    }
-
-    parser->copyBuffer(&mSampleToChunk, offset, size);
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets(
-        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 8 > size) {
-        return ERROR_MALFORMED;
-    }
-
-    if (parser->readU32(offset) != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t entryCount = parser->readU32(offset + 4);
-
-    if (offset + 8 + entryCount * 4 != size) {
-        return ERROR_MALFORMED;
-    }
-
-    parser->copyBuffer(&mChunkOffsets, offset, size);
-
-    return OK;
-}
-
-status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets64(
-        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
-    if (offset + 8 > size) {
-        return ERROR_MALFORMED;
-    }
-
-    if (parser->readU32(offset) != 0) {
-        return ERROR_MALFORMED;
-    }
-
-    uint32_t entryCount = parser->readU32(offset + 4);
-
-    if (offset + 8 + entryCount * 8 != size) {
-        return ERROR_MALFORMED;
-    }
-
-    parser->copyBuffer(&mChunkOffsets64, offset, size);
-
-    return OK;
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/mp4/TrackFragment.h b/media/libstagefright/mp4/TrackFragment.h
deleted file mode 100644
index e1ad46e..0000000
--- a/media/libstagefright/mp4/TrackFragment.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TRACK_FRAGMENT_H_
-
-#define TRACK_FRAGMENT_H_
-
-#include "include/FragmentedMP4Parser.h"
-
-namespace android {
-
-struct FragmentedMP4Parser::TrackFragment : public RefBase {
-    TrackFragment() {}
-
-    virtual status_t getSample(SampleInfo *info) = 0;
-    virtual void advance() = 0;
-
-    virtual status_t signalCompletion() = 0;
-    virtual bool complete() const = 0;
-
-protected:
-    virtual ~TrackFragment() {}
-
-private:
-    DISALLOW_EVIL_CONSTRUCTORS(TrackFragment);
-};
-
-struct FragmentedMP4Parser::DynamicTrackFragment : public FragmentedMP4Parser::TrackFragment {
-    DynamicTrackFragment();
-
-    virtual status_t getSample(SampleInfo *info);
-    virtual void advance();
-
-    void addSample(
-            off64_t dataOffset, size_t sampleSize,
-            uint32_t presentationTime,
-            size_t sampleDescIndex,
-            uint32_t flags);
-
-    // No more samples will be added to this fragment.
-    virtual status_t signalCompletion();
-
-    virtual bool complete() const;
-
-protected:
-    virtual ~DynamicTrackFragment();
-
-private:
-    bool mComplete;
-    size_t mSampleIndex;
-    Vector<SampleInfo> mSamples;
-
-    DISALLOW_EVIL_CONSTRUCTORS(DynamicTrackFragment);
-};
-
-struct FragmentedMP4Parser::StaticTrackFragment : public FragmentedMP4Parser::TrackFragment {
-    StaticTrackFragment();
-
-    virtual status_t getSample(SampleInfo *info);
-    virtual void advance();
-
-    virtual status_t signalCompletion();
-    virtual bool complete() const;
-
-    status_t parseSampleSizes(
-            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseCompactSampleSizes(
-            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseSampleToChunk(
-            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseChunkOffsets(
-            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
-
-    status_t parseChunkOffsets64(
-            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
-
-protected:
-    virtual ~StaticTrackFragment();
-
-private:
-    size_t mSampleIndex;
-    size_t mSampleCount;
-    uint32_t mChunkIndex;
-
-    SampleInfo mSampleInfo;
-
-    sp<ABuffer> mSampleSizes;
-    sp<ABuffer> mCompactSampleSizes;
-
-    sp<ABuffer> mSampleToChunk;
-    ssize_t mSampleToChunkIndex;
-    size_t mSampleToChunkRemaining;
-
-    sp<ABuffer> mChunkOffsets;
-    sp<ABuffer> mChunkOffsets64;
-    uint32_t mPrevChunkIndex;
-    uint64_t mNextSampleOffset;
-
-    void updateSampleInfo();
-
-    DISALLOW_EVIL_CONSTRUCTORS(StaticTrackFragment);
-};
-
-}  // namespace android
-
-#endif  // TRACK_FRAGMENT_H_
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index cb57a2f..d039f7d 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -862,7 +862,7 @@
 }
 
 void ATSParser::Stream::onPayloadData(
-        unsigned PTS_DTS_flags, uint64_t PTS, uint64_t DTS,
+        unsigned PTS_DTS_flags, uint64_t PTS, uint64_t /* DTS */,
         const uint8_t *data, size_t size) {
 #if 0
     ALOGI("payload streamType 0x%02x, PTS = 0x%016llx, dPTS = %lld",
@@ -1267,7 +1267,7 @@
 }
 
 void ATSParser::updatePCR(
-        unsigned PID, uint64_t PCR, size_t byteOffsetFromStart) {
+        unsigned /* PID */, uint64_t PCR, size_t byteOffsetFromStart) {
     ALOGV("PCR 0x%016llx @ %d", PCR, byteOffsetFromStart);
 
     if (mNumPCRs == 2) {
diff --git a/media/libstagefright/mpeg2ts/Android.mk b/media/libstagefright/mpeg2ts/Android.mk
index c1a7a9d..c17a0b7 100644
--- a/media/libstagefright/mpeg2ts/Android.mk
+++ b/media/libstagefright/mpeg2ts/Android.mk
@@ -13,6 +13,8 @@
 	$(TOP)/frameworks/av/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE:= libstagefright_mpeg2ts
 
 ifeq ($(TARGET_ARCH),arm)
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index 52fb2a5..6dfaa94 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -34,7 +34,8 @@
     : mIsAudio(false),
       mFormat(NULL),
       mLastQueuedTimeUs(0),
-      mEOSResult(OK) {
+      mEOSResult(OK),
+      mLatestEnqueuedMeta(NULL) {
     setFormat(meta);
 }
 
@@ -61,7 +62,7 @@
 AnotherPacketSource::~AnotherPacketSource() {
 }
 
-status_t AnotherPacketSource::start(MetaData *params) {
+status_t AnotherPacketSource::start(MetaData * /* params */) {
     return OK;
 }
 
@@ -182,12 +183,24 @@
         return;
     }
 
-    CHECK(buffer->meta()->findInt64("timeUs", &mLastQueuedTimeUs));
+    int64_t lastQueuedTimeUs;
+    CHECK(buffer->meta()->findInt64("timeUs", &lastQueuedTimeUs));
+    mLastQueuedTimeUs = lastQueuedTimeUs;
     ALOGV("queueAccessUnit timeUs=%lld us (%.2f secs)", mLastQueuedTimeUs, mLastQueuedTimeUs / 1E6);
 
     Mutex::Autolock autoLock(mLock);
     mBuffers.push_back(buffer);
     mCondition.signal();
+
+    if (!mLatestEnqueuedMeta.get()) {
+        mLatestEnqueuedMeta = buffer->meta();
+    } else {
+        int64_t latestTimeUs = 0;
+        CHECK(mLatestEnqueuedMeta->findInt64("timeUs", &latestTimeUs));
+        if (lastQueuedTimeUs > latestTimeUs) {
+            mLatestEnqueuedMeta = buffer->meta();
+        }
+    }
 }
 
 void AnotherPacketSource::clear() {
@@ -197,6 +210,7 @@
     mEOSResult = OK;
 
     mFormat = NULL;
+    mLatestEnqueuedMeta = NULL;
 }
 
 void AnotherPacketSource::queueDiscontinuity(
@@ -221,6 +235,7 @@
 
     mEOSResult = OK;
     mLastQueuedTimeUs = 0;
+    mLatestEnqueuedMeta = NULL;
 
     sp<ABuffer> buffer = new ABuffer(0);
     buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type));
@@ -308,4 +323,9 @@
     return (mEOSResult != OK);
 }
 
+sp<AMessage> AnotherPacketSource::getLatestMeta() {
+    Mutex::Autolock autoLock(mLock);
+    return mLatestEnqueuedMeta;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index e16cf78..9b193a2 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -62,6 +62,8 @@
 
     bool isFinished(int64_t duration) const;
 
+    sp<AMessage> getLatestMeta();
+
 protected:
     virtual ~AnotherPacketSource();
 
@@ -74,6 +76,7 @@
     int64_t mLastQueuedTimeUs;
     List<sp<ABuffer> > mBuffers;
     status_t mEOSResult;
+    sp<AMessage> mLatestEnqueuedMeta;
 
     bool wasFormatChange(int32_t discontinuityType) const;
 
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 5c7e741..c0c9717 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -60,7 +60,7 @@
 // update metadata only applicable, and return the payload size
 static unsigned parseAC3SyncFrame(
         const uint8_t *ptr, size_t size, sp<MetaData> *metaData) {
-    static const unsigned channelCountTable[] = {2, 1, 2, 3, 4, 4, 5, 6};
+    static const unsigned channelCountTable[] = {2, 1, 2, 3, 3, 4, 4, 5};
     static const unsigned samplingRateTable[] = {48000, 44100, 32000};
     static const unsigned rates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256,
             320, 384, 448, 512, 576, 640};
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
index dd714c99..bc2a16d 100644
--- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -130,7 +130,8 @@
     return new WrappedTrack(this, mTracks.valueAt(index));
 }
 
-sp<MetaData> MPEG2PSExtractor::getTrackMetaData(size_t index, uint32_t flags) {
+sp<MetaData> MPEG2PSExtractor::getTrackMetaData(
+        size_t index, uint32_t /* flags */) {
     if (index >= mTracks.size()) {
         return NULL;
     }
@@ -625,7 +626,7 @@
 
 status_t MPEG2PSExtractor::Track::appendPESData(
         unsigned PTS_DTS_flags,
-        uint64_t PTS, uint64_t DTS,
+        uint64_t PTS, uint64_t /* DTS */,
         const uint8_t *data, size_t size) {
     if (mQueue == NULL) {
         return OK;
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index d449c34..35ca118 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -141,7 +141,7 @@
 }
 
 sp<MetaData> MPEG2TSExtractor::getTrackMetaData(
-        size_t index, uint32_t flags) {
+        size_t index, uint32_t /* flags */) {
     return index < mSourceImpls.size()
         ? mSourceImpls.editItemAt(index)->getFormat() : NULL;
 }
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 83f4e0a..b81b116 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -41,11 +41,11 @@
     mNumFramesAvailable(0),
     mEndOfStream(false),
     mEndOfStreamSent(false),
-    mRepeatAfterUs(-1ll),
     mMaxTimestampGapUs(-1ll),
     mPrevOriginalTimeUs(-1ll),
     mPrevModifiedTimeUs(-1ll),
     mSkipFramesBeforeNs(-1ll),
+    mRepeatAfterUs(-1ll),
     mRepeatLastFrameGeneration(0),
     mRepeatLastFrameTimestamp(-1ll),
     mLatestSubmittedBufferId(-1),
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 274f2eb..a608479 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -185,7 +185,7 @@
     instance->onObserverDied(mMaster);
 }
 
-bool OMX::livesLocally(node_id node, pid_t pid) {
+bool OMX::livesLocally(node_id /* node */, pid_t pid) {
     return pid == getpid();
 }
 
@@ -424,7 +424,7 @@
         OMX_IN OMX_EVENTTYPE eEvent,
         OMX_IN OMX_U32 nData1,
         OMX_IN OMX_U32 nData2,
-        OMX_IN OMX_PTR pEventData) {
+        OMX_IN OMX_PTR /* pEventData */) {
     ALOGV("OnEvent(%d, %ld, %ld)", eEvent, nData1, nData2);
 
     // Forward to OMXNodeInstance.
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index f3600ba..0fb38fa 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -266,7 +266,7 @@
 }
 
 status_t OMXNodeInstance::getParameter(
-        OMX_INDEXTYPE index, void *params, size_t size) {
+        OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
@@ -275,7 +275,7 @@
 }
 
 status_t OMXNodeInstance::setParameter(
-        OMX_INDEXTYPE index, const void *params, size_t size) {
+        OMX_INDEXTYPE index, const void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_SetParameter(
@@ -285,7 +285,7 @@
 }
 
 status_t OMXNodeInstance::getConfig(
-        OMX_INDEXTYPE index, void *params, size_t size) {
+        OMX_INDEXTYPE index, void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
@@ -293,7 +293,7 @@
 }
 
 status_t OMXNodeInstance::setConfig(
-        OMX_INDEXTYPE index, const void *params, size_t size) {
+        OMX_INDEXTYPE index, const void *params, size_t /* size */) {
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_SetConfig(
@@ -610,7 +610,7 @@
 }
 
 status_t OMXNodeInstance::updateGraphicBufferInMeta(
-        OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
+        OMX_U32 /* portIndex */, const sp<GraphicBuffer>& graphicBuffer,
         OMX::buffer_id buffer) {
     Mutex::Autolock autoLock(mLock);
 
@@ -978,7 +978,7 @@
 
 // static
 OMX_ERRORTYPE OMXNodeInstance::OnEvent(
-        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_HANDLETYPE /* hComponent */,
         OMX_IN OMX_PTR pAppData,
         OMX_IN OMX_EVENTTYPE eEvent,
         OMX_IN OMX_U32 nData1,
@@ -994,7 +994,7 @@
 
 // static
 OMX_ERRORTYPE OMXNodeInstance::OnEmptyBufferDone(
-        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_HANDLETYPE /* hComponent */,
         OMX_IN OMX_PTR pAppData,
         OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
     OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
@@ -1006,7 +1006,7 @@
 
 // static
 OMX_ERRORTYPE OMXNodeInstance::OnFillBufferDone(
-        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_HANDLETYPE /* hComponent */,
         OMX_IN OMX_PTR pAppData,
         OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
     OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
diff --git a/media/libstagefright/omx/SoftOMXComponent.cpp b/media/libstagefright/omx/SoftOMXComponent.cpp
index b1c34dc..646cd32 100644
--- a/media/libstagefright/omx/SoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftOMXComponent.cpp
@@ -257,69 +257,69 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 OMX_ERRORTYPE SoftOMXComponent::sendCommand(
-        OMX_COMMANDTYPE cmd, OMX_U32 param, OMX_PTR data) {
+        OMX_COMMANDTYPE /* cmd */, OMX_U32 /* param */, OMX_PTR /* data */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::getParameter(
-        OMX_INDEXTYPE index, OMX_PTR params) {
+        OMX_INDEXTYPE /* index */, OMX_PTR /* params */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::setParameter(
-        OMX_INDEXTYPE index, const OMX_PTR params) {
+        OMX_INDEXTYPE /* index */, const OMX_PTR /* params */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::getConfig(
-        OMX_INDEXTYPE index, OMX_PTR params) {
+        OMX_INDEXTYPE /* index */, OMX_PTR /* params */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::setConfig(
-        OMX_INDEXTYPE index, const OMX_PTR params) {
+        OMX_INDEXTYPE /* index */, const OMX_PTR /* params */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::getExtensionIndex(
-        const char *name, OMX_INDEXTYPE *index) {
+        const char * /* name */, OMX_INDEXTYPE * /* index */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::useBuffer(
-        OMX_BUFFERHEADERTYPE **buffer,
-        OMX_U32 portIndex,
-        OMX_PTR appPrivate,
-        OMX_U32 size,
-        OMX_U8 *ptr) {
+        OMX_BUFFERHEADERTYPE ** /* buffer */,
+        OMX_U32 /* portIndex */,
+        OMX_PTR /* appPrivate */,
+        OMX_U32 /* size */,
+        OMX_U8 * /* ptr */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::allocateBuffer(
-        OMX_BUFFERHEADERTYPE **buffer,
-        OMX_U32 portIndex,
-        OMX_PTR appPrivate,
-        OMX_U32 size) {
+        OMX_BUFFERHEADERTYPE ** /* buffer */,
+        OMX_U32 /* portIndex */,
+        OMX_PTR /* appPrivate */,
+        OMX_U32 /* size */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::freeBuffer(
-        OMX_U32 portIndex,
-        OMX_BUFFERHEADERTYPE *buffer) {
+        OMX_U32 /* portIndex */,
+        OMX_BUFFERHEADERTYPE * /* buffer */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::emptyThisBuffer(
-        OMX_BUFFERHEADERTYPE *buffer) {
+        OMX_BUFFERHEADERTYPE * /* buffer */) {
     return OMX_ErrorUndefined;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::fillThisBuffer(
-        OMX_BUFFERHEADERTYPE *buffer) {
+        OMX_BUFFERHEADERTYPE * /* buffer */) {
     return OMX_ErrorUndefined;
 }
 
-OMX_ERRORTYPE SoftOMXComponent::getState(OMX_STATETYPE *state) {
+OMX_ERRORTYPE SoftOMXComponent::getState(OMX_STATETYPE * /* state */) {
     return OMX_ErrorUndefined;
 }
 
diff --git a/media/libstagefright/omx/SoftOMXPlugin.cpp b/media/libstagefright/omx/SoftOMXPlugin.cpp
index d6cde73..d49e50b 100644
--- a/media/libstagefright/omx/SoftOMXPlugin.cpp
+++ b/media/libstagefright/omx/SoftOMXPlugin.cpp
@@ -154,7 +154,7 @@
 
 OMX_ERRORTYPE SoftOMXPlugin::enumerateComponents(
         OMX_STRING name,
-        size_t size,
+        size_t /* size */,
         OMX_U32 index) {
     if (index >= kNumComponents) {
         return OMX_ErrorNoMore;
diff --git a/media/libstagefright/omx/tests/Android.mk b/media/libstagefright/omx/tests/Android.mk
index 1061c39..8b79af4 100644
--- a/media/libstagefright/omx/tests/Android.mk
+++ b/media/libstagefright/omx/tests/Android.mk
@@ -11,6 +11,8 @@
 	$(TOP)/frameworks/av/media/libstagefright \
 	$(TOP)/frameworks/native/include/media/openmax
 
+LOCAL_CFLAGS += -Werror
+
 LOCAL_MODULE := omx_tests
 
 LOCAL_MODULE_TAGS := tests
diff --git a/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
index 4c9bf5b..dca5c89 100644
--- a/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
@@ -34,7 +34,9 @@
 namespace android {
 
 AMPEG2TSAssembler::AMPEG2TSAssembler(
-        const sp<AMessage> &notify, const char *desc, const AString &params)
+        const sp<AMessage> &notify,
+        const char * /* desc */,
+        const AString & /* params */)
     : mNotifyMsg(notify),
       mNextExpectedSeqNoValid(false),
       mNextExpectedSeqNo(0) {
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 0d07043..c46d16f 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -114,7 +114,7 @@
     return (mFlags & kFlagEOS) != 0;
 }
 
-status_t ARTPWriter::start(MetaData *params) {
+status_t ARTPWriter::start(MetaData * /* params */) {
     Mutex::Autolock autoLock(mLock);
     if (mFlags & kFlagStarted) {
         return INVALID_OPERATION;
diff --git a/media/libstagefright/rtsp/ARawAudioAssembler.cpp b/media/libstagefright/rtsp/ARawAudioAssembler.cpp
index 0da5dd2..167f7a4 100644
--- a/media/libstagefright/rtsp/ARawAudioAssembler.cpp
+++ b/media/libstagefright/rtsp/ARawAudioAssembler.cpp
@@ -34,7 +34,9 @@
 namespace android {
 
 ARawAudioAssembler::ARawAudioAssembler(
-        const sp<AMessage> &notify, const char *desc, const AString &params)
+        const sp<AMessage> &notify,
+        const char * /* desc */,
+        const AString & /* params */)
     : mNotifyMsg(notify),
       mNextExpectedSeqNoValid(false),
       mNextExpectedSeqNo(0) {
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index 02e44f4..39eedc0 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -30,6 +30,8 @@
     LOCAL_CFLAGS += -Wno-psabi
 endif
 
+LOCAL_CFLAGS += -Werror
+
 include $(BUILD_STATIC_LIBRARY)
 
 ################################################################################
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index cd77aa0..45470a3 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -19,7 +19,11 @@
 #define MY_HANDLER_H_
 
 //#define LOG_NDEBUG 0
+
+#ifndef LOG_TAG
 #define LOG_TAG "MyHandler"
+#endif
+
 #include <utils/Log.h>
 
 #include "APacketSource.h"
@@ -42,6 +46,12 @@
 
 #include "HTTPBase.h"
 
+#if LOG_NDEBUG
+#define UNUSED_UNLESS_VERBOSE(x) (void)(x)
+#else
+#define UNUSED_UNLESS_VERBOSE(x)
+#endif
+
 // If no access units are received within 5 secs, assume that the rtp
 // stream has ended and signal end of stream.
 static int64_t kAccessUnitTimeoutUs = 10000000ll;
@@ -178,7 +188,7 @@
         mConn->connect(mOriginalSessionURL.c_str(), reply);
     }
 
-    AString getControlURL(sp<ASessionDescription> desc) {
+    AString getControlURL() {
         AString sessionLevelControlURL;
         if (mSessionDesc->findAttribute(
                 0,
@@ -545,7 +555,7 @@
                                 mBaseURL = tmp;
                             }
 
-                            mControlURL = getControlURL(mSessionDesc);
+                            mControlURL = getControlURL();
 
                             if (mSessionDesc->countTracks() < 2) {
                                 // There's no actual tracks in this session.
@@ -591,7 +601,7 @@
 
                         mSeekable = !isLiveStream(mSessionDesc);
 
-                        mControlURL = getControlURL(mSessionDesc);
+                        mControlURL = getControlURL();
 
                         if (mSessionDesc->countTracks() < 2) {
                             // There's no actual tracks in this session.
@@ -1805,6 +1815,8 @@
     bool addMediaTimestamp(
             int32_t trackIndex, const TrackInfo *track,
             const sp<ABuffer> &accessUnit) {
+        UNUSED_UNLESS_VERBOSE(trackIndex);
+
         uint32_t rtpTime;
         CHECK(accessUnit->meta()->findInt32(
                     "rtp-time", (int32_t *)&rtpTime));
diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
index ddedad7..aeecdbc 100644
--- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp
+++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp
@@ -527,7 +527,8 @@
 }
 
 // Dequeuing and queuing the buffer without really filling it in.
-void SurfaceMediaSourceTest::oneBufferPassNoFill(int width, int height ) {
+void SurfaceMediaSourceTest::oneBufferPassNoFill(
+        int /* width */, int /* height  */) {
     ANativeWindowBuffer* anb;
     ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(), &anb));
     ASSERT_TRUE(anb != NULL);
diff --git a/media/libstagefright/timedtext/Android.mk b/media/libstagefright/timedtext/Android.mk
index f099bbd..6a8b9fc 100644
--- a/media/libstagefright/timedtext/Android.mk
+++ b/media/libstagefright/timedtext/Android.mk
@@ -9,7 +9,8 @@
         TimedTextSRTSource.cpp    \
         TimedTextPlayer.cpp
 
-LOCAL_CFLAGS += -Wno-multichar
+LOCAL_CFLAGS += -Wno-multichar -Werror
+
 LOCAL_C_INCLUDES:= \
         $(TOP)/frameworks/av/include/media/stagefright/timedtext \
         $(TOP)/frameworks/av/media/libstagefright
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
index 05d6d02..71aa21e 100644
--- a/media/libstagefright/timedtext/TimedTextDriver.cpp
+++ b/media/libstagefright/timedtext/TimedTextDriver.cpp
@@ -45,6 +45,7 @@
         const sp<IMediaHTTPService> &httpService)
     : mLooper(new ALooper),
       mListener(listener),
+      mHTTPService(httpService),
       mState(UNINITIALIZED),
       mCurrentTrackIndex(UINT_MAX) {
     mLooper->setName("TimedTextDriver");
diff --git a/media/libstagefright/timedtext/TimedTextSource.h b/media/libstagefright/timedtext/TimedTextSource.h
index 756cc31..8c1c1cd 100644
--- a/media/libstagefright/timedtext/TimedTextSource.h
+++ b/media/libstagefright/timedtext/TimedTextSource.h
@@ -47,7 +47,7 @@
           int64_t *endTimeUs,
           Parcel *parcel,
           const MediaSource::ReadOptions *options = NULL) = 0;
-  virtual status_t extractGlobalDescriptions(Parcel *parcel) {
+  virtual status_t extractGlobalDescriptions(Parcel * /* parcel */) {
       return INVALID_OPERATION;
   }
   virtual sp<MetaData> getFormat();
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
index 1887b8b..e88a3bd 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
@@ -685,9 +685,8 @@
     return OK;
 }
 
-status_t RTPSender::parseReceiverReport(const uint8_t *data, size_t size) {
-    // hexdump(data, size);
-
+status_t RTPSender::parseReceiverReport(
+        const uint8_t *data, size_t /* size */) {
     float fractionLost = data[12] / 256.0f;
 
     ALOGI("lost %.2f %% of packets during report interval.",
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 05e4018..da405e2 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -746,7 +746,7 @@
 }
 
 status_t WifiDisplaySource::onReceiveM1Response(
-        int32_t sessionID, const sp<ParsedMessage> &msg) {
+        int32_t /* sessionID */, const sp<ParsedMessage> &msg) {
     int32_t statusCode;
     if (!msg->getStatusCode(&statusCode)) {
         return ERROR_MALFORMED;
@@ -991,7 +991,7 @@
 }
 
 status_t WifiDisplaySource::onReceiveM5Response(
-        int32_t sessionID, const sp<ParsedMessage> &msg) {
+        int32_t /* sessionID */, const sp<ParsedMessage> &msg) {
     int32_t statusCode;
     if (!msg->getStatusCode(&statusCode)) {
         return ERROR_MALFORMED;
@@ -1005,7 +1005,7 @@
 }
 
 status_t WifiDisplaySource::onReceiveM16Response(
-        int32_t sessionID, const sp<ParsedMessage> &msg) {
+        int32_t sessionID, const sp<ParsedMessage> & /* msg */) {
     // If only the response was required to include a "Session:" header...
 
     CHECK_EQ(sessionID, mClientSessionID);
@@ -1680,7 +1680,7 @@
 }
 
 void WifiDisplaySource::HDCPObserver::notify(
-        int msg, int ext1, int ext2, const Parcel *obj) {
+        int msg, int ext1, int ext2, const Parcel * /* obj */) {
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("msg", msg);
     notify->setInt32("ext1", ext1);
diff --git a/media/libstagefright/yuv/Android.mk b/media/libstagefright/yuv/Android.mk
index b3f7b1b..bb86dfc 100644
--- a/media/libstagefright/yuv/Android.mk
+++ b/media/libstagefright/yuv/Android.mk
@@ -12,5 +12,7 @@
 LOCAL_MODULE:= libstagefright_yuv
 
 
+LOCAL_CFLAGS += -Werror
+
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libstagefright/yuv/YUVImage.cpp b/media/libstagefright/yuv/YUVImage.cpp
index 7b9000b..bb3e2fd 100644
--- a/media/libstagefright/yuv/YUVImage.cpp
+++ b/media/libstagefright/yuv/YUVImage.cpp
@@ -226,8 +226,8 @@
             &ySrcOffsetIncrement, &uSrcOffsetIncrement, &vSrcOffsetIncrement);
 
     int32_t yDestOffsetIncrement;
-    int32_t uDestOffsetIncrement;
-    int32_t vDestOffsetIncrement;
+    int32_t uDestOffsetIncrement = 0;
+    int32_t vDestOffsetIncrement = 0;
     destImage.getOffsetIncrementsPerDataRow(
             &yDestOffsetIncrement, &uDestOffsetIncrement, &vDestOffsetIncrement);
 
@@ -309,7 +309,7 @@
 
     int32_t yDestOffsetIncrement;
     int32_t uDestOffsetIncrement;
-    int32_t vDestOffsetIncrement;
+    int32_t vDestOffsetIncrement = 0;
     destImage.getOffsetIncrementsPerDataRow(
             &yDestOffsetIncrement, &uDestOffsetIncrement, &vDestOffsetIncrement);
 
@@ -393,9 +393,9 @@
     fprintf(fp, "255\n");
     for (int32_t y = 0; y < mHeight; ++y) {
         for (int32_t x = 0; x < mWidth; ++x) {
-            uint8_t yValue;
-            uint8_t uValue;
-            uint8_t vValue;
+            uint8_t yValue = 0u;
+            uint8_t uValue = 0u;
+            uint8_t vValue = 0u;
             getPixelValue(x, y, &yValue, &uValue, & vValue);
 
             uint8_t rValue;
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 21bd2f4..7615086 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -183,6 +183,7 @@
         (void) property_get("af.tee", value, "0");
         teeEnabled = atoi(value);
     }
+    // FIXME symbolic constants here
     if (teeEnabled & 1) {
         mTeeSinkInputEnabled = true;
     }
@@ -1810,7 +1811,7 @@
             kind = TEE_SINK_NEW;
         } else if (mRecordTeeSink->getStrongCount() != 1) {
             kind = TEE_SINK_NO;
-        } else if (format == mRecordTeeSink->format()) {
+        } else if (Format_isEqual(format, mRecordTeeSink->format())) {
             kind = TEE_SINK_OLD;
         } else {
             kind = TEE_SINK_NEW;
@@ -1847,8 +1848,6 @@
         // pre processing modules
         RecordThread *thread = new RecordThread(this,
                                   input,
-                                  reqSamplingRate,
-                                  reqChannelMask,
                                   id,
                                   primaryOutputDevice_l(),
                                   *pDevices
@@ -1929,18 +1928,21 @@
     return nextUniqueId();
 }
 
-void AudioFlinger::acquireAudioSessionId(int audioSession)
+void AudioFlinger::acquireAudioSessionId(int audioSession, pid_t pid)
 {
     Mutex::Autolock _l(mLock);
     pid_t caller = IPCThreadState::self()->getCallingPid();
-    ALOGV("acquiring %d from %d", audioSession, caller);
+    ALOGV("acquiring %d from %d, for %d", audioSession, caller, pid);
+    if (pid != -1 && (caller == getpid_cached)) {
+        caller = pid;
+    }
 
     // Ignore requests received from processes not known as notification client. The request
     // is likely proxied by mediaserver (e.g CameraService) and releaseAudioSessionId() can be
     // called from a different pid leaving a stale session reference.  Also we don't know how
     // to clear this reference if the client process dies.
     if (mNotificationClients.indexOfKey(caller) < 0) {
-        ALOGV("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
+        ALOGW("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
         return;
     }
 
@@ -1957,11 +1959,14 @@
     ALOGV(" added new entry for %d", audioSession);
 }
 
-void AudioFlinger::releaseAudioSessionId(int audioSession)
+void AudioFlinger::releaseAudioSessionId(int audioSession, pid_t pid)
 {
     Mutex::Autolock _l(mLock);
     pid_t caller = IPCThreadState::self()->getCallingPid();
-    ALOGV("releasing %d from %d", audioSession, caller);
+    ALOGV("releasing %d from %d for %d", audioSession, caller, pid);
+    if (pid != -1 && (caller == getpid_cached)) {
+        caller = pid;
+    }
     size_t num = mAudioSessionRefs.size();
     for (size_t i = 0; i< num; i++) {
         AudioSessionRef *ref = mAudioSessionRefs.itemAt(i);
@@ -2090,7 +2095,7 @@
                                     int triggerSession,
                                     int listenerSession,
                                     sync_event_callback_t callBack,
-                                    void *cookie)
+                                    wp<RefBase> cookie)
 {
     Mutex::Autolock _l(mLock);
 
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 459d2ec..21d05d4 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -193,9 +193,9 @@
 
     virtual int newAudioSessionId();
 
-    virtual void acquireAudioSessionId(int audioSession);
+    virtual void acquireAudioSessionId(int audioSession, pid_t pid);
 
-    virtual void releaseAudioSessionId(int audioSession);
+    virtual void releaseAudioSessionId(int audioSession, pid_t pid);
 
     virtual status_t queryNumberEffects(uint32_t *numEffects) const;
 
@@ -253,7 +253,7 @@
                   int triggerSession,
                   int listenerSession,
                   sync_event_callback_t callBack,
-                  void *cookie)
+                  wp<RefBase> cookie)
         : mType(type), mTriggerSession(triggerSession), mListenerSession(listenerSession),
           mCallback(callBack), mCookie(cookie)
         {}
@@ -266,14 +266,14 @@
         AudioSystem::sync_event_t type() const { return mType; }
         int triggerSession() const { return mTriggerSession; }
         int listenerSession() const { return mListenerSession; }
-        void *cookie() const { return mCookie; }
+        wp<RefBase> cookie() const { return mCookie; }
 
     private:
           const AudioSystem::sync_event_t mType;
           const int mTriggerSession;
           const int mListenerSession;
           sync_event_callback_t mCallback;
-          void * const mCookie;
+          const wp<RefBase> mCookie;
           mutable Mutex mLock;
     };
 
@@ -281,7 +281,7 @@
                                         int triggerSession,
                                         int listenerSession,
                                         sync_event_callback_t callBack,
-                                        void *cookie);
+                                        wp<RefBase> cookie);
 
 private:
     class AudioHwDevice;    // fwd declaration for findSuitableHwDev_l
@@ -638,7 +638,7 @@
     // 0x200000 stereo 16-bit PCM frames = 47.5 seconds at 44.1 kHz, 8 megabytes
     static const size_t kTeeSinkInputFramesDefault = 0x200000;
     static const size_t kTeeSinkOutputFramesDefault = 0x200000;
-    static const size_t kTeeSinkTrackFramesDefault = 0x1000;
+    static const size_t kTeeSinkTrackFramesDefault = 0x200000;
 #endif
 
     // This method reads from a variable without mLock, but the variable is updated under mLock.  So
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index b206116..ca98f16 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -341,7 +341,7 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
 
     // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
     //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
@@ -439,7 +439,7 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
 
     // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
     //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index dc33f29..0592855 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -110,6 +110,38 @@
     uint64_t mLocalTimeFreq;
     int64_t mPTS;
 
+    // returns the inFrameCount required to generate outFrameCount frames.
+    //
+    // Placed here to be a consistent for all resamplers.
+    //
+    // Right now, we use the upper bound without regards to the current state of the
+    // input buffer using integer arithmetic, as follows:
+    //
+    // (static_cast<uint64_t>(outFrameCount)*mInSampleRate + (mSampleRate - 1))/mSampleRate;
+    //
+    // The double precision equivalent (float may not be precise enough):
+    // ceil(static_cast<double>(outFrameCount) * mInSampleRate / mSampleRate);
+    //
+    // this relies on the fact that the mPhaseIncrement is rounded down from
+    // #phases * mInSampleRate/mSampleRate and the fact that Sum(Floor(x)) <= Floor(Sum(x)).
+    // http://www.proofwiki.org/wiki/Sum_of_Floors_Not_Greater_Than_Floor_of_Sums
+    //
+    // (so long as double precision is computed accurately enough to be considered
+    // greater than or equal to the Floor(x) value in int32_t arithmetic; thus this
+    // will not necessarily hold for floats).
+    //
+    // TODO:
+    // Greater accuracy and a tight bound is obtained by:
+    // 1) subtract and adjust for the current state of the AudioBufferProvider buffer.
+    // 2) using the exact integer formula where (ignoring 64b casting)
+    //  inFrameCount = (mPhaseIncrement * (outFrameCount - 1) + mPhaseFraction) / phaseWrapLimit;
+    //  phaseWrapLimit is the wraparound (1 << kNumPhaseBits), if not specified explicitly.
+    //
+    inline size_t getInFrameCountRequired(size_t outFrameCount) {
+        return (static_cast<uint64_t>(outFrameCount)*mInSampleRate
+                + (mSampleRate - 1))/mSampleRate;
+    }
+
 private:
     const src_quality mQuality;
 
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index 1f9714b..8f14ff9 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -60,7 +60,7 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
 
     // fetch first buffer
     if (mBuffer.frameCount == 0) {
@@ -128,7 +128,7 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
 
     // fetch first buffer
     if (mBuffer.frameCount == 0) {
diff --git a/services/audioflinger/AudioResamplerDyn.cpp b/services/audioflinger/AudioResamplerDyn.cpp
index cd67df5..939b128 100644
--- a/services/audioflinger/AudioResamplerDyn.cpp
+++ b/services/audioflinger/AudioResamplerDyn.cpp
@@ -283,17 +283,25 @@
             // 32b coefficients, 64 length
             useS32 = true;
             stopBandAtten = 98.;
-            halfLength = 32;
+            if (inSampleRate >= mSampleRate * 4) {
+                halfLength = 48;
+            } else if (inSampleRate >= mSampleRate * 2) {
+                halfLength = 40;
+            } else {
+                halfLength = 32;
+            }
         } else if (mFilterQuality == DYN_LOW_QUALITY) {
             // 16b coefficients, 16-32 length
             useS32 = false;
             stopBandAtten = 80.;
-            if (mSampleRate >= inSampleRate * 2) {
+            if (inSampleRate >= mSampleRate * 4) {
+                halfLength = 24;
+            } else if (inSampleRate >= mSampleRate * 2) {
                 halfLength = 16;
             } else {
                 halfLength = 8;
             }
-            if (mSampleRate >= inSampleRate) {
+            if (inSampleRate <= mSampleRate) {
                 tbwCheat = 1.05;
             } else {
                 tbwCheat = 1.03;
@@ -303,14 +311,14 @@
             // note: > 64 length filters with 16b coefs can have quantization noise problems
             useS32 = false;
             stopBandAtten = 84.;
-            if (mSampleRate >= inSampleRate * 4) {
+            if (inSampleRate >= mSampleRate * 4) {
                 halfLength = 32;
-            } else if (mSampleRate >= inSampleRate * 2) {
+            } else if (inSampleRate >= mSampleRate * 2) {
                 halfLength = 24;
             } else {
                 halfLength = 16;
             }
-            if (mSampleRate >= inSampleRate) {
+            if (inSampleRate <= mSampleRate) {
                 tbwCheat = 1.03;
             } else {
                 tbwCheat = 1.01;
@@ -458,7 +466,7 @@
     const uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;   // stereo output
-    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
     const uint32_t phaseWrapLimit = c.mL << c.mShift;
 
     // NOTE: be very careful when modifying the code here. register
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index 207f26b..d0a7a58 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -540,7 +540,7 @@
     uint32_t phaseIncrement = mPhaseIncrement;
     size_t outputIndex = 0;
     size_t outputSampleCount = outFrameCount * 2;
-    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
+    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
 
     while (outputIndex < outputSampleCount) {
         // buffer is empty, fetch a new one
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index fc3171f..3ec9889 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -47,6 +47,9 @@
     static  void        appendDumpHeader(String8& result);
             void        dump(char* buffer, size_t size, bool active);
 
+            void        handleSyncStartEvent(const sp<SyncEvent>& event);
+            void        clearSyncStartEvent();
+
 private:
     friend class AudioFlinger;  // for mState
 
@@ -59,4 +62,33 @@
     // releaseBuffer() not overridden
 
     bool                mOverflow;  // overflow on most recent attempt to fill client buffer
+
+           // updated by RecordThread::readInputParameters_l()
+            AudioResampler                      *mResampler;
+
+            // interleaved stereo pairs of fixed-point signed Q19.12
+            int32_t                             *mRsmpOutBuffer;
+            // current allocated frame count for the above, which may be larger than needed
+            size_t                              mRsmpOutFrameCount;
+
+            size_t                              mRsmpInUnrel;   // unreleased frames remaining from
+                                                                // most recent getNextBuffer
+                                                                // for debug only
+
+            // rolling counter that is never cleared
+            int32_t                             mRsmpInFront;   // next available frame
+
+            AudioBufferProvider::Buffer mSink;  // references client's buffer sink in shared memory
+
+            // sync event triggering actual audio capture. Frames read before this event will
+            // be dropped and therefore not read by the application.
+            sp<SyncEvent>                       mSyncStartEvent;
+
+            // number of captured frames to drop after the start sync event has been received.
+            // when < 0, maximum frames to drop before starting capture even if sync event is
+            // not received
+            ssize_t                             mFramesToDrop;
+
+            // used by resampler to find source frames
+            ResamplerBufferProvider *mResamplerBufferProvider;
 };
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index b064e89..3e8c133 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -274,7 +274,8 @@
         mType(type),
         mAudioFlinger(audioFlinger),
         // mSampleRate, mFrameCount, mChannelMask, mChannelCount, mFrameSize, mFormat, mBufferSize
-        // are set by PlaybackThread::readOutputParameters() or RecordThread::readInputParameters()
+        // are set by PlaybackThread::readOutputParameters_l() or
+        // RecordThread::readInputParameters_l()
         mParamStatus(NO_ERROR),
         //FIXME: mStandby should be true here. Is this some kind of hack?
         mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
@@ -1108,7 +1109,7 @@
         }
     }
 
-    readOutputParameters();
+    readOutputParameters_l();
 
     // mStreamTypes[AUDIO_STREAM_CNT] is initialized by stream_type_t default constructor
     // There is no AUDIO_STREAM_MIN, and ++ operator does not compile
@@ -1677,7 +1678,7 @@
     return 0;
 }
 
-void AudioFlinger::PlaybackThread::readOutputParameters()
+void AudioFlinger::PlaybackThread::readOutputParameters_l()
 {
     // unfortunately we have no way of recovering from errors here, hence the LOG_FATAL
     mSampleRate = mOutput->stream->common.get_sample_rate(&mOutput->stream->common);
@@ -1765,7 +1766,7 @@
 
     // force reconfiguration of effect chains and engines to take new buffer size and audio
     // parameters into account
-    // Note that mLock is not held when readOutputParameters() is called from the constructor
+    // Note that mLock is not held when readOutputParameters_l() is called from the constructor
     // but in this case nothing is done below as no audio sessions have effect yet so it doesn't
     // matter.
     // create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains
@@ -3485,7 +3486,7 @@
                                                        keyValuePair.string());
             }
             if (status == NO_ERROR && reconfig) {
-                readOutputParameters();
+                readOutputParameters_l();
                 delete mAudioMixer;
                 mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
                 for (size_t i = 0; i < mTracks.size() ; i++) {
@@ -3827,7 +3828,7 @@
                                                        keyValuePair.string());
             }
             if (status == NO_ERROR && reconfig) {
-                readOutputParameters();
+                readOutputParameters_l();
                 sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED);
             }
         }
@@ -4450,8 +4451,6 @@
 
 AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
                                          AudioStreamIn *input,
-                                         uint32_t sampleRate,
-                                         audio_channel_mask_t channelMask,
                                          audio_io_handle_t id,
                                          audio_devices_t outDevice,
                                          audio_devices_t inDevice
@@ -4460,14 +4459,9 @@
 #endif
                                          ) :
     ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD),
-    mInput(input), mActiveTracksGen(0), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
-    // mRsmpInFrames, mRsmpInFramesP2, mRsmpInUnrel, mRsmpInFront, and mRsmpInRear
-    //      are set by readInputParameters()
-    // mRsmpInIndex LEGACY
-    mReqChannelCount(popcount(channelMask)),
-    mReqSampleRate(sampleRate)
-    // mBytesRead is only meaningful while active, and so is cleared in start()
-    // (but might be better to also clear here for dump?)
+    mInput(input), mActiveTracksGen(0), mRsmpInBuffer(NULL),
+    // mRsmpInFrames and mRsmpInFramesP2 are set by readInputParameters_l()
+    mRsmpInRear(0)
 #ifdef TEE_SINK
     , mTeeSink(teeSink)
 #endif
@@ -4475,7 +4469,7 @@
     snprintf(mName, kNameLength, "AudioIn_%X", id);
     mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mName);
 
-    readInputParameters();
+    readInputParameters_l();
 }
 
 
@@ -4483,8 +4477,6 @@
 {
     mAudioFlinger->unregisterWriter(mNBLogWriter);
     delete[] mRsmpInBuffer;
-    delete mResampler;
-    delete[] mRsmpOutBuffer;
 }
 
 void AudioFlinger::RecordThread::onFirstRef()
@@ -4498,12 +4490,6 @@
 
     inputStandBy();
 
-    // used to verify we've read at least once before evaluating how many bytes were read
-    bool readOnce = false;
-
-    // used to request a deferred sleep, to be executed later while mutex is unlocked
-    bool doSleep = false;
-
 reacquire_wakelock:
     sp<RecordTrack> activeTrack;
     int activeTracksGen;
@@ -4527,17 +4513,22 @@
         }
     }
 
-    // start recording
+    // used to request a deferred sleep, to be executed later while mutex is unlocked
+    uint32_t sleepUs = 0;
+
+    // loop while there is work to do
     for (;;) {
-        TrackBase::track_state activeTrackState;
         Vector< sp<EffectChain> > effectChains;
 
         // sleep with mutex unlocked
-        if (doSleep) {
-            doSleep = false;
-            usleep(kRecordThreadSleepUs);
+        if (sleepUs > 0) {
+            usleep(sleepUs);
+            sleepUs = 0;
         }
 
+        // activeTracks accumulates a copy of a subset of mActiveTracks
+        Vector< sp<RecordTrack> > activeTracks;
+
         { // scope for mLock
             Mutex::Autolock _l(mLock);
 
@@ -4571,236 +4562,307 @@
                     tmp.add(mActiveTracks[i]->uid());
                 }
                 updateWakeLockUids_l(tmp);
-                // FIXME an arbitrary choice
-                activeTrack = mActiveTracks[0];
             }
 
-            if (activeTrack->isTerminated()) {
-                removeTrack_l(activeTrack);
-                mActiveTracks.remove(activeTrack);
-                mActiveTracksGen++;
-                continue;
-            }
+            bool doBroadcast = false;
+            for (size_t i = 0; i < size; ) {
 
-            activeTrackState = activeTrack->mState;
-            switch (activeTrackState) {
-            case TrackBase::PAUSING:
-                standbyIfNotAlreadyInStandby();
-                mActiveTracks.remove(activeTrack);
-                mActiveTracksGen++;
-                mStartStopCond.broadcast();
-                doSleep = true;
-                continue;
-
-            case TrackBase::RESUMING:
-                mStandby = false;
-                if (mReqChannelCount != activeTrack->channelCount()) {
+                activeTrack = mActiveTracks[i];
+                if (activeTrack->isTerminated()) {
+                    removeTrack_l(activeTrack);
                     mActiveTracks.remove(activeTrack);
                     mActiveTracksGen++;
-                    mStartStopCond.broadcast();
+                    size--;
                     continue;
                 }
-                if (readOnce) {
-                    mStartStopCond.broadcast();
-                    // record start succeeds only if first read from audio input succeeds
-                    if (mBytesRead < 0) {
-                        mActiveTracks.remove(activeTrack);
-                        mActiveTracksGen++;
-                        continue;
-                    }
+
+                TrackBase::track_state activeTrackState = activeTrack->mState;
+                switch (activeTrackState) {
+
+                case TrackBase::PAUSING:
+                    mActiveTracks.remove(activeTrack);
+                    mActiveTracksGen++;
+                    doBroadcast = true;
+                    size--;
+                    continue;
+
+                case TrackBase::STARTING_1:
+                    sleepUs = 10000;
+                    i++;
+                    continue;
+
+                case TrackBase::STARTING_2:
+                    doBroadcast = true;
+                    mStandby = false;
                     activeTrack->mState = TrackBase::ACTIVE;
+                    break;
+
+                case TrackBase::ACTIVE:
+                    break;
+
+                case TrackBase::IDLE:
+                    i++;
+                    continue;
+
+                default:
+                    LOG_FATAL("Unexpected activeTrackState %d", activeTrackState);
                 }
-                break;
 
-            case TrackBase::ACTIVE:
-                break;
+                activeTracks.add(activeTrack);
+                i++;
 
-            case TrackBase::IDLE:
-                doSleep = true;
-                continue;
-
-            default:
-                LOG_FATAL("Unexpected activeTrackState %d", activeTrackState);
             }
+            if (doBroadcast) {
+                mStartStopCond.broadcast();
+            }
+
+            // sleep if there are no active tracks to process
+            if (activeTracks.size() == 0) {
+                if (sleepUs == 0) {
+                    sleepUs = kRecordThreadSleepUs;
+                }
+                continue;
+            }
+            sleepUs = 0;
 
             lockEffectChains_l(effectChains);
         }
 
-        // thread mutex is now unlocked, mActiveTracks unknown, activeTrack != 0, kept, immutable
-        // activeTrack->mState unknown, activeTrackState immutable and is ACTIVE or RESUMING
+        // thread mutex is now unlocked, mActiveTracks unknown, activeTracks.size() > 0
 
-        for (size_t i = 0; i < effectChains.size(); i ++) {
+        size_t size = effectChains.size();
+        for (size_t i = 0; i < size; i++) {
             // thread mutex is not locked, but effect chain is locked
             effectChains[i]->process_l();
         }
 
-        AudioBufferProvider::Buffer buffer;
-        buffer.frameCount = mFrameCount;
-        status_t status = activeTrack->getNextBuffer(&buffer);
-        if (status == NO_ERROR) {
-            readOnce = true;
-            size_t framesOut = buffer.frameCount;
-            if (mResampler == NULL) {
-                // no resampling
-                while (framesOut) {
-                    size_t framesIn = mFrameCount - mRsmpInIndex;
-                    if (framesIn > 0) {
-                        int8_t *src = (int8_t *)mRsmpInBuffer + mRsmpInIndex * mFrameSize;
-                        int8_t *dst = buffer.i8 + (buffer.frameCount - framesOut) *
-                                activeTrack->mFrameSize;
-                        if (framesIn > framesOut) {
-                            framesIn = framesOut;
-                        }
-                        mRsmpInIndex += framesIn;
-                        framesOut -= framesIn;
-                        if (mChannelCount == mReqChannelCount) {
-                            memcpy(dst, src, framesIn * mFrameSize);
-                        } else {
-                            if (mChannelCount == 1) {
-                                upmix_to_stereo_i16_from_mono_i16((int16_t *)dst,
-                                        (int16_t *)src, framesIn);
-                            } else {
-                                downmix_to_mono_i16_from_stereo_i16((int16_t *)dst,
-                                        (int16_t *)src, framesIn);
-                            }
-                        }
-                    }
-                    if (framesOut > 0 && mFrameCount == mRsmpInIndex) {
-                        void *readInto;
-                        if (framesOut == mFrameCount && mChannelCount == mReqChannelCount) {
-                            readInto = buffer.raw;
-                            framesOut = 0;
-                        } else {
-                            readInto = mRsmpInBuffer;
-                            mRsmpInIndex = 0;
-                        }
-                        mBytesRead = mInput->stream->read(mInput->stream, readInto, mBufferSize);
-                        if (mBytesRead <= 0) {
-                            // TODO: verify that it's benign to use a stale track state
-                            if ((mBytesRead < 0) && (activeTrackState == TrackBase::ACTIVE))
-                            {
-                                ALOGE("Error reading audio input");
-                                // Force input into standby so that it tries to
-                                // recover at next read attempt
-                                inputStandBy();
-                                doSleep = true;
-                            }
-                            mRsmpInIndex = mFrameCount;
-                            framesOut = 0;
-                            buffer.frameCount = 0;
-                        }
-#ifdef TEE_SINK
-                        else if (mTeeSink != 0) {
-                            (void) mTeeSink->write(readInto,
-                                    mBytesRead >> Format_frameBitShift(mTeeSink->format()));
-                        }
-#endif
-                    }
-                }
-            } else {
-                // resampling
+        // Read from HAL to keep up with fastest client if multiple active tracks, not slowest one.
+        // Only the client(s) that are too slow will overrun. But if even the fastest client is too
+        // slow, then this RecordThread will overrun by not calling HAL read often enough.
+        // If destination is non-contiguous, first read past the nominal end of buffer, then
+        // copy to the right place.  Permitted because mRsmpInBuffer was over-allocated.
 
-                // avoid busy-waiting if client doesn't keep up
-                bool madeProgress = false;
-
-                // keep mRsmpInBuffer full so resampler always has sufficient input
-                for (;;) {
-                    int32_t rear = mRsmpInRear;
-                    ssize_t filled = rear - mRsmpInFront;
-                    ALOG_ASSERT(0 <= filled && (size_t) filled <= mRsmpInFramesP2);
-                    // exit once there is enough data in buffer for resampler
-                    if ((size_t) filled >= mRsmpInFrames) {
-                        break;
-                    }
-                    size_t avail = mRsmpInFramesP2 - filled;
-                    // Only try to read full HAL buffers.
-                    // But if the HAL read returns a partial buffer, use it.
-                    if (avail < mFrameCount) {
-                        ALOGE("insufficient space to read: avail %d < mFrameCount %d",
-                                avail, mFrameCount);
-                        break;
-                    }
-                    // If 'avail' is non-contiguous, first read past the nominal end of buffer, then
-                    // copy to the right place.  Permitted because mRsmpInBuffer was over-allocated.
-                    rear &= mRsmpInFramesP2 - 1;
-                    mBytesRead = mInput->stream->read(mInput->stream,
-                            &mRsmpInBuffer[rear * mChannelCount], mBufferSize);
-                    if (mBytesRead <= 0) {
-                        ALOGE("read failed: mBytesRead=%d < %u", mBytesRead, mBufferSize);
-                        break;
-                    }
-                    ALOG_ASSERT((size_t) mBytesRead <= mBufferSize);
-                    size_t framesRead = mBytesRead / mFrameSize;
-                    ALOG_ASSERT(framesRead > 0);
-                    madeProgress = true;
-                    // If 'avail' was non-contiguous, we now correct for reading past end of buffer.
-                    size_t part1 = mRsmpInFramesP2 - rear;
-                    if (framesRead > part1) {
-                        memcpy(mRsmpInBuffer, &mRsmpInBuffer[mRsmpInFramesP2 * mChannelCount],
-                                (framesRead - part1) * mFrameSize);
-                    }
-                    mRsmpInRear += framesRead;
-                }
-
-                if (!madeProgress) {
-                    ALOGV("Did not make progress");
-                    usleep(((mFrameCount * 1000) / mSampleRate) * 1000);
-                }
-
-                // resampler accumulates, but we only have one source track
-                memset(mRsmpOutBuffer, 0, framesOut * FCC_2 * sizeof(int32_t));
-                mResampler->resample(mRsmpOutBuffer, framesOut,
-                        this /* AudioBufferProvider* */);
-                // ditherAndClamp() works as long as all buffers returned by
-                // activeTrack->getNextBuffer() are 32 bit aligned which should be always true.
-                if (mReqChannelCount == 1) {
-                    // temporarily type pun mRsmpOutBuffer from Q19.12 to int16_t
-                    ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut);
-                    // the resampler always outputs stereo samples:
-                    // do post stereo to mono conversion
-                    downmix_to_mono_i16_from_stereo_i16(buffer.i16, (int16_t *)mRsmpOutBuffer,
-                            framesOut);
-                } else {
-                    ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut);
-                }
-                // now done with mRsmpOutBuffer
-
-            }
-            if (mFramestoDrop == 0) {
-                activeTrack->releaseBuffer(&buffer);
-            } else {
-                if (mFramestoDrop > 0) {
-                    mFramestoDrop -= buffer.frameCount;
-                    if (mFramestoDrop <= 0) {
-                        clearSyncStartEvent();
-                    }
-                } else {
-                    mFramestoDrop += buffer.frameCount;
-                    if (mFramestoDrop >= 0 || mSyncStartEvent == 0 ||
-                            mSyncStartEvent->isCancelled()) {
-                        ALOGW("Synced record %s, session %d, trigger session %d",
-                              (mFramestoDrop >= 0) ? "timed out" : "cancelled",
-                              activeTrack->sessionId(),
-                              (mSyncStartEvent != 0) ? mSyncStartEvent->triggerSession() : 0);
-                        clearSyncStartEvent();
-                    }
-                }
-            }
-            activeTrack->clearOverflow();
+        int32_t rear = mRsmpInRear & (mRsmpInFramesP2 - 1);
+        ssize_t bytesRead = mInput->stream->read(mInput->stream,
+                &mRsmpInBuffer[rear * mChannelCount], mBufferSize);
+        if (bytesRead <= 0) {
+            ALOGE("read failed: bytesRead=%d < %u", bytesRead, mBufferSize);
+            // Force input into standby so that it tries to recover at next read attempt
+            inputStandBy();
+            sleepUs = kRecordThreadSleepUs;
+            continue;
         }
-        // client isn't retrieving buffers fast enough
-        else {
-            if (!activeTrack->setOverflow()) {
-                nsecs_t now = systemTime();
-                if ((now - lastWarning) > kWarningThrottleNs) {
-                    ALOGW("RecordThread: buffer overflow");
-                    lastWarning = now;
+        ALOG_ASSERT((size_t) bytesRead <= mBufferSize);
+        size_t framesRead = bytesRead / mFrameSize;
+        ALOG_ASSERT(framesRead > 0);
+        if (mTeeSink != 0) {
+            (void) mTeeSink->write(&mRsmpInBuffer[rear * mChannelCount], framesRead);
+        }
+        // If destination is non-contiguous, we now correct for reading past end of buffer.
+        size_t part1 = mRsmpInFramesP2 - rear;
+        if (framesRead > part1) {
+            memcpy(mRsmpInBuffer, &mRsmpInBuffer[mRsmpInFramesP2 * mChannelCount],
+                    (framesRead - part1) * mFrameSize);
+        }
+        rear = mRsmpInRear += framesRead;
+
+        size = activeTracks.size();
+        // loop over each active track
+        for (size_t i = 0; i < size; i++) {
+            activeTrack = activeTracks[i];
+
+            enum {
+                OVERRUN_UNKNOWN,
+                OVERRUN_TRUE,
+                OVERRUN_FALSE
+            } overrun = OVERRUN_UNKNOWN;
+
+            // loop over getNextBuffer to handle circular sink
+            for (;;) {
+
+                activeTrack->mSink.frameCount = ~0;
+                status_t status = activeTrack->getNextBuffer(&activeTrack->mSink);
+                size_t framesOut = activeTrack->mSink.frameCount;
+                LOG_ALWAYS_FATAL_IF((status == OK) != (framesOut > 0));
+
+                int32_t front = activeTrack->mRsmpInFront;
+                ssize_t filled = rear - front;
+                size_t framesIn;
+
+                if (filled < 0) {
+                    // should not happen, but treat like a massive overrun and re-sync
+                    framesIn = 0;
+                    activeTrack->mRsmpInFront = rear;
+                    overrun = OVERRUN_TRUE;
+                } else if ((size_t) filled <= mRsmpInFrames) {
+                    framesIn = (size_t) filled;
+                } else {
+                    // client is not keeping up with server, but give it latest data
+                    framesIn = mRsmpInFrames;
+                    activeTrack->mRsmpInFront = front = rear - framesIn;
+                    overrun = OVERRUN_TRUE;
+                }
+
+                if (framesOut == 0 || framesIn == 0) {
+                    break;
+                }
+
+                if (activeTrack->mResampler == NULL) {
+                    // no resampling
+                    if (framesIn > framesOut) {
+                        framesIn = framesOut;
+                    } else {
+                        framesOut = framesIn;
+                    }
+                    int8_t *dst = activeTrack->mSink.i8;
+                    while (framesIn > 0) {
+                        front &= mRsmpInFramesP2 - 1;
+                        size_t part1 = mRsmpInFramesP2 - front;
+                        if (part1 > framesIn) {
+                            part1 = framesIn;
+                        }
+                        int8_t *src = (int8_t *)mRsmpInBuffer + (front * mFrameSize);
+                        if (mChannelCount == activeTrack->mChannelCount) {
+                            memcpy(dst, src, part1 * mFrameSize);
+                        } else if (mChannelCount == 1) {
+                            upmix_to_stereo_i16_from_mono_i16((int16_t *)dst, (int16_t *)src,
+                                    part1);
+                        } else {
+                            downmix_to_mono_i16_from_stereo_i16((int16_t *)dst, (int16_t *)src,
+                                    part1);
+                        }
+                        dst += part1 * activeTrack->mFrameSize;
+                        front += part1;
+                        framesIn -= part1;
+                    }
+                    activeTrack->mRsmpInFront += framesOut;
+
+                } else {
+                    // resampling
+                    // FIXME framesInNeeded should really be part of resampler API, and should
+                    //       depend on the SRC ratio
+                    //       to keep mRsmpInBuffer full so resampler always has sufficient input
+                    size_t framesInNeeded;
+                    // FIXME only re-calculate when it changes, and optimize for common ratios
+                    double inOverOut = (double) mSampleRate / activeTrack->mSampleRate;
+                    double outOverIn = (double) activeTrack->mSampleRate / mSampleRate;
+                    framesInNeeded = ceil(framesOut * inOverOut) + 1;
+                    ALOGV("need %u frames in to produce %u out given in/out ratio of %.4g",
+                                framesInNeeded, framesOut, inOverOut);
+                    // Although we theoretically have framesIn in circular buffer, some of those are
+                    // unreleased frames, and thus must be discounted for purpose of budgeting.
+                    size_t unreleased = activeTrack->mRsmpInUnrel;
+                    framesIn = framesIn > unreleased ? framesIn - unreleased : 0;
+                    if (framesIn < framesInNeeded) {
+                        ALOGV("not enough to resample: have %u frames in but need %u in to "
+                                "produce %u out given in/out ratio of %.4g",
+                                framesIn, framesInNeeded, framesOut, inOverOut);
+                        size_t newFramesOut = framesIn > 0 ? floor((framesIn - 1) * outOverIn) : 0;
+                        LOG_ALWAYS_FATAL_IF(newFramesOut >= framesOut);
+                        if (newFramesOut == 0) {
+                            break;
+                        }
+                        framesInNeeded = ceil(newFramesOut * inOverOut) + 1;
+                        ALOGV("now need %u frames in to produce %u out given out/in ratio of %.4g",
+                                framesInNeeded, newFramesOut, outOverIn);
+                        LOG_ALWAYS_FATAL_IF(framesIn < framesInNeeded);
+                        ALOGV("success 2: have %u frames in and need %u in to produce %u out "
+                              "given in/out ratio of %.4g",
+                              framesIn, framesInNeeded, newFramesOut, inOverOut);
+                        framesOut = newFramesOut;
+                    } else {
+                        ALOGV("success 1: have %u in and need %u in to produce %u out "
+                            "given in/out ratio of %.4g",
+                            framesIn, framesInNeeded, framesOut, inOverOut);
+                    }
+
+                    // reallocate mRsmpOutBuffer as needed; we will grow but never shrink
+                    if (activeTrack->mRsmpOutFrameCount < framesOut) {
+                        // FIXME why does each track need it's own mRsmpOutBuffer? can't they share?
+                        delete[] activeTrack->mRsmpOutBuffer;
+                        // resampler always outputs stereo
+                        activeTrack->mRsmpOutBuffer = new int32_t[framesOut * FCC_2];
+                        activeTrack->mRsmpOutFrameCount = framesOut;
+                    }
+
+                    // resampler accumulates, but we only have one source track
+                    memset(activeTrack->mRsmpOutBuffer, 0, framesOut * FCC_2 * sizeof(int32_t));
+                    activeTrack->mResampler->resample(activeTrack->mRsmpOutBuffer, framesOut,
+                            // FIXME how about having activeTrack implement this interface itself?
+                            activeTrack->mResamplerBufferProvider
+                            /*this*/ /* AudioBufferProvider* */);
+                    // ditherAndClamp() works as long as all buffers returned by
+                    // activeTrack->getNextBuffer() are 32 bit aligned which should be always true.
+                    if (activeTrack->mChannelCount == 1) {
+                        // temporarily type pun mRsmpOutBuffer from Q19.12 to int16_t
+                        ditherAndClamp(activeTrack->mRsmpOutBuffer, activeTrack->mRsmpOutBuffer,
+                                framesOut);
+                        // the resampler always outputs stereo samples:
+                        // do post stereo to mono conversion
+                        downmix_to_mono_i16_from_stereo_i16(activeTrack->mSink.i16,
+                                (int16_t *)activeTrack->mRsmpOutBuffer, framesOut);
+                    } else {
+                        ditherAndClamp((int32_t *)activeTrack->mSink.raw,
+                                activeTrack->mRsmpOutBuffer, framesOut);
+                    }
+                    // now done with mRsmpOutBuffer
+
+                }
+
+                if (framesOut > 0 && (overrun == OVERRUN_UNKNOWN)) {
+                    overrun = OVERRUN_FALSE;
+                }
+
+                if (activeTrack->mFramesToDrop == 0) {
+                    if (framesOut > 0) {
+                        activeTrack->mSink.frameCount = framesOut;
+                        activeTrack->releaseBuffer(&activeTrack->mSink);
+                    }
+                } else {
+                    // FIXME could do a partial drop of framesOut
+                    if (activeTrack->mFramesToDrop > 0) {
+                        activeTrack->mFramesToDrop -= framesOut;
+                        if (activeTrack->mFramesToDrop <= 0) {
+                            activeTrack->clearSyncStartEvent();
+                        }
+                    } else {
+                        activeTrack->mFramesToDrop += framesOut;
+                        if (activeTrack->mFramesToDrop >= 0 || activeTrack->mSyncStartEvent == 0 ||
+                                activeTrack->mSyncStartEvent->isCancelled()) {
+                            ALOGW("Synced record %s, session %d, trigger session %d",
+                                  (activeTrack->mFramesToDrop >= 0) ? "timed out" : "cancelled",
+                                  activeTrack->sessionId(),
+                                  (activeTrack->mSyncStartEvent != 0) ?
+                                          activeTrack->mSyncStartEvent->triggerSession() : 0);
+                            activeTrack->clearSyncStartEvent();
+                        }
+                    }
+                }
+
+                if (framesOut == 0) {
+                    break;
                 }
             }
-            // Release the processor for a while before asking for a new buffer.
-            // This will give the application more chance to read from the buffer and
-            // clear the overflow.
-            doSleep = true;
+
+            switch (overrun) {
+            case OVERRUN_TRUE:
+                // client isn't retrieving buffers fast enough
+                if (!activeTrack->setOverflow()) {
+                    nsecs_t now = systemTime();
+                    // FIXME should lastWarning per track?
+                    if ((now - lastWarning) > kWarningThrottleNs) {
+                        ALOGW("RecordThread: buffer overflow");
+                        lastWarning = now;
+                    }
+                }
+                break;
+            case OVERRUN_FALSE:
+                activeTrack->clearOverflow();
+                break;
+            case OVERRUN_UNKNOWN:
+                break;
+            }
+
         }
 
         // enable changes in effect chain
@@ -4959,114 +5021,92 @@
     status_t status = NO_ERROR;
 
     if (event == AudioSystem::SYNC_EVENT_NONE) {
-        clearSyncStartEvent();
+        recordTrack->clearSyncStartEvent();
     } else if (event != AudioSystem::SYNC_EVENT_SAME) {
-        mSyncStartEvent = mAudioFlinger->createSyncEvent(event,
+        recordTrack->mSyncStartEvent = mAudioFlinger->createSyncEvent(event,
                                        triggerSession,
                                        recordTrack->sessionId(),
                                        syncStartEventCallback,
-                                       this);
+                                       recordTrack);
         // Sync event can be cancelled by the trigger session if the track is not in a
         // compatible state in which case we start record immediately
-        if (mSyncStartEvent->isCancelled()) {
-            clearSyncStartEvent();
+        if (recordTrack->mSyncStartEvent->isCancelled()) {
+            recordTrack->clearSyncStartEvent();
         } else {
             // do not wait for the event for more than AudioSystem::kSyncRecordStartTimeOutMs
-            mFramestoDrop = - ((AudioSystem::kSyncRecordStartTimeOutMs * mReqSampleRate) / 1000);
+            recordTrack->mFramesToDrop = -
+                    ((AudioSystem::kSyncRecordStartTimeOutMs * recordTrack->mSampleRate) / 1000);
         }
     }
 
     {
         // This section is a rendezvous between binder thread executing start() and RecordThread
         AutoMutex lock(mLock);
-        if (mActiveTracks.size() > 0) {
-            // FIXME does not work for multiple active tracks
-            if (mActiveTracks.indexOf(recordTrack) != 0) {
-                status = -EBUSY;
-            } else if (recordTrack->mState == TrackBase::PAUSING) {
+        if (mActiveTracks.indexOf(recordTrack) >= 0) {
+            if (recordTrack->mState == TrackBase::PAUSING) {
+                ALOGV("active record track PAUSING -> ACTIVE");
                 recordTrack->mState = TrackBase::ACTIVE;
+            } else {
+                ALOGV("active record track state %d", recordTrack->mState);
             }
             return status;
         }
 
-        // FIXME why? already set in constructor, 'STARTING_1' would be more accurate
-        recordTrack->mState = TrackBase::IDLE;
+        // TODO consider other ways of handling this, such as changing the state to :STARTING and
+        //      adding the track to mActiveTracks after returning from AudioSystem::startInput(),
+        //      or using a separate command thread
+        recordTrack->mState = TrackBase::STARTING_1;
         mActiveTracks.add(recordTrack);
         mActiveTracksGen++;
         mLock.unlock();
         status_t status = AudioSystem::startInput(mId);
         mLock.lock();
-        // FIXME should verify that mActiveTrack is still == recordTrack
+        // FIXME should verify that recordTrack is still in mActiveTracks
         if (status != NO_ERROR) {
             mActiveTracks.remove(recordTrack);
             mActiveTracksGen++;
-            clearSyncStartEvent();
+            recordTrack->clearSyncStartEvent();
             return status;
         }
-        // FIXME LEGACY
-        mRsmpInIndex = mFrameCount;
-        mRsmpInFront = 0;
-        mRsmpInRear = 0;
-        mRsmpInUnrel = 0;
-        mBytesRead = 0;
-        if (mResampler != NULL) {
-            mResampler->reset();
+        // Catch up with current buffer indices if thread is already running.
+        // This is what makes a new client discard all buffered data.  If the track's mRsmpInFront
+        // was initialized to some value closer to the thread's mRsmpInFront, then the track could
+        // see previously buffered data before it called start(), but with greater risk of overrun.
+
+        recordTrack->mRsmpInFront = mRsmpInRear;
+        recordTrack->mRsmpInUnrel = 0;
+        // FIXME why reset?
+        if (recordTrack->mResampler != NULL) {
+            recordTrack->mResampler->reset();
         }
-        // FIXME hijacking a playback track state name which was intended for start after pause;
-        //       here 'STARTING_2' would be more accurate
-        recordTrack->mState = TrackBase::RESUMING;
+        recordTrack->mState = TrackBase::STARTING_2;
         // signal thread to start
-        ALOGV("Signal record thread");
         mWaitWorkCV.broadcast();
-        // do not wait for mStartStopCond if exiting
-        if (exitPending()) {
-            mActiveTracks.remove(recordTrack);
-            mActiveTracksGen++;
-            status = INVALID_OPERATION;
-            goto startError;
-        }
-        // FIXME incorrect usage of wait: no explicit predicate or loop
-        mStartStopCond.wait(mLock);
         if (mActiveTracks.indexOf(recordTrack) < 0) {
             ALOGV("Record failed to start");
             status = BAD_VALUE;
             goto startError;
         }
-        ALOGV("Record started OK");
         return status;
     }
 
 startError:
     AudioSystem::stopInput(mId);
-    clearSyncStartEvent();
+    recordTrack->clearSyncStartEvent();
+    // FIXME I wonder why we do not reset the state here?
     return status;
 }
 
-void AudioFlinger::RecordThread::clearSyncStartEvent()
-{
-    if (mSyncStartEvent != 0) {
-        mSyncStartEvent->cancel();
-    }
-    mSyncStartEvent.clear();
-    mFramestoDrop = 0;
-}
-
 void AudioFlinger::RecordThread::syncStartEventCallback(const wp<SyncEvent>& event)
 {
     sp<SyncEvent> strongEvent = event.promote();
 
     if (strongEvent != 0) {
-        RecordThread *me = (RecordThread *)strongEvent->cookie();
-        me->handleSyncStartEvent(strongEvent);
-    }
-}
-
-void AudioFlinger::RecordThread::handleSyncStartEvent(const sp<SyncEvent>& event)
-{
-    if (event == mSyncStartEvent) {
-        // TODO: use actual buffer filling status instead of 2 buffers when info is available
-        // from audio HAL
-        mFramestoDrop = mFrameCount * 2;
+        sp<RefBase> ptr = strongEvent->cookie().promote();
+        if (ptr != 0) {
+            RecordTrack *recordTrack = (RecordTrack *)ptr.get();
+            recordTrack->handleSyncStartEvent(strongEvent);
+        }
     }
 }
 
@@ -5151,13 +5191,9 @@
     fdprintf(fd, "\nInput thread %p:\n", this);
 
     if (mActiveTracks.size() > 0) {
-        fdprintf(fd, "  In index: %zu\n", mRsmpInIndex);
         fdprintf(fd, "  Buffer size: %zu bytes\n", mBufferSize);
-        fdprintf(fd, "  Resampling: %d\n", (mResampler != NULL));
-        fdprintf(fd, "  Out channel count: %u\n", mReqChannelCount);
-        fdprintf(fd, "  Out sample rate: %u\n", mReqSampleRate);
     } else {
-        fdprintf(fd, "  No active record client\n");
+        fdprintf(fd, "  No active record clients\n");
     }
 
     dumpBase(fd, args);
@@ -5209,15 +5245,26 @@
 }
 
 // AudioBufferProvider interface
-status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts __unused)
+status_t AudioFlinger::RecordThread::ResamplerBufferProvider::getNextBuffer(
+        AudioBufferProvider::Buffer* buffer, int64_t pts __unused)
 {
-    int32_t rear = mRsmpInRear;
-    int32_t front = mRsmpInFront;
+    RecordTrack *activeTrack = mRecordTrack;
+    sp<ThreadBase> threadBase = activeTrack->mThread.promote();
+    if (threadBase == 0) {
+        buffer->frameCount = 0;
+        buffer->raw = NULL;
+        return NOT_ENOUGH_DATA;
+    }
+    RecordThread *recordThread = (RecordThread *) threadBase.get();
+    int32_t rear = recordThread->mRsmpInRear;
+    int32_t front = activeTrack->mRsmpInFront;
     ssize_t filled = rear - front;
-    ALOG_ASSERT(0 <= filled && (size_t) filled <= mRsmpInFramesP2);
+    // FIXME should not be P2 (don't want to increase latency)
+    // FIXME if client not keeping up, discard
+    LOG_ALWAYS_FATAL_IF(!(0 <= filled && (size_t) filled <= recordThread->mRsmpInFrames));
     // 'filled' may be non-contiguous, so return only the first contiguous chunk
-    front &= mRsmpInFramesP2 - 1;
-    size_t part1 = mRsmpInFramesP2 - front;
+    front &= recordThread->mRsmpInFramesP2 - 1;
+    size_t part1 = recordThread->mRsmpInFramesP2 - front;
     if (part1 > (size_t) filled) {
         part1 = filled;
     }
@@ -5228,29 +5275,31 @@
     }
     if (part1 == 0) {
         // Higher-level should keep mRsmpInBuffer full, and not call resampler if empty
-        ALOGE("RecordThread::getNextBuffer() starved");
+        LOG_ALWAYS_FATAL("RecordThread::getNextBuffer() starved");
         buffer->raw = NULL;
         buffer->frameCount = 0;
-        mRsmpInUnrel = 0;
+        activeTrack->mRsmpInUnrel = 0;
         return NOT_ENOUGH_DATA;
     }
 
-    buffer->raw = mRsmpInBuffer + front * mChannelCount;
+    buffer->raw = recordThread->mRsmpInBuffer + front * recordThread->mChannelCount;
     buffer->frameCount = part1;
-    mRsmpInUnrel = part1;
+    activeTrack->mRsmpInUnrel = part1;
     return NO_ERROR;
 }
 
 // AudioBufferProvider interface
-void AudioFlinger::RecordThread::releaseBuffer(AudioBufferProvider::Buffer* buffer)
+void AudioFlinger::RecordThread::ResamplerBufferProvider::releaseBuffer(
+        AudioBufferProvider::Buffer* buffer)
 {
+    RecordTrack *activeTrack = mRecordTrack;
     size_t stepCount = buffer->frameCount;
     if (stepCount == 0) {
         return;
     }
-    ALOG_ASSERT(stepCount <= mRsmpInUnrel);
-    mRsmpInUnrel -= stepCount;
-    mRsmpInFront += stepCount;
+    ALOG_ASSERT(stepCount <= activeTrack->mRsmpInUnrel);
+    activeTrack->mRsmpInUnrel -= stepCount;
+    activeTrack->mRsmpInFront += stepCount;
     buffer->raw = NULL;
     buffer->frameCount = 0;
 }
@@ -5265,11 +5314,14 @@
         AudioParameter param = AudioParameter(keyValuePair);
         int value;
         audio_format_t reqFormat = mFormat;
-        uint32_t reqSamplingRate = mReqSampleRate;
-        audio_channel_mask_t reqChannelMask = audio_channel_in_mask_from_count(mReqChannelCount);
+        uint32_t samplingRate = mSampleRate;
+        audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(mChannelCount);
 
+        // TODO Investigate when this code runs. Check with audio policy when a sample rate and
+        //      channel count change can be requested. Do we mandate the first client defines the
+        //      HAL sampling rate and channel count or do we allow changes on the fly?
         if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
-            reqSamplingRate = value;
+            samplingRate = value;
             reconfig = true;
         }
         if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
@@ -5285,7 +5337,7 @@
             if (mask != AUDIO_CHANNEL_IN_MONO && mask != AUDIO_CHANNEL_IN_STEREO) {
                 status = BAD_VALUE;
             } else {
-                reqChannelMask = mask;
+                channelMask = mask;
                 reconfig = true;
             }
         }
@@ -5350,15 +5402,15 @@
                     reqFormat == mInput->stream->common.get_format(&mInput->stream->common) &&
                     reqFormat == AUDIO_FORMAT_PCM_16_BIT &&
                     (mInput->stream->common.get_sample_rate(&mInput->stream->common)
-                            <= (2 * reqSamplingRate)) &&
+                            <= (2 * samplingRate)) &&
                     popcount(mInput->stream->common.get_channels(&mInput->stream->common))
                             <= FCC_2 &&
-                    (reqChannelMask == AUDIO_CHANNEL_IN_MONO ||
-                            reqChannelMask == AUDIO_CHANNEL_IN_STEREO)) {
+                    (channelMask == AUDIO_CHANNEL_IN_MONO ||
+                            channelMask == AUDIO_CHANNEL_IN_STEREO)) {
                     status = NO_ERROR;
                 }
                 if (status == NO_ERROR) {
-                    readInputParameters();
+                    readInputParameters_l();
                     sendIoConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
                 }
             }
@@ -5410,15 +5462,8 @@
     mAudioFlinger->audioConfigChanged_l(event, mId, param2);
 }
 
-void AudioFlinger::RecordThread::readInputParameters()
+void AudioFlinger::RecordThread::readInputParameters_l()
 {
-    delete[] mRsmpInBuffer;
-    // mRsmpInBuffer is always assigned a new[] below
-    delete[] mRsmpOutBuffer;
-    mRsmpOutBuffer = NULL;
-    delete mResampler;
-    mResampler = NULL;
-
     mSampleRate = mInput->stream->common.get_sample_rate(&mInput->stream->common);
     mChannelMask = mInput->stream->common.get_channels(&mInput->stream->common);
     mChannelCount = popcount(mChannelMask);
@@ -5429,24 +5474,20 @@
     mFrameSize = audio_stream_frame_size(&mInput->stream->common);
     mBufferSize = mInput->stream->common.get_buffer_size(&mInput->stream->common);
     mFrameCount = mBufferSize / mFrameSize;
+    // This is the formula for calculating the temporary buffer size.
     // With 3 HAL buffers, we can guarantee ability to down-sample the input by ratio of 2:1 to
     // 1 full output buffer, regardless of the alignment of the available input.
+    // The "3" is somewhat arbitrary, and could probably be larger.
+    // A larger value should allow more old data to be read after a track calls start(),
+    // without increasing latency.
     mRsmpInFrames = mFrameCount * 3;
     mRsmpInFramesP2 = roundup(mRsmpInFrames);
+    delete[] mRsmpInBuffer;
     // Over-allocate beyond mRsmpInFramesP2 to permit a HAL read past end of buffer
     mRsmpInBuffer = new int16_t[(mRsmpInFramesP2 + mFrameCount - 1) * mChannelCount];
-    mRsmpInFront = 0;
-    mRsmpInRear = 0;
-    mRsmpInUnrel = 0;
 
-    if (mSampleRate != mReqSampleRate && mChannelCount <= FCC_2 && mReqChannelCount <= FCC_2) {
-        mResampler = AudioResampler::create(16, (int) mChannelCount, mReqSampleRate);
-        mResampler->setSampleRate(mSampleRate);
-        mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN);
-        // resampler always outputs stereo
-        mRsmpOutBuffer = new int32_t[mFrameCount * FCC_2];
-    }
-    mRsmpInIndex = mFrameCount;
+    // AudioRecord mSampleRate and mChannelCount are constant due to AudioRecord API constraints.
+    // But if thread's mSampleRate or mChannelCount changes, how will that affect active tracks?
 }
 
 uint32_t AudioFlinger::RecordThread::getInputFramesLost()
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 999fea3..fa3563c 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -270,8 +270,8 @@
 
                 const sp<AudioFlinger>  mAudioFlinger;
 
-                // updated by PlaybackThread::readOutputParameters() or
-                // RecordThread::readInputParameters()
+                // updated by PlaybackThread::readOutputParameters_l() or
+                // RecordThread::readInputParameters_l()
                 uint32_t                mSampleRate;
                 size_t                  mFrameCount;       // output HAL, direct output, record
                 audio_channel_mask_t    mChannelMask;
@@ -478,7 +478,7 @@
                 status_t         getTimestamp_l(AudioTimestamp& timestamp);
 
 protected:
-    // updated by readOutputParameters()
+    // updated by readOutputParameters_l()
     size_t                          mNormalFrameCount;  // normal mixer and effects
 
     int16_t*                        mMixBuffer;         // frame size aligned mix buffer
@@ -541,7 +541,7 @@
     void        removeTrack_l(const sp<Track>& track);
     void        broadcast_l();
 
-    void        readOutputParameters();
+    void        readOutputParameters_l();
 
     virtual void dumpInternals(int fd, const Vector<String16>& args);
     void        dumpTracks(int fd, const Vector<String16>& args);
@@ -839,17 +839,28 @@
 
 
 // record thread
-class RecordThread : public ThreadBase, public AudioBufferProvider
-                        // derives from AudioBufferProvider interface for use by resampler
+class RecordThread : public ThreadBase
 {
 public:
 
+    class RecordTrack;
+    class ResamplerBufferProvider : public AudioBufferProvider
+                        // derives from AudioBufferProvider interface for use by resampler
+    {
+    public:
+        ResamplerBufferProvider(RecordTrack* recordTrack) : mRecordTrack(recordTrack) { }
+        virtual ~ResamplerBufferProvider() { }
+        // AudioBufferProvider interface
+        virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts);
+        virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
+    private:
+        RecordTrack * const mRecordTrack;
+    };
+
 #include "RecordTracks.h"
 
             RecordThread(const sp<AudioFlinger>& audioFlinger,
                     AudioStreamIn *input,
-                    uint32_t sampleRate,
-                    audio_channel_mask_t channelMask,
                     audio_io_handle_t id,
                     audio_devices_t outDevice,
                     audio_devices_t inDevice
@@ -898,14 +909,11 @@
             AudioStreamIn* clearInput();
             virtual audio_stream_t* stream() const;
 
-    // AudioBufferProvider interface
-    virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts);
-    virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
 
     virtual bool        checkForNewParameters_l();
     virtual String8     getParameters(const String8& keys);
     virtual void        audioConfigChanged_l(int event, int param = 0);
-            void        readInputParameters();
+            void        readInputParameters_l();
     virtual uint32_t    getInputFramesLost();
 
     virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
@@ -921,14 +929,11 @@
     virtual bool     isValidSyncEvent(const sp<SyncEvent>& event) const;
 
     static void syncStartEventCallback(const wp<SyncEvent>& event);
-           void handleSyncStartEvent(const sp<SyncEvent>& event);
 
     virtual size_t      frameCount() const { return mFrameCount; }
             bool        hasFastRecorder() const { return false; }
 
 private:
-            void    clearSyncStartEvent();
-
             // Enter standby if not already in standby, and set mStandby flag
             void    standbyIfNotAlreadyInStandby();
 
@@ -944,34 +949,13 @@
             int                                 mActiveTracksGen;
             Condition                           mStartStopCond;
 
-            // updated by RecordThread::readInputParameters()
-            AudioResampler                      *mResampler;
-            // interleaved stereo pairs of fixed-point signed Q19.12
-            int32_t                             *mRsmpOutBuffer;
-
             // resampler converts input at HAL Hz to output at AudioRecord client Hz
             int16_t                             *mRsmpInBuffer; // see new[] for details on the size
             size_t                              mRsmpInFrames;  // size of resampler input in frames
             size_t                              mRsmpInFramesP2;// size rounded up to a power-of-2
-            size_t                              mRsmpInUnrel;   // unreleased frames remaining from
-                                                                // most recent getNextBuffer
-            // these are rolling counters that are never cleared
-            int32_t                             mRsmpInFront;   // next available frame
+
+            // rolling index that is never cleared
             int32_t                             mRsmpInRear;    // last filled frame + 1
-            size_t                              mRsmpInIndex;   // FIXME legacy
-
-            // client's requested configuration, which may differ from the HAL configuration
-            const uint32_t                      mReqChannelCount;
-            const uint32_t                      mReqSampleRate;
-
-            ssize_t                             mBytesRead;
-            // sync event triggering actual audio capture. Frames read before this event will
-            // be dropped and therefore not read by the application.
-            sp<SyncEvent>                       mSyncStartEvent;
-            // number of captured frames to drop after the start sync event has been received.
-            // when < 0, maximum frames to drop before starting capture even if sync event is
-            // not received
-            ssize_t                             mFramestoDrop;
 
             // For dumpsys
             const sp<NBAIO_Sink>                mTeeSink;
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 05fde7c..58705c4 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -34,7 +34,9 @@
         RESUMING,
         ACTIVE,
         PAUSING,
-        PAUSED
+        PAUSED,
+        STARTING_1,     // for RecordTrack only
+        STARTING_2,     // for RecordTrack only
     };
 
                         TrackBase(ThreadBase *thread,
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index e5152b8..92ed46a 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1785,17 +1785,34 @@
             int uid)
     :   TrackBase(thread, client, sampleRate, format,
                   channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, uid, false /*isOut*/),
-        mOverflow(false)
+        mOverflow(false), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpOutFrameCount(0),
+        // See real initialization of mRsmpInFront at RecordThread::start()
+        mRsmpInUnrel(0), mRsmpInFront(0), mFramesToDrop(0), mResamplerBufferProvider(NULL)
 {
     ALOGV("RecordTrack constructor");
     if (mCblk != NULL) {
         mServerProxy = new AudioRecordServerProxy(mCblk, mBuffer, frameCount, mFrameSize);
     }
+
+    uint32_t channelCount = popcount(channelMask);
+    // FIXME I don't understand either of the channel count checks
+    if (thread->mSampleRate != sampleRate && thread->mChannelCount <= FCC_2 &&
+            channelCount <= FCC_2) {
+        // sink SR
+        mResampler = AudioResampler::create(16, thread->mChannelCount, sampleRate);
+        // source SR
+        mResampler->setSampleRate(thread->mSampleRate);
+        mResampler->setVolume(AudioMixer::UNITY_GAIN, AudioMixer::UNITY_GAIN);
+        mResamplerBufferProvider = new ResamplerBufferProvider(this);
+    }
 }
 
 AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
 {
     ALOGV("%s", __func__);
+    delete mResampler;
+    delete[] mRsmpOutBuffer;
+    delete mResamplerBufferProvider;
 }
 
 // AudioBufferProvider interface
@@ -1868,12 +1885,12 @@
 
 /*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result)
 {
-    result.append("    Active Client Fmt Chn mask Session S   Server fCount\n");
+    result.append("    Active Client Fmt Chn mask Session S   Server fCount Resampling\n");
 }
 
 void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size, bool active)
 {
-    snprintf(buffer, size, "    %6s %6u %3u %08X %7u %1d %08X %6zu\n",
+    snprintf(buffer, size, "    %6s %6u %3u %08X %7u %1d %08X %6zu %10d\n",
             active ? "yes" : "no",
             (mClient == 0) ? getpid_cached : mClient->pid(),
             mFormat,
@@ -1881,7 +1898,32 @@
             mSessionId,
             mState,
             mCblk->mServer,
-            mFrameCount);
+            mFrameCount,
+            mResampler != NULL);
+
+}
+
+void AudioFlinger::RecordThread::RecordTrack::handleSyncStartEvent(const sp<SyncEvent>& event)
+{
+    if (event == mSyncStartEvent) {
+        ssize_t framesToDrop = 0;
+        sp<ThreadBase> threadBase = mThread.promote();
+        if (threadBase != 0) {
+            // TODO: use actual buffer filling status instead of 2 buffers when info is available
+            // from audio HAL
+            framesToDrop = threadBase->mFrameCount * 2;
+        }
+        mFramesToDrop = framesToDrop;
+    }
+}
+
+void AudioFlinger::RecordThread::RecordTrack::clearSyncStartEvent()
+{
+    if (mSyncStartEvent != 0) {
+        mSyncStartEvent->cancel();
+        mSyncStartEvent.clear();
+    }
+    mFramesToDrop = 0;
 }
 
 }; // namespace android
diff --git a/services/audioflinger/test-resample.cpp b/services/audioflinger/test-resample.cpp
index 66fcd90..74d5702 100644
--- a/services/audioflinger/test-resample.cpp
+++ b/services/audioflinger/test-resample.cpp
@@ -34,7 +34,7 @@
 
 static int usage(const char* name) {
     fprintf(stderr,"Usage: %s [-p] [-h] [-v] [-s] [-q {dq|lq|mq|hq|vhq|dlq|dmq|dhq}]"
-                   " [-i input-sample-rate] [-o output-sample-rate] [<input-file>]"
+                   " [-i input-sample-rate] [-o output-sample-rate] [-O #] [<input-file>]"
                    " <output-file>\n", name);
     fprintf(stderr,"    -p    enable profiling\n");
     fprintf(stderr,"    -h    create wav file\n");
@@ -51,6 +51,7 @@
     fprintf(stderr,"              dhq : dynamic high quality\n");
     fprintf(stderr,"    -i    input file sample rate (ignored if input file is specified)\n");
     fprintf(stderr,"    -o    output file sample rate\n");
+    fprintf(stderr,"    -O    # frames output per call to resample()\n");
     return -1;
 }
 
@@ -64,9 +65,10 @@
     int input_freq = 0;
     int output_freq = 0;
     AudioResampler::src_quality quality = AudioResampler::DEFAULT_QUALITY;
+    size_t framesPerCall = 0;
 
     int ch;
-    while ((ch = getopt(argc, argv, "pfhvsq:i:o:")) != -1) {
+    while ((ch = getopt(argc, argv, "pfhvsq:i:o:O:")) != -1) {
         switch (ch) {
         case 'p':
             profileResample = true;
@@ -111,6 +113,9 @@
         case 'o':
             output_freq = atoi(optarg);
             break;
+        case 'O':
+            framesPerCall = atoi(optarg);
+            break;
         case '?':
         default:
             usage(progname);
@@ -343,7 +348,14 @@
     if (gVerbose) {
         printf("resample() %u output frames\n", out_frames);
     }
-    resampler->resample((int*) output_vaddr, out_frames, &provider);
+    if (framesPerCall == 0 || framesPerCall > out_frames) {
+        framesPerCall = out_frames;
+    }
+    for (size_t i = 0; i < out_frames; ) {
+        size_t thisFrames = framesPerCall <= out_frames - i ? framesPerCall : out_frames - i;
+        resampler->resample((int*) output_vaddr + 2*i, thisFrames, &provider);
+        i += thisFrames;
+    }
     if (gVerbose) {
         printf("resample() complete\n");
     }