Merge "audioflinger: fix audio skipping over A2DP" into ics-mr1
diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h
index cc63356..19646b0 100644
--- a/include/media/IStreamSource.h
+++ b/include/media/IStreamSource.h
@@ -52,15 +52,20 @@
     static const char *const kKeyResumeAtPTS;
 
     // When signalling a discontinuity you can optionally
-    // signal that this is a "hard" discontinuity, i.e. the format
-    // or configuration of subsequent stream data differs from that
-    // currently active. To do so, include a non-zero int32_t value
-    // under the key "kKeyFormatChange" when issuing the DISCONTINUITY
+    // specify the type(s) of discontinuity, i.e. if the
+    // audio format has changed, the video format has changed,
+    // time has jumped or any combination thereof.
+    // To do so, include a non-zero int32_t value
+    // under the key "kKeyDiscontinuityMask" when issuing the DISCONTINUITY
     // command.
-    // The new logical stream must start with proper codec initialization
+    // If there is a change in audio/video format, The new logical stream
+    // must start with proper codec initialization
     // information for playback to continue, i.e. SPS and PPS in the case
     // of AVC video etc.
-    static const char *const kKeyFormatChange;
+    // If this key is not present, only a time discontinuity is assumed.
+    // The value should be a bitmask of values from
+    // ATSParser::DiscontinuityType.
+    static const char *const kKeyDiscontinuityMask;
 
     virtual void issueCommand(
             Command cmd, bool synchronous, const sp<AMessage> &msg = NULL) = 0;
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index 5822877..3963d9c 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -166,6 +166,8 @@
 
     bool allYourBuffersAreBelongToUs();
 
+    size_t countBuffersOwnedByComponent(OMX_U32 portIndex) const;
+
     void deferMessage(const sp<AMessage> &msg);
     void processDeferredMessages();
 
diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
index b311f35..078be94 100644
--- a/media/libmedia/IStreamSource.cpp
+++ b/media/libmedia/IStreamSource.cpp
@@ -30,7 +30,7 @@
 const char *const IStreamListener::kKeyResumeAtPTS = "resume-at-PTS";
 
 // static
-const char *const IStreamListener::kKeyFormatChange = "format-change";
+const char *const IStreamListener::kKeyDiscontinuityMask = "discontinuity-mask";
 
 enum {
     // IStreamSource
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 2a5c0a6..93ab704 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -54,6 +54,7 @@
       mVideoEOS(false),
       mScanSourcesPending(false),
       mScanSourcesGeneration(0),
+      mTimeDiscontinuityPending(false),
       mFlushingAudio(NONE),
       mFlushingVideo(NONE),
       mResetInProgress(false),
@@ -462,11 +463,24 @@
         {
             LOGV("kWhatReset");
 
+            if (mRenderer != NULL) {
+                // There's an edge case where the renderer owns all output
+                // buffers and is paused, therefore the decoder will not read
+                // more input data and will never encounter the matching
+                // discontinuity. To avoid this, we resume the renderer.
+
+                if (mFlushingAudio == AWAITING_DISCONTINUITY
+                        || mFlushingVideo == AWAITING_DISCONTINUITY) {
+                    mRenderer->resume();
+                }
+            }
+
             if (mFlushingAudio != NONE || mFlushingVideo != NONE) {
                 // We're currently flushing, postpone the reset until that's
                 // completed.
 
-                LOGV("postponing reset");
+                LOGV("postponing reset mFlushingAudio=%d, mFlushingVideo=%d",
+                        mFlushingAudio, mFlushingVideo);
 
                 mResetPostponed = true;
                 break;
@@ -477,6 +491,8 @@
                 break;
             }
 
+            mTimeDiscontinuityPending = true;
+
             if (mAudioDecoder != NULL) {
                 flushDecoder(true /* audio */, true /* needShutdown */);
             }
@@ -540,7 +556,10 @@
 
     LOGV("both audio and video are flushed now.");
 
-    mRenderer->signalTimeDiscontinuity();
+    if (mTimeDiscontinuityPending) {
+        mRenderer->signalTimeDiscontinuity();
+        mTimeDiscontinuityPending = false;
+    }
 
     if (mAudioDecoder != NULL) {
         mAudioDecoder->signalResume();
@@ -663,10 +682,15 @@
                 CHECK(accessUnit->meta()->findInt32("discontinuity", &type));
 
                 bool formatChange =
-                    type == ATSParser::DISCONTINUITY_FORMATCHANGE;
+                    (audio &&
+                     (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT))
+                    || (!audio &&
+                            (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT));
 
-                LOGV("%s discontinuity (formatChange=%d)",
-                     audio ? "audio" : "video", formatChange);
+                bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0;
+
+                LOGI("%s discontinuity (formatChange=%d, time=%d)",
+                     audio ? "audio" : "video", formatChange, timeChange);
 
                 if (audio) {
                     mSkipRenderingAudioUntilMediaTimeUs = -1;
@@ -674,26 +698,45 @@
                     mSkipRenderingVideoUntilMediaTimeUs = -1;
                 }
 
-                sp<AMessage> extra;
-                if (accessUnit->meta()->findMessage("extra", &extra)
-                        && extra != NULL) {
-                    int64_t resumeAtMediaTimeUs;
-                    if (extra->findInt64(
-                                "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
-                        LOGI("suppressing rendering of %s until %lld us",
-                                audio ? "audio" : "video", resumeAtMediaTimeUs);
+                if (timeChange) {
+                    sp<AMessage> extra;
+                    if (accessUnit->meta()->findMessage("extra", &extra)
+                            && extra != NULL) {
+                        int64_t resumeAtMediaTimeUs;
+                        if (extra->findInt64(
+                                    "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) {
+                            LOGI("suppressing rendering of %s until %lld us",
+                                    audio ? "audio" : "video", resumeAtMediaTimeUs);
 
-                        if (audio) {
-                            mSkipRenderingAudioUntilMediaTimeUs =
-                                resumeAtMediaTimeUs;
-                        } else {
-                            mSkipRenderingVideoUntilMediaTimeUs =
-                                resumeAtMediaTimeUs;
+                            if (audio) {
+                                mSkipRenderingAudioUntilMediaTimeUs =
+                                    resumeAtMediaTimeUs;
+                            } else {
+                                mSkipRenderingVideoUntilMediaTimeUs =
+                                    resumeAtMediaTimeUs;
+                            }
                         }
                     }
                 }
 
-                flushDecoder(audio, formatChange);
+                mTimeDiscontinuityPending =
+                    mTimeDiscontinuityPending || timeChange;
+
+                if (formatChange || timeChange) {
+                    flushDecoder(audio, formatChange);
+                } else {
+                    // This stream is unaffected by the discontinuity
+
+                    if (audio) {
+                        mFlushingAudio = FLUSHED;
+                    } else {
+                        mFlushingVideo = FLUSHED;
+                    }
+
+                    finishFlushIfPossible();
+
+                    return -EWOULDBLOCK;
+                }
             }
 
             reply->setInt32("err", err);
@@ -794,6 +837,11 @@
 }
 
 void NuPlayer::flushDecoder(bool audio, bool needShutdown) {
+    if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) {
+        LOGI("flushDecoder %s without decoder present",
+             audio ? "audio" : "video");
+    }
+
     // Make sure we don't continue to scan sources until we finish flushing.
     ++mScanSourcesGeneration;
     mScanSourcesPending = false;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index f23deea..ffc710e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -112,6 +112,10 @@
         SHUT_DOWN,
     };
 
+    // Once the current flush is complete this indicates whether the
+    // notion of time has changed.
+    bool mTimeDiscontinuityPending;
+
     FlushStatus mFlushingAudio;
     FlushStatus mFlushingVideo;
     bool mResetInProgress;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 640e9fa..0cb7f45 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -628,11 +628,16 @@
         mAudioSink->pause();
     }
 
+    LOGV("now paused audio queue has %d entries, video has %d entries",
+         mAudioQueue.size(), mVideoQueue.size());
+
     mPaused = true;
 }
 
 void NuPlayer::Renderer::onResume() {
-    CHECK(mPaused);
+    if (!mPaused) {
+        return;
+    }
 
     if (mHasAudio) {
         mAudioSink->start();
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index f795654..2e63b3b 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -63,17 +63,22 @@
             mFinalResult = ERROR_END_OF_STREAM;
             break;
         } else if (n == INFO_DISCONTINUITY) {
-            ATSParser::DiscontinuityType type = ATSParser::DISCONTINUITY_SEEK;
+            int32_t type = ATSParser::DISCONTINUITY_SEEK;
 
-            int32_t formatChange;
+            int32_t mask;
             if (extra != NULL
                     && extra->findInt32(
-                        IStreamListener::kKeyFormatChange, &formatChange)
-                    && formatChange != 0) {
-                type = ATSParser::DISCONTINUITY_FORMATCHANGE;
+                        IStreamListener::kKeyDiscontinuityMask, &mask)) {
+                if (mask == 0) {
+                    LOGE("Client specified an illegal discontinuity type.");
+                    return ERROR_UNSUPPORTED;
+                }
+
+                type = mask;
             }
 
-            mTSParser->signalDiscontinuity(type, extra);
+            mTSParser->signalDiscontinuity(
+                    (ATSParser::DiscontinuityType)type, extra);
         } else if (n < 0) {
             CHECK_EQ(n, -EWOULDBLOCK);
             break;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index d947760..dbc9b7e 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -342,6 +342,7 @@
 }
 
 void ACodec::signalFlush() {
+    LOGV("[%s] signalFlush", mComponentName.c_str());
     (new AMessage(kWhatFlush, id()))->post();
 }
 
@@ -1092,6 +1093,20 @@
     return OK;
 }
 
+size_t ACodec::countBuffersOwnedByComponent(OMX_U32 portIndex) const {
+    size_t n = 0;
+
+    for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
+        const BufferInfo &info = mBuffers[portIndex].itemAt(i);
+
+        if (info.mStatus == BufferInfo::OWNED_BY_COMPONENT) {
+            ++n;
+        }
+    }
+
+    return n;
+}
+
 bool ACodec::allYourBuffersAreBelongToUs(
         OMX_U32 portIndex) {
     for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
@@ -2041,6 +2056,14 @@
 
         case kWhatFlush:
         {
+            LOGV("[%s] ExecutingState flushing now "
+                 "(codec owns %d/%d input, %d/%d output).",
+                    mCodec->mComponentName.c_str(),
+                    mCodec->countBuffersOwnedByComponent(kPortIndexInput),
+                    mCodec->mBuffers[kPortIndexInput].size(),
+                    mCodec->countBuffersOwnedByComponent(kPortIndexOutput),
+                    mCodec->mBuffers[kPortIndexOutput].size());
+
             mActive = false;
 
             CHECK_EQ(mCodec->mOMX->sendCommand(
@@ -2180,6 +2203,12 @@
                          err);
 
                     mCodec->signalError();
+
+                    // This is technically not correct, since we were unable
+                    // to allocate output buffers and therefore the output port
+                    // remains disabled. It is necessary however to allow us
+                    // to shutdown the codec properly.
+                    mCodec->changeState(mCodec->mExecutingState);
                 }
 
                 return true;
@@ -2408,6 +2437,9 @@
 
 bool ACodec::FlushingState::onOMXEvent(
         OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) {
+    LOGV("[%s] FlushingState onOMXEvent(%d,%ld)",
+            mCodec->mComponentName.c_str(), event, data1);
+
     switch (event) {
         case OMX_EventCmdComplete:
         {
diff --git a/media/libstagefright/AVIExtractor.cpp b/media/libstagefright/AVIExtractor.cpp
index 0be2ca4..815f987 100644
--- a/media/libstagefright/AVIExtractor.cpp
+++ b/media/libstagefright/AVIExtractor.cpp
@@ -1094,7 +1094,7 @@
     CHECK(meta->findData(kKeyAVCC, &type, &csd, &csdSize));
 
     track->mMeta->setInt32(kKeyWidth, width);
-    track->mMeta->setInt32(kKeyHeight, width);
+    track->mMeta->setInt32(kKeyHeight, height);
     track->mMeta->setData(kKeyAVCC, type, csd, csdSize);
 
     return OK;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index f6d054d..18dd8ef 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1949,6 +1949,8 @@
         mUri = newURI;
     }
 
+    AString sniffedMIME;
+
     if (!strncasecmp("http://", mUri.string(), 7)
             || !strncasecmp("https://", mUri.string(), 8)
             || isWidevineStreaming) {
@@ -1998,7 +2000,6 @@
 
         mConnectingDataSource.clear();
 
-
         String8 contentType = dataSource->getMIMEType();
 
         if (strncasecmp(contentType.string(), "audio/", 6)) {
@@ -2020,16 +2021,51 @@
 
                 mLock.unlock();
 
+                // Initially make sure we have at least 128 bytes for the sniff
+                // to complete without blocking.
+                static const size_t kMinBytesForSniffing = 128;
+
+                off64_t metaDataSize = -1ll;
                 for (;;) {
                     status_t finalStatus;
                     size_t cachedDataRemaining =
                         mCachedSource->approxDataRemaining(&finalStatus);
 
-                    if (finalStatus != OK || cachedDataRemaining >= kHighWaterMarkBytes
+                    if (finalStatus != OK
+                            || (metaDataSize >= 0
+                                && cachedDataRemaining >= metaDataSize)
                             || (mFlags & PREPARE_CANCELLED)) {
                         break;
                     }
 
+                    LOGV("now cached %d bytes of data", cachedDataRemaining);
+
+                    if (metaDataSize < 0
+                            && cachedDataRemaining >= kMinBytesForSniffing) {
+                        String8 tmp;
+                        float confidence;
+                        sp<AMessage> meta;
+                        if (!dataSource->sniff(&tmp, &confidence, &meta)) {
+                            mLock.lock();
+                            return UNKNOWN_ERROR;
+                        }
+
+                        // We successfully identified the file's extractor to
+                        // be, remember this mime type so we don't have to
+                        // sniff it again when we call MediaExtractor::Create()
+                        // below.
+                        sniffedMIME = tmp.string();
+
+                        if (meta == NULL
+                                || !meta->findInt64(
+                                    "meta-data-size", &metaDataSize)) {
+                            metaDataSize = kHighWaterMarkBytes;
+                        }
+
+                        CHECK_GE(metaDataSize, 0ll);
+                        LOGV("metaDataSize = %lld bytes", metaDataSize);
+                    }
+
                     usleep(200000);
                 }
 
@@ -2067,7 +2103,8 @@
         mWVMExtractor->setAdaptiveStreamingMode(true);
         extractor = mWVMExtractor;
     } else {
-        extractor = MediaExtractor::Create(dataSource);
+        extractor = MediaExtractor::Create(
+                dataSource, sniffedMIME.empty() ? NULL : sniffedMIME.c_str());
 
         if (extractor == NULL) {
             return UNKNOWN_ERROR;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 1ebf0a8..f6b06c7 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -30,6 +30,7 @@
 #include <string.h>
 
 #include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/MediaBuffer.h>
 #include <media/stagefright/MediaBufferGroup.h>
@@ -2301,51 +2302,121 @@
 
 // Attempt to actually parse the 'ftyp' atom and determine if a suitable
 // compatible brand is present.
+// Also try to identify where this file's metadata ends
+// (end of the 'moov' atom) and report it to the caller as part of
+// the metadata.
 static bool BetterSniffMPEG4(
-        const sp<DataSource> &source, String8 *mimeType, float *confidence) {
-    uint8_t header[12];
-    if (source->readAt(0, header, 12) != 12
-            || memcmp("ftyp", &header[4], 4)) {
-        return false;
-    }
+        const sp<DataSource> &source, String8 *mimeType, float *confidence,
+        sp<AMessage> *meta) {
+    // We scan up to 128 bytes to identify this file as an MP4.
+    static const off64_t kMaxScanOffset = 128ll;
 
-    size_t atomSize = U32_AT(&header[0]);
-    if (atomSize < 16 || (atomSize % 4) != 0) {
-        return false;
-    }
+    off64_t offset = 0ll;
+    bool foundGoodFileType = false;
+    off64_t moovAtomEndOffset = -1ll;
+    bool done = false;
 
-    bool success = false;
-    if (isCompatibleBrand(U32_AT(&header[8]))) {
-        success = true;
-    } else {
-        size_t numCompatibleBrands = (atomSize - 16) / 4;
-        for (size_t i = 0; i < numCompatibleBrands; ++i) {
-            uint8_t tmp[4];
-            if (source->readAt(16 + i * 4, tmp, 4) != 4) {
+    while (!done && offset < kMaxScanOffset) {
+        uint32_t hdr[2];
+        if (source->readAt(offset, hdr, 8) < 8) {
+            return false;
+        }
+
+        uint64_t chunkSize = ntohl(hdr[0]);
+        uint32_t chunkType = ntohl(hdr[1]);
+        off64_t chunkDataOffset = offset + 8;
+
+        if (chunkSize == 1) {
+            if (source->readAt(offset + 8, &chunkSize, 8) < 8) {
                 return false;
             }
 
-            if (isCompatibleBrand(U32_AT(&tmp[0]))) {
-                success = true;
+            chunkSize = ntoh64(chunkSize);
+            chunkDataOffset += 8;
+
+            if (chunkSize < 16) {
+                // The smallest valid chunk is 16 bytes long in this case.
+                return false;
+            }
+        } else if (chunkSize < 8) {
+            // The smallest valid chunk is 8 bytes long.
+            return false;
+        }
+
+        off64_t chunkDataSize = offset + chunkSize - chunkDataOffset;
+
+        switch (chunkType) {
+            case FOURCC('f', 't', 'y', 'p'):
+            {
+                if (chunkDataSize < 8) {
+                    return false;
+                }
+
+                uint32_t numCompatibleBrands = (chunkDataSize - 8) / 4;
+                for (size_t i = 0; i < numCompatibleBrands + 2; ++i) {
+                    if (i == 1) {
+                        // Skip this index, it refers to the minorVersion,
+                        // not a brand.
+                        continue;
+                    }
+
+                    uint32_t brand;
+                    if (source->readAt(
+                                chunkDataOffset + 4 * i, &brand, 4) < 4) {
+                        return false;
+                    }
+
+                    brand = ntohl(brand);
+
+                    if (isCompatibleBrand(brand)) {
+                        foundGoodFileType = true;
+                        break;
+                    }
+                }
+
+                if (!foundGoodFileType) {
+                    return false;
+                }
+
                 break;
             }
+
+            case FOURCC('m', 'o', 'o', 'v'):
+            {
+                moovAtomEndOffset = offset + chunkSize;
+
+                done = true;
+                break;
+            }
+
+            default:
+                break;
         }
+
+        offset += chunkSize;
     }
 
-    if (!success) {
+    if (!foundGoodFileType) {
         return false;
     }
 
     *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
     *confidence = 0.4f;
 
+    if (moovAtomEndOffset >= 0) {
+        *meta = new AMessage;
+        (*meta)->setInt64("meta-data-size", moovAtomEndOffset);
+
+        LOGV("found metadata size: %lld", moovAtomEndOffset);
+    }
+
     return true;
 }
 
 bool SniffMPEG4(
         const sp<DataSource> &source, String8 *mimeType, float *confidence,
-        sp<AMessage> *) {
-    if (BetterSniffMPEG4(source, mimeType, confidence)) {
+        sp<AMessage> *meta) {
+    if (BetterSniffMPEG4(source, mimeType, confidence, meta)) {
         return true;
     }
 
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index ebad321..69d1785 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -631,14 +631,7 @@
         --left;
     }
 
-    uint32_t x;
-    if (mDataSource->readAt(
-                mSyncSampleOffset + 8 + left * 4, &x, 4) != 4) {
-        return ERROR_IO;
-    }
-
-    x = ntohl(x);
-    --x;
+    uint32_t x = mSyncSamples[left];
 
     if (left + 1 < mNumSyncSamples) {
         uint32_t y = mSyncSamples[left + 1];
@@ -679,13 +672,7 @@
             if (x > start_sample_index) {
                 CHECK(left > 0);
 
-                if (mDataSource->readAt(
-                            mSyncSampleOffset + 8 + (left - 1) * 4, &x, 4) != 4) {
-                    return ERROR_IO;
-                }
-
-                x = ntohl(x);
-                --x;
+                x = mSyncSamples[left - 1];
 
                 CHECK(x <= start_sample_index);
             }
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 2b27ee2..86b33d1 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -336,7 +336,7 @@
         (uint32_t(buffer->height) != h) ||
         (uint32_t(buffer->format) != format) ||
         ((uint32_t(buffer->usage) & usage) != usage)) {
-            usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+            usage |= GraphicBuffer::USAGE_HW_VIDEO_ENCODER;
             status_t error;
             sp<GraphicBuffer> graphicBuffer(
                     mGraphicBufferAlloc->createGraphicBuffer(
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index 72f1282..6cec63a 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -123,6 +123,9 @@
 
     void extractAACFrames(const sp<ABuffer> &buffer);
 
+    bool isAudio() const;
+    bool isVideo() const;
+
     DISALLOW_EVIL_CONSTRUCTORS(Stream);
 };
 
@@ -401,7 +404,7 @@
         case STREAMTYPE_H264:
             mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::H264);
             break;
-        case STREAMTYPE_MPEG2_AUDIO_ATDS:
+        case STREAMTYPE_MPEG2_AUDIO_ADTS:
             mQueue = new ElementaryStreamQueue(ElementaryStreamQueue::AAC);
             break;
         case STREAMTYPE_MPEG1_AUDIO:
@@ -486,6 +489,31 @@
     return OK;
 }
 
+bool ATSParser::Stream::isVideo() const {
+    switch (mStreamType) {
+        case STREAMTYPE_H264:
+        case STREAMTYPE_MPEG1_VIDEO:
+        case STREAMTYPE_MPEG2_VIDEO:
+        case STREAMTYPE_MPEG4_VIDEO:
+            return true;
+
+        default:
+            return false;
+    }
+}
+
+bool ATSParser::Stream::isAudio() const {
+    switch (mStreamType) {
+        case STREAMTYPE_MPEG1_AUDIO:
+        case STREAMTYPE_MPEG2_AUDIO:
+        case STREAMTYPE_MPEG2_AUDIO_ADTS:
+            return true;
+
+        default:
+            return false;
+    }
+}
+
 void ATSParser::Stream::signalDiscontinuity(
         DiscontinuityType type, const sp<AMessage> &extra) {
     if (mQueue == NULL) {
@@ -495,34 +523,34 @@
     mPayloadStarted = false;
     mBuffer->setRange(0, 0);
 
-    switch (type) {
-        case DISCONTINUITY_SEEK:
-        case DISCONTINUITY_FORMATCHANGE:
-        {
-            bool isASeek = (type == DISCONTINUITY_SEEK);
-
-            mQueue->clear(!isASeek);
-
-            uint64_t resumeAtPTS;
-            if (extra != NULL
-                    && extra->findInt64(
-                        IStreamListener::kKeyResumeAtPTS,
-                        (int64_t *)&resumeAtPTS)) {
-                int64_t resumeAtMediaTimeUs =
-                    mProgram->convertPTSToTimestamp(resumeAtPTS);
-
-                extra->setInt64("resume-at-mediatimeUs", resumeAtMediaTimeUs);
-            }
-
-            if (mSource != NULL) {
-                mSource->queueDiscontinuity(type, extra);
-            }
-            break;
+    bool clearFormat = false;
+    if (isAudio()) {
+        if (type & DISCONTINUITY_AUDIO_FORMAT) {
+            clearFormat = true;
         }
+    } else {
+        if (type & DISCONTINUITY_VIDEO_FORMAT) {
+            clearFormat = true;
+        }
+    }
 
-        default:
-            TRESPASS();
-            break;
+    mQueue->clear(clearFormat);
+
+    if (type & DISCONTINUITY_TIME) {
+        uint64_t resumeAtPTS;
+        if (extra != NULL
+                && extra->findInt64(
+                    IStreamListener::kKeyResumeAtPTS,
+                    (int64_t *)&resumeAtPTS)) {
+            int64_t resumeAtMediaTimeUs =
+                mProgram->convertPTSToTimestamp(resumeAtPTS);
+
+            extra->setInt64("resume-at-mediatimeUs", resumeAtMediaTimeUs);
+        }
+    }
+
+    if (mSource != NULL) {
+        mSource->queueDiscontinuity(type, extra);
     }
 }
 
@@ -764,10 +792,7 @@
     switch (type) {
         case VIDEO:
         {
-            if (mStreamType == STREAMTYPE_H264
-                    || mStreamType == STREAMTYPE_MPEG1_VIDEO
-                    || mStreamType == STREAMTYPE_MPEG2_VIDEO
-                    || mStreamType == STREAMTYPE_MPEG4_VIDEO) {
+            if (isVideo()) {
                 return mSource;
             }
             break;
@@ -775,9 +800,7 @@
 
         case AUDIO:
         {
-            if (mStreamType == STREAMTYPE_MPEG1_AUDIO
-                    || mStreamType == STREAMTYPE_MPEG2_AUDIO
-                    || mStreamType == STREAMTYPE_MPEG2_AUDIO_ATDS) {
+            if (isAudio()) {
                 return mSource;
             }
             break;
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 878e534..c8038d1 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -33,9 +33,18 @@
 
 struct ATSParser : public RefBase {
     enum DiscontinuityType {
-        DISCONTINUITY_NONE,
-        DISCONTINUITY_SEEK,
-        DISCONTINUITY_FORMATCHANGE
+        DISCONTINUITY_NONE              = 0,
+        DISCONTINUITY_TIME              = 1,
+        DISCONTINUITY_AUDIO_FORMAT      = 2,
+        DISCONTINUITY_VIDEO_FORMAT      = 4,
+
+        DISCONTINUITY_SEEK              = DISCONTINUITY_TIME,
+
+        // For legacy reasons this also implies a time discontinuity.
+        DISCONTINUITY_FORMATCHANGE      =
+            DISCONTINUITY_AUDIO_FORMAT
+                | DISCONTINUITY_VIDEO_FORMAT
+                | DISCONTINUITY_TIME,
     };
 
     enum Flags {
@@ -71,7 +80,7 @@
         STREAMTYPE_MPEG2_VIDEO          = 0x02,
         STREAMTYPE_MPEG1_AUDIO          = 0x03,
         STREAMTYPE_MPEG2_AUDIO          = 0x04,
-        STREAMTYPE_MPEG2_AUDIO_ATDS     = 0x0f,
+        STREAMTYPE_MPEG2_AUDIO_ADTS     = 0x0f,
         STREAMTYPE_MPEG4_VIDEO          = 0x10,
         STREAMTYPE_H264                 = 0x1b,
     };
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
index ce07e32..f782ce5 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.cpp
@@ -29,8 +29,17 @@
 namespace android {
 
 AnotherPacketSource::AnotherPacketSource(const sp<MetaData> &meta)
-    : mFormat(meta),
+    : mIsAudio(false),
+      mFormat(meta),
       mEOSResult(OK) {
+    const char *mime;
+    CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+    if (!strncasecmp("audio/", mime, 6)) {
+        mIsAudio = true;
+    } else {
+        CHECK(!strncasecmp("video/", mime, 6));
+    }
 }
 
 void AnotherPacketSource::setFormat(const sp<MetaData> &meta) {
@@ -67,8 +76,7 @@
 
         int32_t discontinuity;
         if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) {
-
-            if (discontinuity == ATSParser::DISCONTINUITY_FORMATCHANGE) {
+            if (wasFormatChange(discontinuity)) {
                 mFormat.clear();
             }
 
@@ -96,7 +104,7 @@
 
         int32_t discontinuity;
         if (buffer->meta()->findInt32("discontinuity", &discontinuity)) {
-            if (discontinuity == ATSParser::DISCONTINUITY_FORMATCHANGE) {
+            if (wasFormatChange(discontinuity)) {
                 mFormat.clear();
             }
 
@@ -117,6 +125,15 @@
     return mEOSResult;
 }
 
+bool AnotherPacketSource::wasFormatChange(
+        int32_t discontinuityType) const {
+    if (mIsAudio) {
+        return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0;
+    }
+
+    return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0;
+}
+
 void AnotherPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
     int32_t damaged;
     if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
diff --git a/media/libstagefright/mpeg2ts/AnotherPacketSource.h b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
index 439c785..c99f7f2 100644
--- a/media/libstagefright/mpeg2ts/AnotherPacketSource.h
+++ b/media/libstagefright/mpeg2ts/AnotherPacketSource.h
@@ -61,10 +61,13 @@
     Mutex mLock;
     Condition mCondition;
 
+    bool mIsAudio;
     sp<MetaData> mFormat;
     List<sp<ABuffer> > mBuffers;
     status_t mEOSResult;
 
+    bool wasFormatChange(int32_t discontinuityType) const;
+
     DISALLOW_EVIL_CONSTRUCTORS(AnotherPacketSource);
 };
 
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
index f55be6e..a089dbf 100644
--- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -543,7 +543,7 @@
         case ATSParser::STREAMTYPE_H264:
             mode = ElementaryStreamQueue::H264;
             break;
-        case ATSParser::STREAMTYPE_MPEG2_AUDIO_ATDS:
+        case ATSParser::STREAMTYPE_MPEG2_AUDIO_ADTS:
             mode = ElementaryStreamQueue::AAC;
             break;
         case ATSParser::STREAMTYPE_MPEG1_AUDIO:
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 20225ba..cfea7e8 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -25,10 +25,12 @@
 #include "MtpDataPacket.h"
 #include "MtpStringBuffer.h"
 
+#define MTP_BUFFER_SIZE 16384
+
 namespace android {
 
 MtpDataPacket::MtpDataPacket()
-    :   MtpPacket(16384),   // MAX_USBFS_BUFFER_SIZE
+    :   MtpPacket(MTP_BUFFER_SIZE),   // MAX_USBFS_BUFFER_SIZE
         mOffset(MTP_CONTAINER_HEADER_SIZE)
 {
 }
@@ -345,7 +347,7 @@
 
 #ifdef MTP_DEVICE 
 int MtpDataPacket::read(int fd) {
-    int ret = ::read(fd, mBuffer, mBufferSize);
+    int ret = ::read(fd, mBuffer, MTP_BUFFER_SIZE);
     if (ret < MTP_CONTAINER_HEADER_SIZE)
         return -1;
     mPacketSize = ret;
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index dc6c011..1dcfb74 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -1053,11 +1053,14 @@
     int result = mDatabase->getObjectFilePath(handle, filePath, fileLength, format);
     if (result == MTP_RESPONSE_OK) {
         LOGV("deleting %s", (const char *)filePath);
-        deletePath((const char *)filePath);
-        return mDatabase->deleteFile(handle);
-    } else {
-        return result;
+        result = mDatabase->deleteFile(handle);
+        // Don't delete the actual files unless the database deletion is allowed
+        if (result == MTP_RESPONSE_OK) {
+            deletePath((const char *)filePath);
+        }
     }
+
+    return result;
 }
 
 MtpResponseCode MtpServer::doGetObjectPropDesc() {