Merge "Fix missing mutex lock in Drm::binderDied" into lmp-mr1-dev
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 6a0f2a6..f3b7fbb 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -99,8 +99,6 @@
     // to be non-zero if status == NO_ERROR
     static status_t getOutputSamplingRate(uint32_t* samplingRate,
             audio_stream_type_t stream);
-    static status_t getOutputSamplingRateForAttr(uint32_t* samplingRate,
-                const audio_attributes_t *attr);
     static status_t getOutputFrameCount(size_t* frameCount,
             audio_stream_type_t stream);
     static status_t getOutputLatency(uint32_t* latency,
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index 3629c8b..0970b2b 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -85,8 +85,6 @@
     status_t initEncoder();
     void releaseEncoder();
     status_t feedEncoderInputBuffers();
-    void scheduleDoMoreWork();
-    status_t doMoreWork(int32_t numInput, int32_t numOutput);
     void suspend();
     void resume(int64_t skipFramesBeforeUs = -1ll);
     void signalEOS(status_t err = ERROR_END_OF_STREAM);
@@ -108,8 +106,6 @@
     bool mDoMoreWorkPending;
     sp<AMessage> mEncoderActivityNotify;
     sp<IGraphicBufferProducer> mGraphicBufferProducer;
-    Vector<sp<ABuffer> > mEncoderInputBuffers;
-    Vector<sp<ABuffer> > mEncoderOutputBuffers;
     List<MediaBuffer *> mInputBufferQueue;
     List<size_t> mAvailEncoderInputIndices;
     List<int64_t> mDecodingTimeQueue; // decoding time (us) for video
diff --git a/include/media/stagefright/foundation/ADebug.h b/include/media/stagefright/foundation/ADebug.h
index 450dcfe..1d0e2cb 100644
--- a/include/media/stagefright/foundation/ADebug.h
+++ b/include/media/stagefright/foundation/ADebug.h
@@ -80,6 +80,36 @@
             __FILE__ ":" LITERAL_TO_STRING(__LINE__)            \
                 " Should not be here.");
 
+struct ADebug {
+    enum Level {
+        kDebugNone,             // no debug
+        kDebugLifeCycle,        // lifecycle events: creation/deletion
+        kDebugState,            // commands and events
+        kDebugConfig,           // configuration
+        kDebugInternalState,    // internal state changes
+        kDebugAll,              // all
+        kDebugMax = kDebugAll,
+
+    };
+
+    // parse the property or string to get the debug level for a component name
+    // string format is:
+    // <level>[:<glob>][,<level>[:<glob>]...]
+    // - <level> is 0-5 corresponding to ADebug::Level
+    // - <glob> is used to match component name case insensitively, if omitted, it
+    //   matches all components
+    // - string is read left-to-right, and the last matching level is returned, or
+    //   the def if no terms matched
+    static Level GetDebugLevelFromProperty(
+            const char *name, const char *propertyName, Level def = kDebugNone);
+    static Level GetDebugLevelFromString(
+            const char *name, const char *value, Level def = kDebugNone);
+
+    // remove redundant segments of a codec name, and return a newly allocated
+    // string suitable for debugging
+    static char *GetDebugName(const char *name);
+};
+
 }  // namespace android
 
 #endif  // A_DEBUG_H_
diff --git a/include/media/stagefright/foundation/AStringUtils.h b/include/media/stagefright/foundation/AStringUtils.h
new file mode 100644
index 0000000..76a7791
--- /dev/null
+++ b/include/media/stagefright/foundation/AStringUtils.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 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 A_STRING_UTILS_H_
+#define A_STRING_UTILS_H_
+
+#include <stdlib.h>
+
+namespace android {
+
+struct AStringUtils {
+    // similar to strncmp or strcasecmp, but case sensitivity is parametric
+    static int Compare(const char *a, const char *b, size_t len, bool ignoreCase);
+
+    // matches a string (str) to a glob pattern that supports:
+    //    * - matches any number of characters
+    static bool MatchesGlob(
+            const char *glob, size_t globLen, const char *str, size_t strLen, bool ignoreCase);
+};
+
+}  // namespace android
+
+#endif  // A_STRING_UTILS_H_
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index f5c3383..fce4389 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -247,19 +247,6 @@
     return getSamplingRate(output, samplingRate);
 }
 
-status_t AudioSystem::getOutputSamplingRateForAttr(uint32_t* samplingRate,
-        const audio_attributes_t *attr)
-{
-    if (attr == NULL) {
-        return BAD_VALUE;
-    }
-    audio_io_handle_t output = getOutputForAttr(attr);
-    if (output == 0) {
-        return PERMISSION_DENIED;
-    }
-    return getSamplingRate(output, samplingRate);
-}
-
 status_t AudioSystem::getSamplingRate(audio_io_handle_t output,
                                       uint32_t* samplingRate)
 {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index cd493f6..2f57b9d 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -304,17 +304,6 @@
                 mAttributes.usage, mAttributes.content_type, mAttributes.flags, mAttributes.tags);
     }
 
-    status_t status;
-    if (sampleRate == 0) {
-        status = AudioSystem::getOutputSamplingRateForAttr(&sampleRate, &mAttributes);
-        if (status != NO_ERROR) {
-            ALOGE("Could not get output sample rate for stream type %d; status %d",
-                    mStreamType, status);
-            return status;
-        }
-    }
-    mSampleRate = sampleRate;
-
     // these below should probably come from the audioFlinger too...
     if (format == AUDIO_FORMAT_DEFAULT) {
         format = AUDIO_FORMAT_PCM_16_BIT;
@@ -373,6 +362,12 @@
         // so no need to check for specific PCM formats here
     }
 
+    // sampling rate must be specified for direct outputs
+    if (sampleRate == 0 && (flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+        return BAD_VALUE;
+    }
+    mSampleRate = sampleRate;
+
     // Make copy of input parameter offloadInfo so that in the future:
     //  (a) createTrack_l doesn't need it as an input parameter
     //  (b) we can support re-creation of offloaded tracks
@@ -413,7 +408,7 @@
     }
 
     // create the IAudioTrack
-    status = createTrack_l();
+    status_t status = createTrack_l();
 
     if (status != NO_ERROR) {
         if (mAudioTrackThread != 0) {
@@ -680,15 +675,18 @@
         return INVALID_OPERATION;
     }
 
+    AutoMutex lock(mLock);
+    if (mOutput == AUDIO_IO_HANDLE_NONE) {
+        return NO_INIT;
+    }
     uint32_t afSamplingRate;
-    if (AudioSystem::getOutputSamplingRateForAttr(&afSamplingRate, &mAttributes) != NO_ERROR) {
+    if (AudioSystem::getSamplingRate(mOutput, &afSamplingRate) != NO_ERROR) {
         return NO_INIT;
     }
     if (rate == 0 || rate > afSamplingRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX) {
         return BAD_VALUE;
     }
 
-    AutoMutex lock(mLock);
     mSampleRate = rate;
     mProxy->setSampleRate(rate);
 
@@ -963,7 +961,9 @@
         ALOGE("getSamplingRate(output=%d) status %d", output, status);
         goto release;
     }
-
+    if (mSampleRate == 0) {
+        mSampleRate = afSampleRate;
+    }
     // Client decides whether the track is TIMED (see below), but can only express a preference
     // for FAST.  Server will perform additional tests.
     if ((mFlags & AUDIO_OUTPUT_FLAG_FAST) && !((
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index c120898..d461af3 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -2125,6 +2125,7 @@
         // immutable with respect to future writes.
         //
         // It is thus safe for another thread to read the AudioCache.
+        Mutex::Autolock lock(mLock);
         mCommandComplete = true;
         mSignal.signal();
     }
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 0e520a8..d446cec 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -45,6 +45,10 @@
         bool uidValid,
         uid_t uid)
     : Source(notify),
+      mAudioTimeUs(0),
+      mAudioLastDequeueTimeUs(0),
+      mVideoTimeUs(0),
+      mVideoLastDequeueTimeUs(0),
       mFetchSubtitleDataGeneration(0),
       mFetchTimedTextDataGeneration(0),
       mDurationUs(0ll),
@@ -62,8 +66,6 @@
 }
 
 void NuPlayer::GenericSource::resetDataSource() {
-    mAudioTimeUs = 0;
-    mVideoTimeUs = 0;
     mHTTPService.clear();
     mHttpSource.clear();
     mUri.clear();
@@ -644,17 +646,13 @@
           track->mSource->start();
           track->mIndex = trackIndex;
 
-          status_t avail;
-          if (!track->mPackets->hasBufferAvailable(&avail)) {
-              // sync from other source
-              TRESPASS();
-              break;
-          }
-
           int64_t timeUs, actualTimeUs;
           const bool formatChange = true;
-          sp<AMessage> latestMeta = track->mPackets->getLatestEnqueuedMeta();
-          CHECK(latestMeta != NULL && latestMeta->findInt64("timeUs", &timeUs));
+          if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
+              timeUs = mAudioLastDequeueTimeUs;
+          } else {
+              timeUs = mVideoLastDequeueTimeUs;
+          }
           readBuffer(trackType, timeUs, &actualTimeUs, formatChange);
           readBuffer(counterpartType, -1, NULL, formatChange);
           ALOGV("timeUs %lld actualTimeUs %lld", timeUs, actualTimeUs);
@@ -866,6 +864,11 @@
     int64_t timeUs;
     status_t eosResult; // ignored
     CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs));
+    if (audio) {
+        mAudioLastDequeueTimeUs = timeUs;
+    } else {
+        mVideoLastDequeueTimeUs = timeUs;
+    }
 
     if (mSubtitleTrack.mSource != NULL
             && !mSubtitleTrack.mPackets->hasBufferAvailable(&eosResult)) {
@@ -1132,10 +1135,12 @@
         readBuffer(MEDIA_TRACK_TYPE_VIDEO, seekTimeUs, &actualTimeUs);
 
         seekTimeUs = actualTimeUs;
+        mVideoLastDequeueTimeUs = seekTimeUs;
     }
 
     if (mAudioTrack.mSource != NULL) {
         readBuffer(MEDIA_TRACK_TYPE_AUDIO, seekTimeUs);
+        mAudioLastDequeueTimeUs = seekTimeUs;
     }
 
     setDrmPlaybackStatusIfNeeded(Playback::START, seekTimeUs / 1000);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index f8601ea..7a03df0 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -106,8 +106,10 @@
 
     Track mAudioTrack;
     int64_t mAudioTimeUs;
+    int64_t mAudioLastDequeueTimeUs;
     Track mVideoTrack;
     int64_t mVideoTimeUs;
+    int64_t mVideoLastDequeueTimeUs;
     Track mSubtitleTrack;
     Track mTimedTextTrack;
 
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 02e9caf..e335055 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -139,6 +139,14 @@
     return mLiveSession->getTrackInfo(trackIndex);
 }
 
+ssize_t NuPlayer::HTTPLiveSource::getSelectedTrack(media_track_type type) const {
+    if (mLiveSession == NULL) {
+        return -1;
+    } else {
+        return mLiveSession->getSelectedTrack(type);
+    }
+}
+
 status_t NuPlayer::HTTPLiveSource::selectTrack(size_t trackIndex, bool select) {
     status_t err = mLiveSession->selectTrack(trackIndex, select);
 
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
index 6b5f6af..98b826e 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.h
@@ -42,6 +42,7 @@
     virtual status_t getDuration(int64_t *durationUs);
     virtual size_t getTrackCount() const;
     virtual sp<AMessage> getTrackInfo(size_t trackIndex) const;
+    virtual ssize_t getSelectedTrack(media_track_type /* type */) const;
     virtual status_t selectTrack(size_t trackIndex, bool select);
     virtual status_t seekTo(int64_t seekTimeUs);
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 47bd989..4f88f02 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -165,8 +165,6 @@
       mTimeDiscontinuityPending(false),
       mFlushingAudio(NONE),
       mFlushingVideo(NONE),
-      mSkipRenderingAudioUntilMediaTimeUs(-1ll),
-      mSkipRenderingVideoUntilMediaTimeUs(-1ll),
       mNumFramesTotal(0ll),
       mNumFramesDropped(0ll),
       mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
@@ -701,19 +699,14 @@
 
                 handleFlushComplete(audio, true /* isDecoder */);
                 finishFlushIfPossible();
-            } else if (what == Decoder::kWhatOutputFormatChanged) {
+            } else if (what == Decoder::kWhatVideoSizeChanged) {
                 sp<AMessage> format;
                 CHECK(msg->findMessage("format", &format));
 
-                if (audio) {
-                    openAudioSink(format, false /*offloadOnly*/);
-                } else {
-                    // video
-                    sp<AMessage> inputFormat =
-                            mSource->getFormat(false /* audio */);
+                sp<AMessage> inputFormat =
+                        mSource->getFormat(false /* audio */);
 
-                    updateVideoSize(inputFormat, format);
-                }
+                updateVideoSize(inputFormat, format);
             } else if (what == Decoder::kWhatShutdownCompleted) {
                 ALOGV("%s shutdown completed", audio ? "audio" : "video");
                 if (audio) {
@@ -779,7 +772,7 @@
                         break;                    // Finish anyways.
                 }
                 notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
-            } else if (what == Decoder::kWhatDrainThisBuffer) {
+            } else if (what == Decoder::kWhatRenderBufferTime) {
                 renderBuffer(audio, msg);
             } else {
                 ALOGV("Unhandled decoder notification %d '%c%c%c%c'.",
@@ -967,8 +960,6 @@
     mOffloadAudio = false;
     mAudioEOS = false;
     mVideoEOS = false;
-    mSkipRenderingAudioUntilMediaTimeUs = -1;
-    mSkipRenderingVideoUntilMediaTimeUs = -1;
     mNumFramesTotal = 0;
     mNumFramesDropped = 0;
     mStarted = true;
@@ -1024,6 +1015,13 @@
         mRenderer->setVideoFrameRate(rate);
     }
 
+    if (mVideoDecoder != NULL) {
+        mVideoDecoder->setRenderer(mRenderer);
+    }
+    if (mAudioDecoder != NULL) {
+        mAudioDecoder->setRenderer(mRenderer);
+    }
+
     postScanSources();
 }
 
@@ -1182,16 +1180,16 @@
         notify->setInt32("generation", mAudioDecoderGeneration);
 
         if (mOffloadAudio) {
-            *decoder = new DecoderPassThrough(notify);
+            *decoder = new DecoderPassThrough(notify, mSource, mRenderer);
         } else {
-            *decoder = new Decoder(notify);
+            *decoder = new Decoder(notify, mSource, mRenderer);
         }
     } else {
         sp<AMessage> notify = new AMessage(kWhatVideoNotify, id());
         ++mVideoDecoderGeneration;
         notify->setInt32("generation", mVideoDecoderGeneration);
 
-        *decoder = new Decoder(notify, mNativeWindow);
+        *decoder = new Decoder(notify, mSource, mRenderer, mNativeWindow);
     }
     (*decoder)->init();
     (*decoder)->configure(format);
@@ -1280,33 +1278,6 @@
                 ALOGI("%s discontinuity (formatChange=%d, time=%d)",
                      audio ? "audio" : "video", formatChange, timeChange);
 
-                if (audio) {
-                    mSkipRenderingAudioUntilMediaTimeUs = -1;
-                } else {
-                    mSkipRenderingVideoUntilMediaTimeUs = -1;
-                }
-
-                if (timeChange) {
-                    sp<AMessage> extra;
-                    if (accessUnit->meta()->findMessage("extra", &extra)
-                            && extra != NULL) {
-                        int64_t resumeAtMediaTimeUs;
-                        if (extra->findInt64(
-                                    "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
-                            ALOGI("suppressing rendering of %s until %lld us",
-                                    audio ? "audio" : "video", resumeAtMediaTimeUs);
-
-                            if (audio) {
-                                mSkipRenderingAudioUntilMediaTimeUs =
-                                    resumeAtMediaTimeUs;
-                            } else {
-                                mSkipRenderingVideoUntilMediaTimeUs =
-                                    resumeAtMediaTimeUs;
-                            }
-                        }
-                    }
-                }
-
                 mTimeDiscontinuityPending =
                     mTimeDiscontinuityPending || timeChange;
 
@@ -1447,9 +1418,6 @@
 void NuPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) {
     // ALOGV("renderBuffer %s", audio ? "audio" : "video");
 
-    sp<AMessage> reply;
-    CHECK(msg->findMessage("reply", &reply));
-
     if ((audio && mFlushingAudio != NONE)
             || (!audio && mFlushingVideo != NONE)) {
         // We're currently attempting to flush the decoder, in order
@@ -1460,40 +1428,15 @@
         ALOGV("we're still flushing the %s decoder, sending its output buffer"
              " right back.", audio ? "audio" : "video");
 
-        reply->post();
         return;
     }
 
-    sp<ABuffer> buffer;
-    CHECK(msg->findBuffer("buffer", &buffer));
-
     int64_t mediaTimeUs;
-    CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs));
-
-    int64_t &skipUntilMediaTimeUs =
-        audio
-            ? mSkipRenderingAudioUntilMediaTimeUs
-            : mSkipRenderingVideoUntilMediaTimeUs;
-
-    if (skipUntilMediaTimeUs >= 0) {
-
-        if (mediaTimeUs < skipUntilMediaTimeUs) {
-            ALOGV("dropping %s buffer at time %lld as requested.",
-                 audio ? "audio" : "video",
-                 mediaTimeUs);
-
-            reply->post();
-            return;
-        }
-
-        skipUntilMediaTimeUs = -1;
-    }
+    CHECK(msg->findInt64("timeUs", &mediaTimeUs));
 
     if (!audio && mCCDecoder->isSelected()) {
         mCCDecoder->display(mediaTimeUs);
     }
-
-    mRenderer->queueBuffer(audio, buffer, reply);
 }
 
 void NuPlayer::updateVideoSize(
@@ -1593,7 +1536,6 @@
     mScanSourcesPending = false;
 
     decoder->signalFlush(newFormat);
-    mRenderer->flush(audio);
 
     FlushStatus newStatus =
         needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 121f7dd..5f6deee 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -181,9 +181,6 @@
     FlushStatus mFlushingAudio;
     FlushStatus mFlushingVideo;
 
-    int64_t mSkipRenderingAudioUntilMediaTimeUs;
-    int64_t mSkipRenderingVideoUntilMediaTimeUs;
-
     int64_t mNumFramesTotal, mNumFramesDropped;
 
     int32_t mVideoScalingMode;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 27f6131..e695c43 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -21,6 +21,9 @@
 
 #include "NuPlayerDecoder.h"
 
+#include "NuPlayerRenderer.h"
+#include "NuPlayerSource.h"
+
 #include <media/ICrypto.h>
 #include <media/stagefright/foundation/ABitReader.h>
 #include <media/stagefright/foundation/ABuffer.h>
@@ -35,9 +38,14 @@
 
 NuPlayer::Decoder::Decoder(
         const sp<AMessage> &notify,
+        const sp<Source> &source,
+        const sp<Renderer> &renderer,
         const sp<NativeWindowWrapper> &nativeWindow)
     : mNotify(notify),
       mNativeWindow(nativeWindow),
+      mSource(source),
+      mRenderer(renderer),
+      mSkipRenderingUntilMediaTimeUs(-1ll),
       mBufferGeneration(0),
       mPaused(true),
       mComponentName("decoder") {
@@ -169,7 +177,9 @@
             mInputBuffers.size(),
             mOutputBuffers.size());
 
-    requestCodecNotification();
+    if (mRenderer != NULL) {
+        requestCodecNotification();
+    }
     mPaused = false;
 }
 
@@ -191,6 +201,7 @@
     }
 
     mPendingInputMessages.clear();
+    mSkipRenderingUntilMediaTimeUs = -1;
 }
 
 void NuPlayer::Decoder::requestCodecNotification() {
@@ -217,6 +228,12 @@
     msg->post();
 }
 
+void NuPlayer::Decoder::setRenderer(const sp<Renderer> &renderer) {
+    sp<AMessage> msg = new AMessage(kWhatSetRenderer, id());
+    msg->setObject("renderer", renderer);
+    msg->post();
+}
+
 void NuPlayer::Decoder::signalUpdateFormat(const sp<AMessage> &format) {
     sp<AMessage> msg = new AMessage(kWhatUpdateFormat, id());
     msg->setMessage("format", format);
@@ -342,8 +359,6 @@
         }
     }
 
-
-
     if (buffer == NULL /* includes !hasBuffer */) {
         int32_t streamErr = ERROR_END_OF_STREAM;
         CHECK(msg->findInt32("err", &streamErr) || !hasBuffer);
@@ -375,6 +390,17 @@
             handleError(streamErr);
         }
     } else {
+        sp<AMessage> extra;
+        if (buffer->meta()->findMessage("extra", &extra) && extra != NULL) {
+            int64_t resumeAtMediaTimeUs;
+            if (extra->findInt64(
+                        "resume-at-mediaTimeUs", &resumeAtMediaTimeUs)) {
+                ALOGI("[%s] suppressing rendering until %lld us",
+                        mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
+                mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
+            }
+        }
+
         int64_t timeUs = 0;
         uint32_t flags = 0;
         CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
@@ -454,10 +480,27 @@
             return false;
         }
 
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatOutputFormatChanged);
-        notify->setMessage("format", format);
-        notify->post();
+        if (isVideo()) {
+            sp<AMessage> notify = mNotify->dup();
+            notify->setInt32("what", kWhatVideoSizeChanged);
+            notify->setMessage("format", format);
+            notify->post();
+        } else if (mRenderer != NULL) {
+            uint32_t flags;
+            int64_t durationUs;
+            bool hasVideo = (mSource->getFormat(false /* audio */) != NULL);
+            if (!hasVideo &&
+                    mSource->getDuration(&durationUs) == OK &&
+                    durationUs
+                        > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) {
+                flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+            } else {
+                flags = AUDIO_OUTPUT_FLAG_NONE;
+            }
+
+            mRenderer->openAudioSink(
+                    format, false /* offloadOnly */, hasVideo, flags);
+        }
         return true;
     } else if (res == INFO_DISCONTINUITY) {
         // nothing to do
@@ -485,21 +528,26 @@
     reply->setSize("buffer-ix", bufferIx);
     reply->setInt32("generation", mBufferGeneration);
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatDrainThisBuffer);
-    notify->setBuffer("buffer", buffer);
-    notify->setMessage("reply", reply);
-    notify->post();
+    if (mSkipRenderingUntilMediaTimeUs >= 0) {
+        if (timeUs < mSkipRenderingUntilMediaTimeUs) {
+            ALOGV("[%s] dropping buffer at time %lld as requested.",
+                     mComponentName.c_str(), (long long)timeUs);
 
-    // FIXME: This should be handled after rendering is complete,
-    // but Renderer needs it now
-    if (flags & MediaCodec::BUFFER_FLAG_EOS) {
-        ALOGV("queueing eos [%s]", mComponentName.c_str());
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatEOS);
-        notify->setInt32("err", ERROR_END_OF_STREAM);
-        notify->post();
+            reply->post();
+            return true;
+        }
+
+        mSkipRenderingUntilMediaTimeUs = -1;
     }
+
+    if (mRenderer != NULL) {
+        // send the buffer to renderer.
+        mRenderer->queueBuffer(!isVideo(), buffer, reply);
+        if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+            mRenderer->queueEOS(!isVideo(), ERROR_END_OF_STREAM);
+        }
+    }
+
     return true;
 }
 
@@ -508,6 +556,17 @@
     int32_t render;
     size_t bufferIx;
     CHECK(msg->findSize("buffer-ix", &bufferIx));
+
+    if (isVideo()) {
+        int64_t timeUs;
+        sp<ABuffer> buffer = mOutputBuffers[bufferIx];
+        buffer->meta()->findInt64("timeUs", &timeUs);
+        sp<AMessage> notify = mNotify->dup();
+        notify->setInt32("what", kWhatRenderBufferTime);
+        notify->setInt64("timeUs", timeUs);
+        notify->post();
+    }
+
     if (msg->findInt32("render", &render) && render) {
         int64_t timestampNs;
         CHECK(msg->findInt64("timestampNs", &timestampNs));
@@ -523,6 +582,10 @@
 }
 
 void NuPlayer::Decoder::onFlush() {
+    if (mRenderer != NULL) {
+        mRenderer->flush(!isVideo());
+    }
+
     status_t err = OK;
     if (mCodec != NULL) {
         err = mCodec->flush();
@@ -594,6 +657,18 @@
             break;
         }
 
+        case kWhatSetRenderer:
+        {
+            bool hadNoRenderer = (mRenderer == NULL);
+            sp<RefBase> obj;
+            CHECK(msg->findObject("renderer", &obj));
+            mRenderer = static_cast<Renderer *>(obj.get());
+            if (hadNoRenderer && mRenderer != NULL) {
+                requestCodecNotification();
+            }
+            break;
+        }
+
         case kWhatUpdateFormat:
         {
             sp<AMessage> format;
@@ -772,6 +847,10 @@
     return seamless;
 }
 
+bool NuPlayer::Decoder::isVideo() {
+    return mNativeWindow != NULL;
+}
+
 struct CCData {
     CCData(uint8_t type, uint8_t data1, uint8_t data2)
         : mType(type), mData1(data1), mData2(data2) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
index dba3eee..c6ceb4e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h
@@ -30,11 +30,15 @@
 
 struct NuPlayer::Decoder : public AHandler {
     Decoder(const sp<AMessage> &notify,
+            const sp<Source> &source,
+            const sp<Renderer> &renderer = NULL,
             const sp<NativeWindowWrapper> &nativeWindow = NULL);
 
     virtual void configure(const sp<AMessage> &format);
     virtual void init();
 
+    virtual void setRenderer(const sp<Renderer> &renderer);
+
     status_t getInputBuffers(Vector<sp<ABuffer> > *dstBuffers) const;
     virtual void signalFlush(const sp<AMessage> &format = NULL);
     virtual void signalUpdateFormat(const sp<AMessage> &format);
@@ -45,8 +49,8 @@
 
     enum {
         kWhatFillThisBuffer      = 'flTB',
-        kWhatDrainThisBuffer     = 'drTB',
-        kWhatOutputFormatChanged = 'fmtC',
+        kWhatRenderBufferTime    = 'rnBT',
+        kWhatVideoSizeChanged    = 'viSC',
         kWhatFlushCompleted      = 'flsC',
         kWhatShutdownCompleted   = 'shDC',
         kWhatEOS                 = 'eos ',
@@ -59,10 +63,10 @@
 
     virtual void onMessageReceived(const sp<AMessage> &msg);
 
-private:
     enum {
         kWhatCodecNotify        = 'cdcN',
         kWhatConfigure          = 'conf',
+        kWhatSetRenderer        = 'setR',
         kWhatGetInputBuffers    = 'gInB',
         kWhatInputBufferFilled  = 'inpF',
         kWhatRenderBuffer       = 'rndr',
@@ -71,9 +75,13 @@
         kWhatUpdateFormat       = 'uFmt',
     };
 
+private:
     sp<AMessage> mNotify;
     sp<NativeWindowWrapper> mNativeWindow;
 
+    sp<Source> mSource;
+    sp<Renderer> mRenderer;
+
     sp<AMessage> mInputFormat;
     sp<AMessage> mOutputFormat;
     sp<MediaCodec> mCodec;
@@ -89,6 +97,8 @@
     Vector<bool> mInputBufferIsDequeued;
     Vector<MediaBuffer *> mMediaBuffers;
 
+    int64_t mSkipRenderingUntilMediaTimeUs;
+
     void handleError(int32_t err);
     bool handleAnInputBuffer();
     bool handleAnOutputBuffer();
@@ -110,6 +120,7 @@
 
     bool supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const;
     void rememberCodecSpecificData(const sp<AMessage> &format);
+    bool isVideo();
 
     DISALLOW_EVIL_CONSTRUCTORS(Decoder);
 };
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
index f7aacdd..d2721ed 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp
@@ -21,6 +21,9 @@
 
 #include "NuPlayerDecoderPassThrough.h"
 
+#include "NuPlayerRenderer.h"
+#include "NuPlayerSource.h"
+
 #include <media/ICrypto.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -36,15 +39,21 @@
 static const size_t kMaxPendingBuffers = 1 + (kMaxCachedBytes / NuPlayer::kAggregateBufferSizeBytes);
 
 NuPlayer::DecoderPassThrough::DecoderPassThrough(
-        const sp<AMessage> &notify)
-    : Decoder(notify),
+        const sp<AMessage> &notify,
+        const sp<Source> &source,
+        const sp<Renderer> &renderer)
+    : Decoder(notify, source),
       mNotify(notify),
+      mSource(source),
+      mRenderer(renderer),
+      mSkipRenderingUntilMediaTimeUs(-1ll),
       mBufferGeneration(0),
       mReachedEOS(true),
       mPendingBuffersToFill(0),
       mPendingBuffersToDrain(0),
       mCachedBytes(0),
       mComponentName("pass through decoder") {
+    ALOGW_IF(renderer == NULL, "expect a non-NULL renderer");
     mDecoderLooper = new ALooper;
     mDecoderLooper->setName("NuPlayerDecoderPassThrough");
     mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
@@ -90,10 +99,17 @@
 
     requestMaxBuffers();
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatOutputFormatChanged);
-    notify->setMessage("format", format);
-    notify->post();
+    uint32_t flags;
+    int64_t durationUs;
+    if (mSource->getDuration(&durationUs) == OK &&
+            durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) {
+        flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
+    } else {
+        flags = AUDIO_OUTPUT_FLAG_NONE;
+    }
+
+    mRenderer->openAudioSink(
+            format, true /* offloadOnly */, false /* hasVideo */, flags);
 }
 
 bool NuPlayer::DecoderPassThrough::isStaleReply(const sp<AMessage> &msg) {
@@ -138,25 +154,52 @@
     msg->findBuffer("buffer", &buffer);
     if (buffer == NULL) {
         mReachedEOS = true;
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatEOS);
-        notify->setInt32("err", ERROR_END_OF_STREAM);
-        notify->post();
+        if (mRenderer != NULL) {
+            mRenderer->queueEOS(true /* audio */, ERROR_END_OF_STREAM);
+        }
         return;
     }
 
-    mCachedBytes += buffer->size();
+    sp<AMessage> extra;
+    if (buffer->meta()->findMessage("extra", &extra) && extra != NULL) {
+        int64_t resumeAtMediaTimeUs;
+        if (extra->findInt64(
+                    "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
+            ALOGI("[%s] suppressing rendering until %lld us",
+                    mComponentName.c_str(), (long long)resumeAtMediaTimeUs);
+            mSkipRenderingUntilMediaTimeUs = resumeAtMediaTimeUs;
+        }
+    }
+
+    int32_t bufferSize = buffer->size();
+    mCachedBytes += bufferSize;
+
+    if (mSkipRenderingUntilMediaTimeUs >= 0) {
+        int64_t timeUs = 0;
+        CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
+
+        if (timeUs < mSkipRenderingUntilMediaTimeUs) {
+            ALOGV("[%s] dropping buffer at time %lld as requested.",
+                     mComponentName.c_str(), (long long)timeUs);
+
+            onBufferConsumed(bufferSize);
+            return;
+        }
+
+        mSkipRenderingUntilMediaTimeUs = -1;
+    }
+
+    if (mRenderer == NULL) {
+        onBufferConsumed(bufferSize);
+        return;
+    }
 
     sp<AMessage> reply = new AMessage(kWhatBufferConsumed, id());
     reply->setInt32("generation", mBufferGeneration);
-    reply->setInt32("size", buffer->size());
+    reply->setInt32("size", bufferSize);
 
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatDrainThisBuffer);
-    notify->setBuffer("buffer", buffer);
-    notify->setMessage("reply", reply);
-    notify->post();
+    mRenderer->queueBuffer(true /* audio */, buffer, reply);
+
     ++mPendingBuffersToDrain;
     ALOGV("onInputBufferFilled: #ToFill = %zu, #ToDrain = %zu, cachedBytes = %zu",
             mPendingBuffersToFill, mPendingBuffersToDrain, mCachedBytes);
@@ -172,6 +215,11 @@
 
 void NuPlayer::DecoderPassThrough::onFlush() {
     ++mBufferGeneration;
+    mSkipRenderingUntilMediaTimeUs = -1;
+
+    if (mRenderer != NULL) {
+        mRenderer->flush(true /* audio */);
+    }
 
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatFlushCompleted);
@@ -192,6 +240,7 @@
 
 void NuPlayer::DecoderPassThrough::onShutdown() {
     ++mBufferGeneration;
+    mSkipRenderingUntilMediaTimeUs = -1;
 
     sp<AMessage> notify = mNotify->dup();
     notify->setInt32("what", kWhatShutdownCompleted);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
index fb20257..7742d30 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.h
@@ -25,7 +25,9 @@
 namespace android {
 
 struct NuPlayer::DecoderPassThrough : public Decoder {
-    DecoderPassThrough(const sp<AMessage> &notify);
+    DecoderPassThrough(const sp<AMessage> &notify,
+                       const sp<Source> &source,
+                       const sp<Renderer> &renderer);
 
     virtual void configure(const sp<AMessage> &format);
     virtual void init();
@@ -45,16 +47,15 @@
 private:
     enum {
         kWhatRequestABuffer     = 'reqB',
-        kWhatConfigure          = 'conf',
-        kWhatInputBufferFilled  = 'inpF',
         kWhatBufferConsumed     = 'bufC',
-        kWhatFlush              = 'flus',
-        kWhatShutdown           = 'shuD',
     };
 
     sp<AMessage> mNotify;
     sp<ALooper> mDecoderLooper;
 
+    sp<Source> mSource;
+    sp<Renderer> mRenderer;
+
     /** Returns true if a buffer was requested.
      * Returns false if at EOS or cache already full.
      */
@@ -68,6 +69,8 @@
     void requestMaxBuffers();
     void onShutdown();
 
+    int64_t mSkipRenderingUntilMediaTimeUs;
+
     int32_t mBufferGeneration;
     bool    mReachedEOS;
     // TODO mPendingBuffersToFill and mPendingBuffersToDrain are only for
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index b9a1a6c..b42b480 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -628,6 +628,11 @@
                 if (mLooping || (mAutoLoop
                         && (mAudioSink == NULL || mAudioSink->realtime()))) {
                     mPlayer->seekToAsync(0);
+                    if (mAudioSink != NULL) {
+                        // The renderer has stopped the sink at the end in order to play out
+                        // the last little bit of audio. If we're looping, we need to restart it.
+                        mAudioSink->start();
+                    }
                     break;
                 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 5d9001c..73bc829 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -20,8 +20,6 @@
 
 #include "NuPlayerRenderer.h"
 
-#include <cutils/properties.h>
-
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -43,16 +41,6 @@
 // static
 const int64_t NuPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll;
 
-static bool sFrameAccurateAVsync = false;
-
-static void readProperties() {
-    char value[PROPERTY_VALUE_MAX];
-    if (property_get("persist.sys.media.avsync", value, NULL)) {
-        sFrameAccurateAVsync =
-            !strcmp("1", value) || !strcasecmp("true", value);
-    }
-}
-
 NuPlayer::Renderer::Renderer(
         const sp<MediaPlayerBase::AudioSink> &sink,
         const sp<AMessage> &notify,
@@ -87,7 +75,6 @@
       mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
       mTotalBuffersQueued(0),
       mLastAudioBufferDrained(0) {
-    readProperties();
 }
 
 NuPlayer::Renderer::~Renderer() {
@@ -629,6 +616,10 @@
 
             mAudioQueue.erase(mAudioQueue.begin());
             entry = NULL;
+            // Need to stop the track here, because that will play out the last
+            // little bit at the end of the file. Otherwise short files won't play.
+            mAudioSink->stop();
+            mNumFramesWritten = 0;
             return false;
         }
 
@@ -792,11 +783,6 @@
 
     ALOGW_IF(delayUs > 500000, "unusually high delayUs: %" PRId64, delayUs);
     // post 2 display refreshes before rendering is due
-    // FIXME currently this increases power consumption, so unless frame-accurate
-    // AV sync is requested, post closer to required render time (at 0.63 vsyncs)
-    if (!sFrameAccurateAVsync) {
-        twoVsyncsUs >>= 4;
-    }
     msg->post(delayUs > twoVsyncsUs ? delayUs - twoVsyncsUs : 0);
 
     mDrainVideoQueuePending = true;
@@ -1174,8 +1160,6 @@
 }
 
 void NuPlayer::Renderer::onResume() {
-    readProperties();
-
     if (!mPaused) {
         return;
     }
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index d7ddc89..11069e4 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1349,9 +1349,12 @@
             uint32_t replyID;
             CHECK(msg->senderAwaitsResponse(&replyID));
 
-            if (!(mFlags & kFlagIsComponentAllocated) && mState != INITIALIZED
+            if (!((mFlags & kFlagIsComponentAllocated) && targetState == UNINITIALIZED) // See 1
+                    && mState != INITIALIZED
                     && mState != CONFIGURED && !isExecuting()) {
-                // We may be in "UNINITIALIZED" state already and
+                // 1) Permit release to shut down the component if allocated.
+                //
+                // 2) We may be in "UNINITIALIZED" state already and
                 // also shutdown the encoder/decoder without the
                 // client being aware of this if media server died while
                 // we were being stopped. The client would assume that
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 0fecda8..c26e909 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -422,24 +422,16 @@
         }
     }
 
+    mEncoderActivityNotify = new AMessage(
+            kWhatEncoderActivity, mReflector->id());
+    mEncoder->setCallback(mEncoderActivityNotify);
+
     err = mEncoder->start();
 
     if (err != OK) {
         return err;
     }
 
-    err = mEncoder->getInputBuffers(&mEncoderInputBuffers);
-
-    if (err != OK) {
-        return err;
-    }
-
-    err = mEncoder->getOutputBuffers(&mEncoderOutputBuffers);
-
-    if (err != OK) {
-        return err;
-    }
-
     mEncoderReachedEOS = false;
     mErrorCode = OK;
 
@@ -461,14 +453,6 @@
             mbuf->release();
         }
     }
-
-    for (size_t i = 0; i < mEncoderInputBuffers.size(); ++i) {
-        sp<ABuffer> accessUnit = mEncoderInputBuffers.itemAt(i);
-        accessUnit->setMediaBufferBase(NULL);
-    }
-
-    mEncoderInputBuffers.clear();
-    mEncoderOutputBuffers.clear();
 }
 
 status_t MediaCodecSource::postSynchronouslyAndReturnError(
@@ -539,20 +523,6 @@
     }
 }
 
-void MediaCodecSource::scheduleDoMoreWork() {
-    if (mDoMoreWorkPending) {
-        return;
-    }
-
-    mDoMoreWorkPending = true;
-
-    if (mEncoderActivityNotify == NULL) {
-        mEncoderActivityNotify = new AMessage(
-                kWhatEncoderActivity, mReflector->id());
-    }
-    mEncoder->requestActivityNotification(mEncoderActivityNotify);
-}
-
 status_t MediaCodecSource::feedEncoderInputBuffers() {
     while (!mInputBufferQueue.empty()
             && !mAvailEncoderInputIndices.empty()) {
@@ -587,16 +557,22 @@
 #endif // DEBUG_DRIFT_TIME
             }
 
+            sp<ABuffer> inbuf;
+            status_t err = mEncoder->getInputBuffer(bufferIndex, &inbuf);
+            if (err != OK || inbuf == NULL) {
+                mbuf->release();
+                signalEOS();
+                break;
+            }
+
             size = mbuf->size();
 
-            memcpy(mEncoderInputBuffers.itemAt(bufferIndex)->data(),
-                   mbuf->data(), size);
+            memcpy(inbuf->data(), mbuf->data(), size);
 
             if (mIsVideo) {
                 // video encoder will release MediaBuffer when done
                 // with underlying data.
-                mEncoderInputBuffers.itemAt(bufferIndex)->setMediaBufferBase(
-                        mbuf);
+                inbuf->setMediaBufferBase(mbuf);
             } else {
                 mbuf->release();
             }
@@ -615,50 +591,120 @@
     return OK;
 }
 
-status_t MediaCodecSource::doMoreWork(int32_t numInput, int32_t numOutput) {
+status_t MediaCodecSource::onStart(MetaData *params) {
+    if (mStopping) {
+        ALOGE("Failed to start while we're stopping");
+        return INVALID_OPERATION;
+    }
+
+    if (mStarted) {
+        ALOGI("MediaCodecSource (%s) resuming", mIsVideo ? "video" : "audio");
+        if (mFlags & FLAG_USE_SURFACE_INPUT) {
+            resume();
+        } else {
+            CHECK(mPuller != NULL);
+            mPuller->resume();
+        }
+        return OK;
+    }
+
+    ALOGI("MediaCodecSource (%s) starting", mIsVideo ? "video" : "audio");
+
     status_t err = OK;
 
-    if (!(mFlags & FLAG_USE_SURFACE_INPUT)) {
-        while (numInput-- > 0) {
-            size_t bufferIndex;
-            err = mEncoder->dequeueInputBuffer(&bufferIndex);
+    if (mFlags & FLAG_USE_SURFACE_INPUT) {
+        int64_t startTimeUs;
+        if (!params || !params->findInt64(kKeyTime, &startTimeUs)) {
+            startTimeUs = -1ll;
+        }
+        resume(startTimeUs);
+    } else {
+        CHECK(mPuller != NULL);
+        sp<AMessage> notify = new AMessage(
+                kWhatPullerNotify, mReflector->id());
+        err = mPuller->start(params, notify);
+        if (err != OK) {
+            return err;
+        }
+    }
 
-            if (err != OK) {
+    ALOGI("MediaCodecSource (%s) started", mIsVideo ? "video" : "audio");
+
+    mStarted = true;
+    return OK;
+}
+
+void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
+    switch (msg->what()) {
+    case kWhatPullerNotify:
+    {
+        MediaBuffer *mbuf;
+        CHECK(msg->findPointer("accessUnit", (void**)&mbuf));
+
+        if (mbuf == NULL) {
+            ALOGV("puller (%s) reached EOS",
+                    mIsVideo ? "video" : "audio");
+            signalEOS();
+        }
+
+        if (mEncoder == NULL) {
+            ALOGV("got msg '%s' after encoder shutdown.",
+                  msg->debugString().c_str());
+
+            if (mbuf != NULL) {
+                mbuf->release();
+            }
+
+            break;
+        }
+
+        mInputBufferQueue.push_back(mbuf);
+
+        feedEncoderInputBuffers();
+
+        break;
+    }
+    case kWhatEncoderActivity:
+    {
+        if (mEncoder == NULL) {
+            break;
+        }
+
+        int32_t cbID;
+        CHECK(msg->findInt32("callbackID", &cbID));
+        if (cbID == MediaCodec::CB_INPUT_AVAILABLE) {
+            int32_t index;
+            CHECK(msg->findInt32("index", &index));
+
+            mAvailEncoderInputIndices.push_back(index);
+            feedEncoderInputBuffers();
+        } else if (cbID == MediaCodec::CB_OUTPUT_AVAILABLE) {
+            int32_t index;
+            size_t offset;
+            size_t size;
+            int64_t timeUs;
+            int32_t flags;
+            native_handle_t* handle = NULL;
+
+            CHECK(msg->findInt32("index", &index));
+            CHECK(msg->findSize("offset", &offset));
+            CHECK(msg->findSize("size", &size));
+            CHECK(msg->findInt64("timeUs", &timeUs));
+            CHECK(msg->findInt32("flags", &flags));
+
+            if (flags & MediaCodec::BUFFER_FLAG_EOS) {
+                mEncoder->releaseOutputBuffer(index);
+                signalEOS();
                 break;
             }
 
-            mAvailEncoderInputIndices.push_back(bufferIndex);
-        }
-
-        feedEncoderInputBuffers();
-    }
-
-    while (numOutput-- > 0) {
-        size_t bufferIndex;
-        size_t offset;
-        size_t size;
-        int64_t timeUs;
-        uint32_t flags;
-        native_handle_t* handle = NULL;
-        err = mEncoder->dequeueOutputBuffer(
-                &bufferIndex, &offset, &size, &timeUs, &flags);
-
-        if (err != OK) {
-            if (err == INFO_FORMAT_CHANGED) {
-                continue;
-            } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
-                mEncoder->getOutputBuffers(&mEncoderOutputBuffers);
-                continue;
+            sp<ABuffer> outbuf;
+            status_t err = mEncoder->getOutputBuffer(index, &outbuf);
+            if (err != OK || outbuf == NULL) {
+                signalEOS();
+                break;
             }
 
-            if (err == -EAGAIN) {
-                err = OK;
-            }
-            break;
-        }
-        if (!(flags & MediaCodec::BUFFER_FLAG_EOS)) {
-            sp<ABuffer> outbuf = mEncoderOutputBuffers.itemAt(bufferIndex);
-
             MediaBuffer *mbuf = new MediaBuffer(outbuf->size());
             memcpy(mbuf->data(), outbuf->data(), outbuf->size());
 
@@ -709,121 +755,16 @@
                 mOutputBufferQueue.push_back(mbuf);
                 mOutputBufferCond.signal();
             }
-        }
 
-        mEncoder->releaseOutputBuffer(bufferIndex);
-
-        if (flags & MediaCodec::BUFFER_FLAG_EOS) {
-            err = ERROR_END_OF_STREAM;
-            break;
-        }
-    }
-
-    return err;
-}
-
-status_t MediaCodecSource::onStart(MetaData *params) {
-    if (mStopping) {
-        ALOGE("Failed to start while we're stopping");
-        return INVALID_OPERATION;
-    }
-
-    if (mStarted) {
-        ALOGI("MediaCodecSource (%s) resuming", mIsVideo ? "video" : "audio");
-        if (mFlags & FLAG_USE_SURFACE_INPUT) {
-            resume();
-        } else {
-            CHECK(mPuller != NULL);
-            mPuller->resume();
-        }
-        return OK;
-    }
-
-    ALOGI("MediaCodecSource (%s) starting", mIsVideo ? "video" : "audio");
-
-    status_t err = OK;
-
-    if (mFlags & FLAG_USE_SURFACE_INPUT) {
-        int64_t startTimeUs;
-        if (!params || !params->findInt64(kKeyTime, &startTimeUs)) {
-            startTimeUs = -1ll;
-        }
-        resume(startTimeUs);
-        scheduleDoMoreWork();
-    } else {
-        CHECK(mPuller != NULL);
-        sp<AMessage> notify = new AMessage(
-                kWhatPullerNotify, mReflector->id());
-        err = mPuller->start(params, notify);
-        if (err != OK) {
-            return err;
-        }
-    }
-
-    ALOGI("MediaCodecSource (%s) started", mIsVideo ? "video" : "audio");
-
-    mStarted = true;
-    return OK;
-}
-
-void MediaCodecSource::onMessageReceived(const sp<AMessage> &msg) {
-    switch (msg->what()) {
-    case kWhatPullerNotify:
-    {
-        MediaBuffer *mbuf;
-        CHECK(msg->findPointer("accessUnit", (void**)&mbuf));
-
-        if (mbuf == NULL) {
-            ALOGV("puller (%s) reached EOS",
-                    mIsVideo ? "video" : "audio");
+            mEncoder->releaseOutputBuffer(index);
+       } else if (cbID == MediaCodec::CB_ERROR) {
+            status_t err;
+            CHECK(msg->findInt32("err", &err));
+            ALOGE("Encoder (%s) reported error : 0x%x",
+                    mIsVideo ? "video" : "audio", err);
             signalEOS();
-        }
-
-        if (mEncoder == NULL) {
-            ALOGV("got msg '%s' after encoder shutdown.",
-                  msg->debugString().c_str());
-
-            if (mbuf != NULL) {
-                mbuf->release();
-            }
-
-            break;
-        }
-
-        mInputBufferQueue.push_back(mbuf);
-
-        feedEncoderInputBuffers();
-        scheduleDoMoreWork();
-
-        break;
-    }
-    case kWhatEncoderActivity:
-    {
-        mDoMoreWorkPending = false;
-
-        if (mEncoder == NULL) {
-            break;
-        }
-
-        int32_t numInput, numOutput;
-
-        if (!msg->findInt32("input-buffers", &numInput)) {
-            numInput = INT32_MAX;
-        }
-        if (!msg->findInt32("output-buffers", &numOutput)) {
-            numOutput = INT32_MAX;
-        }
-
-        status_t err = doMoreWork(numInput, numOutput);
-
-        if (err == OK) {
-            scheduleDoMoreWork();
-        } else {
-            // reached EOS, or error
-            signalEOS(err);
-        }
-
-        break;
+       }
+       break;
     }
     case kWhatStart:
     {
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 288e07a..f26563e 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -47,10 +47,11 @@
 #include <media/stagefright/SkipCutBuffer.h>
 #include <utils/Vector.h>
 
-#include <OMX_Audio.h>
 #include <OMX_AudioExt.h>
 #include <OMX_Component.h>
 #include <OMX_IndexExt.h>
+#include <OMX_VideoExt.h>
+#include <OMX_AsString.h>
 
 #include "include/avc_utils.h"
 
@@ -4078,220 +4079,6 @@
     CHECK(!"should not be here.");
 }
 
-static const char *imageCompressionFormatString(OMX_IMAGE_CODINGTYPE type) {
-    static const char *kNames[] = {
-        "OMX_IMAGE_CodingUnused",
-        "OMX_IMAGE_CodingAutoDetect",
-        "OMX_IMAGE_CodingJPEG",
-        "OMX_IMAGE_CodingJPEG2K",
-        "OMX_IMAGE_CodingEXIF",
-        "OMX_IMAGE_CodingTIFF",
-        "OMX_IMAGE_CodingGIF",
-        "OMX_IMAGE_CodingPNG",
-        "OMX_IMAGE_CodingLZW",
-        "OMX_IMAGE_CodingBMP",
-    };
-
-    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
-
-    if (type < 0 || (size_t)type >= numNames) {
-        return "UNKNOWN";
-    } else {
-        return kNames[type];
-    }
-}
-
-static const char *colorFormatString(OMX_COLOR_FORMATTYPE type) {
-    static const char *kNames[] = {
-        "OMX_COLOR_FormatUnused",
-        "OMX_COLOR_FormatMonochrome",
-        "OMX_COLOR_Format8bitRGB332",
-        "OMX_COLOR_Format12bitRGB444",
-        "OMX_COLOR_Format16bitARGB4444",
-        "OMX_COLOR_Format16bitARGB1555",
-        "OMX_COLOR_Format16bitRGB565",
-        "OMX_COLOR_Format16bitBGR565",
-        "OMX_COLOR_Format18bitRGB666",
-        "OMX_COLOR_Format18bitARGB1665",
-        "OMX_COLOR_Format19bitARGB1666",
-        "OMX_COLOR_Format24bitRGB888",
-        "OMX_COLOR_Format24bitBGR888",
-        "OMX_COLOR_Format24bitARGB1887",
-        "OMX_COLOR_Format25bitARGB1888",
-        "OMX_COLOR_Format32bitBGRA8888",
-        "OMX_COLOR_Format32bitARGB8888",
-        "OMX_COLOR_FormatYUV411Planar",
-        "OMX_COLOR_FormatYUV411PackedPlanar",
-        "OMX_COLOR_FormatYUV420Planar",
-        "OMX_COLOR_FormatYUV420PackedPlanar",
-        "OMX_COLOR_FormatYUV420SemiPlanar",
-        "OMX_COLOR_FormatYUV422Planar",
-        "OMX_COLOR_FormatYUV422PackedPlanar",
-        "OMX_COLOR_FormatYUV422SemiPlanar",
-        "OMX_COLOR_FormatYCbYCr",
-        "OMX_COLOR_FormatYCrYCb",
-        "OMX_COLOR_FormatCbYCrY",
-        "OMX_COLOR_FormatCrYCbY",
-        "OMX_COLOR_FormatYUV444Interleaved",
-        "OMX_COLOR_FormatRawBayer8bit",
-        "OMX_COLOR_FormatRawBayer10bit",
-        "OMX_COLOR_FormatRawBayer8bitcompressed",
-        "OMX_COLOR_FormatL2",
-        "OMX_COLOR_FormatL4",
-        "OMX_COLOR_FormatL8",
-        "OMX_COLOR_FormatL16",
-        "OMX_COLOR_FormatL24",
-        "OMX_COLOR_FormatL32",
-        "OMX_COLOR_FormatYUV420PackedSemiPlanar",
-        "OMX_COLOR_FormatYUV422PackedSemiPlanar",
-        "OMX_COLOR_Format18BitBGR666",
-        "OMX_COLOR_Format24BitARGB6666",
-        "OMX_COLOR_Format24BitABGR6666",
-    };
-
-    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
-
-    if (type == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar) {
-        return "OMX_TI_COLOR_FormatYUV420PackedSemiPlanar";
-    } else if (type == OMX_QCOM_COLOR_FormatYVU420SemiPlanar) {
-        return "OMX_QCOM_COLOR_FormatYVU420SemiPlanar";
-    } else if (type < 0 || (size_t)type >= numNames) {
-        return "UNKNOWN";
-    } else {
-        return kNames[type];
-    }
-}
-
-static const char *videoCompressionFormatString(OMX_VIDEO_CODINGTYPE type) {
-    static const char *kNames[] = {
-        "OMX_VIDEO_CodingUnused",
-        "OMX_VIDEO_CodingAutoDetect",
-        "OMX_VIDEO_CodingMPEG2",
-        "OMX_VIDEO_CodingH263",
-        "OMX_VIDEO_CodingMPEG4",
-        "OMX_VIDEO_CodingWMV",
-        "OMX_VIDEO_CodingRV",
-        "OMX_VIDEO_CodingAVC",
-        "OMX_VIDEO_CodingMJPEG",
-    };
-
-    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
-
-    if (type < 0 || (size_t)type >= numNames) {
-        return "UNKNOWN";
-    } else {
-        return kNames[type];
-    }
-}
-
-static const char *audioCodingTypeString(OMX_AUDIO_CODINGTYPE type) {
-    static const char *kNames[] = {
-        "OMX_AUDIO_CodingUnused",
-        "OMX_AUDIO_CodingAutoDetect",
-        "OMX_AUDIO_CodingPCM",
-        "OMX_AUDIO_CodingADPCM",
-        "OMX_AUDIO_CodingAMR",
-        "OMX_AUDIO_CodingGSMFR",
-        "OMX_AUDIO_CodingGSMEFR",
-        "OMX_AUDIO_CodingGSMHR",
-        "OMX_AUDIO_CodingPDCFR",
-        "OMX_AUDIO_CodingPDCEFR",
-        "OMX_AUDIO_CodingPDCHR",
-        "OMX_AUDIO_CodingTDMAFR",
-        "OMX_AUDIO_CodingTDMAEFR",
-        "OMX_AUDIO_CodingQCELP8",
-        "OMX_AUDIO_CodingQCELP13",
-        "OMX_AUDIO_CodingEVRC",
-        "OMX_AUDIO_CodingSMV",
-        "OMX_AUDIO_CodingG711",
-        "OMX_AUDIO_CodingG723",
-        "OMX_AUDIO_CodingG726",
-        "OMX_AUDIO_CodingG729",
-        "OMX_AUDIO_CodingAAC",
-        "OMX_AUDIO_CodingMP3",
-        "OMX_AUDIO_CodingSBC",
-        "OMX_AUDIO_CodingVORBIS",
-        "OMX_AUDIO_CodingOPUS",
-        "OMX_AUDIO_CodingWMA",
-        "OMX_AUDIO_CodingRA",
-        "OMX_AUDIO_CodingMIDI",
-    };
-
-    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
-
-    if (type < 0 || (size_t)type >= numNames) {
-        return "UNKNOWN";
-    } else {
-        return kNames[type];
-    }
-}
-
-static const char *audioPCMModeString(OMX_AUDIO_PCMMODETYPE type) {
-    static const char *kNames[] = {
-        "OMX_AUDIO_PCMModeLinear",
-        "OMX_AUDIO_PCMModeALaw",
-        "OMX_AUDIO_PCMModeMULaw",
-    };
-
-    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
-
-    if (type < 0 || (size_t)type >= numNames) {
-        return "UNKNOWN";
-    } else {
-        return kNames[type];
-    }
-}
-
-static const char *amrBandModeString(OMX_AUDIO_AMRBANDMODETYPE type) {
-    static const char *kNames[] = {
-        "OMX_AUDIO_AMRBandModeUnused",
-        "OMX_AUDIO_AMRBandModeNB0",
-        "OMX_AUDIO_AMRBandModeNB1",
-        "OMX_AUDIO_AMRBandModeNB2",
-        "OMX_AUDIO_AMRBandModeNB3",
-        "OMX_AUDIO_AMRBandModeNB4",
-        "OMX_AUDIO_AMRBandModeNB5",
-        "OMX_AUDIO_AMRBandModeNB6",
-        "OMX_AUDIO_AMRBandModeNB7",
-        "OMX_AUDIO_AMRBandModeWB0",
-        "OMX_AUDIO_AMRBandModeWB1",
-        "OMX_AUDIO_AMRBandModeWB2",
-        "OMX_AUDIO_AMRBandModeWB3",
-        "OMX_AUDIO_AMRBandModeWB4",
-        "OMX_AUDIO_AMRBandModeWB5",
-        "OMX_AUDIO_AMRBandModeWB6",
-        "OMX_AUDIO_AMRBandModeWB7",
-        "OMX_AUDIO_AMRBandModeWB8",
-    };
-
-    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
-
-    if (type < 0 || (size_t)type >= numNames) {
-        return "UNKNOWN";
-    } else {
-        return kNames[type];
-    }
-}
-
-static const char *amrFrameFormatString(OMX_AUDIO_AMRFRAMEFORMATTYPE type) {
-    static const char *kNames[] = {
-        "OMX_AUDIO_AMRFrameFormatConformance",
-        "OMX_AUDIO_AMRFrameFormatIF1",
-        "OMX_AUDIO_AMRFrameFormatIF2",
-        "OMX_AUDIO_AMRFrameFormatFSF",
-        "OMX_AUDIO_AMRFrameFormatRTPPayload",
-        "OMX_AUDIO_AMRFrameFormatITU",
-    };
-
-    size_t numNames = sizeof(kNames) / sizeof(kNames[0]);
-
-    if (type < 0 || (size_t)type >= numNames) {
-        return "UNKNOWN";
-    } else {
-        return kNames[type];
-    }
-}
-
 void OMXCodec::dumpPortStatus(OMX_U32 portIndex) {
     OMX_PARAM_PORTDEFINITIONTYPE def;
     InitOMXParams(&def);
@@ -4322,10 +4109,10 @@
             printf("  nStride = %" PRIu32 "\n", imageDef->nStride);
 
             printf("  eCompressionFormat = %s\n",
-                   imageCompressionFormatString(imageDef->eCompressionFormat));
+                   asString(imageDef->eCompressionFormat));
 
             printf("  eColorFormat = %s\n",
-                   colorFormatString(imageDef->eColorFormat));
+                   asString(imageDef->eColorFormat));
 
             break;
         }
@@ -4341,10 +4128,10 @@
             printf("  nStride = %" PRIu32 "\n", videoDef->nStride);
 
             printf("  eCompressionFormat = %s\n",
-                   videoCompressionFormatString(videoDef->eCompressionFormat));
+                   asString(videoDef->eCompressionFormat));
 
             printf("  eColorFormat = %s\n",
-                   colorFormatString(videoDef->eColorFormat));
+                   asString(videoDef->eColorFormat));
 
             break;
         }
@@ -4356,7 +4143,7 @@
             printf("\n");
             printf("  // Audio\n");
             printf("  eEncoding = %s\n",
-                   audioCodingTypeString(audioDef->eEncoding));
+                   asString(audioDef->eEncoding));
 
             if (audioDef->eEncoding == OMX_AUDIO_CodingPCM) {
                 OMX_AUDIO_PARAM_PCMMODETYPE params;
@@ -4376,7 +4163,7 @@
                        params.eNumData == OMX_NumericalDataSigned
                         ? "signed" : "unsigned");
 
-                printf("  ePCMMode = %s\n", audioPCMModeString(params.ePCMMode));
+                printf("  ePCMMode = %s\n", asString(params.ePCMMode));
             } else if (audioDef->eEncoding == OMX_AUDIO_CodingAMR) {
                 OMX_AUDIO_PARAM_AMRTYPE amr;
                 InitOMXParams(&amr);
@@ -4388,9 +4175,9 @@
 
                 printf("  nChannels = %" PRIu32 "\n", amr.nChannels);
                 printf("  eAMRBandMode = %s\n",
-                        amrBandModeString(amr.eAMRBandMode));
+                        asString(amr.eAMRBandMode));
                 printf("  eAMRFrameFormat = %s\n",
-                        amrFrameFormatString(amr.eAMRFrameFormat));
+                        asString(amr.eAMRFrameFormat));
             }
 
             break;
@@ -4699,12 +4486,7 @@
         const char *componentName, const char *mime,
         bool isEncoder,
         CodecCapabilities *caps) {
-    if (strncmp(componentName, "OMX.", 4)) {
-        // Not an OpenMax component but a software codec.
-        caps->mFlags = 0;
-        caps->mComponentName = componentName;
-        return OK;
-    }
+    bool isVideo = !strncasecmp(mime, "video/", 6);
 
     sp<OMXCodecObserver> observer = new OMXCodecObserver;
     IOMX::node_id node;
@@ -4719,59 +4501,62 @@
     caps->mFlags = 0;
     caps->mComponentName = componentName;
 
-    OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
-    InitOMXParams(&param);
+    // NOTE: OMX does not provide a way to query AAC profile support
+    if (isVideo) {
+        OMX_VIDEO_PARAM_PROFILELEVELTYPE param;
+        InitOMXParams(&param);
 
-    param.nPortIndex = !isEncoder ? 0 : 1;
+        param.nPortIndex = !isEncoder ? 0 : 1;
 
-    for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
-        err = omx->getParameter(
-                node, OMX_IndexParamVideoProfileLevelQuerySupported,
-                &param, sizeof(param));
+        for (param.nProfileIndex = 0;; ++param.nProfileIndex) {
+            err = omx->getParameter(
+                    node, OMX_IndexParamVideoProfileLevelQuerySupported,
+                    &param, sizeof(param));
 
-        if (err != OK) {
-            break;
+            if (err != OK) {
+                break;
+            }
+
+            CodecProfileLevel profileLevel;
+            profileLevel.mProfile = param.eProfile;
+            profileLevel.mLevel = param.eLevel;
+
+            caps->mProfileLevels.push(profileLevel);
         }
 
-        CodecProfileLevel profileLevel;
-        profileLevel.mProfile = param.eProfile;
-        profileLevel.mLevel = param.eLevel;
+        // Color format query
+        // return colors in the order reported by the OMX component
+        // prefix "flexible" standard ones with the flexible equivalent
+        OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
+        InitOMXParams(&portFormat);
+        portFormat.nPortIndex = !isEncoder ? 1 : 0;
+        for (portFormat.nIndex = 0;; ++portFormat.nIndex)  {
+            err = omx->getParameter(
+                    node, OMX_IndexParamVideoPortFormat,
+                    &portFormat, sizeof(portFormat));
+            if (err != OK) {
+                break;
+            }
 
-        caps->mProfileLevels.push(profileLevel);
-    }
-
-    // Color format query
-    // return colors in the order reported by the OMX component
-    // prefix "flexible" standard ones with the flexible equivalent
-    OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
-    InitOMXParams(&portFormat);
-    portFormat.nPortIndex = !isEncoder ? 1 : 0;
-    for (portFormat.nIndex = 0;; ++portFormat.nIndex)  {
-        err = omx->getParameter(
-                node, OMX_IndexParamVideoPortFormat,
-                &portFormat, sizeof(portFormat));
-        if (err != OK) {
-            break;
-        }
-
-        OMX_U32 flexibleEquivalent;
-        if (ACodec::isFlexibleColorFormat(
-                    omx, node, portFormat.eColorFormat, &flexibleEquivalent)) {
-            bool marked = false;
-            for (size_t i = 0; i < caps->mColorFormats.size(); i++) {
-                if (caps->mColorFormats.itemAt(i) == flexibleEquivalent) {
-                    marked = true;
-                    break;
+            OMX_U32 flexibleEquivalent;
+            if (ACodec::isFlexibleColorFormat(
+                        omx, node, portFormat.eColorFormat, &flexibleEquivalent)) {
+                bool marked = false;
+                for (size_t i = 0; i < caps->mColorFormats.size(); i++) {
+                    if (caps->mColorFormats.itemAt(i) == flexibleEquivalent) {
+                        marked = true;
+                        break;
+                    }
+                }
+                if (!marked) {
+                    caps->mColorFormats.push(flexibleEquivalent);
                 }
             }
-            if (!marked) {
-                caps->mColorFormats.push(flexibleEquivalent);
-            }
+            caps->mColorFormats.push(portFormat.eColorFormat);
         }
-        caps->mColorFormats.push(portFormat.eColorFormat);
     }
 
-    if (!isEncoder && !strncmp(mime, "video/", 6)) {
+    if (isVideo && !isEncoder) {
         if (omx->storeMetaDataInBuffers(
                     node, 1 /* port index */, OMX_TRUE) == OK ||
             omx->prepareForAdaptivePlayback(
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 821bd81..6219053 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -38,6 +38,7 @@
     int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb);
     int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb);
     int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb);
+    long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op);
 }
 
 namespace android {
@@ -84,6 +85,8 @@
 private:
     struct Page {
         uint64_t mGranulePosition;
+        int32_t mPrevPacketSize;
+        uint64_t mPrevPacketPos;
         uint32_t mSerialNo;
         uint32_t mPageNo;
         uint8_t mFlags;
@@ -121,6 +124,8 @@
     status_t verifyHeader(
             MediaBuffer *buffer, uint8_t type);
 
+    int32_t packetBlockSize(MediaBuffer *buffer);
+
     void parseFileMetaData();
 
     status_t findPrevGranulePosition(off64_t pageOffset, uint64_t *granulePos);
@@ -373,6 +378,7 @@
     mFirstPacketInPage = true;
     mCurrentPageSamples = 0;
     mCurrentPage.mNumSegments = 0;
+    mCurrentPage.mPrevPacketSize = -1;
     mNextLaceIndex = 0;
 
     // XXX what if new page continues packet from last???
@@ -489,16 +495,6 @@
                 tmp->set_range(0, buffer->range_length());
                 buffer->release();
             } else {
-                // XXX Not only is this not technically the correct time for
-                // this packet, we also stamp every packet in this page
-                // with the same time. This needs fixing later.
-
-                if (mVi.rate) {
-                    // Rate may not have been initialized yet if we're currently
-                    // reading the configuration packets...
-                    // Fortunately, the timestamp doesn't matter for those.
-                    timeUs = mCurrentPage.mGranulePosition * 1000000ll / mVi.rate;
-                }
                 tmp->set_range(0, 0);
             }
             buffer = tmp;
@@ -521,16 +517,34 @@
             if (gotFullPacket) {
                 // We've just read the entire packet.
 
-                if (timeUs >= 0) {
-                    buffer->meta_data()->setInt64(kKeyTime, timeUs);
-                }
-
                 if (mFirstPacketInPage) {
                     buffer->meta_data()->setInt32(
                             kKeyValidSamples, mCurrentPageSamples);
                     mFirstPacketInPage = false;
                 }
 
+                if (mVi.rate) {
+                    // Rate may not have been initialized yet if we're currently
+                    // reading the configuration packets...
+                    // Fortunately, the timestamp doesn't matter for those.
+                    int32_t curBlockSize = packetBlockSize(buffer);
+                    if (mCurrentPage.mPrevPacketSize < 0) {
+                        mCurrentPage.mPrevPacketSize = curBlockSize;
+                        mCurrentPage.mPrevPacketPos =
+                                mCurrentPage.mGranulePosition - mCurrentPageSamples;
+                        timeUs = mCurrentPage.mPrevPacketPos * 1000000ll / mVi.rate;
+                    } else {
+                        // The effective block size is the average of the two overlapped blocks
+                        int32_t actualBlockSize =
+                                (curBlockSize + mCurrentPage.mPrevPacketSize) / 2;
+                        timeUs = mCurrentPage.mPrevPacketPos * 1000000ll / mVi.rate;
+                        // The actual size output by the decoder will be half the effective
+                        // size, due to the overlap
+                        mCurrentPage.mPrevPacketPos += actualBlockSize / 2;
+                        mCurrentPage.mPrevPacketSize = curBlockSize;
+                    }
+                    buffer->meta_data()->setInt64(kKeyTime, timeUs);
+                }
                 *out = buffer;
 
                 return OK;
@@ -686,6 +700,35 @@
     }
 }
 
+int32_t MyVorbisExtractor::packetBlockSize(MediaBuffer *buffer) {
+    const uint8_t *data =
+        (const uint8_t *)buffer->data() + buffer->range_offset();
+
+    size_t size = buffer->range_length();
+
+    ogg_buffer buf;
+    buf.data = (uint8_t *)data;
+    buf.size = size;
+    buf.refcount = 1;
+    buf.ptr.owner = NULL;
+
+    ogg_reference ref;
+    ref.buffer = &buf;
+    ref.begin = 0;
+    ref.length = size;
+    ref.next = NULL;
+
+    ogg_packet pack;
+    pack.packet = &ref;
+    pack.bytes = ref.length;
+    pack.b_o_s = 0;
+    pack.e_o_s = 0;
+    pack.granulepos = 0;
+    pack.packetno = 0;
+
+    return vorbis_packet_blocksize(&mVi, &pack);
+}
+
 status_t MyVorbisExtractor::verifyHeader(
         MediaBuffer *buffer, uint8_t type) {
     const uint8_t *data =
@@ -730,6 +773,10 @@
             ALOGV("upper-bitrate = %ld", mVi.bitrate_upper);
             ALOGV("nominal-bitrate = %ld", mVi.bitrate_nominal);
             ALOGV("window-bitrate = %ld", mVi.bitrate_window);
+            ALOGV("blocksizes: %d/%d",
+                    vorbis_info_blocksize(&mVi, 0),
+                    vorbis_info_blocksize(&mVi, 1)
+                    );
 
             off64_t size;
             if (mSource->getSize(&size) == OK) {
diff --git a/media/libstagefright/foundation/ADebug.cpp b/media/libstagefright/foundation/ADebug.cpp
new file mode 100644
index 0000000..ec4a960
--- /dev/null
+++ b/media/libstagefright/foundation/ADebug.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright 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 <errno.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#define LOG_TAG "ADebug"
+#include <utils/Log.h>
+#include <utils/misc.h>
+
+#include <cutils/properties.h>
+
+#include <ADebug.h>
+#include <AStringUtils.h>
+#include <AUtils.h>
+
+namespace android {
+
+//static
+ADebug::Level ADebug::GetDebugLevelFromString(
+        const char *name, const char *value, ADebug::Level def) {
+    // split on ,
+    const char *next = value, *current;
+    const unsigned long maxLevel = (unsigned long)kDebugMax;
+    while (next != NULL) {
+        current = next;
+        next = strchr(current, ',');
+        if (next != NULL) {
+            ++next;  // pass ,
+        }
+
+        while (isspace(*current)) {
+            ++current;
+        }
+        // check for :
+        char *colon = strchr(current, ':');
+
+        // get level
+        char *end;
+        errno = 0;  // strtoul does not clear errno, but it can be set for any return value
+        unsigned long level = strtoul(current, &end, 10);
+        while (isspace(*end)) {
+            ++end;
+        }
+        if (errno != 0 || end == current || (end != colon && *end != '\0' && end != next)) {
+            // invalid level - skip
+            continue;
+        }
+        if (colon != NULL) {
+            // check if pattern matches
+            do {  // skip colon and spaces
+                ++colon;
+            } while (isspace(*colon));
+            size_t globLen = (next == NULL ? strlen(colon) : (next - 1 - colon));
+            while (globLen > 0 && isspace(colon[globLen - 1])) {
+                --globLen;  // trim glob
+            }
+
+            if (!AStringUtils::MatchesGlob(
+                    colon, globLen, name, strlen(name), true /* ignoreCase */)) {
+                continue;
+            }
+        }
+
+        // update debug level
+        def = (Level)min(level, maxLevel);
+    }
+    return def;
+}
+
+//static
+ADebug::Level ADebug::GetDebugLevelFromProperty(
+        const char *name, const char *propertyName, ADebug::Level def) {
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get(propertyName, value, NULL)) {
+        return GetDebugLevelFromString(name, value, def);
+    }
+    return def;
+}
+
+//static
+char *ADebug::GetDebugName(const char *name) {
+    char *debugName = strdup(name);
+    const char *terms[] = { "omx", "video", "audio" };
+    for (size_t i = 0; i < NELEM(terms) && debugName != NULL; i++) {
+        const char *term = terms[i];
+        const size_t len = strlen(term);
+        char *match = strcasestr(debugName, term);
+        if (match != NULL && (match == debugName || match[-1] == '.'
+                || match[len] == '.' || match[len] == '\0')) {
+            char *src = match + len;
+            if (match == debugName || match[-1] == '.') {
+                src += (*src == '.');  // remove trailing or double .
+            }
+            memmove(match, src, debugName + strlen(debugName) - src + 1);
+        }
+    }
+
+    return debugName;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/foundation/AStringUtils.cpp b/media/libstagefright/foundation/AStringUtils.cpp
new file mode 100644
index 0000000..e5a846c
--- /dev/null
+++ b/media/libstagefright/foundation/AStringUtils.cpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright 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 <string.h>
+#include <AStringUtils.h>
+
+namespace android {
+
+// static
+int AStringUtils::Compare(const char *a, const char *b, size_t len, bool ignoreCase) {
+    // this method relies on a trailing '\0' if a or b are shorter than len
+    return ignoreCase ? strncasecmp(a, b, len) : strncmp(a, b, len);
+}
+
+// static
+bool AStringUtils::MatchesGlob(
+        const char *glob, size_t globLen, const char *str, size_t strLen, bool ignoreCase) {
+    // this method does not assume a trailing '\0'
+    size_t ix = 0, globIx = 0;
+
+    // pattern must match until first '*'
+    while (globIx < globLen && glob[globIx] != '*') {
+        ++globIx;
+    }
+    if (strLen < globIx || Compare(str, glob, globIx /* len */, ignoreCase)) {
+        return false;
+    }
+    ix = globIx;
+
+    // process by * separated sections
+    while (globIx < globLen) {
+        ++globIx;
+        size_t start = globIx;
+        while (globIx < globLen && glob[globIx] != '*') {
+            ++globIx;
+        }
+        size_t len = globIx - start;
+        const char *pattern = glob + start;
+
+        if (globIx == globLen) {
+            // last pattern must match tail
+            if (ix + len > strLen) {
+                return false;
+            }
+            const char *tail = str + strLen - len;
+            return !Compare(tail, pattern, len, ignoreCase);
+        }
+        // progress after first occurrence of pattern
+        while (ix + len <= strLen && Compare(str + ix, pattern, len, ignoreCase)) {
+            ++ix;
+        }
+        if (ix + len > strLen) {
+            return false;
+        }
+        ix += len;
+        // we will loop around as globIx < globLen
+    }
+
+    // we only get here if there were no * in the pattern
+    return ix == strLen;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index 90a6a23..c1dd6ce 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -5,6 +5,7 @@
     AAtomizer.cpp                 \
     ABitReader.cpp                \
     ABuffer.cpp                   \
+    ADebug.cpp                    \
     AHandler.cpp                  \
     AHierarchicalStateMachine.cpp \
     ALooper.cpp                   \
@@ -12,6 +13,7 @@
     AMessage.cpp                  \
     ANetworkSession.cpp           \
     AString.cpp                   \
+    AStringUtils.cpp              \
     ParsedMessage.cpp             \
     base64.cpp                    \
     hexdump.cpp
@@ -22,6 +24,7 @@
 LOCAL_SHARED_LIBRARIES := \
         libbinder         \
         libutils          \
+        libcutils         \
         liblog
 
 LOCAL_CFLAGS += -Wno-multichar -Werror
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 874c118..5eb4652 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -1164,6 +1164,14 @@
     return err;
 }
 
+ssize_t LiveSession::getSelectedTrack(media_track_type type) const {
+    if (mPlaylist == NULL) {
+        return -1;
+    } else {
+        return mPlaylist->getSelectedTrack(type);
+    }
+}
+
 bool LiveSession::canSwitchUp() {
     // Allow upwards bandwidth switch when a stream has buffered at least 10 seconds.
     status_t err = OK;
diff --git a/media/libstagefright/httplive/LiveSession.h b/media/libstagefright/httplive/LiveSession.h
index 7aacca6..896a8fc 100644
--- a/media/libstagefright/httplive/LiveSession.h
+++ b/media/libstagefright/httplive/LiveSession.h
@@ -19,6 +19,7 @@
 #define LIVE_SESSION_H_
 
 #include <media/stagefright/foundation/AHandler.h>
+#include <media/mediaplayer.h>
 
 #include <utils/String8.h>
 
@@ -73,6 +74,7 @@
     size_t getTrackCount() const;
     sp<AMessage> getTrackInfo(size_t trackIndex) const;
     status_t selectTrack(size_t index, bool select);
+    ssize_t getSelectedTrack(media_track_type /* type */) const;
 
     bool isSeekable() const;
     bool hasDynamicDuration() const;
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 1651dee..eb62c7a 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -66,6 +66,9 @@
     virtual ~MediaGroup();
 
 private:
+
+    friend struct M3UParser;
+
     struct Media {
         AString mName;
         AString mURI;
@@ -356,6 +359,38 @@
     return mSelectedIndex;
 }
 
+ssize_t M3UParser::getSelectedTrack(media_track_type type) const {
+    MediaGroup::Type groupType;
+    switch (type) {
+        case MEDIA_TRACK_TYPE_VIDEO:
+            groupType = MediaGroup::TYPE_VIDEO;
+            break;
+
+        case MEDIA_TRACK_TYPE_AUDIO:
+            groupType = MediaGroup::TYPE_AUDIO;
+            break;
+
+        case MEDIA_TRACK_TYPE_SUBTITLE:
+            groupType = MediaGroup::TYPE_SUBS;
+            break;
+
+        default:
+            return -1;
+    }
+
+    for (size_t i = 0, ii = 0; i < mMediaGroups.size(); ++i) {
+        sp<MediaGroup> group = mMediaGroups.valueAt(i);
+        size_t tracks = group->countTracks();
+        if (groupType != group->mType) {
+            ii += tracks;
+        } else if (group->mSelectedIndex >= 0) {
+            return ii + group->mSelectedIndex;
+        }
+    }
+
+    return -1;
+}
+
 bool M3UParser::getTypeURI(size_t index, const char *key, AString *uri) const {
     if (!mIsVariantPlaylist) {
         *uri = mBaseURI;
diff --git a/media/libstagefright/httplive/M3UParser.h b/media/libstagefright/httplive/M3UParser.h
index d588afe..1cad060 100644
--- a/media/libstagefright/httplive/M3UParser.h
+++ b/media/libstagefright/httplive/M3UParser.h
@@ -21,6 +21,7 @@
 #include <media/stagefright/foundation/ABase.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/foundation/AString.h>
+#include <media/mediaplayer.h>
 #include <utils/Vector.h>
 
 namespace android {
@@ -46,6 +47,7 @@
     size_t getTrackCount() const;
     sp<AMessage> getTrackInfo(size_t index) const;
     ssize_t getSelectedIndex() const;
+    ssize_t getSelectedTrack(media_track_type /* type */) const;
 
     bool getTypeURI(size_t index, const char *key, AString *uri) const;
 
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 89181b5..e247550 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -700,8 +700,7 @@
                     mRefreshState = (RefreshState)(mRefreshState + 1);
                 }
             } else {
-                ALOGE("failed to load playlist at url '%s'", mURI.c_str());
-                notifyError(ERROR_IO);
+                ALOGE("failed to load playlist at url '%s'", uriDebugString(mURI).c_str());
                 return ERROR_IO;
             }
         } else {
@@ -724,26 +723,25 @@
 }
 
 void PlaylistFetcher::onDownloadNext() {
-    if (refreshPlaylist() != OK) {
-        return;
-    }
-
-    int32_t firstSeqNumberInPlaylist;
-    if (mPlaylist->meta() == NULL || !mPlaylist->meta()->findInt32(
-                "media-sequence", &firstSeqNumberInPlaylist)) {
-        firstSeqNumberInPlaylist = 0;
-    }
-
+    status_t err = refreshPlaylist();
+    int32_t firstSeqNumberInPlaylist = 0;
+    int32_t lastSeqNumberInPlaylist = 0;
     bool discontinuity = false;
 
-    const int32_t lastSeqNumberInPlaylist =
-        firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1;
+    if (mPlaylist != NULL) {
+        if (mPlaylist->meta() != NULL) {
+            mPlaylist->meta()->findInt32("media-sequence", &firstSeqNumberInPlaylist);
+        }
 
-    if (mDiscontinuitySeq < 0) {
-        mDiscontinuitySeq = mPlaylist->getDiscontinuitySeq();
+        lastSeqNumberInPlaylist =
+                firstSeqNumberInPlaylist + (int32_t)mPlaylist->size() - 1;
+
+        if (mDiscontinuitySeq < 0) {
+            mDiscontinuitySeq = mPlaylist->getDiscontinuitySeq();
+        }
     }
 
-    if (mSeqNumber < 0) {
+    if (mPlaylist != NULL && mSeqNumber < 0) {
         CHECK_GE(mStartTimeUs, 0ll);
 
         if (mSegmentStartTimeUs < 0) {
@@ -785,19 +783,26 @@
         }
     }
 
+    // if mPlaylist is NULL then err must be non-OK; but the other way around might not be true
     if (mSeqNumber < firstSeqNumberInPlaylist
-            || mSeqNumber > lastSeqNumberInPlaylist) {
-        if (!mPlaylist->isComplete() && mNumRetries < kMaxNumRetries) {
+            || mSeqNumber > lastSeqNumberInPlaylist
+            || err != OK) {
+        if ((err != OK || !mPlaylist->isComplete()) && mNumRetries < kMaxNumRetries) {
             ++mNumRetries;
 
-            if (mSeqNumber > lastSeqNumberInPlaylist) {
+            if (mSeqNumber > lastSeqNumberInPlaylist || err != OK) {
+                // make sure we reach this retry logic on refresh failures
+                // by adding an err != OK clause to all enclosing if's.
+
                 // refresh in increasing fraction (1/2, 1/3, ...) of the
                 // playlist's target duration or 3 seconds, whichever is less
-                int32_t targetDurationSecs;
-                CHECK(mPlaylist->meta()->findInt32(
-                        "target-duration", &targetDurationSecs));
-                int64_t delayUs = mPlaylist->size() * targetDurationSecs *
-                        1000000ll / (1 + mNumRetries);
+                int64_t delayUs = kMaxMonitorDelayUs;
+                if (mPlaylist != NULL && mPlaylist->meta() != NULL) {
+                    int32_t targetDurationSecs;
+                    CHECK(mPlaylist->meta()->findInt32("target-duration", &targetDurationSecs));
+                    delayUs = mPlaylist->size() * targetDurationSecs *
+                            1000000ll / (1 + mNumRetries);
+                }
                 if (delayUs > kMaxMonitorDelayUs) {
                     delayUs = kMaxMonitorDelayUs;
                 }
@@ -809,7 +814,12 @@
                 return;
             }
 
-            // we've missed the boat, let's start from the lowest sequence
+            if (err != OK) {
+                notifyError(err);
+                return;
+            }
+
+            // we've missed the boat, let's start 3 segments prior to the latest sequence
             // number available and signal a discontinuity.
 
             ALOGI("We've missed the boat, restarting playback."
@@ -963,8 +973,8 @@
     } while (bytesRead != 0);
 
     if (bufferStartsWithTsSyncByte(buffer)) {
-        // If we still don't see a stream after fetching a full ts segment mark it as
-        // nonexistent.
+        // If we don't see a stream in the program table after fetching a full ts segment
+        // mark it as nonexistent.
         const size_t kNumTypes = ATSParser::NUM_SOURCE_TYPES;
         ATSParser::SourceType srcTypes[kNumTypes] =
                 { ATSParser::VIDEO, ATSParser::AUDIO };
@@ -979,7 +989,7 @@
                 static_cast<AnotherPacketSource *>(
                     mTSParser->getSource(srcType).get());
 
-            if (source == NULL) {
+            if (!mTSParser->hasSource(srcType)) {
                 ALOGW("MPEG2 Transport stream does not contain %s data.",
                       srcType == ATSParser::VIDEO ? "video" : "audio");
 
@@ -996,7 +1006,7 @@
         return;
     }
 
-    status_t err = OK;
+    err = OK;
     if (tsBuffer != NULL) {
         AString method;
         CHECK(buffer->meta()->findString("cipher-method", &method));
@@ -1587,6 +1597,7 @@
                 mStartTimeUsNotify->setInt32("streamMask", LiveSession::STREAMTYPE_AUDIO);
                 mStartTimeUsNotify->post();
                 mStartTimeUsNotify.clear();
+                mStartup = false;
             }
         }
 
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index 24d431c..104dcfc 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -31,7 +31,7 @@
 
 struct OMXNodeInstance {
     OMXNodeInstance(
-            OMX *owner, const sp<IOMXObserver> &observer);
+            OMX *owner, const sp<IOMXObserver> &observer, const char *name);
 
     void setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle);
 
@@ -149,6 +149,18 @@
     KeyedVector<OMX_BUFFERHEADERTYPE *, OMX::buffer_id> mBufferHeaderToBufferID;
 #endif
 
+    // For debug support
+    char *mName;
+    int DEBUG;
+    size_t mNumPortBuffers[2];  // modified under mLock, read outside for debug
+    Mutex mDebugLock;
+    // following are modified and read under mDebugLock
+    int DEBUG_BUMP;
+    SortedVector<OMX_BUFFERHEADERTYPE *> mInputBuffersWithCodec, mOutputBuffersWithCodec;
+    size_t mDebugLevelBumpPendingBuffers[2];
+    void bumpDebugLevel_l(size_t numInputBuffers, size_t numOutputBuffers);
+    void unbumpDebugLevel_l(size_t portIndex);
+
     ~OMXNodeInstance();
 
     void addActiveBuffer(OMX_U32 portIndex, OMX::buffer_id id);
@@ -186,6 +198,10 @@
             OMX_U32 portIndex, OMX_BOOL enable,
             OMX_BOOL useGraphicBuffer, OMX_BOOL *usingGraphicBufferInMeta);
 
+    status_t emptyBuffer_l(
+            OMX_BUFFERHEADERTYPE *header,
+            OMX_U32 flags, OMX_TICKS timestamp, intptr_t debugAddr);
+
     sp<GraphicBufferSource> getGraphicBufferSource();
     void setGraphicBufferSource(const sp<GraphicBufferSource>& bufferSource);
 
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 2587ec7..4f0862c 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -413,16 +413,16 @@
 
     const mkvparser::CuePoint* pCP;
     mkvparser::Tracks const *pTracks = pSegment->GetTracks();
-    unsigned long int trackCount = pTracks->GetTracksCount();
     while (!pCues->DoneParsing()) {
         pCues->LoadCuePoint();
         pCP = pCues->GetLast();
         CHECK(pCP);
 
+        size_t trackCount = mExtractor->mTracks.size();
         for (size_t index = 0; index < trackCount; ++index) {
-            const mkvparser::Track *pTrack = pTracks->GetTrackByIndex(index);
+            MatroskaExtractor::TrackInfo& track = mExtractor->mTracks.editItemAt(index);
+            const mkvparser::Track *pTrack = pTracks->GetTrackByNumber(track.mTrackNum);
             if (pTrack && pTrack->GetType() == 1 && pCP->Find(pTrack)) { // VIDEO_TRACK
-                MatroskaExtractor::TrackInfo& track = mExtractor->mTracks.editItemAt(index);
                 track.mCuePoints.push_back(pCP);
             }
         }
@@ -434,12 +434,13 @@
     }
 
     const mkvparser::CuePoint::TrackPosition *pTP = NULL;
-    const mkvparser::Track *thisTrack = pTracks->GetTrackByIndex(mIndex);
+    const mkvparser::Track *thisTrack = pTracks->GetTrackByNumber(mTrackNum);
     if (thisTrack->GetType() == 1) { // video
         MatroskaExtractor::TrackInfo& track = mExtractor->mTracks.editItemAt(mIndex);
         pTP = track.find(seekTimeNs);
     } else {
         // The Cue index is built around video keyframes
+        unsigned long int trackCount = pTracks->GetTracksCount();
         for (size_t index = 0; index < trackCount; ++index) {
             const mkvparser::Track *pTrack = pTracks->GetTrackByIndex(index);
             if (pTrack && pTrack->GetType() == 1 && pCues->Find(seekTimeNs, pTrack, pCP, pTP)) {
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index eab7616..482ccff 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -63,6 +63,7 @@
     void signalEOS(status_t finalResult);
 
     sp<MediaSource> getSource(SourceType type);
+    bool hasSource(SourceType type) const;
 
     int64_t convertPTSToTimestamp(uint64_t PTS);
 
@@ -119,6 +120,9 @@
 
     sp<MediaSource> getSource(SourceType type);
 
+    bool isAudio() const;
+    bool isVideo() const;
+
 protected:
     virtual ~Stream();
 
@@ -146,9 +150,6 @@
 
     void extractAACFrames(const sp<ABuffer> &buffer);
 
-    bool isAudio() const;
-    bool isVideo() const;
-
     DISALLOW_EVIL_CONSTRUCTORS(Stream);
 };
 
@@ -440,6 +441,19 @@
     return NULL;
 }
 
+bool ATSParser::Program::hasSource(SourceType type) const {
+    for (size_t i = 0; i < mStreams.size(); ++i) {
+        const sp<Stream> &stream = mStreams.valueAt(i);
+        if (type == AUDIO && stream->isAudio()) {
+            return true;
+        } else if (type == VIDEO && stream->isVideo()) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 int64_t ATSParser::Program::convertPTSToTimestamp(uint64_t PTS) {
     if (!(mParser->mFlags & TS_TIMESTAMPS_ARE_ABSOLUTE)) {
         if (!mFirstPTSValid) {
@@ -665,7 +679,7 @@
             int64_t resumeAtMediaTimeUs =
                 mProgram->convertPTSToTimestamp(resumeAtPTS);
 
-            extra->setInt64("resume-at-mediatimeUs", resumeAtMediaTimeUs);
+            extra->setInt64("resume-at-mediaTimeUs", resumeAtMediaTimeUs);
         }
     }
 
@@ -1278,6 +1292,17 @@
     return NULL;
 }
 
+bool ATSParser::hasSource(SourceType type) const {
+    for (size_t i = 0; i < mPrograms.size(); ++i) {
+        const sp<Program> &program = mPrograms.itemAt(i);
+        if (program->hasSource(type)) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 bool ATSParser::PTSTimeDeltaEstablished() {
     if (mPrograms.isEmpty()) {
         return false;
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 204934d..5d76cbd 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -74,6 +74,7 @@
         NUM_SOURCE_TYPES = 2
     };
     sp<MediaSource> getSource(SourceType type);
+    bool hasSource(SourceType type) const;
 
     bool PTSTimeDeltaEstablished();
 
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index ed40bdd..c579d4c 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -262,15 +262,15 @@
         }
     }
 
+    mEOSResult = OK;
+    mLastQueuedTimeUs = 0;
+    mLatestEnqueuedMeta = NULL;
+
     if (type == ATSParser::DISCONTINUITY_NONE) {
         return;
     }
 
-    mEOSResult = OK;
-    mLastQueuedTimeUs = 0;
-    mLatestEnqueuedMeta = NULL;
     ++mQueuedDiscontinuityCount;
-
     sp<ABuffer> buffer = new ABuffer(0);
     buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type));
     buffer->meta()->setMessage("extra", extra);
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 41407e4..6d46eee 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -225,7 +225,7 @@
 
     *node = 0;
 
-    OMXNodeInstance *instance = new OMXNodeInstance(this, observer);
+    OMXNodeInstance *instance = new OMXNodeInstance(this, observer, name);
 
     OMX_COMPONENTTYPE *handle;
     OMX_ERRORTYPE err = mMaster->makeComponentInstance(
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index f9c84e2..c04d95f 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -18,11 +18,15 @@
 #define LOG_TAG "OMXNodeInstance"
 #include <utils/Log.h>
 
+#include <inttypes.h>
+
 #include "../include/OMXNodeInstance.h"
 #include "OMXMaster.h"
 #include "GraphicBufferSource.h"
 
 #include <OMX_Component.h>
+#include <OMX_IndexExt.h>
+#include <OMX_AsString.h>
 
 #include <binder/IMemory.h>
 #include <gui/BufferQueue.h>
@@ -30,7 +34,68 @@
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MediaErrors.h>
 
+#include <utils/misc.h>
+
 static const OMX_U32 kPortIndexInput = 0;
+static const OMX_U32 kPortIndexOutput = 1;
+
+#define CLOGW(fmt, ...) ALOGW("[%x:%s] " fmt, mNodeID, mName, ##__VA_ARGS__)
+
+#define CLOG_ERROR_IF(cond, fn, err, fmt, ...) \
+    ALOGE_IF(cond, #fn "(%x:%s, " fmt ") ERROR: %s(%#x)", \
+    mNodeID, mName, ##__VA_ARGS__, asString(err), err)
+#define CLOG_ERROR(fn, err, fmt, ...) CLOG_ERROR_IF(true, fn, err, fmt, ##__VA_ARGS__)
+#define CLOG_IF_ERROR(fn, err, fmt, ...) \
+    CLOG_ERROR_IF((err) != OMX_ErrorNone, fn, err, fmt, ##__VA_ARGS__)
+
+#define CLOGI_(level, fn, fmt, ...) \
+    ALOGI_IF(DEBUG >= (level), #fn "(%x:%s, " fmt ")", mNodeID, mName, ##__VA_ARGS__)
+#define CLOGD_(level, fn, fmt, ...) \
+    ALOGD_IF(DEBUG >= (level), #fn "(%x:%s, " fmt ")", mNodeID, mName, ##__VA_ARGS__)
+
+#define CLOG_LIFE(fn, fmt, ...)     CLOGI_(ADebug::kDebugLifeCycle,     fn, fmt, ##__VA_ARGS__)
+#define CLOG_STATE(fn, fmt, ...)    CLOGI_(ADebug::kDebugState,         fn, fmt, ##__VA_ARGS__)
+#define CLOG_CONFIG(fn, fmt, ...)   CLOGI_(ADebug::kDebugConfig,        fn, fmt, ##__VA_ARGS__)
+#define CLOG_INTERNAL(fn, fmt, ...) CLOGD_(ADebug::kDebugInternalState, fn, fmt, ##__VA_ARGS__)
+
+#define CLOG_DEBUG_IF(cond, fn, fmt, ...) \
+    ALOGD_IF(cond, #fn "(%x, " fmt ")", mNodeID, ##__VA_ARGS__)
+
+#define CLOG_BUFFER(fn, fmt, ...) \
+    CLOG_DEBUG_IF(DEBUG >= ADebug::kDebugAll, fn, fmt, ##__VA_ARGS__)
+#define CLOG_BUMPED_BUFFER(fn, fmt, ...) \
+    CLOG_DEBUG_IF(DEBUG_BUMP >= ADebug::kDebugAll, fn, fmt, ##__VA_ARGS__)
+
+/* buffer formatting */
+#define BUFFER_FMT(port, fmt, ...) "%s:%u " fmt, portString(port), (port), ##__VA_ARGS__
+#define NEW_BUFFER_FMT(buffer_id, port, fmt, ...) \
+    BUFFER_FMT(port, fmt ") (#%zu => %#x", ##__VA_ARGS__, mActiveBuffers.size(), (buffer_id))
+
+#define SIMPLE_BUFFER(port, size, data) BUFFER_FMT(port, "%zu@%p", (size), (data))
+#define SIMPLE_NEW_BUFFER(buffer_id, port, size, data) \
+    NEW_BUFFER_FMT(buffer_id, port, "%zu@%p", (size), (data))
+
+#define EMPTY_BUFFER(addr, header) "%#x [%u@%p]", \
+    (addr), (header)->nAllocLen, (header)->pBuffer
+#define FULL_BUFFER(addr, header) "%#" PRIxPTR " [%u@%p (%u..+%u) f=%x ts=%lld]", \
+    (intptr_t)(addr), (header)->nAllocLen, (header)->pBuffer, \
+    (header)->nOffset, (header)->nFilledLen, (header)->nFlags, (header)->nTimeStamp
+
+#define WITH_STATS_WRAPPER(fmt, ...) fmt " { IN=%zu/%zu OUT=%zu/%zu }", ##__VA_ARGS__, \
+    mInputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexInput], \
+    mOutputBuffersWithCodec.size(), mNumPortBuffers[kPortIndexOutput]
+// TRICKY: this is needed so formatting macros expand before substitution
+#define WITH_STATS(fmt, ...) WITH_STATS_WRAPPER(fmt, ##__VA_ARGS__)
+
+template<class T>
+static void InitOMXParams(T *params) {
+    memset(params, 0, sizeof(T));
+    params->nSize = sizeof(T);
+    params->nVersion.s.nVersionMajor = 1;
+    params->nVersion.s.nVersionMinor = 0;
+    params->nVersion.s.nRevision = 0;
+    params->nVersion.s.nStep = 0;
+}
 
 namespace android {
 
@@ -56,8 +121,8 @@
         }
 
         memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
-               header->pBuffer + header->nOffset,
-               header->nFilledLen);
+                header->pBuffer + header->nOffset,
+                header->nFilledLen);
     }
 
     void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
@@ -66,8 +131,8 @@
         }
 
         memcpy(header->pBuffer + header->nOffset,
-               (const OMX_U8 *)mMem->pointer() + header->nOffset,
-               header->nFilledLen);
+                (const OMX_U8 *)mMem->pointer() + header->nOffset,
+                header->nFilledLen);
     }
 
     void setGraphicBuffer(const sp<GraphicBuffer> &graphicBuffer) {
@@ -89,8 +154,17 @@
     &OnEvent, &OnEmptyBufferDone, &OnFillBufferDone
 };
 
+static inline const char *portString(OMX_U32 portIndex) {
+    switch (portIndex) {
+        case kPortIndexInput:  return "Input";
+        case kPortIndexOutput: return "Output";
+        case ~0:               return "All";
+        default:               return "port";
+    }
+}
+
 OMXNodeInstance::OMXNodeInstance(
-        OMX *owner, const sp<IOMXObserver> &observer)
+        OMX *owner, const sp<IOMXObserver> &observer, const char *name)
     : mOwner(owner),
       mNodeID(0),
       mHandle(NULL),
@@ -100,15 +174,25 @@
       , mBufferIDCount(0)
 #endif
 {
+    mName = ADebug::GetDebugName(name);
+    DEBUG = ADebug::GetDebugLevelFromProperty(name, "debug.stagefright.omx-debug");
+    ALOGV("debug level for %s is %d", name, DEBUG);
+    DEBUG_BUMP = DEBUG;
+    mNumPortBuffers[0] = 0;
+    mNumPortBuffers[1] = 0;
+    mDebugLevelBumpPendingBuffers[0] = 0;
+    mDebugLevelBumpPendingBuffers[1] = 0;
 }
 
 OMXNodeInstance::~OMXNodeInstance() {
+    free(mName);
     CHECK(mHandle == NULL);
 }
 
 void OMXNodeInstance::setHandle(OMX::node_id node_id, OMX_HANDLETYPE handle) {
-    CHECK(mHandle == NULL);
     mNodeID = node_id;
+    CLOG_LIFE(allocateNode, "handle=%p", handle);
+    CHECK(mHandle == NULL);
     mHandle = handle;
 }
 
@@ -120,6 +204,7 @@
 void OMXNodeInstance::setGraphicBufferSource(
         const sp<GraphicBufferSource>& bufferSource) {
     Mutex::Autolock autoLock(mGraphicBufferSourceLock);
+    CLOG_INTERNAL(setGraphicBufferSource, "%p", bufferSource.get());
     mGraphicBufferSource = bufferSource;
 }
 
@@ -140,6 +225,7 @@
         case OMX_ErrorNone:
             return OK;
         case OMX_ErrorUnsupportedSetting:
+        case OMX_ErrorUnsupportedIndex:
             return ERROR_UNSUPPORTED;
         default:
             return UNKNOWN_ERROR;
@@ -147,6 +233,7 @@
 }
 
 status_t OMXNodeInstance::freeNode(OMXMaster *master) {
+    CLOG_LIFE(freeNode, "handle=%p", mHandle);
     static int32_t kMaxNumIterations = 10;
 
     // exit if we have already freed the node
@@ -175,10 +262,11 @@
             OMX_ERRORTYPE err;
             int32_t iteration = 0;
             while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
-                   && state != OMX_StateIdle
-                   && state != OMX_StateInvalid) {
+                    && state != OMX_StateIdle
+                    && state != OMX_StateInvalid) {
                 if (++iteration > kMaxNumIterations) {
-                    ALOGE("component failed to enter Idle state, aborting.");
+                    CLOGW("failed to enter Idle state (now %s(%d), aborting.",
+                            asString(state), state);
                     state = OMX_StateInvalid;
                     break;
                 }
@@ -204,10 +292,11 @@
             OMX_ERRORTYPE err;
             int32_t iteration = 0;
             while ((err = OMX_GetState(mHandle, &state)) == OMX_ErrorNone
-                   && state != OMX_StateLoaded
-                   && state != OMX_StateInvalid) {
+                    && state != OMX_StateLoaded
+                    && state != OMX_StateInvalid) {
                 if (++iteration > kMaxNumIterations) {
-                    ALOGE("component failed to enter Loaded state, aborting.");
+                    CLOGW("failed to enter Loaded state (now %s(%d), aborting.",
+                            asString(state), state);
                     state = OMX_StateInvalid;
                     break;
                 }
@@ -225,20 +314,18 @@
             break;
 
         default:
-            CHECK(!"should not be here, unknown state.");
+            LOG_ALWAYS_FATAL("unknown state %s(%#x).", asString(state), state);
             break;
     }
 
-    ALOGV("calling destroyComponentInstance");
+    ALOGV("[%x:%s] calling destroyComponentInstance", mNodeID, mName);
     OMX_ERRORTYPE err = master->destroyComponentInstance(
             static_cast<OMX_COMPONENTTYPE *>(mHandle));
-    ALOGV("destroyComponentInstance returned err %d", err);
 
     mHandle = NULL;
-
-    if (err != OMX_ErrorNone) {
-        ALOGE("FreeHandle FAILED with error 0x%08x.", err);
-    }
+    CLOG_IF_ERROR(freeNode, err, "");
+    free(mName);
+    mName = NULL;
 
     mOwner->invalidateNodeID(mNodeID);
     mNodeID = 0;
@@ -270,7 +357,17 @@
 
     Mutex::Autolock autoLock(mLock);
 
+    // bump internal-state debug level for 2 input and output frames past a command
+    {
+        Mutex::Autolock _l(mDebugLock);
+        bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */);
+    }
+
+    const char *paramString =
+        cmd == OMX_CommandStateSet ? asString((OMX_STATETYPE)param) : portString(param);
+    CLOG_STATE(sendCommand, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param);
     OMX_ERRORTYPE err = OMX_SendCommand(mHandle, cmd, param, NULL);
+    CLOG_IF_ERROR(sendCommand, err, "%s(%d), %s(%d)", asString(cmd), cmd, paramString, param);
     return StatusFromOMXError(err);
 }
 
@@ -279,17 +376,23 @@
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_GetParameter(mHandle, index, params);
-    ALOGE_IF(err != OMX_ErrorNone, "getParameter(%d) ERROR: %#x", index, err);
+    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
+    // some errors are expected for getParameter
+    if (err != OMX_ErrorNoMore) {
+        CLOG_IF_ERROR(getParameter, err, "%s(%#x)", asString(extIndex), index);
+    }
     return StatusFromOMXError(err);
 }
 
 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_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
+    CLOG_CONFIG(setParameter, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
     OMX_ERRORTYPE err = OMX_SetParameter(
             mHandle, index, const_cast<void *>(params));
-    ALOGE_IF(err != OMX_ErrorNone, "setParameter(%d) ERROR: %#x", index, err);
+    CLOG_IF_ERROR(setParameter, err, "%s(%#x)", asString(extIndex), index);
     return StatusFromOMXError(err);
 }
 
@@ -298,16 +401,23 @@
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_GetConfig(mHandle, index, params);
+    OMX_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
+    // some errors are expected for getConfig
+    if (err != OMX_ErrorNoMore) {
+        CLOG_IF_ERROR(getConfig, err, "%s(%#x)", asString(extIndex), index);
+    }
     return StatusFromOMXError(err);
 }
 
 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_INDEXEXTTYPE extIndex = (OMX_INDEXEXTTYPE)index;
+    CLOG_CONFIG(setConfig, "%s(%#x), %zu@%p)", asString(extIndex), index, size, params);
 
     OMX_ERRORTYPE err = OMX_SetConfig(
             mHandle, index, const_cast<void *>(params));
-
+    CLOG_IF_ERROR(setConfig, err, "%s(%#x)", asString(extIndex), index);
     return StatusFromOMXError(err);
 }
 
@@ -315,13 +425,14 @@
     Mutex::Autolock autoLock(mLock);
 
     OMX_ERRORTYPE err = OMX_GetState(mHandle, state);
-
+    CLOG_IF_ERROR(getState, err, "");
     return StatusFromOMXError(err);
 }
 
 status_t OMXNodeInstance::enableGraphicBuffers(
         OMX_U32 portIndex, OMX_BOOL enable) {
     Mutex::Autolock autoLock(mLock);
+    CLOG_CONFIG(enableGraphicBuffers, "%s:%u, %d", portString(portIndex), portIndex, enable);
     OMX_STRING name = const_cast<OMX_STRING>(
             "OMX.google.android.index.enableAndroidNativeBuffers");
 
@@ -329,32 +440,19 @@
     OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
 
     if (err != OMX_ErrorNone) {
-        if (enable) {
-            ALOGE("OMX_GetExtensionIndex %s failed", name);
-        }
-
+        CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
         return StatusFromOMXError(err);
     }
 
-    OMX_VERSIONTYPE ver;
-    ver.s.nVersionMajor = 1;
-    ver.s.nVersionMinor = 0;
-    ver.s.nRevision = 0;
-    ver.s.nStep = 0;
-    EnableAndroidNativeBuffersParams params = {
-        sizeof(EnableAndroidNativeBuffersParams), ver, portIndex, enable,
-    };
+    EnableAndroidNativeBuffersParams params;
+    InitOMXParams(&params);
+    params.nPortIndex = portIndex;
+    params.enable = enable;
 
     err = OMX_SetParameter(mHandle, index, &params);
-
-    if (err != OMX_ErrorNone) {
-        ALOGE("OMX_EnableAndroidNativeBuffers failed with error %d (0x%08x)",
-                err, err);
-
-        return UNKNOWN_ERROR;
-    }
-
-    return OK;
+    CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d", name, index,
+            portString(portIndex), portIndex, enable);
+    return StatusFromOMXError(err);
 }
 
 status_t OMXNodeInstance::getGraphicBufferUsage(
@@ -367,26 +465,19 @@
     OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_GetExtensionIndex %s failed", name);
-
+        CLOG_ERROR(getExtensionIndex, err, "%s", name);
         return StatusFromOMXError(err);
     }
 
-    OMX_VERSIONTYPE ver;
-    ver.s.nVersionMajor = 1;
-    ver.s.nVersionMinor = 0;
-    ver.s.nRevision = 0;
-    ver.s.nStep = 0;
-    GetAndroidNativeBufferUsageParams params = {
-        sizeof(GetAndroidNativeBufferUsageParams), ver, portIndex, 0,
-    };
+    GetAndroidNativeBufferUsageParams params;
+    InitOMXParams(&params);
+    params.nPortIndex = portIndex;
 
     err = OMX_GetParameter(mHandle, index, &params);
-
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_GetAndroidNativeBufferUsage failed with error %d (0x%08x)",
-                err, err);
-        return UNKNOWN_ERROR;
+        CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u", name, index,
+                portString(portIndex), portIndex);
+        return StatusFromOMXError(err);
     }
 
     *usage = params.nUsage;
@@ -398,6 +489,7 @@
         OMX_U32 portIndex,
         OMX_BOOL enable) {
     Mutex::Autolock autolock(mLock);
+    CLOG_CONFIG(storeMetaDataInBuffers, "%s:%u en:%d", portString(portIndex), portIndex, enable);
     return storeMetaDataInBuffers_l(
             portIndex, enable,
             OMX_FALSE /* useGraphicBuffer */, NULL /* usingGraphicBufferInMetadata */);
@@ -424,37 +516,42 @@
                 : OMX_ErrorBadParameter;
     if (err == OMX_ErrorNone) {
         *usingGraphicBufferInMetadata = OMX_TRUE;
+        name = graphicBufferName;
     } else {
-        *usingGraphicBufferInMetadata = OMX_FALSE;
         err = OMX_GetExtensionIndex(mHandle, name, &index);
     }
 
+    OMX_ERRORTYPE xerr = err;
+    if (err == OMX_ErrorNone) {
+        StoreMetaDataInBuffersParams params;
+        InitOMXParams(&params);
+        params.nPortIndex = portIndex;
+        params.bStoreMetaData = enable;
+
+        err = OMX_SetParameter(mHandle, index, &params);
+    }
+
+    // don't log loud error if component does not support metadata mode on the output
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_GetExtensionIndex %s failed", name);
-        return StatusFromOMXError(err);
-    }
-
-    StoreMetaDataInBuffersParams params;
-    memset(&params, 0, sizeof(params));
-    params.nSize = sizeof(params);
-
-    // Version: 1.0.0.0
-    params.nVersion.s.nVersionMajor = 1;
-
-    params.nPortIndex = portIndex;
-    params.bStoreMetaData = enable;
-    if ((err = OMX_SetParameter(mHandle, index, &params)) != OMX_ErrorNone) {
-        ALOGE("OMX_SetParameter() failed for StoreMetaDataInBuffers: 0x%08x", err);
         *usingGraphicBufferInMetadata = OMX_FALSE;
-        return UNKNOWN_ERROR;
+        if (err == OMX_ErrorUnsupportedIndex && portIndex == kPortIndexOutput) {
+            CLOGW("component does not support metadata mode; using fallback");
+        } else if (xerr != OMX_ErrorNone) {
+            CLOG_ERROR(getExtensionIndex, xerr, "%s", name);
+        } else {
+            CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d GB=%d", name, index,
+                    portString(portIndex), portIndex, enable, useGraphicBuffer);
+        }
     }
-    return err;
+    return StatusFromOMXError(err);
 }
 
 status_t OMXNodeInstance::prepareForAdaptivePlayback(
         OMX_U32 portIndex, OMX_BOOL enable, OMX_U32 maxFrameWidth,
         OMX_U32 maxFrameHeight) {
     Mutex::Autolock autolock(mLock);
+    CLOG_CONFIG(prepareForAdaptivePlayback, "%s:%u en=%d max=%ux%u",
+            portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
 
     OMX_INDEXTYPE index;
     OMX_STRING name = const_cast<OMX_STRING>(
@@ -462,33 +559,29 @@
 
     OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
     if (err != OMX_ErrorNone) {
-        ALOGW_IF(enable, "OMX_GetExtensionIndex %s failed", name);
+        CLOG_ERROR_IF(enable, getExtensionIndex, err, "%s", name);
         return StatusFromOMXError(err);
     }
 
     PrepareForAdaptivePlaybackParams params;
-    params.nSize = sizeof(params);
-    params.nVersion.s.nVersionMajor = 1;
-    params.nVersion.s.nVersionMinor = 0;
-    params.nVersion.s.nRevision = 0;
-    params.nVersion.s.nStep = 0;
-
+    InitOMXParams(&params);
     params.nPortIndex = portIndex;
     params.bEnable = enable;
     params.nMaxFrameWidth = maxFrameWidth;
     params.nMaxFrameHeight = maxFrameHeight;
-    if ((err = OMX_SetParameter(mHandle, index, &params)) != OMX_ErrorNone) {
-        ALOGW("OMX_SetParameter failed for PrepareForAdaptivePlayback "
-              "with error %d (0x%08x)", err, err);
-        return UNKNOWN_ERROR;
-    }
-    return err;
+
+    err = OMX_SetParameter(mHandle, index, &params);
+    CLOG_IF_ERROR(setParameter, err, "%s(%#x): %s:%u en=%d max=%ux%u", name, index,
+            portString(portIndex), portIndex, enable, maxFrameWidth, maxFrameHeight);
+    return StatusFromOMXError(err);
 }
 
 status_t OMXNodeInstance::configureVideoTunnelMode(
         OMX_U32 portIndex, OMX_BOOL tunneled, OMX_U32 audioHwSync,
         native_handle_t **sidebandHandle) {
     Mutex::Autolock autolock(mLock);
+    CLOG_CONFIG(configureVideoTunnelMode, "%s:%u tun=%d sync=%u",
+            portString(portIndex), portIndex, tunneled, audioHwSync);
 
     OMX_INDEXTYPE index;
     OMX_STRING name = const_cast<OMX_STRING>(
@@ -496,36 +589,33 @@
 
     OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
     if (err != OMX_ErrorNone) {
-        ALOGE("configureVideoTunnelMode extension is missing!");
+        CLOG_ERROR_IF(tunneled, getExtensionIndex, err, "%s", name);
         return StatusFromOMXError(err);
     }
 
     ConfigureVideoTunnelModeParams tunnelParams;
-    tunnelParams.nSize = sizeof(tunnelParams);
-    tunnelParams.nVersion.s.nVersionMajor = 1;
-    tunnelParams.nVersion.s.nVersionMinor = 0;
-    tunnelParams.nVersion.s.nRevision = 0;
-    tunnelParams.nVersion.s.nStep = 0;
-
+    InitOMXParams(&tunnelParams);
     tunnelParams.nPortIndex = portIndex;
     tunnelParams.bTunneled = tunneled;
     tunnelParams.nAudioHwSync = audioHwSync;
     err = OMX_SetParameter(mHandle, index, &tunnelParams);
     if (err != OMX_ErrorNone) {
-        ALOGE("configureVideoTunnelMode failed! (err %d).", err);
-        return UNKNOWN_ERROR;
+        CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u tun=%d sync=%u", name, index,
+                portString(portIndex), portIndex, tunneled, audioHwSync);
+        return StatusFromOMXError(err);
     }
 
     err = OMX_GetParameter(mHandle, index, &tunnelParams);
     if (err != OMX_ErrorNone) {
-        ALOGE("GetVideoTunnelWindow failed! (err %d).", err);
-        return UNKNOWN_ERROR;
+        CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u tun=%d sync=%u", name, index,
+                portString(portIndex), portIndex, tunneled, audioHwSync);
+        return StatusFromOMXError(err);
     }
     if (sidebandHandle) {
         *sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow;
     }
 
-    return err;
+    return OK;
 }
 
 status_t OMXNodeInstance::useBuffer(
@@ -542,14 +632,14 @@
             params->size(), static_cast<OMX_U8 *>(params->pointer()));
 
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
+        CLOG_ERROR(useBuffer, err, SIMPLE_BUFFER(portIndex, params->size(), params->pointer()));
 
         delete buffer_meta;
         buffer_meta = NULL;
 
         *buffer = 0;
 
-        return UNKNOWN_ERROR;
+        return StatusFromOMXError(err);
     }
 
     CHECK_EQ(header->pAppPrivate, buffer_meta);
@@ -563,6 +653,8 @@
         bufferSource->addCodecBuffer(header);
     }
 
+    CLOG_BUFFER(useBuffer, NEW_BUFFER_FMT(
+            *buffer, portIndex, "%zu@%p", params->size(), params->pointer()));
     return OK;
 }
 
@@ -572,17 +664,14 @@
 
     // port definition
     OMX_PARAM_PORTDEFINITIONTYPE def;
-    def.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
-    def.nVersion.s.nVersionMajor = 1;
-    def.nVersion.s.nVersionMinor = 0;
-    def.nVersion.s.nRevision = 0;
-    def.nVersion.s.nStep = 0;
+    InitOMXParams(&def);
     def.nPortIndex = portIndex;
     OMX_ERRORTYPE err = OMX_GetParameter(mHandle, OMX_IndexParamPortDefinition, &def);
-    if (err != OMX_ErrorNone)
-    {
-        ALOGE("%s::%d:Error getting OMX_IndexParamPortDefinition", __FUNCTION__, __LINE__);
-        return err;
+    if (err != OMX_ErrorNone) {
+        OMX_INDEXTYPE index = OMX_IndexParamPortDefinition;
+        CLOG_ERROR(getParameter, err, "%s(%#x): %s:%u",
+                asString(index), index, portString(portIndex), portIndex);
+        return UNKNOWN_ERROR;
     }
 
     BufferMeta *bufferMeta = new BufferMeta(graphicBuffer);
@@ -600,11 +689,11 @@
             bufferHandle);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_UseBuffer failed with error %d (0x%08x)", err, err);
+        CLOG_ERROR(useBuffer, err, BUFFER_FMT(portIndex, "%u@%p", def.nBufferSize, bufferHandle));
         delete bufferMeta;
         bufferMeta = NULL;
         *buffer = 0;
-        return UNKNOWN_ERROR;
+        return StatusFromOMXError(err);
     }
 
     CHECK_EQ(header->pBuffer, bufferHandle);
@@ -613,7 +702,8 @@
     *buffer = makeBufferID(header);
 
     addActiveBuffer(portIndex, *buffer);
-
+    CLOG_BUFFER(useGraphicBuffer2, NEW_BUFFER_FMT(
+            *buffer, portIndex, "%u@%p", def.nBufferSize, bufferHandle));
     return OK;
 }
 
@@ -637,10 +727,8 @@
     OMX_STRING name = const_cast<OMX_STRING>(
         "OMX.google.android.index.useAndroidNativeBuffer");
     OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
-
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_GetExtensionIndex %s failed", name);
-
+        CLOG_ERROR(getExtensionIndex, err, "%s", name);
         return StatusFromOMXError(err);
     }
 
@@ -661,15 +749,15 @@
     err = OMX_SetParameter(mHandle, index, &params);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_UseAndroidNativeBuffer failed with error %d (0x%08x)", err,
-                err);
+        CLOG_ERROR(setParameter, err, "%s(%#x): %s:%u meta=%p GB=%p", name, index,
+                portString(portIndex), portIndex, bufferMeta, graphicBuffer->handle);
 
         delete bufferMeta;
         bufferMeta = NULL;
 
         *buffer = 0;
 
-        return UNKNOWN_ERROR;
+        return StatusFromOMXError(err);
     }
 
     CHECK_EQ(header->pAppPrivate, bufferMeta);
@@ -677,12 +765,13 @@
     *buffer = makeBufferID(header);
 
     addActiveBuffer(portIndex, *buffer);
-
+    CLOG_BUFFER(useGraphicBuffer, NEW_BUFFER_FMT(
+            *buffer, portIndex, "GB=%p", graphicBuffer->handle));
     return OK;
 }
 
 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);
 
@@ -693,7 +782,8 @@
     bufferMeta->setGraphicBuffer(graphicBuffer);
     metadata->eType = kMetadataBufferTypeGrallocSource;
     metadata->pHandle = graphicBuffer->handle;
-
+    CLOG_BUFFER(updateGraphicBufferInMeta, "%s:%u, %#x := %p",
+            portString(portIndex), portIndex, buffer, graphicBuffer->handle);
     return OK;
 }
 
@@ -719,19 +809,21 @@
     // Retrieve the width and height of the graphic buffer, set when the
     // codec was configured.
     OMX_PARAM_PORTDEFINITIONTYPE def;
-    def.nSize = sizeof(def);
-    def.nVersion.s.nVersionMajor = 1;
-    def.nVersion.s.nVersionMinor = 0;
-    def.nVersion.s.nRevision = 0;
-    def.nVersion.s.nStep = 0;
+    InitOMXParams(&def);
     def.nPortIndex = portIndex;
     OMX_ERRORTYPE oerr = OMX_GetParameter(
             mHandle, OMX_IndexParamPortDefinition, &def);
-    CHECK(oerr == OMX_ErrorNone);
+    if (oerr != OMX_ErrorNone) {
+        OMX_INDEXTYPE index = OMX_IndexParamPortDefinition;
+        CLOG_ERROR(getParameter, oerr, "%s(%#x): %s:%u",
+                asString(index), index, portString(portIndex), portIndex);
+        return UNKNOWN_ERROR;
+    }
 
     if (def.format.video.eColorFormat != OMX_COLOR_FormatAndroidOpaque) {
-        ALOGE("createInputSurface requires COLOR_FormatSurface "
-              "(AndroidOpaque) color format");
+        CLOGW("createInputSurface requires COLOR_FormatSurface "
+                "(AndroidOpaque) color format instead of %s(%#x)",
+                asString(def.format.video.eColorFormat), def.format.video.eColorFormat);
         return INVALID_OPERATION;
     }
 
@@ -754,9 +846,9 @@
     // flag set).  Seems easier than doing the equivalent from here.
     sp<GraphicBufferSource> bufferSource(getGraphicBufferSource());
     if (bufferSource == NULL) {
-        ALOGW("signalEndOfInputStream can only be used with Surface input");
+        CLOGW("signalEndOfInputStream can only be used with Surface input");
         return INVALID_OPERATION;
-    };
+    }
     return bufferSource->signalEndOfInputStream();
 }
 
@@ -773,14 +865,13 @@
             mHandle, &header, portIndex, buffer_meta, size);
 
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
-
+        CLOG_ERROR(allocateBuffer, err, BUFFER_FMT(portIndex, "%zu@", size));
         delete buffer_meta;
         buffer_meta = NULL;
 
         *buffer = 0;
 
-        return UNKNOWN_ERROR;
+        return StatusFromOMXError(err);
     }
 
     CHECK_EQ(header->pAppPrivate, buffer_meta);
@@ -794,6 +885,7 @@
     if (bufferSource != NULL && portIndex == kPortIndexInput) {
         bufferSource->addCodecBuffer(header);
     }
+    CLOG_BUFFER(allocateBuffer, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p", size, *buffer_data));
 
     return OK;
 }
@@ -811,14 +903,14 @@
             mHandle, &header, portIndex, buffer_meta, params->size());
 
     if (err != OMX_ErrorNone) {
-        ALOGE("OMX_AllocateBuffer failed with error %d (0x%08x)", err, err);
-
+        CLOG_ERROR(allocateBufferWithBackup, err,
+                SIMPLE_BUFFER(portIndex, params->size(), params->pointer()));
         delete buffer_meta;
         buffer_meta = NULL;
 
         *buffer = 0;
 
-        return UNKNOWN_ERROR;
+        return StatusFromOMXError(err);
     }
 
     CHECK_EQ(header->pAppPrivate, buffer_meta);
@@ -832,12 +924,16 @@
         bufferSource->addCodecBuffer(header);
     }
 
+    CLOG_BUFFER(allocateBufferWithBackup, NEW_BUFFER_FMT(*buffer, portIndex, "%zu@%p :> %p",
+            params->size(), params->pointer(), header->pBuffer));
+
     return OK;
 }
 
 status_t OMXNodeInstance::freeBuffer(
         OMX_U32 portIndex, OMX::buffer_id buffer) {
     Mutex::Autolock autoLock(mLock);
+    CLOG_BUFFER(freeBuffer, "%s:%u %#x", portString(portIndex), portIndex, buffer);
 
     removeActiveBuffer(portIndex, buffer);
 
@@ -845,6 +941,7 @@
     BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
 
     OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
+    CLOG_IF_ERROR(freeBuffer, err, "%s:%u %#x", portString(portIndex), portIndex, buffer);
 
     delete buffer_meta;
     buffer_meta = NULL;
@@ -861,8 +958,18 @@
     header->nOffset = 0;
     header->nFlags = 0;
 
-    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
+    {
+        Mutex::Autolock _l(mDebugLock);
+        mOutputBuffersWithCodec.add(header);
+        CLOG_BUMPED_BUFFER(fillBuffer, WITH_STATS(EMPTY_BUFFER(buffer, header)));
+    }
 
+    OMX_ERRORTYPE err = OMX_FillThisBuffer(mHandle, header);
+    if (err != OMX_ErrorNone) {
+        CLOG_ERROR(fillBuffer, err, EMPTY_BUFFER(buffer, header));
+        Mutex::Autolock _l(mDebugLock);
+        mOutputBuffersWithCodec.remove(header);
+    }
     return StatusFromOMXError(err);
 }
 
@@ -875,14 +982,66 @@
     OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
     header->nFilledLen = rangeLength;
     header->nOffset = rangeOffset;
-    header->nFlags = flags;
-    header->nTimeStamp = timestamp;
 
     BufferMeta *buffer_meta =
         static_cast<BufferMeta *>(header->pAppPrivate);
     buffer_meta->CopyToOMX(header);
 
+    return emptyBuffer_l(header, flags, timestamp, (intptr_t)buffer);
+}
+
+// log queued buffer activity for the next few input and/or output frames
+// if logging at internal state level
+void OMXNodeInstance::bumpDebugLevel_l(size_t numInputBuffers, size_t numOutputBuffers) {
+    if (DEBUG == ADebug::kDebugInternalState) {
+        DEBUG_BUMP = ADebug::kDebugAll;
+        if (numInputBuffers > 0) {
+            mDebugLevelBumpPendingBuffers[kPortIndexInput] = numInputBuffers;
+        }
+        if (numOutputBuffers > 0) {
+            mDebugLevelBumpPendingBuffers[kPortIndexOutput] = numOutputBuffers;
+        }
+    }
+}
+
+void OMXNodeInstance::unbumpDebugLevel_l(size_t portIndex) {
+    if (mDebugLevelBumpPendingBuffers[portIndex]) {
+        --mDebugLevelBumpPendingBuffers[portIndex];
+    }
+    if (!mDebugLevelBumpPendingBuffers[0]
+            && !mDebugLevelBumpPendingBuffers[1]) {
+        DEBUG_BUMP = DEBUG;
+    }
+}
+
+status_t OMXNodeInstance::emptyBuffer_l(
+        OMX_BUFFERHEADERTYPE *header, OMX_U32 flags, OMX_TICKS timestamp, intptr_t debugAddr) {
+    header->nFlags = flags;
+    header->nTimeStamp = timestamp;
+
+    {
+        Mutex::Autolock _l(mDebugLock);
+        mInputBuffersWithCodec.add(header);
+
+        // bump internal-state debug level for 2 input frames past a buffer with CSD
+        if ((flags & OMX_BUFFERFLAG_CODECCONFIG) != 0) {
+            bumpDebugLevel_l(2 /* numInputBuffers */, 0 /* numOutputBuffers */);
+        }
+
+        CLOG_BUMPED_BUFFER(emptyBuffer, WITH_STATS(FULL_BUFFER(debugAddr, header)));
+    }
+
     OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
+    CLOG_IF_ERROR(emptyBuffer, err, FULL_BUFFER(debugAddr, header));
+
+    {
+        Mutex::Autolock _l(mDebugLock);
+        if (err != OMX_ErrorNone) {
+            mInputBuffersWithCodec.remove(header);
+        } else if (!(flags & OMX_BUFFERFLAG_CODECCONFIG)) {
+            unbumpDebugLevel_l(kPortIndexInput);
+        }
+    }
 
     return StatusFromOMXError(err);
 }
@@ -896,15 +1055,8 @@
 
     header->nFilledLen = rangeLength;
     header->nOffset = rangeOffset;
-    header->nFlags = flags;
-    header->nTimeStamp = timestamp;
 
-    OMX_ERRORTYPE err = OMX_EmptyThisBuffer(mHandle, header);
-    if (err != OMX_ErrorNone) {
-        ALOGW("emptyDirectBuffer failed, OMX err=0x%x", err);
-    }
-
-    return StatusFromOMXError(err);
+    return emptyBuffer_l(header, flags, timestamp, (intptr_t)header->pBuffer);
 }
 
 status_t OMXNodeInstance::getExtensionIndex(
@@ -917,11 +1069,25 @@
     return StatusFromOMXError(err);
 }
 
+inline static const char *asString(IOMX::InternalOptionType i, const char *def = "??") {
+    switch (i) {
+        case IOMX::INTERNAL_OPTION_SUSPEND:           return "SUSPEND";
+        case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
+            return "REPEAT_PREVIOUS_FRAME_DELAY";
+        case IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP: return "MAX_TIMESTAMP_GAP";
+        case IOMX::INTERNAL_OPTION_START_TIME:        return "START_TIME";
+        case IOMX::INTERNAL_OPTION_TIME_LAPSE:        return "TIME_LAPSE";
+        default:                                      return def;
+    }
+}
+
 status_t OMXNodeInstance::setInternalOption(
         OMX_U32 portIndex,
         IOMX::InternalOptionType type,
         const void *data,
         size_t size) {
+    CLOG_CONFIG(setInternalOption, "%s(%d): %s:%u %zu@%p",
+            asString(type), type, portString(portIndex), portIndex, size, data);
     switch (type) {
         case IOMX::INTERNAL_OPTION_SUSPEND:
         case IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY:
@@ -933,6 +1099,7 @@
                 getGraphicBufferSource();
 
             if (bufferSource == NULL || portIndex != kPortIndexInput) {
+                CLOGW("setInternalOption is only for Surface input");
                 return ERROR_UNSUPPORTED;
             }
 
@@ -942,6 +1109,7 @@
                 }
 
                 bool suspend = *(bool *)data;
+                CLOG_CONFIG(setInternalOption, "suspend=%d", suspend);
                 bufferSource->suspend(suspend);
             } else if (type ==
                     IOMX::INTERNAL_OPTION_REPEAT_PREVIOUS_FRAME_DELAY){
@@ -950,7 +1118,7 @@
                 }
 
                 int64_t delayUs = *(int64_t *)data;
-
+                CLOG_CONFIG(setInternalOption, "delayUs=%lld", (long long)delayUs);
                 return bufferSource->setRepeatPreviousFrameDelayUs(delayUs);
             } else if (type ==
                     IOMX::INTERNAL_OPTION_MAX_TIMESTAMP_GAP){
@@ -959,7 +1127,7 @@
                 }
 
                 int64_t maxGapUs = *(int64_t *)data;
-
+                CLOG_CONFIG(setInternalOption, "gapUs=%lld", (long long)maxGapUs);
                 return bufferSource->setMaxTimestampGapUs(maxGapUs);
             } else if (type == IOMX::INTERNAL_OPTION_START_TIME) {
                 if (size != sizeof(int64_t)) {
@@ -967,13 +1135,18 @@
                 }
 
                 int64_t skipFramesBeforeUs = *(int64_t *)data;
-
+                CLOG_CONFIG(setInternalOption, "beforeUs=%lld", (long long)skipFramesBeforeUs);
                 bufferSource->setSkipFramesBeforeUs(skipFramesBeforeUs);
             } else { // IOMX::INTERNAL_OPTION_TIME_LAPSE
                 if (size != sizeof(int64_t) * 2) {
                     return INVALID_OPERATION;
                 }
 
+                int64_t timePerFrameUs = ((int64_t *)data)[0];
+                int64_t timePerCaptureUs = ((int64_t *)data)[1];
+                CLOG_CONFIG(setInternalOption, "perFrameUs=%lld perCaptureUs=%lld",
+                        (long long)timePerFrameUs, (long long)timePerCaptureUs);
+
                 bufferSource->setTimeLapseUs((int64_t *)data);
             }
 
@@ -992,6 +1165,16 @@
         OMX_BUFFERHEADERTYPE *buffer =
             findBufferHeader(msg.u.extended_buffer_data.buffer);
 
+        {
+            Mutex::Autolock _l(mDebugLock);
+            mOutputBuffersWithCodec.remove(buffer);
+
+            CLOG_BUMPED_BUFFER(
+                    FBD, WITH_STATS(FULL_BUFFER(msg.u.extended_buffer_data.buffer, buffer)));
+
+            unbumpDebugLevel_l(kPortIndexOutput);
+        }
+
         BufferMeta *buffer_meta =
             static_cast<BufferMeta *>(buffer->pAppPrivate);
 
@@ -1007,16 +1190,23 @@
             return;
         }
     } else if (msg.type == omx_message::EMPTY_BUFFER_DONE) {
+        OMX_BUFFERHEADERTYPE *buffer =
+            findBufferHeader(msg.u.buffer_data.buffer);
+
+        {
+            Mutex::Autolock _l(mDebugLock);
+            mInputBuffersWithCodec.remove(buffer);
+
+            CLOG_BUMPED_BUFFER(
+                    EBD, WITH_STATS(EMPTY_BUFFER(msg.u.buffer_data.buffer, buffer)));
+        }
+
         if (bufferSource != NULL) {
             // This is one of the buffers used exclusively by
             // GraphicBufferSource.
             // Don't dispatch a message back to ACodec, since it doesn't
             // know that anyone asked to have the buffer emptied and will
             // be very confused.
-
-            OMX_BUFFERHEADERTYPE *buffer =
-                findBufferHeader(msg.u.buffer_data.buffer);
-
             bufferSource->codecBufferEmptied(buffer);
             return;
         }
@@ -1040,6 +1230,43 @@
 // Don't try to acquire mLock here -- in rare circumstances this will hang.
 void OMXNodeInstance::onEvent(
         OMX_EVENTTYPE event, OMX_U32 arg1, OMX_U32 arg2) {
+    const char *arg1String = "??";
+    const char *arg2String = "??";
+    ADebug::Level level = ADebug::kDebugInternalState;
+
+    switch (event) {
+        case OMX_EventCmdComplete:
+            arg1String = asString((OMX_COMMANDTYPE)arg1);
+            switch (arg1) {
+                case OMX_CommandStateSet:
+                    arg2String = asString((OMX_STATETYPE)arg2);
+                    level = ADebug::kDebugState;
+                    break;
+                case OMX_CommandFlush:
+                case OMX_CommandPortEnable:
+                {
+                    // bump internal-state debug level for 2 input and output frames
+                    Mutex::Autolock _l(mDebugLock);
+                    bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */);
+                }
+                // fall through
+                default:
+                    arg2String = portString(arg2);
+            }
+            break;
+        case OMX_EventError:
+            arg1String = asString((OMX_ERRORTYPE)arg1);
+            level = ADebug::kDebugLifeCycle;
+            break;
+        case OMX_EventPortSettingsChanged:
+            arg2String = asString((OMX_INDEXEXTTYPE)arg2);
+            // fall through
+        default:
+            arg1String = portString(arg1);
+    }
+
+    CLOGI_(level, onEvent, "%s(%x), %s(%x), %s(%x)",
+            asString(event), event, arg1String, arg1, arg2String, arg2);
     const sp<GraphicBufferSource>& bufferSource(getGraphicBufferSource());
 
     if (bufferSource != NULL
@@ -1097,23 +1324,27 @@
     active.mPortIndex = portIndex;
     active.mID = id;
     mActiveBuffers.push(active);
+
+    if (portIndex < NELEM(mNumPortBuffers)) {
+        ++mNumPortBuffers[portIndex];
+    }
 }
 
 void OMXNodeInstance::removeActiveBuffer(
         OMX_U32 portIndex, OMX::buffer_id id) {
-    bool found = false;
     for (size_t i = 0; i < mActiveBuffers.size(); ++i) {
         if (mActiveBuffers[i].mPortIndex == portIndex
-            && mActiveBuffers[i].mID == id) {
-            found = true;
+                && mActiveBuffers[i].mID == id) {
             mActiveBuffers.removeItemsAt(i);
-            break;
+
+            if (portIndex < NELEM(mNumPortBuffers)) {
+                --mNumPortBuffers[portIndex];
+            }
+            return;
         }
     }
 
-    if (!found) {
-        ALOGW("Attempt to remove an active buffer we know nothing about...");
-    }
+     CLOGW("Attempt to remove an active buffer [%#x] we know nothing about...", id);
 }
 
 void OMXNodeInstance::freeActiveBuffers() {
@@ -1134,7 +1365,7 @@
     OMX::buffer_id buffer;
     do { // handle the very unlikely case of ID overflow
         if (++mBufferIDCount == 0) {
-           ++mBufferIDCount;
+            ++mBufferIDCount;
         }
         buffer = (OMX::buffer_id)mBufferIDCount;
     } while (mBufferIDToBufferHeader.indexOfKey(buffer) >= 0);
diff --git a/media/libstagefright/omx/SoftOMXComponent.cpp b/media/libstagefright/omx/SoftOMXComponent.cpp
index 646cd32..df978f8 100644
--- a/media/libstagefright/omx/SoftOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftOMXComponent.cpp
@@ -283,7 +283,7 @@
 
 OMX_ERRORTYPE SoftOMXComponent::getExtensionIndex(
         const char * /* name */, OMX_INDEXTYPE * /* index */) {
-    return OMX_ErrorUndefined;
+    return OMX_ErrorUnsupportedIndex;
 }
 
 OMX_ERRORTYPE SoftOMXComponent::useBuffer(
diff --git a/media/libstagefright/tests/Utils_test.cpp b/media/libstagefright/tests/Utils_test.cpp
index f2825dd..43e0269 100644
--- a/media/libstagefright/tests/Utils_test.cpp
+++ b/media/libstagefright/tests/Utils_test.cpp
@@ -24,6 +24,7 @@
 #include <unistd.h>
 
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AStringUtils.h>
 #include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/Utils.h>
 
@@ -32,6 +33,100 @@
 class UtilsTest : public ::testing::Test {
 };
 
+TEST_F(UtilsTest, TestStringUtils) {
+    ASSERT_EQ(AStringUtils::Compare("Audio", "AudioExt", 5, false), 0);
+    ASSERT_EQ(AStringUtils::Compare("Audio", "audiOExt", 5, true), 0);
+    ASSERT_NE(AStringUtils::Compare("Audio", "audioExt", 5, false), 0);
+    ASSERT_NE(AStringUtils::Compare("Audio", "AudiOExt", 5, false), 0);
+
+    ASSERT_LT(AStringUtils::Compare("Audio", "AudioExt", 7, false), 0);
+    ASSERT_LT(AStringUtils::Compare("Audio", "audiOExt", 7, true), 0);
+
+    ASSERT_GT(AStringUtils::Compare("AudioExt", "Audio", 7, false), 0);
+    ASSERT_GT(AStringUtils::Compare("audiOext", "Audio", 7, true), 0);
+
+    ASSERT_LT(AStringUtils::Compare("Audio", "Video", 5, false), 0);
+    ASSERT_LT(AStringUtils::Compare("Audio1", "Audio2", 6, false), 0);
+    ASSERT_LT(AStringUtils::Compare("audio", "VIDEO", 5, true), 0);
+    ASSERT_LT(AStringUtils::Compare("audio1", "AUDIO2", 6, true), 0);
+
+    ASSERT_GT(AStringUtils::Compare("Video", "Audio", 5, false), 0);
+    ASSERT_GT(AStringUtils::Compare("Audio2", "Audio1", 6, false), 0);
+    ASSERT_GT(AStringUtils::Compare("VIDEO", "audio", 5, true), 0);
+    ASSERT_GT(AStringUtils::Compare("AUDIO2", "audio1", 6, true), 0);
+
+    ASSERT_TRUE(AStringUtils::MatchesGlob("AudioA", 5, "AudioB", 5, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("AudioA", 6, "AudioA", 5, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("AudioA", 5, "AudioA", 6, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("AudioA", 5, "audiOB", 5, false));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("AudioA", 5, "audiOB", 5, true));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("AudioA", 6, "AudioA", 5, true));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("AudioA", 5, "AudioA", 6, true));
+
+    ASSERT_TRUE(AStringUtils::MatchesGlob("*1", 1, "String8", 6, true));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("*1", 1, "String8", 6, false));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("*1", 1, "String8", 0, true));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("*1", 1, "String8", 0, false));
+
+    ASSERT_TRUE(AStringUtils::MatchesGlob("*ring1", 5, "String8", 6, false));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("*ring2", 5, "STRING8", 6, true));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("*ring4", 5, "StRing8", 6, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("*ring5", 5, "StrinG8", 6, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("*ring8", 5, "String8", 7, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("*ring8", 5, "String8", 7, true));
+
+    ASSERT_TRUE(AStringUtils::MatchesGlob("Str*1", 4, "String8", 6, false));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("Str*2", 4, "STRING8", 6, true));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*3", 4, "string8", 6, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*4", 4, "StRing8", 6, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*5", 4, "AString8", 7, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*6", 4, "AString8", 7, true));
+
+    ASSERT_TRUE(AStringUtils::MatchesGlob("Str*ng1", 6, "String8", 6, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*ng2", 6, "string8", 6, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*ng3", 6, "StRing8", 6, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*ng4", 6, "StriNg8", 6, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*ng5", 6, "StrinG8", 6, false));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("Str*ng6", 6, "STRING8", 6, true));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*ng8", 6, "AString8", 7, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*ng1", 6, "String16", 7, false));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("Str*ing9", 7, "String8", 6, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*ringA", 8, "String8", 6, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*ng8", 6, "AString8", 7, true));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*ng1", 6, "String16", 7, true));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("Str*ing9", 7, "STRING8", 6, true));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("Str*ringA", 8, "String8", 6, true));
+
+    ASSERT_TRUE(AStringUtils::MatchesGlob("*str*str1", 8, "bestrestroom", 9, false));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("*str*str1", 8, "bestrestrestroom", 13, false));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("*str*stro", 8, "bestrestrestroom", 14, false));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("*str*str*1", 9, "bestrestrestroom", 14, false));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("*str*str1", 8, "beSTReSTRoom", 9, true));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("*str*str1", 8, "beSTRestreSTRoom", 13, true));
+    ASSERT_FALSE(AStringUtils::MatchesGlob("*str*stro", 8, "bestreSTReSTRoom", 14, true));
+    ASSERT_TRUE(AStringUtils::MatchesGlob("*str*str*1", 9, "bestreSTReSTRoom", 14, true));
+}
+
+TEST_F(UtilsTest, TestDebug) {
+#define LVL(x) (ADebug::Level)(x)
+    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "", LVL(5)), LVL(5));
+    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "   \t  \n ", LVL(2)), LVL(2));
+    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "3", LVL(5)), LVL(3));
+    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "3:*deo", LVL(5)), LVL(3));
+    ASSERT_EQ(ADebug::GetDebugLevelFromString(
+            "video", "\t\n 3 \t\n:\t\n video \t\n", LVL(5)), LVL(3));
+    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "3:*deo,2:vid*", LVL(5)), LVL(2));
+    ASSERT_EQ(ADebug::GetDebugLevelFromString(
+            "avideo", "\t\n 3 \t\n:\t\n avideo \t\n,\t\n 2 \t\n:\t\n video \t\n", LVL(5)), LVL(3));
+    ASSERT_EQ(ADebug::GetDebugLevelFromString(
+            "audio.omx", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(2));
+    ASSERT_EQ(ADebug::GetDebugLevelFromString(
+            "video.omx", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(3));
+    ASSERT_EQ(ADebug::GetDebugLevelFromString("video", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(3));
+    ASSERT_EQ(ADebug::GetDebugLevelFromString("omx", "4:*omx,3:*d*o*,2:audio*", LVL(5)), LVL(4));
+#undef LVL
+}
+
 TEST_F(UtilsTest, TestFourCC) {
     ASSERT_EQ(FOURCC('s', 't', 'm' , 'u'), 'stmu');
 }
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index e6e19e3..052b700 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -51,104 +51,178 @@
     MtpPacket::putUInt32(MTP_CONTAINER_TRANSACTION_ID_OFFSET, id);
 }
 
-uint16_t MtpDataPacket::getUInt16() {
-    int offset = mOffset;
-    uint16_t result = (uint16_t)mBuffer[offset] | ((uint16_t)mBuffer[offset + 1] << 8);
-    mOffset += 2;
-    return result;
+bool MtpDataPacket::getUInt8(uint8_t& value) {
+    if (mPacketSize - mOffset < sizeof(value))
+        return false;
+    value = mBuffer[mOffset++];
+    return true;
 }
 
-uint32_t MtpDataPacket::getUInt32() {
+bool MtpDataPacket::getUInt16(uint16_t& value) {
+    if (mPacketSize - mOffset < sizeof(value))
+        return false;
     int offset = mOffset;
-    uint32_t result = (uint32_t)mBuffer[offset] | ((uint32_t)mBuffer[offset + 1] << 8) |
+    value = (uint16_t)mBuffer[offset] | ((uint16_t)mBuffer[offset + 1] << 8);
+    mOffset += sizeof(value);
+    return true;
+}
+
+bool MtpDataPacket::getUInt32(uint32_t& value) {
+    if (mPacketSize - mOffset < sizeof(value))
+        return false;
+    int offset = mOffset;
+    value = (uint32_t)mBuffer[offset] | ((uint32_t)mBuffer[offset + 1] << 8) |
            ((uint32_t)mBuffer[offset + 2] << 16)  | ((uint32_t)mBuffer[offset + 3] << 24);
-    mOffset += 4;
-    return result;
+    mOffset += sizeof(value);
+    return true;
 }
 
-uint64_t MtpDataPacket::getUInt64() {
+bool MtpDataPacket::getUInt64(uint64_t& value) {
+    if (mPacketSize - mOffset < sizeof(value))
+        return false;
     int offset = mOffset;
-    uint64_t result = (uint64_t)mBuffer[offset] | ((uint64_t)mBuffer[offset + 1] << 8) |
+    value = (uint64_t)mBuffer[offset] | ((uint64_t)mBuffer[offset + 1] << 8) |
            ((uint64_t)mBuffer[offset + 2] << 16) | ((uint64_t)mBuffer[offset + 3] << 24) |
            ((uint64_t)mBuffer[offset + 4] << 32) | ((uint64_t)mBuffer[offset + 5] << 40) |
            ((uint64_t)mBuffer[offset + 6] << 48)  | ((uint64_t)mBuffer[offset + 7] << 56);
-    mOffset += 8;
-    return result;
+    mOffset += sizeof(value);
+    return true;
 }
 
-void MtpDataPacket::getUInt128(uint128_t& value) {
-    value[0] = getUInt32();
-    value[1] = getUInt32();
-    value[2] = getUInt32();
-    value[3] = getUInt32();
+bool MtpDataPacket::getUInt128(uint128_t& value) {
+    return getUInt32(value[0]) && getUInt32(value[1]) && getUInt32(value[2]) && getUInt32(value[3]);
 }
 
-void MtpDataPacket::getString(MtpStringBuffer& string)
+bool MtpDataPacket::getString(MtpStringBuffer& string)
 {
-    string.readFromPacket(this);
+    return string.readFromPacket(this);
 }
 
 Int8List* MtpDataPacket::getAInt8() {
+    uint32_t count;
+    if (!getUInt32(count))
+        return NULL;
     Int8List* result = new Int8List;
-    int count = getUInt32();
-    for (int i = 0; i < count; i++)
-        result->push(getInt8());
+    for (uint32_t i = 0; i < count; i++) {
+        int8_t value;
+        if (!getInt8(value)) {
+            delete result;
+            return NULL;
+        }
+        result->push(value);
+    }
     return result;
 }
 
 UInt8List* MtpDataPacket::getAUInt8() {
+    uint32_t count;
+    if (!getUInt32(count))
+        return NULL;
     UInt8List* result = new UInt8List;
-    int count = getUInt32();
-    for (int i = 0; i < count; i++)
-        result->push(getUInt8());
+    for (uint32_t i = 0; i < count; i++) {
+        uint8_t value;
+        if (!getUInt8(value)) {
+            delete result;
+            return NULL;
+        }
+        result->push(value);
+    }
     return result;
 }
 
 Int16List* MtpDataPacket::getAInt16() {
+    uint32_t count;
+    if (!getUInt32(count))
+        return NULL;
     Int16List* result = new Int16List;
-    int count = getUInt32();
-    for (int i = 0; i < count; i++)
-        result->push(getInt16());
+    for (uint32_t i = 0; i < count; i++) {
+        int16_t value;
+        if (!getInt16(value)) {
+            delete result;
+            return NULL;
+        }
+        result->push(value);
+    }
     return result;
 }
 
 UInt16List* MtpDataPacket::getAUInt16() {
+    uint32_t count;
+    if (!getUInt32(count))
+        return NULL;
     UInt16List* result = new UInt16List;
-    int count = getUInt32();
-    for (int i = 0; i < count; i++)
-        result->push(getUInt16());
+    for (uint32_t i = 0; i < count; i++) {
+        uint16_t value;
+        if (!getUInt16(value)) {
+            delete result;
+            return NULL;
+        }
+        result->push(value);
+    }
     return result;
 }
 
 Int32List* MtpDataPacket::getAInt32() {
+    uint32_t count;
+    if (!getUInt32(count))
+        return NULL;
     Int32List* result = new Int32List;
-    int count = getUInt32();
-    for (int i = 0; i < count; i++)
-        result->push(getInt32());
+    for (uint32_t i = 0; i < count; i++) {
+        int32_t value;
+        if (!getInt32(value)) {
+            delete result;
+            return NULL;
+        }
+        result->push(value);
+    }
     return result;
 }
 
 UInt32List* MtpDataPacket::getAUInt32() {
+    uint32_t count;
+    if (!getUInt32(count))
+        return NULL;
     UInt32List* result = new UInt32List;
-    int count = getUInt32();
-    for (int i = 0; i < count; i++)
-        result->push(getUInt32());
+    for (uint32_t i = 0; i < count; i++) {
+        uint32_t value;
+        if (!getUInt32(value)) {
+            delete result;
+            return NULL;
+        }
+        result->push(value);
+    }
     return result;
 }
 
 Int64List* MtpDataPacket::getAInt64() {
+    uint32_t count;
+    if (!getUInt32(count))
+        return NULL;
     Int64List* result = new Int64List;
-    int count = getUInt32();
-    for (int i = 0; i < count; i++)
-        result->push(getInt64());
+    for (uint32_t i = 0; i < count; i++) {
+        int64_t value;
+        if (!getInt64(value)) {
+            delete result;
+            return NULL;
+        }
+        result->push(value);
+    }
     return result;
 }
 
 UInt64List* MtpDataPacket::getAUInt64() {
+    uint32_t count;
+    if (!getUInt32(count))
+        return NULL;
     UInt64List* result = new UInt64List;
-    int count = getUInt32();
-    for (int i = 0; i < count; i++)
-        result->push(getUInt64());
+    for (uint32_t i = 0; i < count; i++) {
+        uint64_t value;
+        if (!getUInt64(value)) {
+            delete result;
+            return NULL;
+        }
+        result->push(value);
+    }
     return result;
 }
 
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 2b81063..13d3bd9 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -30,7 +30,7 @@
 class MtpDataPacket : public MtpPacket {
 private:
     // current offset for get/put methods
-    int                 mOffset;
+    size_t              mOffset;
 
 public:
                         MtpDataPacket();
@@ -42,17 +42,18 @@
     void                setTransactionID(MtpTransactionID id);
 
     inline const uint8_t*     getData() const { return mBuffer + MTP_CONTAINER_HEADER_SIZE; }
-    inline uint8_t      getUInt8() { return (uint8_t)mBuffer[mOffset++]; }
-    inline int8_t       getInt8() { return (int8_t)mBuffer[mOffset++]; }
-    uint16_t            getUInt16();
-    inline int16_t      getInt16() { return (int16_t)getUInt16(); }
-    uint32_t            getUInt32();
-    inline int32_t      getInt32() { return (int32_t)getUInt32(); }
-    uint64_t            getUInt64();
-    inline int64_t      getInt64() { return (int64_t)getUInt64(); }
-    void                getUInt128(uint128_t& value);
-    inline void         getInt128(int128_t& value) { getUInt128((uint128_t&)value); }
-    void                getString(MtpStringBuffer& string);
+
+    bool                getUInt8(uint8_t& value);
+    inline bool         getInt8(int8_t& value) { return getUInt8((uint8_t&)value); }
+    bool                getUInt16(uint16_t& value);
+    inline bool         getInt16(int16_t& value) { return getUInt16((uint16_t&)value); }
+    bool                getUInt32(uint32_t& value);
+    inline bool         getInt32(int32_t& value) { return getUInt32((uint32_t&)value); }
+    bool                getUInt64(uint64_t& value);
+    inline bool         getInt64(int64_t& value) { return getUInt64((uint64_t&)value); }
+    bool                getUInt128(uint128_t& value);
+    inline bool         getInt128(int128_t& value) { return getUInt128((uint128_t&)value); }
+    bool                getString(MtpStringBuffer& string);
 
     Int8List*           getAInt8();
     UInt8List*          getAUInt8();
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index d6d5dd5..e0d679d 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -313,8 +313,10 @@
     MtpResponseCode ret = readResponse();
     if (ret == MTP_RESPONSE_OK) {
         MtpDeviceInfo* info = new MtpDeviceInfo;
-        info->read(mData);
-        return info;
+        if (info->read(mData))
+            return info;
+        else
+            delete info;
     }
     return NULL;
 }
@@ -346,8 +348,10 @@
     MtpResponseCode ret = readResponse();
     if (ret == MTP_RESPONSE_OK) {
         MtpStorageInfo* info = new MtpStorageInfo(storageID);
-        info->read(mData);
-        return info;
+        if (info->read(mData))
+            return info;
+        else
+            delete info;
     }
     return NULL;
 }
@@ -385,8 +389,10 @@
     MtpResponseCode ret = readResponse();
     if (ret == MTP_RESPONSE_OK) {
         MtpObjectInfo* info = new MtpObjectInfo(handle);
-        info->read(mData);
-        return info;
+        if (info->read(mData))
+            return info;
+        else
+            delete info;
     }
     return NULL;
 }
@@ -547,8 +553,10 @@
     MtpResponseCode ret = readResponse();
     if (ret == MTP_RESPONSE_OK) {
         MtpProperty* property = new MtpProperty;
-        property->read(mData);
-        return property;
+        if (property->read(mData))
+            return property;
+        else
+            delete property;
     }
     return NULL;
 }
@@ -566,15 +574,17 @@
     MtpResponseCode ret = readResponse();
     if (ret == MTP_RESPONSE_OK) {
         MtpProperty* property = new MtpProperty;
-        property->read(mData);
-        return property;
+        if (property->read(mData))
+            return property;
+        else
+            delete property;
     }
     return NULL;
 }
 
 bool MtpDevice::readObject(MtpObjectHandle handle,
         bool (* callback)(void* data, int offset, int length, void* clientData),
-        int objectSize, void* clientData) {
+        size_t objectSize, void* clientData) {
     Mutex::Autolock autoLock(mMutex);
     bool result = false;
 
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index b69203e..9b0acbf 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -98,7 +98,7 @@
     bool                    readObject(MtpObjectHandle handle,
                                     bool (* callback)(void* data, int offset,
                                             int length, void* clientData),
-                                    int objectSize, void* clientData);
+                                    size_t objectSize, void* clientData);
     bool                    readObject(MtpObjectHandle handle, const char* destPath, int group,
                                     int perm);
 
diff --git a/media/mtp/MtpDeviceInfo.cpp b/media/mtp/MtpDeviceInfo.cpp
index 108e2b8..3e1dff7 100644
--- a/media/mtp/MtpDeviceInfo.cpp
+++ b/media/mtp/MtpDeviceInfo.cpp
@@ -28,7 +28,7 @@
         mVendorExtensionID(0),
         mVendorExtensionVersion(0),
         mVendorExtensionDesc(NULL),
-        mFunctionalCode(0),
+        mFunctionalMode(0),
         mOperations(NULL),
         mEvents(NULL),
         mDeviceProperties(NULL),
@@ -59,39 +59,46 @@
         free(mSerial);
 }
 
-void MtpDeviceInfo::read(MtpDataPacket& packet) {
+bool MtpDeviceInfo::read(MtpDataPacket& packet) {
     MtpStringBuffer string;
 
     // read the device info
-    mStandardVersion = packet.getUInt16();
-    mVendorExtensionID = packet.getUInt32();
-    mVendorExtensionVersion = packet.getUInt16();
+    if (!packet.getUInt16(mStandardVersion)) return false;
+    if (!packet.getUInt32(mVendorExtensionID)) return false;
+    if (!packet.getUInt16(mVendorExtensionVersion)) return false;
 
-    packet.getString(string);
+    if (!packet.getString(string)) return false;
     mVendorExtensionDesc = strdup((const char *)string);
 
-    mFunctionalCode = packet.getUInt16();
+    if (!packet.getUInt16(mFunctionalMode)) return false;
     mOperations = packet.getAUInt16();
+    if (!mOperations) return false;
     mEvents = packet.getAUInt16();
+    if (!mEvents) return false;
     mDeviceProperties = packet.getAUInt16();
+    if (!mDeviceProperties) return false;
     mCaptureFormats = packet.getAUInt16();
+    if (!mCaptureFormats) return false;
     mPlaybackFormats = packet.getAUInt16();
+    if (!mCaptureFormats) return false;
 
-    packet.getString(string);
+    if (!packet.getString(string)) return false;
     mManufacturer = strdup((const char *)string);
-    packet.getString(string);
+    if (!packet.getString(string)) return false;
     mModel = strdup((const char *)string);
-    packet.getString(string);
+    if (!packet.getString(string)) return false;
     mVersion = strdup((const char *)string);
-    packet.getString(string);
+    if (!packet.getString(string)) return false;
     mSerial = strdup((const char *)string);
+
+    return true;
 }
 
 void MtpDeviceInfo::print() {
     ALOGV("Device Info:\n\tmStandardVersion: %d\n\tmVendorExtensionID: %d\n\tmVendorExtensionVersiony: %d\n",
             mStandardVersion, mVendorExtensionID, mVendorExtensionVersion);
-    ALOGV("\tmVendorExtensionDesc: %s\n\tmFunctionalCode: %d\n\tmManufacturer: %s\n\tmModel: %s\n\tmVersion: %s\n\tmSerial: %s\n",
-            mVendorExtensionDesc, mFunctionalCode, mManufacturer, mModel, mVersion, mSerial);
+    ALOGV("\tmVendorExtensionDesc: %s\n\tmFunctionalMode: %d\n\tmManufacturer: %s\n\tmModel: %s\n\tmVersion: %s\n\tmSerial: %s\n",
+            mVendorExtensionDesc, mFunctionalMode, mManufacturer, mModel, mVersion, mSerial);
 }
 
 }  // namespace android
diff --git a/media/mtp/MtpDeviceInfo.h b/media/mtp/MtpDeviceInfo.h
index 2abaa10..bcda9a5 100644
--- a/media/mtp/MtpDeviceInfo.h
+++ b/media/mtp/MtpDeviceInfo.h
@@ -29,7 +29,7 @@
     uint32_t                mVendorExtensionID;
     uint16_t                mVendorExtensionVersion;
     char*                   mVendorExtensionDesc;
-    uint16_t                mFunctionalCode;
+    uint16_t                mFunctionalMode;
     UInt16List*             mOperations;
     UInt16List*             mEvents;
     MtpDevicePropertyList*  mDeviceProperties;
@@ -44,7 +44,7 @@
                             MtpDeviceInfo();
     virtual                 ~MtpDeviceInfo();
 
-    void                    read(MtpDataPacket& packet);
+    bool                    read(MtpDataPacket& packet);
 
     void                    print();
 };
diff --git a/media/mtp/MtpObjectInfo.cpp b/media/mtp/MtpObjectInfo.cpp
index cd15343..0573104 100644
--- a/media/mtp/MtpObjectInfo.cpp
+++ b/media/mtp/MtpObjectInfo.cpp
@@ -55,39 +55,41 @@
         free(mKeywords);
 }
 
-void MtpObjectInfo::read(MtpDataPacket& packet) {
+bool MtpObjectInfo::read(MtpDataPacket& packet) {
     MtpStringBuffer string;
     time_t time;
 
-    mStorageID = packet.getUInt32();
-    mFormat = packet.getUInt16();
-    mProtectionStatus = packet.getUInt16();
-    mCompressedSize = packet.getUInt32();
-    mThumbFormat = packet.getUInt16();
-    mThumbCompressedSize = packet.getUInt32();
-    mThumbPixWidth = packet.getUInt32();
-    mThumbPixHeight = packet.getUInt32();
-    mImagePixWidth = packet.getUInt32();
-    mImagePixHeight = packet.getUInt32();
-    mImagePixDepth = packet.getUInt32();
-    mParent = packet.getUInt32();
-    mAssociationType = packet.getUInt16();
-    mAssociationDesc = packet.getUInt32();
-    mSequenceNumber = packet.getUInt32();
+    if (!packet.getUInt32(mStorageID)) return false;
+    if (!packet.getUInt16(mFormat)) return false;
+    if (!packet.getUInt16(mProtectionStatus)) return false;
+    if (!packet.getUInt32(mCompressedSize)) return false;
+    if (!packet.getUInt16(mThumbFormat)) return false;
+    if (!packet.getUInt32(mThumbCompressedSize)) return false;
+    if (!packet.getUInt32(mThumbPixWidth)) return false;
+    if (!packet.getUInt32(mThumbPixHeight)) return false;
+    if (!packet.getUInt32(mImagePixWidth)) return false;
+    if (!packet.getUInt32(mImagePixHeight)) return false;
+    if (!packet.getUInt32(mImagePixDepth)) return false;
+    if (!packet.getUInt32(mParent)) return false;
+    if (!packet.getUInt16(mAssociationType)) return false;
+    if (!packet.getUInt32(mAssociationDesc)) return false;
+    if (!packet.getUInt32(mSequenceNumber)) return false;
 
-    packet.getString(string);
+    if (!packet.getString(string)) return false;
     mName = strdup((const char *)string);
 
-    packet.getString(string);
+    if (!packet.getString(string)) return false;
     if (parseDateTime((const char*)string, time))
         mDateCreated = time;
 
-    packet.getString(string);
+    if (!packet.getString(string)) return false;
     if (parseDateTime((const char*)string, time))
         mDateModified = time;
 
-    packet.getString(string);
+    if (!packet.getString(string)) return false;
     mKeywords = strdup((const char *)string);
+
+    return true;
 }
 
 void MtpObjectInfo::print() {
diff --git a/media/mtp/MtpObjectInfo.h b/media/mtp/MtpObjectInfo.h
index c7a449c..86780f1 100644
--- a/media/mtp/MtpObjectInfo.h
+++ b/media/mtp/MtpObjectInfo.h
@@ -50,7 +50,7 @@
                         MtpObjectInfo(MtpObjectHandle handle);
     virtual             ~MtpObjectInfo();
 
-    void                read(MtpDataPacket& packet);
+    bool                read(MtpDataPacket& packet);
 
     void                print();
 };
diff --git a/media/mtp/MtpPacket.cpp b/media/mtp/MtpPacket.cpp
index dd07843..bab1335 100644
--- a/media/mtp/MtpPacket.cpp
+++ b/media/mtp/MtpPacket.cpp
@@ -52,7 +52,7 @@
     memset(mBuffer, 0, mBufferSize);
 }
 
-void MtpPacket::allocate(int length) {
+void MtpPacket::allocate(size_t length) {
     if (length > mBufferSize) {
         int newLength = length + mAllocationIncrement;
         mBuffer = (uint8_t *)realloc(mBuffer, newLength);
diff --git a/media/mtp/MtpPacket.h b/media/mtp/MtpPacket.h
index 0ffb1d3..037722a 100644
--- a/media/mtp/MtpPacket.h
+++ b/media/mtp/MtpPacket.h
@@ -28,11 +28,11 @@
 protected:
     uint8_t*            mBuffer;
     // current size of the buffer
-    int                 mBufferSize;
+    size_t              mBufferSize;
     // number of bytes to add when resizing the buffer
-    int                 mAllocationIncrement;
+    size_t              mAllocationIncrement;
     // size of the data in the packet
-    int                 mPacketSize;
+    size_t              mPacketSize;
 
 public:
                         MtpPacket(int bufferSize);
@@ -41,7 +41,7 @@
     // sets packet size to the default container size and sets buffer to zero
     virtual void        reset();
 
-    void                allocate(int length);
+    void                allocate(size_t length);
     void                dump();
     void                copyFrom(const MtpPacket& src);
 
diff --git a/media/mtp/MtpProperty.cpp b/media/mtp/MtpProperty.cpp
index c500901..d58e2a4 100644
--- a/media/mtp/MtpProperty.cpp
+++ b/media/mtp/MtpProperty.cpp
@@ -106,15 +106,15 @@
         free(mMinimumValue.str);
         free(mMaximumValue.str);
         if (mDefaultArrayValues) {
-            for (int i = 0; i < mDefaultArrayLength; i++)
+            for (uint32_t i = 0; i < mDefaultArrayLength; i++)
                 free(mDefaultArrayValues[i].str);
         }
         if (mCurrentArrayValues) {
-            for (int i = 0; i < mCurrentArrayLength; i++)
+            for (uint32_t i = 0; i < mCurrentArrayLength; i++)
                 free(mCurrentArrayValues[i].str);
         }
         if (mEnumValues) {
-            for (int i = 0; i < mEnumLength; i++)
+            for (uint16_t i = 0; i < mEnumLength; i++)
                 free(mEnumValues[i].str);
         }
     }
@@ -123,11 +123,14 @@
     delete[] mEnumValues;
 }
 
-void MtpProperty::read(MtpDataPacket& packet) {
-    mCode = packet.getUInt16();
+bool MtpProperty::read(MtpDataPacket& packet) {
+    uint8_t temp8;
+
+    if (!packet.getUInt16(mCode)) return false;
     bool deviceProp = isDeviceProperty();
-    mType = packet.getUInt16();
-    mWriteable = (packet.getUInt8() == 1);
+    if (!packet.getUInt16(mType)) return false;
+    if (!packet.getUInt8(temp8)) return false;
+    mWriteable = (temp8 == 1);
     switch (mType) {
         case MTP_TYPE_AINT8:
         case MTP_TYPE_AUINT8:
@@ -140,28 +143,36 @@
         case MTP_TYPE_AINT128:
         case MTP_TYPE_AUINT128:
             mDefaultArrayValues = readArrayValues(packet, mDefaultArrayLength);
-            if (deviceProp)
+            if (!mDefaultArrayValues) return false;
+            if (deviceProp) {
                 mCurrentArrayValues = readArrayValues(packet, mCurrentArrayLength);
+                if (!mCurrentArrayValues) return false;
+            }
             break;
         default:
-            readValue(packet, mDefaultValue);
-            if (deviceProp)
-                readValue(packet, mCurrentValue);
+            if (!readValue(packet, mDefaultValue)) return false;
+            if (deviceProp) {
+                if (!readValue(packet, mCurrentValue)) return false;
+            }
     }
-    if (!deviceProp)
-        mGroupCode = packet.getUInt32();
-    mFormFlag = packet.getUInt8();
+    if (!deviceProp) {
+        if (!packet.getUInt32(mGroupCode)) return false;
+    }
+    if (!packet.getUInt8(mFormFlag)) return false;
 
     if (mFormFlag == kFormRange) {
-            readValue(packet, mMinimumValue);
-            readValue(packet, mMaximumValue);
-            readValue(packet, mStepSize);
+            if (!readValue(packet, mMinimumValue)) return false;
+            if (!readValue(packet, mMaximumValue)) return false;
+            if (!readValue(packet, mStepSize)) return false;
     } else if (mFormFlag == kFormEnum) {
-        mEnumLength = packet.getUInt16();
+        if (!packet.getUInt16(mEnumLength)) return false;
         mEnumValues = new MtpPropertyValue[mEnumLength];
-        for (int i = 0; i < mEnumLength; i++)
-            readValue(packet, mEnumValues[i]);
+        for (int i = 0; i < mEnumLength; i++) {
+            if (!readValue(packet, mEnumValues[i])) return false;
+        }
     }
+
+    return true;
 }
 
 void MtpProperty::write(MtpDataPacket& packet) {
@@ -409,57 +420,59 @@
     }
 }
 
-void MtpProperty::readValue(MtpDataPacket& packet, MtpPropertyValue& value) {
+bool MtpProperty::readValue(MtpDataPacket& packet, MtpPropertyValue& value) {
     MtpStringBuffer stringBuffer;
 
     switch (mType) {
         case MTP_TYPE_INT8:
         case MTP_TYPE_AINT8:
-            value.u.i8 = packet.getInt8();
+            if (!packet.getInt8(value.u.i8)) return false;
             break;
         case MTP_TYPE_UINT8:
         case MTP_TYPE_AUINT8:
-            value.u.u8 = packet.getUInt8();
+            if (!packet.getUInt8(value.u.u8)) return false;
             break;
         case MTP_TYPE_INT16:
         case MTP_TYPE_AINT16:
-            value.u.i16 = packet.getInt16();
+            if (!packet.getInt16(value.u.i16)) return false;
             break;
         case MTP_TYPE_UINT16:
         case MTP_TYPE_AUINT16:
-            value.u.u16 = packet.getUInt16();
+            if (!packet.getUInt16(value.u.u16)) return false;
             break;
         case MTP_TYPE_INT32:
         case MTP_TYPE_AINT32:
-            value.u.i32 = packet.getInt32();
+            if (!packet.getInt32(value.u.i32)) return false;
             break;
         case MTP_TYPE_UINT32:
         case MTP_TYPE_AUINT32:
-            value.u.u32 = packet.getUInt32();
+            if (!packet.getUInt32(value.u.u32)) return false;
             break;
         case MTP_TYPE_INT64:
         case MTP_TYPE_AINT64:
-            value.u.i64 = packet.getInt64();
+            if (!packet.getInt64(value.u.i64)) return false;
             break;
         case MTP_TYPE_UINT64:
         case MTP_TYPE_AUINT64:
-            value.u.u64 = packet.getUInt64();
+            if (!packet.getUInt64(value.u.u64)) return false;
             break;
         case MTP_TYPE_INT128:
         case MTP_TYPE_AINT128:
-            packet.getInt128(value.u.i128);
+            if (!packet.getInt128(value.u.i128)) return false;
             break;
         case MTP_TYPE_UINT128:
         case MTP_TYPE_AUINT128:
-            packet.getUInt128(value.u.u128);
+            if (!packet.getUInt128(value.u.u128)) return false;
             break;
         case MTP_TYPE_STR:
-            packet.getString(stringBuffer);
+            if (!packet.getString(stringBuffer)) return false;
             value.str = strdup(stringBuffer);
             break;
         default:
             ALOGE("unknown type %04X in MtpProperty::readValue", mType);
+            return false;
     }
+    return true;
 }
 
 void MtpProperty::writeValue(MtpDataPacket& packet, MtpPropertyValue& value) {
@@ -517,8 +530,9 @@
     }
 }
 
-MtpPropertyValue* MtpProperty::readArrayValues(MtpDataPacket& packet, int& length) {
-    length = packet.getUInt32();
+MtpPropertyValue* MtpProperty::readArrayValues(MtpDataPacket& packet, uint32_t& length) {
+    if (!packet.getUInt32(length)) return NULL;
+
     // Fail if resulting array is over 2GB.  This is because the maximum array
     // size may be less than SIZE_MAX on some platforms.
     if ( CC_UNLIKELY(
@@ -528,14 +542,17 @@
         return NULL;
     }
     MtpPropertyValue* result = new MtpPropertyValue[length];
-    for (int i = 0; i < length; i++)
-        readValue(packet, result[i]);
+    for (uint32_t i = 0; i < length; i++)
+        if (!readValue(packet, result[i])) {
+            delete result;
+            return NULL;
+        }
     return result;
 }
 
-void MtpProperty::writeArrayValues(MtpDataPacket& packet, MtpPropertyValue* values, int length) {
+void MtpProperty::writeArrayValues(MtpDataPacket& packet, MtpPropertyValue* values, uint32_t length) {
     packet.putUInt32(length);
-    for (int i = 0; i < length; i++)
+    for (uint32_t i = 0; i < length; i++)
         writeValue(packet, values[i]);
 }
 
diff --git a/media/mtp/MtpProperty.h b/media/mtp/MtpProperty.h
index 06ca56e..2e2ead1 100644
--- a/media/mtp/MtpProperty.h
+++ b/media/mtp/MtpProperty.h
@@ -49,9 +49,9 @@
     MtpPropertyValue    mCurrentValue;
 
     // for array types
-    int                 mDefaultArrayLength;
+    uint32_t            mDefaultArrayLength;
     MtpPropertyValue*   mDefaultArrayValues;
-    int                 mCurrentArrayLength;
+    uint32_t            mCurrentArrayLength;
     MtpPropertyValue*   mCurrentArrayValues;
 
     enum {
@@ -70,7 +70,7 @@
     MtpPropertyValue    mStepSize;
 
     // for enum form
-    int                 mEnumLength;
+    uint16_t            mEnumLength;
     MtpPropertyValue*   mEnumValues;
 
 public:
@@ -83,7 +83,7 @@
 
     inline MtpPropertyCode getPropertyCode() const { return mCode; }
 
-    void                read(MtpDataPacket& packet);
+    bool                read(MtpDataPacket& packet);
     void                write(MtpDataPacket& packet);
 
     void                setDefaultValue(const uint16_t* string);
@@ -102,11 +102,11 @@
                         }
 
 private:
-    void                readValue(MtpDataPacket& packet, MtpPropertyValue& value);
+    bool                readValue(MtpDataPacket& packet, MtpPropertyValue& value);
     void                writeValue(MtpDataPacket& packet, MtpPropertyValue& value);
-    MtpPropertyValue*   readArrayValues(MtpDataPacket& packet, int& length);
+    MtpPropertyValue*   readArrayValues(MtpDataPacket& packet, uint32_t& length);
     void                writeArrayValues(MtpDataPacket& packet,
-                                            MtpPropertyValue* values, int length);
+                                            MtpPropertyValue* values, uint32_t length);
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpRequestPacket.cpp b/media/mtp/MtpRequestPacket.cpp
index 0e58e01..40b11b0 100644
--- a/media/mtp/MtpRequestPacket.cpp
+++ b/media/mtp/MtpRequestPacket.cpp
@@ -27,7 +27,8 @@
 namespace android {
 
 MtpRequestPacket::MtpRequestPacket()
-    :   MtpPacket(512)
+    :   MtpPacket(512),
+        mParameterCount(0)
 {
 }
 
@@ -37,10 +38,21 @@
 #ifdef MTP_DEVICE
 int MtpRequestPacket::read(int fd) {
     int ret = ::read(fd, mBuffer, mBufferSize);
-    if (ret >= 0)
+    if (ret < 0) {
+        // file read error
+        return ret;
+    }
+
+    // request packet should have 12 byte header followed by 0 to 5 32-bit arguments
+    if (ret >= MTP_CONTAINER_HEADER_SIZE
+            && ret <= MTP_CONTAINER_HEADER_SIZE + 5 * sizeof(uint32_t)
+            && ((ret - MTP_CONTAINER_HEADER_SIZE) & 3) == 0) {
         mPacketSize = ret;
-    else
-        mPacketSize = 0;
+        mParameterCount = (ret - MTP_CONTAINER_HEADER_SIZE) / sizeof(uint32_t);
+    } else {
+        ALOGE("Malformed MTP request packet");
+        ret = -1;
+    }
     return ret;
 }
 #endif
diff --git a/media/mtp/MtpRequestPacket.h b/media/mtp/MtpRequestPacket.h
index 1201f11..79b798d 100644
--- a/media/mtp/MtpRequestPacket.h
+++ b/media/mtp/MtpRequestPacket.h
@@ -43,6 +43,10 @@
     inline MtpOperationCode    getOperationCode() const { return getContainerCode(); }
     inline void                setOperationCode(MtpOperationCode code)
                                                     { return setContainerCode(code); }
+    inline int                  getParameterCount() const { return mParameterCount; }
+
+private:
+    int     mParameterCount;
 };
 
 }; // namespace android
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index aa43967..931a09d 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -495,6 +495,9 @@
         mResponse.setParameter(1, mSessionID);
         return MTP_RESPONSE_SESSION_ALREADY_OPEN;
     }
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
+
     mSessionID = mRequest.getParameter(1);
     mSessionOpen = true;
 
@@ -529,6 +532,9 @@
 
     if (!mSessionOpen)
         return MTP_RESPONSE_SESSION_NOT_OPEN;
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
+
     MtpStorageID id = mRequest.getParameter(1);
     MtpStorage* storage = getStorage(id);
     if (!storage)
@@ -550,6 +556,8 @@
 MtpResponseCode MtpServer::doGetObjectPropsSupported() {
     if (!mSessionOpen)
         return MTP_RESPONSE_SESSION_NOT_OPEN;
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectFormat format = mRequest.getParameter(1);
     MtpObjectPropertyList* properties = mDatabase->getSupportedObjectProperties(format);
     mData.putAUInt16(properties);
@@ -560,6 +568,8 @@
 MtpResponseCode MtpServer::doGetObjectHandles() {
     if (!mSessionOpen)
         return MTP_RESPONSE_SESSION_NOT_OPEN;
+    if (mRequest.getParameterCount() < 3)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
@@ -577,6 +587,8 @@
 MtpResponseCode MtpServer::doGetNumObjects() {
     if (!mSessionOpen)
         return MTP_RESPONSE_SESSION_NOT_OPEN;
+    if (mRequest.getParameterCount() < 3)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
@@ -599,6 +611,8 @@
         return MTP_RESPONSE_SESSION_NOT_OPEN;
     if (!hasStorage())
         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
 
     // FIXME - check for invalid object handle
@@ -617,9 +631,13 @@
         return MTP_RESPONSE_SESSION_NOT_OPEN;
     if (!hasStorage())
         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpStorageID handle = mRequest.getParameter(1);
 
     MtpObjectHandleList* references = mData.getAUInt32();
+    if (!references)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpResponseCode result = mDatabase->setObjectReferences(handle, references);
     delete references;
     return result;
@@ -628,6 +646,8 @@
 MtpResponseCode MtpServer::doGetObjectPropValue() {
     if (!hasStorage())
         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    if (mRequest.getParameterCount() < 2)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
     MtpObjectProperty property = mRequest.getParameter(2);
     ALOGV("GetObjectPropValue %d %s\n", handle,
@@ -639,6 +659,8 @@
 MtpResponseCode MtpServer::doSetObjectPropValue() {
     if (!hasStorage())
         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    if (mRequest.getParameterCount() < 2)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
     MtpObjectProperty property = mRequest.getParameter(2);
     ALOGV("SetObjectPropValue %d %s\n", handle,
@@ -648,6 +670,8 @@
 }
 
 MtpResponseCode MtpServer::doGetDevicePropValue() {
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpDeviceProperty property = mRequest.getParameter(1);
     ALOGV("GetDevicePropValue %s\n",
             MtpDebug::getDevicePropCodeName(property));
@@ -656,6 +680,8 @@
 }
 
 MtpResponseCode MtpServer::doSetDevicePropValue() {
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpDeviceProperty property = mRequest.getParameter(1);
     ALOGV("SetDevicePropValue %s\n",
             MtpDebug::getDevicePropCodeName(property));
@@ -664,6 +690,8 @@
 }
 
 MtpResponseCode MtpServer::doResetDevicePropValue() {
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpDeviceProperty property = mRequest.getParameter(1);
     ALOGV("ResetDevicePropValue %s\n",
             MtpDebug::getDevicePropCodeName(property));
@@ -674,6 +702,8 @@
 MtpResponseCode MtpServer::doGetObjectPropList() {
     if (!hasStorage())
         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    if (mRequest.getParameterCount() < 5)
+        return MTP_RESPONSE_INVALID_PARAMETER;
 
     MtpObjectHandle handle = mRequest.getParameter(1);
     // use uint32_t so we can support 0xFFFFFFFF
@@ -691,6 +721,8 @@
 MtpResponseCode MtpServer::doGetObjectInfo() {
     if (!hasStorage())
         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
     MtpObjectInfo info(handle);
     MtpResponseCode result = mDatabase->getObjectInfo(handle, info);
@@ -732,6 +764,8 @@
 MtpResponseCode MtpServer::doGetObject() {
     if (!hasStorage())
         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
     MtpString pathBuf;
     int64_t fileLength;
@@ -765,6 +799,8 @@
 }
 
 MtpResponseCode MtpServer::doGetThumb() {
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
     size_t thumbSize;
     void* thumb = mDatabase->getThumbnail(handle, thumbSize);
@@ -783,6 +819,8 @@
 MtpResponseCode MtpServer::doGetPartialObject(MtpOperationCode operation) {
     if (!hasStorage())
         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    if (mRequest.getParameterCount() < 4)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
     uint64_t offset;
     uint32_t length;
@@ -832,6 +870,11 @@
 
 MtpResponseCode MtpServer::doSendObjectInfo() {
     MtpString path;
+    uint16_t temp16;
+    uint32_t temp32;
+
+    if (mRequest.getParameterCount() < 2)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpStorageID storageID = mRequest.getParameter(1);
     MtpStorage* storage = getStorage(storageID);
     MtpObjectHandle parent = mRequest.getParameter(2);
@@ -853,25 +896,29 @@
     }
 
     // read only the fields we need
-    mData.getUInt32();  // storage ID
-    MtpObjectFormat format = mData.getUInt16();
-    mData.getUInt16();  // protection status
-    mSendObjectFileSize = mData.getUInt32();
-    mData.getUInt16();  // thumb format
-    mData.getUInt32();  // thumb compressed size
-    mData.getUInt32();  // thumb pix width
-    mData.getUInt32();  // thumb pix height
-    mData.getUInt32();  // image pix width
-    mData.getUInt32();  // image pix height
-    mData.getUInt32();  // image bit depth
-    mData.getUInt32();  // parent
-    uint16_t associationType = mData.getUInt16();
-    uint32_t associationDesc = mData.getUInt32();   // association desc
-    mData.getUInt32();  // sequence number
+    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // storage ID
+    if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
+    MtpObjectFormat format = temp16;
+    if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;  // protection status
+    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
+    mSendObjectFileSize = temp32;
+    if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb format
+    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb compressed size
+    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb pix width
+    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // thumb pix height
+    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // image pix width
+    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // image pix height
+    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // image bit depth
+    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // parent
+    if (!mData.getUInt16(temp16)) return MTP_RESPONSE_INVALID_PARAMETER;
+    uint16_t associationType = temp16;
+    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;
+    uint32_t associationDesc = temp32;        // association desc
+    if (!mData.getUInt32(temp32)) return MTP_RESPONSE_INVALID_PARAMETER;  // sequence number
     MtpStringBuffer name, created, modified;
-    mData.getString(name);    // file name
-    mData.getString(created);      // date created
-    mData.getString(modified);     // date modified
+    if (!mData.getString(name)) return MTP_RESPONSE_INVALID_PARAMETER;    // file name
+    if (!mData.getString(created)) return MTP_RESPONSE_INVALID_PARAMETER;      // date created
+    if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER;     // date modified
     // keywords follow
 
     ALOGV("name: %s format: %04X\n", (const char *)name, format);
@@ -1066,6 +1113,8 @@
 MtpResponseCode MtpServer::doDeleteObject() {
     if (!hasStorage())
         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    if (mRequest.getParameterCount() < 2)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
     MtpObjectFormat format = mRequest.getParameter(2);
     // FIXME - support deleting all objects if handle is 0xFFFFFFFF
@@ -1087,6 +1136,8 @@
 }
 
 MtpResponseCode MtpServer::doGetObjectPropDesc() {
+    if (mRequest.getParameterCount() < 2)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectProperty propCode = mRequest.getParameter(1);
     MtpObjectFormat format = mRequest.getParameter(2);
     ALOGV("GetObjectPropDesc %s %s\n", MtpDebug::getObjectPropCodeName(propCode),
@@ -1100,6 +1151,8 @@
 }
 
 MtpResponseCode MtpServer::doGetDevicePropDesc() {
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpDeviceProperty propCode = mRequest.getParameter(1);
     ALOGV("GetDevicePropDesc %s\n", MtpDebug::getDevicePropCodeName(propCode));
     MtpProperty* property = mDatabase->getDevicePropertyDesc(propCode);
@@ -1113,6 +1166,8 @@
 MtpResponseCode MtpServer::doSendPartialObject() {
     if (!hasStorage())
         return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+    if (mRequest.getParameterCount() < 4)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
     uint64_t offset = mRequest.getParameter(2);
     uint64_t offset2 = mRequest.getParameter(3);
@@ -1180,6 +1235,8 @@
 }
 
 MtpResponseCode MtpServer::doTruncateObject() {
+    if (mRequest.getParameterCount() < 3)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
     ObjectEdit* edit = getEditObject(handle);
     if (!edit) {
@@ -1199,6 +1256,8 @@
 }
 
 MtpResponseCode MtpServer::doBeginEditObject() {
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
     if (getEditObject(handle)) {
         ALOGE("object already open for edit in doBeginEditObject");
@@ -1223,6 +1282,8 @@
 }
 
 MtpResponseCode MtpServer::doEndEditObject() {
+    if (mRequest.getParameterCount() < 1)
+        return MTP_RESPONSE_INVALID_PARAMETER;
     MtpObjectHandle handle = mRequest.getParameter(1);
     ObjectEdit* edit = getEditObject(handle);
     if (!edit) {
diff --git a/media/mtp/MtpStorageInfo.cpp b/media/mtp/MtpStorageInfo.cpp
index 2b1a9ae..5d4ebbf 100644
--- a/media/mtp/MtpStorageInfo.cpp
+++ b/media/mtp/MtpStorageInfo.cpp
@@ -45,21 +45,23 @@
         free(mVolumeIdentifier);
 }
 
-void MtpStorageInfo::read(MtpDataPacket& packet) {
+bool MtpStorageInfo::read(MtpDataPacket& packet) {
     MtpStringBuffer string;
 
     // read the device info
-    mStorageType = packet.getUInt16();
-    mFileSystemType = packet.getUInt16();
-    mAccessCapability = packet.getUInt16();
-    mMaxCapacity = packet.getUInt64();
-    mFreeSpaceBytes = packet.getUInt64();
-    mFreeSpaceObjects = packet.getUInt32();
+    if (!packet.getUInt16(mStorageType)) return false;
+    if (!packet.getUInt16(mFileSystemType)) return false;
+    if (!packet.getUInt16(mAccessCapability)) return false;
+    if (!packet.getUInt64(mMaxCapacity)) return false;
+    if (!packet.getUInt64(mFreeSpaceBytes)) return false;
+    if (!packet.getUInt32(mFreeSpaceObjects)) return false;
 
-    packet.getString(string);
+    if (!packet.getString(string)) return false;
     mStorageDescription = strdup((const char *)string);
-    packet.getString(string);
+    if (!packet.getString(string)) return false;
     mVolumeIdentifier = strdup((const char *)string);
+
+    return true;
 }
 
 void MtpStorageInfo::print() {
diff --git a/media/mtp/MtpStorageInfo.h b/media/mtp/MtpStorageInfo.h
index 2cb626e..35a8189 100644
--- a/media/mtp/MtpStorageInfo.h
+++ b/media/mtp/MtpStorageInfo.h
@@ -39,7 +39,7 @@
                         MtpStorageInfo(MtpStorageID id);
     virtual             ~MtpStorageInfo();
 
-    void                read(MtpDataPacket& packet);
+    bool                read(MtpDataPacket& packet);
 
     void                print();
 };
diff --git a/media/mtp/MtpStringBuffer.cpp b/media/mtp/MtpStringBuffer.cpp
index f3420a4..df04694 100644
--- a/media/mtp/MtpStringBuffer.cpp
+++ b/media/mtp/MtpStringBuffer.cpp
@@ -123,11 +123,17 @@
     mByteCount = dest - mBuffer;
 }
 
-void MtpStringBuffer::readFromPacket(MtpDataPacket* packet) {
-    int count = packet->getUInt8();
+bool MtpStringBuffer::readFromPacket(MtpDataPacket* packet) {
+    uint8_t count;
+    if (!packet->getUInt8(count))
+        return false;
+
     uint8_t* dest = mBuffer;
     for (int i = 0; i < count; i++) {
-        uint16_t ch = packet->getUInt16();
+        uint16_t ch;
+
+        if (!packet->getUInt16(ch))
+            return false;
         if (ch >= 0x0800) {
             *dest++ = (uint8_t)(0xE0 | (ch >> 12));
             *dest++ = (uint8_t)(0x80 | ((ch >> 6) & 0x3F));
@@ -142,6 +148,7 @@
     *dest++ = 0;
     mCharCount = count;
     mByteCount = dest - mBuffer;
+    return true;
 }
 
 void MtpStringBuffer::writeToPacket(MtpDataPacket* packet) const {
diff --git a/media/mtp/MtpStringBuffer.h b/media/mtp/MtpStringBuffer.h
index e5150df..85d91e8 100644
--- a/media/mtp/MtpStringBuffer.h
+++ b/media/mtp/MtpStringBuffer.h
@@ -46,7 +46,7 @@
     void            set(const char* src);
     void            set(const uint16_t* src);
 
-    void            readFromPacket(MtpDataPacket* packet);
+    bool            readFromPacket(MtpDataPacket* packet);
     void            writeToPacket(MtpDataPacket* packet) const;
 
     inline int      getCharCount() const { return mCharCount; }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index b9308fa..037c73b 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -611,15 +611,16 @@
 
 // ExtendedAudioBufferProvider interface
 
-// Note that framesReady() takes a mutex on the control block using tryLock().
-// This could result in priority inversion if framesReady() is called by the normal mixer,
-// as the normal mixer thread runs at lower
-// priority than the client's callback thread:  there is a short window within framesReady()
-// during which the normal mixer could be preempted, and the client callback would block.
-// Another problem can occur if framesReady() is called by the fast mixer:
-// the tryLock() could block for up to 1 ms, and a sequence of these could delay fast mixer.
-// FIXME Replace AudioTrackShared control block implementation by a non-blocking FIFO queue.
+// framesReady() may return an approximation of the number of frames if called
+// from a different thread than the one calling Proxy->obtainBuffer() and
+// Proxy->releaseBuffer(). Also note there is no mutual exclusion in the
+// AudioTrackServerProxy so be especially careful calling with FastTracks.
 size_t AudioFlinger::PlaybackThread::Track::framesReady() const {
+    if (mSharedBuffer != 0 && (isStopped() || isStopping())) {
+        // Static tracks return zero frames immediately upon stopping (for FastTracks).
+        // The remainder of the buffer is not drained.
+        return 0;
+    }
     return mAudioTrackServerProxy->framesReady();
 }
 
diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp
index 584e170..fff7746 100644
--- a/services/audiopolicy/AudioPolicyManager.cpp
+++ b/services/audiopolicy/AudioPolicyManager.cpp
@@ -3563,7 +3563,8 @@
         // check if one opened input is not needed any more after disconnecting one device
         for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
             desc = mInputs.valueAt(input_index);
-            if (!(desc->mProfile->mSupportedDevices.types() & mAvailableInputDevices.types())) {
+            if (!(desc->mProfile->mSupportedDevices.types() & mAvailableInputDevices.types() &
+                    ~AUDIO_DEVICE_BIT_IN)) {
                 ALOGV("checkInputsForDevice(): disconnecting adding input %d",
                       mInputs.keyAt(input_index));
                 inputs.add(mInputs.keyAt(input_index));
@@ -3578,7 +3579,7 @@
                  profile_index < mHwModules[module_index]->mInputProfiles.size();
                  profile_index++) {
                 sp<IOProfile> profile = mHwModules[module_index]->mInputProfiles[profile_index];
-                if (profile->mSupportedDevices.types() & device) {
+                if (profile->mSupportedDevices.types() & device & ~AUDIO_DEVICE_BIT_IN) {
                     ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %zu",
                           profile_index, module_index);
                     if (profile->mSamplingRates[0] == 0) {
@@ -3795,7 +3796,9 @@
     }
 
     bool isScoConnected =
-            (mAvailableInputDevices.types() & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) != 0;
+            ((mAvailableInputDevices.types() & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET &
+                    ~AUDIO_DEVICE_BIT_IN) != 0) ||
+            ((mAvailableOutputDevices.types() & AUDIO_DEVICE_OUT_ALL_SCO) != 0);
     // suspend A2DP output if:
     //      (NOT already suspended) &&
     //      ((SCO device is connected &&
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
index 312a78c..40d53b3 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
@@ -168,6 +168,19 @@
             faceIds = entry.data.i32;
         }
 
+        entry = frame.find(ANDROID_SCALER_CROP_REGION);
+        if (entry.count < 4) {
+            ALOGE("%s: Camera %d: Unable to read crop region (count = %d)",
+                    __FUNCTION__, client->getCameraId(), entry.count);
+            return res;
+        }
+
+        Parameters::CropRegion scalerCrop = {
+            static_cast<float>(entry.data.i32[0]),
+            static_cast<float>(entry.data.i32[1]),
+            static_cast<float>(entry.data.i32[2]),
+            static_cast<float>(entry.data.i32[3])};
+
         faces.setCapacity(metadata.number_of_faces);
 
         size_t maxFaces = metadata.number_of_faces;
@@ -183,26 +196,30 @@
 
             camera_face_t face;
 
-            face.rect[0] = l.mParameters.arrayXToNormalized(faceRects[i*4 + 0]);
-            face.rect[1] = l.mParameters.arrayYToNormalized(faceRects[i*4 + 1]);
-            face.rect[2] = l.mParameters.arrayXToNormalized(faceRects[i*4 + 2]);
-            face.rect[3] = l.mParameters.arrayYToNormalized(faceRects[i*4 + 3]);
+            face.rect[0] = l.mParameters.arrayXToNormalizedWithCrop(
+                                faceRects[i*4 + 0], scalerCrop);
+            face.rect[1] = l.mParameters.arrayYToNormalizedWithCrop(
+                                faceRects[i*4 + 1], scalerCrop);
+            face.rect[2] = l.mParameters.arrayXToNormalizedWithCrop(
+                                faceRects[i*4 + 2], scalerCrop);
+            face.rect[3] = l.mParameters.arrayYToNormalizedWithCrop(
+                                faceRects[i*4 + 3], scalerCrop);
 
             face.score = faceScores[i];
             if (faceDetectMode == ANDROID_STATISTICS_FACE_DETECT_MODE_FULL) {
                 face.id = faceIds[i];
-                face.left_eye[0] =
-                    l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 0]);
-                face.left_eye[1] =
-                    l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 1]);
-                face.right_eye[0] =
-                    l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 2]);
-                face.right_eye[1] =
-                    l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 3]);
-                face.mouth[0] =
-                    l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 4]);
-                face.mouth[1] =
-                    l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 5]);
+                face.left_eye[0] = l.mParameters.arrayXToNormalizedWithCrop(
+                        faceLandmarks[i*6 + 0], scalerCrop);
+                face.left_eye[1] = l.mParameters.arrayYToNormalizedWithCrop(
+                        faceLandmarks[i*6 + 1], scalerCrop);
+                face.right_eye[0] = l.mParameters.arrayXToNormalizedWithCrop(
+                        faceLandmarks[i*6 + 2], scalerCrop);
+                face.right_eye[1] = l.mParameters.arrayYToNormalizedWithCrop(
+                        faceLandmarks[i*6 + 3], scalerCrop);
+                face.mouth[0] = l.mParameters.arrayXToNormalizedWithCrop(
+                        faceLandmarks[i*6 + 4], scalerCrop);
+                face.mouth[1] = l.mParameters.arrayYToNormalizedWithCrop(
+                        faceLandmarks[i*6 + 5], scalerCrop);
             } else {
                 face.id = 0;
                 face.left_eye[0] = face.left_eye[1] = -2000;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 42a5507..74bbb9d 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -2619,58 +2619,6 @@
     return (y + 1000) * (previewCrop.height - 1) / 2000;
 }
 
-int Parameters::arrayXToCrop(int x) const {
-    CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
-    return x - previewCrop.left;
-}
-
-int Parameters::arrayYToCrop(int y) const {
-    CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
-    return y - previewCrop.top;
-}
-
-int Parameters::cropXToNormalized(int x) const {
-    CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
-    return x * 2000 / (previewCrop.width - 1) - 1000;
-}
-
-int Parameters::cropYToNormalized(int y) const {
-    CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW);
-    return y * 2000 / (previewCrop.height - 1) - 1000;
-}
-
-int Parameters::arrayXToNormalized(int width) const {
-    int ret = cropXToNormalized(arrayXToCrop(width));
-
-    ALOG_ASSERT(ret >= -1000, "Calculated normalized value out of "
-        "lower bounds %d", ret);
-    ALOG_ASSERT(ret <= 1000, "Calculated normalized value out of "
-        "upper bounds %d", ret);
-
-    // Work-around for HAL pre-scaling the coordinates themselves
-    if (quirks.meteringCropRegion) {
-        return width * 2000 / (fastInfo.arrayWidth - 1) - 1000;
-    }
-
-    return ret;
-}
-
-int Parameters::arrayYToNormalized(int height) const {
-    int ret = cropYToNormalized(arrayYToCrop(height));
-
-    ALOG_ASSERT(ret >= -1000, "Calculated normalized value out of lower bounds"
-        " %d", ret);
-    ALOG_ASSERT(ret <= 1000, "Calculated normalized value out of upper bounds"
-        " %d", ret);
-
-    // Work-around for HAL pre-scaling the coordinates themselves
-    if (quirks.meteringCropRegion) {
-        return height * 2000 / (fastInfo.arrayHeight - 1) - 1000;
-    }
-
-    return ret;
-}
-
 int Parameters::normalizedXToArray(int x) const {
 
     // Work-around for HAL pre-scaling the coordinates themselves
@@ -2690,6 +2638,54 @@
     return cropYToArray(normalizedYToCrop(y));
 }
 
+
+Parameters::CropRegion Parameters::calculatePreviewCrop(
+        const CropRegion &scalerCrop) const {
+    float left, top, width, height;
+    float previewAspect = static_cast<float>(previewWidth) / previewHeight;
+    float cropAspect = scalerCrop.width / scalerCrop.height;
+
+    if (previewAspect > cropAspect) {
+        width = scalerCrop.width;
+        height = cropAspect * scalerCrop.height / previewAspect;
+
+        left = scalerCrop.left;
+        top = scalerCrop.top + (scalerCrop.height - height) / 2;
+    } else {
+        width = previewAspect * scalerCrop.width / cropAspect;
+        height = scalerCrop.height;
+
+        left = scalerCrop.left + (scalerCrop.width - width) / 2;
+        top = scalerCrop.top;
+    }
+
+    CropRegion previewCrop = {left, top, width, height};
+
+    return previewCrop;
+}
+
+int Parameters::arrayXToNormalizedWithCrop(int x,
+        const CropRegion &scalerCrop) const {
+    // Work-around for HAL pre-scaling the coordinates themselves
+    if (quirks.meteringCropRegion) {
+        return x * 2000 / (fastInfo.arrayWidth - 1) - 1000;
+    } else {
+        CropRegion previewCrop = calculatePreviewCrop(scalerCrop);
+        return (x - previewCrop.left) * 2000 / (previewCrop.width - 1) - 1000;
+    }
+}
+
+int Parameters::arrayYToNormalizedWithCrop(int y,
+        const CropRegion &scalerCrop) const {
+    // Work-around for HAL pre-scaling the coordinates themselves
+    if (quirks.meteringCropRegion) {
+        return y * 2000 / (fastInfo.arrayHeight - 1) - 1000;
+    } else {
+        CropRegion previewCrop = calculatePreviewCrop(scalerCrop);
+        return (y - previewCrop.top) * 2000 / (previewCrop.height - 1) - 1000;
+    }
+}
+
 status_t Parameters::getFilteredSizes(Size limit, Vector<Size> *sizes) {
     if (info == NULL) {
         ALOGE("%s: Static metadata is not initialized", __FUNCTION__);
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 815cc55..389cb92 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -325,13 +325,17 @@
     // Note that this doesn't apply to the (deprecated) single FPS value.
     static const int kFpsToApiScale = 1000;
 
-    // Transform between (-1000,-1000)-(1000,1000) normalized coords from camera
-    // API and HAL2 (0,0)-(activePixelArray.width/height) coordinates
-    int arrayXToNormalized(int width) const;
-    int arrayYToNormalized(int height) const;
+    // Transform from (-1000,-1000)-(1000,1000) normalized coords from camera
+    // API to HAL2 (0,0)-(activePixelArray.width/height) coordinates
     int normalizedXToArray(int x) const;
     int normalizedYToArray(int y) const;
 
+    // Transform from HAL3 (0,0)-(activePixelArray.width/height) coordinates to
+    // (-1000,-1000)-(1000,1000) normalized coordinates given a scaler crop
+    // region.
+    int arrayXToNormalizedWithCrop(int x, const CropRegion &scalerCrop) const;
+    int arrayYToNormalizedWithCrop(int y, const CropRegion &scalerCrop) const;
+
     struct Range {
         int min;
         int max;
@@ -341,20 +345,20 @@
 
 private:
 
-    // Convert between HAL2 sensor array coordinates and
-    // viewfinder crop-region relative array coordinates
+    // Convert from viewfinder crop-region relative array coordinates
+    // to HAL2 sensor array coordinates
     int cropXToArray(int x) const;
     int cropYToArray(int y) const;
-    int arrayXToCrop(int x) const;
-    int arrayYToCrop(int y) const;
 
-    // Convert between viewfinder crop-region relative array coordinates
-    // and camera API (-1000,1000)-(1000,1000) normalized coords
-    int cropXToNormalized(int x) const;
-    int cropYToNormalized(int y) const;
+    // Convert from camera API (-1000,1000)-(1000,1000) normalized coords
+    // to viewfinder crop-region relative array coordinates
     int normalizedXToCrop(int x) const;
     int normalizedYToCrop(int y) const;
 
+    // Given a scaler crop region, calculate preview crop region based on
+    // preview aspect ratio.
+    CropRegion calculatePreviewCrop(const CropRegion &scalerCrop) const;
+
     Vector<Size> availablePreviewSizes;
     Vector<Size> availableVideoSizes;
     // Get size list (that are no larger than limit) from static metadata.
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
index 8caadd6..d1158d6 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ b/services/camera/libcameraservice/device2/Camera2Device.cpp
@@ -793,11 +793,6 @@
         mStreamSlotCount = 0;
         return OK;
     }
-    camera_metadata_t *buf2 = clone_camera_metadata(buf);
-    if (!buf2) {
-        ALOGE("%s: Unable to clone metadata buffer!", __FUNCTION__);
-        return NO_MEMORY;
-    }
 
     if (mStreamSlotCount > 1) {
         List<camera_metadata_t*>::iterator deleter = ++mStreamSlot.begin();
@@ -806,9 +801,9 @@
     }
     if (mStreamSlotCount == 1) {
         free_camera_metadata( *(mStreamSlot.begin()) );
-        *(mStreamSlot.begin()) = buf2;
+        *(mStreamSlot.begin()) = buf;
     } else {
-        mStreamSlot.push_front(buf2);
+        mStreamSlot.push_front(buf);
         mStreamSlotCount = 1;
     }
     return signalConsumerLocked();
@@ -827,12 +822,7 @@
     mStreamSlotCount = 0;
     for (List<camera_metadata_t*>::const_iterator r = bufs.begin();
          r != bufs.end(); r++) {
-        camera_metadata_t *r2 = clone_camera_metadata(*r);
-        if (!r2) {
-            ALOGE("%s: Unable to clone metadata buffer!", __FUNCTION__);
-            return NO_MEMORY;
-        }
-        mStreamSlot.push_back(r2);
+        mStreamSlot.push_back(*r);
         mStreamSlotCount++;
     }
     return signalConsumerLocked();
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
index 2a3f1d9..4def8ae 100644
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ b/services/camera/libcameraservice/device2/Camera2Device.h
@@ -124,8 +124,8 @@
 
         // Set repeating buffer(s); if the queue is empty on a dequeue call, the
         // queue copies the contents of the stream slot into the queue, and then
-        // dequeues the first new entry. The metadata buffers passed in are
-        // copied.
+        // dequeues the first new entry. The methods take the ownership of the
+        // metadata buffers passed in.
         status_t setStreamSlot(camera_metadata_t *buf);
         status_t setStreamSlot(const List<camera_metadata_t*> &bufs);