Merge "Improvements to our MPEG2 Transport Stream parser" into jb-mr1-dev
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 26a25b0..34108b3 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -547,7 +547,7 @@
     status_t allocateTimedBuffer(size_t size, sp<IMemory>* buffer);
 
     /* queue a buffer obtained via allocateTimedBuffer for playback at the
-       given timestamp.  PTS units a microseconds on the media time timeline.
+       given timestamp.  PTS units are microseconds on the media time timeline.
        The media time transform (set with setMediaTimeTransform) set by the
        audio producer will handle converting from media time to local time
        (perhaps going through the common time timeline in the case of
diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h
index 19646b0..61b9d5a 100644
--- a/include/media/IStreamSource.h
+++ b/include/media/IStreamSource.h
@@ -33,6 +33,12 @@
     virtual void setBuffers(const Vector<sp<IMemory> > &buffers) = 0;
 
     virtual void onBufferAvailable(size_t index) = 0;
+
+    enum {
+        // Video PES packets contain exactly one (aligned) access unit.
+        kFlagAlignedVideoData = 1,
+    };
+    virtual uint32_t flags() const { return 0; }
 };
 
 struct IStreamListener : public IInterface {
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 73d396e..362d022 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1144,7 +1144,7 @@
 
     // If the track is not invalid already, try to allocate a buffer.  alloc
     // fails indicating that the server is dead, flag the track as invalid so
-    // we can attempt to restore in in just a bit.
+    // we can attempt to restore in just a bit.
     if (!(mCblk->flags & CBLK_INVALID_MSK)) {
         result = mAudioTrack->allocateTimedBuffer(size, buffer);
         if (result == DEAD_OBJECT) {
diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
index 078be94..78d810d 100644
--- a/media/libmedia/IStreamSource.cpp
+++ b/media/libmedia/IStreamSource.cpp
@@ -37,6 +37,7 @@
     SET_LISTENER = IBinder::FIRST_CALL_TRANSACTION,
     SET_BUFFERS,
     ON_BUFFER_AVAILABLE,
+    FLAGS,
 
     // IStreamListener
     QUEUE_BUFFER,
@@ -72,6 +73,14 @@
         remote()->transact(
                 ON_BUFFER_AVAILABLE, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual uint32_t flags() const {
+        Parcel data, reply;
+        data.writeInterfaceToken(IStreamSource::getInterfaceDescriptor());
+        remote()->transact(FLAGS, data, &reply);
+
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(StreamSource, "android.hardware.IStreamSource");
@@ -109,6 +118,13 @@
             break;
         }
 
+        case FLAGS:
+        {
+            CHECK_INTERFACE(IStreamSource, data, reply);
+            reply->writeInt32(this->flags());
+            break;
+        }
+
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmediaplayerservice/nuplayer/Android.mk b/media/libmediaplayerservice/nuplayer/Android.mk
index f469054..f946c1c 100644
--- a/media/libmediaplayerservice/nuplayer/Android.mk
+++ b/media/libmediaplayerservice/nuplayer/Android.mk
@@ -12,8 +12,6 @@
         RTSPSource.cpp                  \
         StreamingSource.cpp             \
         mp4/MP4Source.cpp               \
-        mp4/Parser.cpp                  \
-        mp4/TrackFragment.cpp           \
 
 LOCAL_C_INCLUDES := \
 	$(TOP)/frameworks/av/media/libstagefright/httplive            \
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 4a704e3..5a7a785 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -23,6 +23,7 @@
 #include "AnotherPacketSource.h"
 #include "MyHandler.h"
 
+#include <media/stagefright/MediaDefs.h>
 #include <media/stagefright/MetaData.h>
 
 namespace android {
@@ -159,6 +160,13 @@
 }
 
 sp<AnotherPacketSource> NuPlayer::RTSPSource::getSource(bool audio) {
+    if (mTSParser != NULL) {
+        sp<MediaSource> source = mTSParser->getSource(
+                audio ? ATSParser::AUDIO : ATSParser::VIDEO);
+
+        return static_cast<AnotherPacketSource *>(source.get());
+    }
+
     return audio ? mAudioTrack : mVideoTrack;
 }
 
@@ -255,7 +263,12 @@
         {
             size_t trackIndex;
             CHECK(msg->findSize("trackIndex", &trackIndex));
-            CHECK_LT(trackIndex, mTracks.size());
+
+            if (mTSParser == NULL) {
+                CHECK_LT(trackIndex, mTracks.size());
+            } else {
+                CHECK_EQ(trackIndex, 0u);
+            }
 
             sp<ABuffer> accessUnit;
             CHECK(msg->findBuffer("accessUnit", &accessUnit));
@@ -267,6 +280,37 @@
                 break;
             }
 
+            if (mTSParser != NULL) {
+                size_t offset = 0;
+                status_t err = OK;
+                while (offset + 188 <= accessUnit->size()) {
+                    err = mTSParser->feedTSPacket(
+                            accessUnit->data() + offset, 188);
+                    if (err != OK) {
+                        break;
+                    }
+
+                    offset += 188;
+                }
+
+                if (offset < accessUnit->size()) {
+                    err = ERROR_MALFORMED;
+                }
+
+                if (err != OK) {
+                    sp<AnotherPacketSource> source = getSource(false /* audio */);
+                    if (source != NULL) {
+                        source->signalEOS(err);
+                    }
+
+                    source = getSource(true /* audio */);
+                    if (source != NULL) {
+                        source->signalEOS(err);
+                    }
+                }
+                break;
+            }
+
             TrackInfo *info = &mTracks.editItemAt(trackIndex);
 
             sp<AnotherPacketSource> source = info->mSource;
@@ -296,14 +340,28 @@
 
         case MyHandler::kWhatEOS:
         {
-            size_t trackIndex;
-            CHECK(msg->findSize("trackIndex", &trackIndex));
-            CHECK_LT(trackIndex, mTracks.size());
-
             int32_t finalResult;
             CHECK(msg->findInt32("finalResult", &finalResult));
             CHECK_NE(finalResult, (status_t)OK);
 
+            if (mTSParser != NULL) {
+                sp<AnotherPacketSource> source = getSource(false /* audio */);
+                if (source != NULL) {
+                    source->signalEOS(finalResult);
+                }
+
+                source = getSource(true /* audio */);
+                if (source != NULL) {
+                    source->signalEOS(finalResult);
+                }
+
+                return;
+            }
+
+            size_t trackIndex;
+            CHECK(msg->findSize("trackIndex", &trackIndex));
+            CHECK_LT(trackIndex, mTracks.size());
+
             TrackInfo *info = &mTracks.editItemAt(trackIndex);
             sp<AnotherPacketSource> source = info->mSource;
             if (source != NULL) {
@@ -364,6 +422,14 @@
         const char *mime;
         CHECK(format->findCString(kKeyMIMEType, &mime));
 
+        if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
+            // Very special case for MPEG2 Transport Streams.
+            CHECK_EQ(numTracks, 1u);
+
+            mTSParser = new ATSParser;
+            return;
+        }
+
         bool isAudio = !strncasecmp(mime, "audio/", 6);
         bool isVideo = !strncasecmp(mime, "video/", 6);
 
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.h b/media/libmediaplayerservice/nuplayer/RTSPSource.h
index c8409e5..f07c724 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.h
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.h
@@ -20,6 +20,8 @@
 
 #include "NuPlayerSource.h"
 
+#include "ATSParser.h"
+
 #include <media/stagefright/foundation/AHandlerReflector.h>
 
 namespace android {
@@ -99,6 +101,8 @@
     sp<AnotherPacketSource> mAudioTrack;
     sp<AnotherPacketSource> mVideoTrack;
 
+    sp<ATSParser> mTSParser;
+
     int32_t mSeekGeneration;
 
     sp<AnotherPacketSource> getSource(bool audio);
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
index 25c91e9..c80d13f 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
+++ b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
@@ -16,7 +16,7 @@
 
 #include "MP4Source.h"
 
-#include "Parser.h"
+#include "FragmentedMP4Parser.h"
 #include "../NuPlayerStreamListener.h"
 
 #include <media/IStreamSource.h>
@@ -26,7 +26,7 @@
 
 namespace android {
 
-struct StreamSource : public Parser::Source {
+struct StreamSource : public FragmentedMP4Parser::Source {
     StreamSource(const sp<IStreamSource> &source)
         : mListener(new NuPlayer::NuPlayerStreamListener(source, 0)),
           mPosition(0) {
@@ -103,7 +103,7 @@
 MP4Source::MP4Source(const sp<IStreamSource> &source)
     : mSource(source),
       mLooper(new ALooper),
-      mParser(new Parser),
+      mParser(new FragmentedMP4Parser),
       mEOS(false) {
     mLooper->registerHandler(mParser);
 }
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
index 57430aa..4e927af 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
+++ b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.h
@@ -21,7 +21,7 @@
 
 namespace android {
 
-struct Parser;
+struct FragmentedMP4Parser;
 
 struct MP4Source : public NuPlayer::Source {
     MP4Source(const sp<IStreamSource> &source);
@@ -41,7 +41,7 @@
 private:
     sp<IStreamSource> mSource;
     sp<ALooper> mLooper;
-    sp<Parser> mParser;
+    sp<FragmentedMP4Parser> mParser;
     bool mEOS;
 
     DISALLOW_EVIL_CONSTRUCTORS(MP4Source);
diff --git a/media/libnbaio/README.txt b/media/libnbaio/README.txt
new file mode 100644
index 0000000..8d74ab2
--- /dev/null
+++ b/media/libnbaio/README.txt
@@ -0,0 +1,40 @@
+libnbaio (for "Non-Blocking Audio I/O") was originally intended to
+be a purely non-blocking API.  It has evolved to now include
+a few blocking implementations of the interface.
+
+Note: as used here, "short transfer count" means the return value for
+read() or write() that indicates the actual number of successfully
+transferred frames is less than the requested number of frames.
+
+Pipe
+----
+supports 1 writer and N readers
+
+no mutexes, so safe to use between SCHED_NORMAL and SCHED_FIFO threads
+
+writes:
+  non-blocking
+  never return a short transfer count
+  overwrite data if not consumed quickly enough
+
+reads:
+  non-blocking
+  return a short transfer count if not enough data
+  will lose data if reader doesn't keep up
+
+MonoPipe
+--------
+supports 1 writer and 1 reader
+
+no mutexes, so safe to use between SCHED_NORMAL and SCHED_FIFO threads
+
+write are optionally blocking:
+  if configured to block, then will wait until space available before returning
+  if configured to not block, then will return a short transfer count
+    and will never overwrite data
+
+reads:
+  non-blocking
+  return a short transfer count if not enough data
+  never lose data
+
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 3fd0f85..1522e75 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -53,6 +53,8 @@
         WVMExtractor.cpp                  \
         XINGSeeker.cpp                    \
         avc_utils.cpp                     \
+        mp4/FragmentedMP4Parser.cpp       \
+        mp4/TrackFragment.cpp             \
 
 LOCAL_C_INCLUDES:= \
         $(TOP)/frameworks/av/include/media/stagefright/timedtext \
diff --git a/media/libmediaplayerservice/nuplayer/mp4/Parser.h b/media/libstagefright/include/FragmentedMP4Parser.h
similarity index 95%
rename from media/libmediaplayerservice/nuplayer/mp4/Parser.h
rename to media/libstagefright/include/FragmentedMP4Parser.h
index 0d8d0f5..bd8fe32 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/Parser.h
+++ b/media/libstagefright/include/FragmentedMP4Parser.h
@@ -25,7 +25,7 @@
 
 struct ABuffer;
 
-struct Parser : public AHandler {
+struct FragmentedMP4Parser : public AHandler {
     struct Source : public RefBase {
         Source() {}
 
@@ -38,7 +38,7 @@
         DISALLOW_EVIL_CONSTRUCTORS(Source);
     };
 
-    Parser();
+    FragmentedMP4Parser();
 
     void start(const char *filename);
     void start(const sp<Source> &source);
@@ -49,7 +49,7 @@
     virtual void onMessageReceived(const sp<AMessage> &msg);
 
 protected:
-    virtual ~Parser();
+    virtual ~FragmentedMP4Parser();
 
 private:
     enum {
@@ -67,7 +67,7 @@
     struct DispatchEntry {
         uint32_t mType;
         uint32_t mParentType;
-        status_t (Parser::*mHandler)(uint32_t, size_t, uint64_t);
+        status_t (FragmentedMP4Parser::*mHandler)(uint32_t, size_t, uint64_t);
     };
 
     struct Container {
@@ -246,7 +246,7 @@
             sp<ABuffer> *dst,
             size_t offset, uint64_t size, size_t extra = 0) const;
 
-    DISALLOW_EVIL_CONSTRUCTORS(Parser);
+    DISALLOW_EVIL_CONSTRUCTORS(FragmentedMP4Parser);
 };
 
 }  // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/mp4/Parser.cpp b/media/libstagefright/mp4/FragmentedMP4Parser.cpp
similarity index 92%
rename from media/libmediaplayerservice/nuplayer/mp4/Parser.cpp
rename to media/libstagefright/mp4/FragmentedMP4Parser.cpp
index f664e92..e130a80 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/Parser.cpp
+++ b/media/libstagefright/mp4/FragmentedMP4Parser.cpp
@@ -15,13 +15,13 @@
  */
 
 //#define LOG_NDEBUG 0
-#define LOG_TAG "Parser"
+#define LOG_TAG "FragmentedMP4Parser"
 #include <utils/Log.h>
 
-#include "Parser.h"
+#include "include/FragmentedMP4Parser.h"
+#include "include/ESDS.h"
 #include "TrackFragment.h"
 
-#include "ESDS.h"
 
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
@@ -31,8 +31,6 @@
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/Utils.h>
 
-#include "../NuPlayerStreamListener.h"
-
 namespace android {
 
 static const char *Fourcc2String(uint32_t fourcc) {
@@ -52,7 +50,7 @@
 }
 
 // static
-const Parser::DispatchEntry Parser::kDispatchTable[] = {
+const FragmentedMP4Parser::DispatchEntry FragmentedMP4Parser::kDispatchTable[] = {
     { FOURCC('m', 'o', 'o', 'v'), 0, NULL },
     { FOURCC('t', 'r', 'a', 'k'), FOURCC('m', 'o', 'o', 'v'), NULL },
     { FOURCC('u', 'd', 't', 'a'), FOURCC('t', 'r', 'a', 'k'), NULL },
@@ -61,24 +59,24 @@
     { FOURCC('i', 'l', 's', 't'), FOURCC('m', 'e', 't', 'a'), NULL },
 
     { FOURCC('t', 'k', 'h', 'd'), FOURCC('t', 'r', 'a', 'k'),
-        &Parser::parseTrackHeader
+        &FragmentedMP4Parser::parseTrackHeader
     },
 
     { FOURCC('m', 'v', 'e', 'x'), FOURCC('m', 'o', 'o', 'v'), NULL },
 
     { FOURCC('t', 'r', 'e', 'x'), FOURCC('m', 'v', 'e', 'x'),
-        &Parser::parseTrackExtends
+        &FragmentedMP4Parser::parseTrackExtends
     },
 
     { FOURCC('e', 'd', 't', 's'), FOURCC('t', 'r', 'a', 'k'), NULL },
     { FOURCC('m', 'd', 'i', 'a'), FOURCC('t', 'r', 'a', 'k'), NULL },
 
     { FOURCC('m', 'd', 'h', 'd'), FOURCC('m', 'd', 'i', 'a'),
-        &Parser::parseMediaHeader
+        &FragmentedMP4Parser::parseMediaHeader
     },
 
     { FOURCC('h', 'd', 'l', 'r'), FOURCC('m', 'd', 'i', 'a'),
-        &Parser::parseMediaHandler
+        &FragmentedMP4Parser::parseMediaHandler
     },
 
     { FOURCC('m', 'i', 'n', 'f'), FOURCC('m', 'd', 'i', 'a'), NULL },
@@ -87,45 +85,45 @@
     { FOURCC('s', 't', 's', 'd'), FOURCC('s', 't', 'b', 'l'), NULL },
 
     { FOURCC('s', 't', 's', 'z'), FOURCC('s', 't', 'b', 'l'),
-        &Parser::parseSampleSizes },
+        &FragmentedMP4Parser::parseSampleSizes },
 
     { FOURCC('s', 't', 'z', '2'), FOURCC('s', 't', 'b', 'l'),
-        &Parser::parseCompactSampleSizes },
+        &FragmentedMP4Parser::parseCompactSampleSizes },
 
     { FOURCC('s', 't', 's', 'c'), FOURCC('s', 't', 'b', 'l'),
-        &Parser::parseSampleToChunk },
+        &FragmentedMP4Parser::parseSampleToChunk },
 
     { FOURCC('s', 't', 'c', 'o'), FOURCC('s', 't', 'b', 'l'),
-        &Parser::parseChunkOffsets },
+        &FragmentedMP4Parser::parseChunkOffsets },
 
     { FOURCC('c', 'o', '6', '4'), FOURCC('s', 't', 'b', 'l'),
-        &Parser::parseChunkOffsets64 },
+        &FragmentedMP4Parser::parseChunkOffsets64 },
 
     { FOURCC('a', 'v', 'c', 'C'), FOURCC('a', 'v', 'c', '1'),
-        &Parser::parseAVCCodecSpecificData },
+        &FragmentedMP4Parser::parseAVCCodecSpecificData },
 
     { FOURCC('e', 's', 'd', 's'), FOURCC('m', 'p', '4', 'a'),
-        &Parser::parseESDSCodecSpecificData },
+        &FragmentedMP4Parser::parseESDSCodecSpecificData },
 
     { FOURCC('e', 's', 'd', 's'), FOURCC('m', 'p', '4', 'v'),
-        &Parser::parseESDSCodecSpecificData },
+        &FragmentedMP4Parser::parseESDSCodecSpecificData },
 
-    { FOURCC('m', 'd', 'a', 't'), 0, &Parser::parseMediaData },
+    { FOURCC('m', 'd', 'a', 't'), 0, &FragmentedMP4Parser::parseMediaData },
 
     { FOURCC('m', 'o', 'o', 'f'), 0, NULL },
     { FOURCC('t', 'r', 'a', 'f'), FOURCC('m', 'o', 'o', 'f'), NULL },
 
     { FOURCC('t', 'f', 'h', 'd'), FOURCC('t', 'r', 'a', 'f'),
-        &Parser::parseTrackFragmentHeader
+        &FragmentedMP4Parser::parseTrackFragmentHeader
     },
     { FOURCC('t', 'r', 'u', 'n'), FOURCC('t', 'r', 'a', 'f'),
-        &Parser::parseTrackFragmentRun
+        &FragmentedMP4Parser::parseTrackFragmentRun
     },
 
     { FOURCC('m', 'f', 'r', 'a'), 0, NULL },
 };
 
-struct FileSource : public Parser::Source {
+struct FileSource : public FragmentedMP4Parser::Source {
     FileSource(const char *filename)
         : mFile(fopen(filename, "rb")) {
             CHECK(mFile != NULL);
@@ -142,28 +140,28 @@
     DISALLOW_EVIL_CONSTRUCTORS(FileSource);
 };
 
-Parser::Parser()
+FragmentedMP4Parser::FragmentedMP4Parser()
     : mBufferPos(0),
       mSuspended(false),
       mFinalResult(OK) {
 }
 
-Parser::~Parser() {
+FragmentedMP4Parser::~FragmentedMP4Parser() {
 }
 
-void Parser::start(const char *filename) {
+void FragmentedMP4Parser::start(const char *filename) {
     sp<AMessage> msg = new AMessage(kWhatStart, id());
     msg->setObject("source", new FileSource(filename));
     msg->post();
 }
 
-void Parser::start(const sp<Source> &source) {
+void FragmentedMP4Parser::start(const sp<Source> &source) {
     sp<AMessage> msg = new AMessage(kWhatStart, id());
     msg->setObject("source", source);
     msg->post();
 }
 
-sp<AMessage> Parser::getFormat(bool audio) {
+sp<AMessage> FragmentedMP4Parser::getFormat(bool audio) {
     sp<AMessage> msg = new AMessage(kWhatGetFormat, id());
     msg->setInt32("audio", audio);
 
@@ -185,7 +183,7 @@
     return format;
 }
 
-status_t Parser::dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit) {
+status_t FragmentedMP4Parser::dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit) {
     sp<AMessage> msg = new AMessage(kWhatDequeueAccessUnit, id());
     msg->setInt32("audio", audio);
 
@@ -205,7 +203,7 @@
     return OK;
 }
 
-ssize_t Parser::findTrack(bool wantAudio) const {
+ssize_t FragmentedMP4Parser::findTrack(bool wantAudio) const {
     for (size_t i = 0; i < mTracks.size(); ++i) {
         const TrackInfo *info = &mTracks.valueAt(i);
 
@@ -227,7 +225,7 @@
     return -EWOULDBLOCK;
 }
 
-void Parser::onMessageReceived(const sp<AMessage> &msg) {
+void FragmentedMP4Parser::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatStart:
         {
@@ -373,7 +371,7 @@
     }
 }
 
-status_t Parser::onProceed() {
+status_t FragmentedMP4Parser::onProceed() {
     status_t err;
 
     if ((err = need(8)) != OK) {
@@ -565,7 +563,7 @@
 }
 
 // static
-int Parser::CompareSampleLocation(
+int FragmentedMP4Parser::CompareSampleLocation(
         const SampleInfo &sample, const MediaDataInfo &mdatInfo) {
     if (sample.mOffset + sample.mSize < mdatInfo.mOffset) {
         return -1;
@@ -586,7 +584,7 @@
     return 0;
 }
 
-void Parser::resumeIfNecessary() {
+void FragmentedMP4Parser::resumeIfNecessary() {
     if (!mSuspended) {
         return;
     }
@@ -597,7 +595,7 @@
     (new AMessage(kWhatProceed, id()))->post();
 }
 
-status_t Parser::getSample(
+status_t FragmentedMP4Parser::getSample(
         TrackInfo *info, sp<TrackFragment> *fragment, SampleInfo *sampleInfo) {
     for (;;) {
         if (info->mFragments.empty()) {
@@ -625,7 +623,7 @@
     }
 }
 
-status_t Parser::onDequeueAccessUnit(
+status_t FragmentedMP4Parser::onDequeueAccessUnit(
         size_t trackIndex, sp<ABuffer> *accessUnit) {
     TrackInfo *info = &mTracks.editValueAt(trackIndex);
 
@@ -730,7 +728,7 @@
     return 0;
 }
 
-status_t Parser::makeAccessUnit(
+status_t FragmentedMP4Parser::makeAccessUnit(
         TrackInfo *info,
         const SampleInfo &sample,
         const MediaDataInfo &mdatInfo,
@@ -801,7 +799,7 @@
     return OK;
 }
 
-status_t Parser::need(size_t size) {
+status_t FragmentedMP4Parser::need(size_t size) {
     if (!fitsContainer(size)) {
         return -EINVAL;
     }
@@ -819,7 +817,7 @@
     return -EAGAIN;
 }
 
-void Parser::enter(off64_t offset, uint32_t type, uint64_t size) {
+void FragmentedMP4Parser::enter(off64_t offset, uint32_t type, uint64_t size) {
     Container container;
     container.mOffset = offset;
     container.mType = type;
@@ -829,32 +827,32 @@
     mStack.push(container);
 }
 
-bool Parser::fitsContainer(uint64_t size) const {
+bool FragmentedMP4Parser::fitsContainer(uint64_t size) const {
     CHECK(!mStack.isEmpty());
     const Container &container = mStack.itemAt(mStack.size() - 1);
 
     return container.mExtendsToEOF || size <= container.mBytesRemaining;
 }
 
-uint16_t Parser::readU16(size_t offset) {
+uint16_t FragmentedMP4Parser::readU16(size_t offset) {
     CHECK_LE(offset + 2, mBuffer->size());
 
     const uint8_t *ptr = mBuffer->data() + offset;
     return (ptr[0] << 8) | ptr[1];
 }
 
-uint32_t Parser::readU32(size_t offset) {
+uint32_t FragmentedMP4Parser::readU32(size_t offset) {
     CHECK_LE(offset + 4, mBuffer->size());
 
     const uint8_t *ptr = mBuffer->data() + offset;
     return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
 }
 
-uint64_t Parser::readU64(size_t offset) {
+uint64_t FragmentedMP4Parser::readU64(size_t offset) {
     return (((uint64_t)readU32(offset)) << 32) | readU32(offset + 4);
 }
 
-void Parser::skip(off_t distance) {
+void FragmentedMP4Parser::skip(off_t distance) {
     CHECK(!mStack.isEmpty());
     for (size_t i = mStack.size(); i-- > 0;) {
         Container *container = &mStack.editItemAt(i);
@@ -916,7 +914,7 @@
     mBufferPos += distance;
 }
 
-status_t Parser::parseTrackHeader(
+status_t FragmentedMP4Parser::parseTrackHeader(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 4 > size) {
         return -EINVAL;
@@ -963,7 +961,7 @@
     return OK;
 }
 
-status_t Parser::parseMediaHeader(
+status_t FragmentedMP4Parser::parseMediaHeader(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 4 > size) {
         return -EINVAL;
@@ -996,7 +994,7 @@
     return OK;
 }
 
-status_t Parser::parseMediaHandler(
+status_t FragmentedMP4Parser::parseMediaHandler(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 12 > size) {
         return -EINVAL;
@@ -1024,7 +1022,7 @@
     return OK;
 }
 
-status_t Parser::parseVisualSampleEntry(
+status_t FragmentedMP4Parser::parseVisualSampleEntry(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 78 > size) {
         return -EINVAL;
@@ -1067,7 +1065,7 @@
     return OK;
 }
 
-status_t Parser::parseAudioSampleEntry(
+status_t FragmentedMP4Parser::parseAudioSampleEntry(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 28 > size) {
         return -EINVAL;
@@ -1133,37 +1131,37 @@
     format->setBuffer(StringPrintf("csd-%d", index).c_str(), csd);
 }
 
-status_t Parser::parseSampleSizes(
+status_t FragmentedMP4Parser::parseSampleSizes(
         uint32_t type, size_t offset, uint64_t size) {
     return editTrack(mCurrentTrackID)->mStaticFragment->parseSampleSizes(
             this, type, offset, size);
 }
 
-status_t Parser::parseCompactSampleSizes(
+status_t FragmentedMP4Parser::parseCompactSampleSizes(
         uint32_t type, size_t offset, uint64_t size) {
     return editTrack(mCurrentTrackID)->mStaticFragment->parseCompactSampleSizes(
             this, type, offset, size);
 }
 
-status_t Parser::parseSampleToChunk(
+status_t FragmentedMP4Parser::parseSampleToChunk(
         uint32_t type, size_t offset, uint64_t size) {
     return editTrack(mCurrentTrackID)->mStaticFragment->parseSampleToChunk(
             this, type, offset, size);
 }
 
-status_t Parser::parseChunkOffsets(
+status_t FragmentedMP4Parser::parseChunkOffsets(
         uint32_t type, size_t offset, uint64_t size) {
     return editTrack(mCurrentTrackID)->mStaticFragment->parseChunkOffsets(
             this, type, offset, size);
 }
 
-status_t Parser::parseChunkOffsets64(
+status_t FragmentedMP4Parser::parseChunkOffsets64(
         uint32_t type, size_t offset, uint64_t size) {
     return editTrack(mCurrentTrackID)->mStaticFragment->parseChunkOffsets64(
             this, type, offset, size);
 }
 
-status_t Parser::parseAVCCodecSpecificData(
+status_t FragmentedMP4Parser::parseAVCCodecSpecificData(
         uint32_t type, size_t offset, uint64_t size) {
     TrackInfo *trackInfo = editTrack(mCurrentTrackID);
 
@@ -1246,7 +1244,7 @@
     return OK;
 }
 
-status_t Parser::parseESDSCodecSpecificData(
+status_t FragmentedMP4Parser::parseESDSCodecSpecificData(
         uint32_t type, size_t offset, uint64_t size) {
     TrackInfo *trackInfo = editTrack(mCurrentTrackID);
 
@@ -1351,7 +1349,7 @@
     return OK;
 }
 
-status_t Parser::parseMediaData(
+status_t FragmentedMP4Parser::parseMediaData(
         uint32_t type, size_t offset, uint64_t size) {
     ALOGV("skipping 'mdat' chunk at offsets 0x%08lx-0x%08llx.",
           mBufferPos + offset, mBufferPos + size);
@@ -1372,7 +1370,7 @@
     return OK;
 }
 
-status_t Parser::parseTrackExtends(
+status_t FragmentedMP4Parser::parseTrackExtends(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 24 > size) {
         return -EINVAL;
@@ -1393,7 +1391,7 @@
     return OK;
 }
 
-Parser::TrackInfo *Parser::editTrack(
+FragmentedMP4Parser::TrackInfo *FragmentedMP4Parser::editTrack(
         uint32_t trackID, bool createIfNecessary) {
     ssize_t i = mTracks.indexOfKey(trackID);
 
@@ -1422,7 +1420,7 @@
     return &mTracks.editValueAt(mTracks.indexOfKey(trackID));
 }
 
-status_t Parser::parseTrackFragmentHeader(
+status_t FragmentedMP4Parser::parseTrackFragmentHeader(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 8 > size) {
         return -EINVAL;
@@ -1512,7 +1510,7 @@
     return OK;
 }
 
-status_t Parser::parseTrackFragmentRun(
+status_t FragmentedMP4Parser::parseTrackFragmentRun(
         uint32_t type, size_t offset, uint64_t size) {
     if (offset + 8 > size) {
         return -EINVAL;
@@ -1670,7 +1668,7 @@
     return OK;
 }
 
-void Parser::copyBuffer(
+void FragmentedMP4Parser::copyBuffer(
         sp<ABuffer> *dst, size_t offset, uint64_t size, size_t extra) const {
     sp<ABuffer> buf = new ABuffer(size + extra);
     memcpy(buf->data(), mBuffer->data() + offset, size);
diff --git a/media/libmediaplayerservice/nuplayer/mp4/TrackFragment.cpp b/media/libstagefright/mp4/TrackFragment.cpp
similarity index 82%
rename from media/libmediaplayerservice/nuplayer/mp4/TrackFragment.cpp
rename to media/libstagefright/mp4/TrackFragment.cpp
index a4c31ea..3699038 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/TrackFragment.cpp
+++ b/media/libstagefright/mp4/TrackFragment.cpp
@@ -28,15 +28,15 @@
 
 namespace android {
 
-Parser::DynamicTrackFragment::DynamicTrackFragment()
+FragmentedMP4Parser::DynamicTrackFragment::DynamicTrackFragment()
     : mComplete(false),
       mSampleIndex(0) {
 }
 
-Parser::DynamicTrackFragment::~DynamicTrackFragment() {
+FragmentedMP4Parser::DynamicTrackFragment::~DynamicTrackFragment() {
 }
 
-status_t Parser::DynamicTrackFragment::getSample(SampleInfo *info) {
+status_t FragmentedMP4Parser::DynamicTrackFragment::getSample(SampleInfo *info) {
     if (mSampleIndex >= mSamples.size()) {
         return mComplete ? ERROR_END_OF_STREAM : -EWOULDBLOCK;
     }
@@ -46,11 +46,11 @@
     return OK;
 }
 
-void Parser::DynamicTrackFragment::advance() {
+void FragmentedMP4Parser::DynamicTrackFragment::advance() {
     ++mSampleIndex;
 }
 
-void Parser::DynamicTrackFragment::addSample(
+void FragmentedMP4Parser::DynamicTrackFragment::addSample(
         off64_t dataOffset, size_t sampleSize,
         uint32_t presentationTime,
         size_t sampleDescIndex,
@@ -65,19 +65,19 @@
     sampleInfo->mFlags = flags;
 }
 
-status_t Parser::DynamicTrackFragment::signalCompletion() {
+status_t FragmentedMP4Parser::DynamicTrackFragment::signalCompletion() {
     mComplete = true;
 
     return OK;
 }
 
-bool Parser::DynamicTrackFragment::complete() const {
+bool FragmentedMP4Parser::DynamicTrackFragment::complete() const {
     return mComplete;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 
-Parser::StaticTrackFragment::StaticTrackFragment()
+FragmentedMP4Parser::StaticTrackFragment::StaticTrackFragment()
     : mSampleIndex(0),
       mSampleCount(0),
       mChunkIndex(0),
@@ -87,10 +87,10 @@
       mNextSampleOffset(0) {
 }
 
-Parser::StaticTrackFragment::~StaticTrackFragment() {
+FragmentedMP4Parser::StaticTrackFragment::~StaticTrackFragment() {
 }
 
-status_t Parser::StaticTrackFragment::getSample(SampleInfo *info) {
+status_t FragmentedMP4Parser::StaticTrackFragment::getSample(SampleInfo *info) {
     if (mSampleIndex >= mSampleCount) {
         return ERROR_END_OF_STREAM;
     }
@@ -104,7 +104,7 @@
     return OK;
 }
 
-void Parser::StaticTrackFragment::updateSampleInfo() {
+void FragmentedMP4Parser::StaticTrackFragment::updateSampleInfo() {
     if (mSampleIndex >= mSampleCount) {
         return;
     }
@@ -185,7 +185,7 @@
     mSampleInfo.mFlags = 0;
 }
 
-void Parser::StaticTrackFragment::advance() {
+void FragmentedMP4Parser::StaticTrackFragment::advance() {
     mNextSampleOffset += mSampleInfo.mSize;
 
     ++mSampleIndex;
@@ -223,7 +223,7 @@
     ptr[3] = x & 0xff;
 }
 
-status_t Parser::StaticTrackFragment::signalCompletion() {
+status_t FragmentedMP4Parser::StaticTrackFragment::signalCompletion() {
     mSampleToChunkIndex = 0;
 
     mSampleToChunkRemaining =
@@ -236,12 +236,12 @@
     return OK;
 }
 
-bool Parser::StaticTrackFragment::complete() const {
+bool FragmentedMP4Parser::StaticTrackFragment::complete() const {
     return true;
 }
 
-status_t Parser::StaticTrackFragment::parseSampleSizes(
-        Parser *parser, uint32_t type, size_t offset, uint64_t size) {
+status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleSizes(
+        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
     if (offset + 12 > size) {
         return ERROR_MALFORMED;
     }
@@ -264,8 +264,8 @@
     return OK;
 }
 
-status_t Parser::StaticTrackFragment::parseCompactSampleSizes(
-        Parser *parser, uint32_t type, size_t offset, uint64_t size) {
+status_t FragmentedMP4Parser::StaticTrackFragment::parseCompactSampleSizes(
+        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
     if (offset + 12 > size) {
         return ERROR_MALFORMED;
     }
@@ -293,8 +293,8 @@
     return OK;
 }
 
-status_t Parser::StaticTrackFragment::parseSampleToChunk(
-        Parser *parser, uint32_t type, size_t offset, uint64_t size) {
+status_t FragmentedMP4Parser::StaticTrackFragment::parseSampleToChunk(
+        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
     if (offset + 8 > size) {
         return ERROR_MALFORMED;
     }
@@ -318,8 +318,8 @@
     return OK;
 }
 
-status_t Parser::StaticTrackFragment::parseChunkOffsets(
-        Parser *parser, uint32_t type, size_t offset, uint64_t size) {
+status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets(
+        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
     if (offset + 8 > size) {
         return ERROR_MALFORMED;
     }
@@ -339,8 +339,8 @@
     return OK;
 }
 
-status_t Parser::StaticTrackFragment::parseChunkOffsets64(
-        Parser *parser, uint32_t type, size_t offset, uint64_t size) {
+status_t FragmentedMP4Parser::StaticTrackFragment::parseChunkOffsets64(
+        FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size) {
     if (offset + 8 > size) {
         return ERROR_MALFORMED;
     }
diff --git a/media/libmediaplayerservice/nuplayer/mp4/TrackFragment.h b/media/libstagefright/mp4/TrackFragment.h
similarity index 77%
rename from media/libmediaplayerservice/nuplayer/mp4/TrackFragment.h
rename to media/libstagefright/mp4/TrackFragment.h
index 1498aad..e1ad46e 100644
--- a/media/libmediaplayerservice/nuplayer/mp4/TrackFragment.h
+++ b/media/libstagefright/mp4/TrackFragment.h
@@ -18,11 +18,11 @@
 
 #define TRACK_FRAGMENT_H_
 
-#include "Parser.h"
+#include "include/FragmentedMP4Parser.h"
 
 namespace android {
 
-struct Parser::TrackFragment : public RefBase {
+struct FragmentedMP4Parser::TrackFragment : public RefBase {
     TrackFragment() {}
 
     virtual status_t getSample(SampleInfo *info) = 0;
@@ -38,7 +38,7 @@
     DISALLOW_EVIL_CONSTRUCTORS(TrackFragment);
 };
 
-struct Parser::DynamicTrackFragment : public Parser::TrackFragment {
+struct FragmentedMP4Parser::DynamicTrackFragment : public FragmentedMP4Parser::TrackFragment {
     DynamicTrackFragment();
 
     virtual status_t getSample(SampleInfo *info);
@@ -66,7 +66,7 @@
     DISALLOW_EVIL_CONSTRUCTORS(DynamicTrackFragment);
 };
 
-struct Parser::StaticTrackFragment : public Parser::TrackFragment {
+struct FragmentedMP4Parser::StaticTrackFragment : public FragmentedMP4Parser::TrackFragment {
     StaticTrackFragment();
 
     virtual status_t getSample(SampleInfo *info);
@@ -76,19 +76,19 @@
     virtual bool complete() const;
 
     status_t parseSampleSizes(
-            Parser *parser, uint32_t type, size_t offset, uint64_t size);
+            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
 
     status_t parseCompactSampleSizes(
-            Parser *parser, uint32_t type, size_t offset, uint64_t size);
+            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
 
     status_t parseSampleToChunk(
-            Parser *parser, uint32_t type, size_t offset, uint64_t size);
+            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
 
     status_t parseChunkOffsets(
-            Parser *parser, uint32_t type, size_t offset, uint64_t size);
+            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
 
     status_t parseChunkOffsets64(
-            Parser *parser, uint32_t type, size_t offset, uint64_t size);
+            FragmentedMP4Parser *parser, uint32_t type, size_t offset, uint64_t size);
 
 protected:
     virtual ~StaticTrackFragment();
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 1cab077..e58e9bf 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -33,8 +33,9 @@
 
 namespace android {
 
-ElementaryStreamQueue::ElementaryStreamQueue(Mode mode)
-    : mMode(mode) {
+ElementaryStreamQueue::ElementaryStreamQueue(Mode mode, uint32_t flags)
+    : mMode(mode),
+      mFlags(flags) {
 }
 
 sp<MetaData> ElementaryStreamQueue::getFormat() {
@@ -289,6 +290,31 @@
 }
 
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
+    if ((mFlags & kFlag_AlignedData) && mMode == H264) {
+        if (mRangeInfos.empty()) {
+            return NULL;
+        }
+
+        RangeInfo info = *mRangeInfos.begin();
+        mRangeInfos.erase(mRangeInfos.begin());
+
+        sp<ABuffer> accessUnit = new ABuffer(info.mLength);
+        memcpy(accessUnit->data(), mBuffer->data(), info.mLength);
+        accessUnit->meta()->setInt64("timeUs", info.mTimestampUs);
+
+        memmove(mBuffer->data(),
+                mBuffer->data() + info.mLength,
+                mBuffer->size() - info.mLength);
+
+        mBuffer->setRange(0, mBuffer->size() - info.mLength);
+
+        if (mFormat == NULL) {
+            mFormat = MakeAVCCodecSpecificData(accessUnit);
+        }
+
+        return accessUnit;
+    }
+
     switch (mMode) {
         case H264:
             return dequeueAccessUnitH264();
@@ -436,8 +462,8 @@
 
 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
     const uint8_t *data = mBuffer->data();
-    size_t size = mBuffer->size();
 
+    size_t size = mBuffer->size();
     Vector<NALPosition> nals;
 
     size_t totalSize = 0;
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 4035ed3..72aa2e7 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -36,7 +36,12 @@
         MPEG_VIDEO,
         MPEG4_VIDEO,
     };
-    ElementaryStreamQueue(Mode mode);
+
+    enum Flags {
+        // Data appended to the queue is always at access unit boundaries.
+        kFlag_AlignedData = 1,
+    };
+    ElementaryStreamQueue(Mode mode, uint32_t flags = 0);
 
     status_t appendData(const void *data, size_t size, int64_t timeUs);
     void clear(bool clearFormat);
@@ -52,6 +57,7 @@
     };
 
     Mode mMode;
+    uint32_t mFlags;
 
     sp<ABuffer> mBuffer;
     List<RangeInfo> mRangeInfos;
diff --git a/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
new file mode 100644
index 0000000..4c9bf5b
--- /dev/null
+++ b/media/libstagefright/rtsp/AMPEG2TSAssembler.cpp
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AMPEG2TSAssembler"
+#include <utils/Log.h>
+
+#include "AMPEG2TSAssembler.h"
+
+#include "ARTPSource.h"
+#include "ASessionDescription.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+AMPEG2TSAssembler::AMPEG2TSAssembler(
+        const sp<AMessage> &notify, const char *desc, const AString &params)
+    : mNotifyMsg(notify),
+      mNextExpectedSeqNoValid(false),
+      mNextExpectedSeqNo(0) {
+}
+
+AMPEG2TSAssembler::~AMPEG2TSAssembler() {
+}
+
+ARTPAssembler::AssemblyStatus AMPEG2TSAssembler::assembleMore(
+        const sp<ARTPSource> &source) {
+    return addPacket(source);
+}
+
+ARTPAssembler::AssemblyStatus AMPEG2TSAssembler::addPacket(
+        const sp<ARTPSource> &source) {
+    List<sp<ABuffer> > *queue = source->queue();
+
+    if (queue->empty()) {
+        return NOT_ENOUGH_DATA;
+    }
+
+    if (mNextExpectedSeqNoValid) {
+        List<sp<ABuffer> >::iterator it = queue->begin();
+        while (it != queue->end()) {
+            if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) {
+                break;
+            }
+
+            it = queue->erase(it);
+        }
+
+        if (queue->empty()) {
+            return NOT_ENOUGH_DATA;
+        }
+    }
+
+    sp<ABuffer> buffer = *queue->begin();
+
+    if (!mNextExpectedSeqNoValid) {
+        mNextExpectedSeqNoValid = true;
+        mNextExpectedSeqNo = (uint32_t)buffer->int32Data();
+    } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) {
+        ALOGV("Not the sequence number I expected");
+
+        return WRONG_SEQUENCE_NUMBER;
+    }
+
+    // hexdump(buffer->data(), buffer->size());
+
+    if ((buffer->size() % 188) > 0) {
+        queue->erase(queue->begin());
+        ++mNextExpectedSeqNo;
+
+        ALOGV("Not a multiple of transport packet size.");
+
+        return MALFORMED_PACKET;
+    }
+
+    sp<AMessage> msg = mNotifyMsg->dup();
+    msg->setBuffer("access-unit", buffer);
+    msg->post();
+
+    queue->erase(queue->begin());
+    ++mNextExpectedSeqNo;
+
+    return OK;
+}
+
+void AMPEG2TSAssembler::packetLost() {
+    CHECK(mNextExpectedSeqNoValid);
+    ++mNextExpectedSeqNo;
+}
+
+void AMPEG2TSAssembler::onByeReceived() {
+    sp<AMessage> msg = mNotifyMsg->dup();
+    msg->setInt32("eos", true);
+    msg->post();
+}
+
+}  // namespace android
+
+
diff --git a/media/libstagefright/rtsp/AMPEG2TSAssembler.h b/media/libstagefright/rtsp/AMPEG2TSAssembler.h
new file mode 100644
index 0000000..712e18e
--- /dev/null
+++ b/media/libstagefright/rtsp/AMPEG2TSAssembler.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef A_MPEG2_TS_ASSEMBLER_H_
+
+#define A_MPEG2_TS_ASSEMBLER_H_
+
+#include "ARTPAssembler.h"
+
+namespace android {
+
+struct AMessage;
+struct AString;
+struct MetaData;
+
+struct AMPEG2TSAssembler : public ARTPAssembler {
+    AMPEG2TSAssembler(
+            const sp<AMessage> &notify,
+            const char *desc, const AString &params);
+
+protected:
+    virtual ~AMPEG2TSAssembler();
+
+    virtual AssemblyStatus assembleMore(const sp<ARTPSource> &source);
+    virtual void onByeReceived();
+    virtual void packetLost();
+
+private:
+    sp<AMessage> mNotifyMsg;
+    bool mNextExpectedSeqNoValid;
+    uint32_t mNextExpectedSeqNo;
+
+    AssemblyStatus addPacket(const sp<ARTPSource> &source);
+
+    DISALLOW_EVIL_CONSTRUCTORS(AMPEG2TSAssembler);
+};
+
+}  // namespace android
+
+#endif  // A_MPEG2_TS_ASSEMBLER_H_
+
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index ddd2f06..462c384 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -566,6 +566,8 @@
                 codecSpecificData->data(), codecSpecificData->size());
     } else if (ARawAudioAssembler::Supports(desc.c_str())) {
         ARawAudioAssembler::MakeFormat(desc.c_str(), mFormat);
+    } else if (!strncasecmp("MP2T/", desc.c_str(), 5)) {
+        mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
     } else {
         mInitCheck = ERROR_UNSUPPORTED;
     }
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index ed68790..d7c3bd6 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -23,6 +23,7 @@
 #include "AAMRAssembler.h"
 #include "AAVCAssembler.h"
 #include "AH263Assembler.h"
+#include "AMPEG2TSAssembler.h"
 #include "AMPEG4AudioAssembler.h"
 #include "AMPEG4ElementaryAssembler.h"
 #include "ARawAudioAssembler.h"
@@ -73,6 +74,8 @@
         mIssueFIRRequests = true;
     } else if (ARawAudioAssembler::Supports(desc.c_str())) {
         mAssembler = new ARawAudioAssembler(notify, desc.c_str(), params);
+    } else if (!strncasecmp(desc.c_str(), "MP2T/", 5)) {
+        mAssembler = new AMPEG2TSAssembler(notify, desc.c_str(), params);
     } else {
         TRESPASS();
     }
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index d0f5259..49e2daf 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -6,6 +6,7 @@
         AAMRAssembler.cpp           \
         AAVCAssembler.cpp           \
         AH263Assembler.cpp          \
+        AMPEG2TSAssembler.cpp       \
         AMPEG4AudioAssembler.cpp    \
         AMPEG4ElementaryAssembler.cpp \
         APacketSource.cpp           \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 1a37f4f..14f74b5 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -169,8 +169,8 @@
 // for the track.  The client then sub-divides this into smaller buffers for its use.
 // Currently the client uses double-buffering by default, but doesn't tell us about that.
 // So for now we just assume that client is double-buffered.
-// FIXME It would be better for client to tell us whether it wants double-buffering or N-buffering,
-// so we could allocate the right amount of memory.
+// FIXME It would be better for client to tell AudioFlinger whether it wants double-buffering or
+// N-buffering, so AudioFlinger could allocate the right amount of memory.
 // See the client's minBufCount and mNotificationFramesAct calculations for details.
 static const int kFastTrackMultiplier = 2;
 
@@ -258,11 +258,11 @@
 AudioFlinger::~AudioFlinger()
 {
     while (!mRecordThreads.isEmpty()) {
-        // closeInput() will remove first entry from mRecordThreads
+        // closeInput_nonvirtual() will remove specified entry from mRecordThreads
         closeInput_nonvirtual(mRecordThreads.keyAt(0));
     }
     while (!mPlaybackThreads.isEmpty()) {
-        // closeOutput() will remove first entry from mPlaybackThreads
+        // closeOutput_nonvirtual() will remove specified entry from mPlaybackThreads
         closeOutput_nonvirtual(mPlaybackThreads.keyAt(0));
     }
 
@@ -1134,7 +1134,7 @@
 
 AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
         audio_devices_t device, type_t type)
-    :   Thread(false),
+    :   Thread(false /*canCallJava*/),
         mType(type),
         mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mNormalFrameCount(0),
         // mChannelMask
@@ -1142,6 +1142,7 @@
         mFrameSize(1), mFormat(AUDIO_FORMAT_INVALID),
         mParamStatus(NO_ERROR),
         mStandby(false), mDevice(device), mId(id),
+        // mName will be set by concrete (non-virtual) subclass
         mDeathRecipient(new PMDeathRecipient(this))
 {
 }
@@ -6097,7 +6098,7 @@
                     if (mChannelCount == 1 && mReqChannelCount == 1) {
                         framesOut >>= 1;
                     }
-                    mResampler->resample(mRsmpOutBuffer, framesOut, this);
+                    mResampler->resample(mRsmpOutBuffer, framesOut, this /* AudioBufferProvider* */);
                     // ditherAndClamp() works as long as all buffers returned by mActiveTrack->getNextBuffer()
                     // are 32 bit aligned which should be always true.
                     if (mChannelCount == 2 && mReqChannelCount == 1) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index b4aefc1..4723cd9 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -454,8 +454,9 @@
             /*const*/ sp<Client> mClient;   // see explanation at ~TrackBase() why not const
             sp<IMemory>         mCblkMemory;
             audio_track_cblk_t* mCblk;
-            void*               mBuffer;
-            void*               mBufferEnd;
+            void*               mBuffer;    // start of track buffer, typically in shared memory
+            void*               mBufferEnd; // &mBuffer[mFrameCount * frameSize], where frameSize
+                                            //   is based on mChannelCount and 16-bit samples
             uint32_t            mFrameCount;
             // we don't really need a lock for these
             track_state         mState;
@@ -1364,6 +1365,7 @@
 
     // record thread
     class RecordThread : public ThreadBase, public AudioBufferProvider
+                            // derives from AudioBufferProvider interface for use by resampler
     {
     public:
 
@@ -1420,7 +1422,7 @@
         void        dumpInternals(int fd, const Vector<String16>& args);
         void        dumpTracks(int fd, const Vector<String16>& args);
 
-        // Thread
+        // Thread virtuals
         virtual bool        threadLoop();
         virtual status_t    readyToRun();
 
@@ -1968,9 +1970,10 @@
                 DefaultKeyedVector< audio_io_handle_t, sp<PlaybackThread> >  mPlaybackThreads;
                 stream_type_t                       mStreamTypes[AUDIO_STREAM_CNT];
 
-                // both are protected by mLock
+                // member variables below are protected by mLock
                 float                               mMasterVolume;
                 bool                                mMasterMute;
+                // end of variables protected by mLock
 
                 DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> >    mRecordThreads;
 
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 7cac025..f62c0a0 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -109,7 +109,12 @@
                 __FUNCTION__, mId, strerror(-res), res);
         return res;
     }
-
+    res = set_camera_metadata_vendor_tag_ops(mVendorTagOps);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: Unable to set tag ops: %s (%d)",
+            __FUNCTION__, mId, strerror(-res), res);
+        return res;
+    }
     setNotifyCallback(NULL);
 
     return OK;