Merge "Move fragmented mp4 parser to libstagefright" into jb-mr1-dev
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/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/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/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           \