experimental support for fragmented mp4 playback in nuplayer

cherry picked from change 170999

Change-Id: I407775f0290154ad4961134839a15c9f296424c0
diff --git a/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
new file mode 100644
index 0000000..25c91e9
--- /dev/null
+++ b/media/libmediaplayerservice/nuplayer/mp4/MP4Source.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "MP4Source.h"
+
+#include "Parser.h"
+#include "../NuPlayerStreamListener.h"
+
+#include <media/IStreamSource.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+struct StreamSource : public Parser::Source {
+    StreamSource(const sp<IStreamSource> &source)
+        : mListener(new NuPlayer::NuPlayerStreamListener(source, 0)),
+          mPosition(0) {
+        mListener->start();
+    }
+
+    virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
+        if (offset < mPosition) {
+            return -EPIPE;
+        }
+
+        while (offset > mPosition) {
+            char buffer[1024];
+            off64_t skipBytes = offset - mPosition;
+            if (skipBytes > sizeof(buffer)) {
+                skipBytes = sizeof(buffer);
+            }
+
+            sp<AMessage> extra;
+            ssize_t n;
+            for (;;) {
+                n = mListener->read(buffer, skipBytes, &extra);
+
+                if (n == -EWOULDBLOCK) {
+                    usleep(10000);
+                    continue;
+                }
+
+                break;
+            }
+
+            ALOGV("skipped %ld bytes at offset %lld", n, mPosition);
+
+            if (n < 0) {
+                return n;
+            }
+
+            mPosition += n;
+        }
+
+        sp<AMessage> extra;
+        size_t total = 0;
+        while (total < size) {
+            ssize_t n = mListener->read(
+                    (uint8_t *)data + total, size - total, &extra);
+
+            if (n == -EWOULDBLOCK) {
+                usleep(10000);
+                continue;
+            } else if (n == 0) {
+                break;
+            } else if (n < 0) {
+                mPosition += total;
+                return n;
+            }
+
+            total += n;
+        }
+
+        ALOGV("read %ld bytes at offset %lld", n, mPosition);
+
+        mPosition += total;
+
+        return total;
+    }
+
+private:
+    sp<NuPlayer::NuPlayerStreamListener> mListener;
+    off64_t mPosition;
+
+    DISALLOW_EVIL_CONSTRUCTORS(StreamSource);
+};
+
+MP4Source::MP4Source(const sp<IStreamSource> &source)
+    : mSource(source),
+      mLooper(new ALooper),
+      mParser(new Parser),
+      mEOS(false) {
+    mLooper->registerHandler(mParser);
+}
+
+MP4Source::~MP4Source() {
+}
+
+void MP4Source::start() {
+    mLooper->start(false /* runOnCallingThread */);
+    mParser->start(new StreamSource(mSource));
+}
+
+status_t MP4Source::feedMoreTSData() {
+    return mEOS ? ERROR_END_OF_STREAM : (status_t)OK;
+}
+
+sp<AMessage> MP4Source::getFormat(bool audio) {
+    return mParser->getFormat(audio);
+}
+
+status_t MP4Source::dequeueAccessUnit(
+        bool audio, sp<ABuffer> *accessUnit) {
+    return mParser->dequeueAccessUnit(audio, accessUnit);
+}
+
+}  // namespace android