Switch stagefright's approach to prefetching to the new model. The java MediaPlayer is now notified about rebuffering start/end via info messages.

Change-Id: If8185ba329ce8b6663b1ad39a4efb0ad3be81df2
diff --git a/api/current.xml b/api/current.xml
index 9930f44..fed772f 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -88756,6 +88756,28 @@
  visibility="public"
 >
 </field>
+<field name="MEDIA_INFO_BUFFERING_END"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="702"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="MEDIA_INFO_BUFFERING_START"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="701"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="MEDIA_INFO_METADATA_UPDATE"
  type="int"
  transient="false"
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 7fad1b7..dc783ce 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -93,6 +93,11 @@
     // The video is too complex for the decoder: it can't decode frames fast
     // enough. Possibly only the audio plays fine at this stage.
     MEDIA_INFO_VIDEO_TRACK_LAGGING = 700,
+    // MediaPlayer is temporarily pausing playback internally in order to
+    // buffer more data.
+    MEDIA_INFO_BUFFERING_START = 701,
+    // MediaPlayer is resuming playback after filling buffers.
+    MEDIA_INFO_BUFFERING_END = 702,
     // 8xx
     // Bad interleaving means that a media has been improperly interleaved or not
     // interleaved at all, e.g has all the video samples first then all the audio
diff --git a/include/media/stagefright/CachingDataSource.h b/include/media/stagefright/CachingDataSource.h
deleted file mode 100644
index 42d50e5..0000000
--- a/include/media/stagefright/CachingDataSource.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2009 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 CACHING_DATASOURCE_H_
-
-#define CACHING_DATASOURCE_H_
-
-#include <media/stagefright/DataSource.h>
-#include <media/stagefright/MediaErrors.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class CachingDataSource : public DataSource {
-public:
-    CachingDataSource(
-            const sp<DataSource> &source, size_t pageSize, int numPages);
-
-    virtual status_t initCheck() const;
-
-    virtual ssize_t readAt(off_t offset, void *data, size_t size);
-
-    virtual status_t getSize(off_t *size);
-
-    virtual uint32_t flags();
-
-protected:
-    virtual ~CachingDataSource();
-
-private:
-    struct Page {
-        Page *mPrev, *mNext;
-        off_t mOffset;
-        size_t mLength;
-        void *mData;
-    };
-
-    sp<DataSource> mSource;
-    void *mData;
-    size_t mPageSize;
-    Page *mFirst, *mLast;
-
-    Page *allocate_page();
-
-    Mutex mLock;
-
-    CachingDataSource(const CachingDataSource &);
-    CachingDataSource &operator=(const CachingDataSource &);
-};
-
-}  // namespace android
-
-#endif  // CACHING_DATASOURCE_H_
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
deleted file mode 100644
index 0400bea..0000000
--- a/include/media/stagefright/HTTPDataSource.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2009 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 HTTP_DATASOURCE_H_
-
-#define HTTP_DATASOURCE_H_
-
-#include <media/stagefright/DataSource.h>
-#include <utils/String8.h>
-#include <utils/threads.h>
-
-namespace android {
-
-class HTTPStream;
-
-class HTTPDataSource : public DataSource {
-public:
-    HTTPDataSource(
-            const char *host, int port, const char *path,
-            const KeyedVector<String8, String8> *headers = NULL);
-
-    HTTPDataSource(
-            const char *uri,
-            const KeyedVector<String8, String8> *headers = NULL);
-
-    status_t connect();
-    void disconnect();
-
-    virtual status_t initCheck() const;
-
-    virtual ssize_t readAt(off_t offset, void *data, size_t size);
-
-    virtual status_t getSize(off_t *size);
-
-    virtual uint32_t flags();
-
-protected:
-    virtual ~HTTPDataSource();
-
-private:
-    enum {
-        kBufferSize = 64 * 1024,
-
-        // If we encounter a socket-read error we'll try reconnecting
-        // and restarting the read for at most this many times.
-        kMaxNumRetries = 3,
-    };
-
-    enum State {
-        DISCONNECTED,
-        CONNECTING,
-        CONNECTED
-    };
-
-    State mState;
-    mutable Mutex mStateLock;
-
-    String8 mHeaders;
-
-    String8 mStartingHost;
-    String8 mStartingPath;
-    int mStartingPort;
-
-    HTTPStream *mHttp;
-
-    void *mBuffer;
-    size_t mBufferLength;
-    off_t mBufferOffset;
-
-    bool mContentLengthValid;
-    unsigned long long mContentLength;
-
-    int32_t mNumRetriesLeft;
-
-    void init(const KeyedVector<String8, String8> *headers);
-
-    ssize_t sendRangeRequest(size_t offset);
-    void initHeaders(const KeyedVector<String8, String8> *overrides);
-
-    status_t connectWithRedirectsAndRange(off_t rangeStart);
-    void applyTimeoutResponse();
-
-    HTTPDataSource(const HTTPDataSource &);
-    HTTPDataSource &operator=(const HTTPDataSource &);
-};
-
-}  // namespace android
-
-#endif  // HTTP_DATASOURCE_H_
-
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 7672f0f..c9d4650 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1523,6 +1523,15 @@
      */
     public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700;
 
+    /** MediaPlayer is temporarily pausing playback internally in order to
+     * buffer more data.
+     */
+    public static final int MEDIA_INFO_BUFFERING_START = 701;
+
+    /** MediaPlayer is resuming playback after filling buffers.
+     */
+    public static final int MEDIA_INFO_BUFFERING_END = 702;
+
     /** Bad interleaving means that a media has been improperly interleaved or
      * not interleaved at all, e.g has all the video samples first then all the
      * audio ones. Video is playing but a lot of disk seeks may be happening.
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 7608ec8..00a6995 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -22,19 +22,18 @@
         AudioPlayer.cpp           \
         AudioSource.cpp           \
         AwesomePlayer.cpp         \
-        CachingDataSource.cpp     \
         CameraSource.cpp          \
         DataSource.cpp            \
         FileSource.cpp            \
-        HTTPDataSource.cpp        \
         HTTPStream.cpp            \
         JPEGSource.cpp            \
         MP3Extractor.cpp          \
         MPEG4Extractor.cpp        \
         MPEG4Writer.cpp           \
         MediaExtractor.cpp        \
+        NuCachedSource2.cpp       \
+        NuHTTPDataSource.cpp      \
         OggExtractor.cpp          \
-        Prefetcher.cpp            \
         SampleIterator.cpp        \
         SampleTable.cpp           \
         ShoutcastSource.cpp       \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 4c9856d..2a8c035 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -23,12 +23,12 @@
 #include "include/ARTSPController.h"
 #include "include/AwesomePlayer.h"
 #include "include/LiveSource.h"
-#include "include/Prefetcher.h"
 #include "include/SoftwareRenderer.h"
+#include "include/NuCachedSource2.h"
+#include "include/ThrottledSource.h"
 
 #include <binder/IPCThreadState.h>
 #include <media/stagefright/AudioPlayer.h>
-#include <media/stagefright/CachingDataSource.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
 #include <media/stagefright/MediaBuffer.h>
@@ -354,11 +354,7 @@
 
     cancelPlayerEvents();
 
-    if (mPrefetcher != NULL) {
-        CHECK_EQ(mPrefetcher->getStrongCount(), 1);
-    }
-    mPrefetcher.clear();
-
+    mCachedSource.clear();
     mAudioTrack.clear();
     mVideoTrack.clear();
 
@@ -448,30 +444,45 @@
     }
     mBufferingEventPending = false;
 
-    int64_t durationUs;
-    {
-        Mutex::Autolock autoLock(mMiscStateLock);
-        durationUs = mDurationUs;
+    if (mCachedSource == NULL) {
+        return;
     }
 
-    int64_t cachedDurationUs = mPrefetcher->getCachedDurationUs();
+    size_t lowWatermark = 400000;
+    size_t highWatermark = 1000000;
 
-    LOGI("cache holds %.2f secs worth of data.", cachedDurationUs / 1E6);
+    off_t size;
+    if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
+        int64_t bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
 
-    if (durationUs >= 0) {
-        int64_t positionUs;
-        getPosition(&positionUs);
+        size_t cachedSize = mCachedSource->cachedSize();
+        int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
 
-        cachedDurationUs += positionUs;
+        double percentage = (double)cachedDurationUs / mDurationUs;
 
-        double percentage = (double)cachedDurationUs / durationUs;
         notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
 
-        postBufferingEvent_l();
-    } else {
-        // LOGE("Not sending buffering status because duration is unknown.");
-        postBufferingEvent_l();
+        lowWatermark = 2 * bitrate / 8;  // 2 secs
+        highWatermark = 10 * bitrate / 8;  // 10 secs
     }
+
+    bool eos;
+    size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
+
+    if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) {
+        LOGI("cache is running low (< %d) , pausing.", lowWatermark);
+        mFlags |= CACHE_UNDERRUN;
+        pause_l();
+        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
+    } else if ((mFlags & CACHE_UNDERRUN)
+            && (eos || cachedDataRemaining > highWatermark)) {
+        LOGI("cache has filled up (> %d), resuming.", highWatermark);
+        mFlags &= ~CACHE_UNDERRUN;
+        play_l();
+        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
+    }
+
+    postBufferingEvent_l();
 }
 
 void AwesomePlayer::onStreamDone() {
@@ -508,6 +519,9 @@
 
 status_t AwesomePlayer::play() {
     Mutex::Autolock autoLock(mLock);
+
+    mFlags &= ~CACHE_UNDERRUN;
+
     return play_l();
 }
 
@@ -632,6 +646,9 @@
 
 status_t AwesomePlayer::pause() {
     Mutex::Autolock autoLock(mLock);
+
+    mFlags &= ~CACHE_UNDERRUN;
+
     return pause_l();
 }
 
@@ -652,7 +669,7 @@
 }
 
 bool AwesomePlayer::isPlaying() const {
-    return mFlags & PLAYING;
+    return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
 }
 
 void AwesomePlayer::setISurface(const sp<ISurface> &isurface) {
@@ -719,6 +736,11 @@
 }
 
 status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
+    if (mFlags & CACHE_UNDERRUN) {
+        mFlags &= ~CACHE_UNDERRUN;
+        play_l();
+    }
+
     mSeeking = true;
     mSeekNotificationSent = false;
     mSeekTimeUs = timeUs;
@@ -764,10 +786,6 @@
 void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
     CHECK(source != NULL);
 
-    if (mPrefetcher != NULL) {
-        source = mPrefetcher->addSource(source);
-    }
-
     mAudioTrack = source;
 }
 
@@ -814,10 +832,6 @@
 void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
     CHECK(source != NULL);
 
-    if (mPrefetcher != NULL) {
-        source = mPrefetcher->addSource(source);
-    }
-
     mVideoTrack = source;
 }
 
@@ -869,6 +883,21 @@
             mVideoBuffer->release();
             mVideoBuffer = NULL;
         }
+
+        if (mCachedSource != NULL && mAudioSource != NULL) {
+            // We're going to seek the video source first, followed by
+            // the audio source.
+            // In order to avoid jumps in the DataSource offset caused by
+            // the audio codec prefetching data from the old locations
+            // while the video codec is already reading data from the new
+            // locations, we'll "pause" the audio source, causing it to
+            // stop reading input data until a subsequent seek.
+
+            if (mAudioPlayer != NULL) {
+                mAudioPlayer->pause();
+            }
+            mAudioSource->pause();
+        }
     }
 
     if (!mVideoBuffer) {
@@ -925,6 +954,7 @@
             LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
 
             mAudioPlayer->seekTo(timeUs);
+            mAudioPlayer->resume();
             mWatchForAudioSeekComplete = true;
             mWatchForAudioEOS = true;
         } else if (!mSeekNotificationSent) {
@@ -1012,10 +1042,6 @@
 }
 
 void AwesomePlayer::postBufferingEvent_l() {
-    if (mPrefetcher == NULL) {
-        return;
-    }
-
     if (mBufferingEventPending) {
         return;
     }
@@ -1123,10 +1149,10 @@
     sp<DataSource> dataSource;
 
     if (!strncasecmp("http://", mUri.string(), 7)) {
-        mConnectingDataSource = new HTTPDataSource(mUri, &mUriHeaders);
+        mConnectingDataSource = new NuHTTPDataSource;
 
         mLock.unlock();
-        status_t err = mConnectingDataSource->connect();
+        status_t err = mConnectingDataSource->connect(mUri/*, mUriHeaders */);
         mLock.lock();
 
         if (err != OK) {
@@ -1136,22 +1162,29 @@
             return err;
         }
 
-        dataSource = new CachingDataSource(
-                mConnectingDataSource, 64 * 1024, 10);
-
+#if 0
+        mCachedSource = new NuCachedSource2(
+                new ThrottledSource(
+                    mConnectingDataSource, 50 * 1024 /* bytes/sec */));
+#else
+        mCachedSource = new NuCachedSource2(mConnectingDataSource);
+#endif
         mConnectingDataSource.clear();
+
+        dataSource = mCachedSource;
     } else if (!strncasecmp(mUri.string(), "httplive://", 11)) {
         String8 uri("http://");
         uri.append(mUri.string() + 11);
 
         dataSource = new LiveSource(uri.string());
 
-        if (dataSource->flags() & DataSource::kWantsPrefetching) {
-            mPrefetcher = new Prefetcher;
-        }
+        mCachedSource = new NuCachedSource2(dataSource);
+        dataSource = mCachedSource;
 
         sp<MediaExtractor> extractor =
             MediaExtractor::Create(dataSource, MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
+
+        return setDataSource_l(extractor);
     } else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
         if (mLooper == NULL) {
             mLooper = new ALooper;
@@ -1183,10 +1216,6 @@
         return UNKNOWN_ERROR;
     }
 
-    if (dataSource->flags() & DataSource::kWantsPrefetching) {
-        mPrefetcher = new Prefetcher;
-    }
-
     return setDataSource_l(extractor);
 }
 
@@ -1211,8 +1240,6 @@
 }
 
 void AwesomePlayer::onPrepareAsyncEvent() {
-    sp<Prefetcher> prefetcher;
-
     {
         Mutex::Autolock autoLock(mLock);
 
@@ -1248,39 +1275,6 @@
                 return;
             }
         }
-
-        prefetcher = mPrefetcher;
-    }
-
-    if (prefetcher != NULL) {
-        {
-            Mutex::Autolock autoLock(mLock);
-            if (mFlags & PREPARE_CANCELLED) {
-                LOGI("prepare was cancelled before preparing the prefetcher");
-
-                prefetcher.clear();
-                abortPrepare(UNKNOWN_ERROR);
-                return;
-            }
-        }
-
-        LOGI("calling prefetcher->prepare()");
-        status_t result =
-            prefetcher->prepare(&AwesomePlayer::ContinuePreparation, this);
-
-        prefetcher.clear();
-
-        if (result == OK) {
-            LOGI("prefetcher is done preparing");
-        } else {
-            Mutex::Autolock autoLock(mLock);
-
-            CHECK_EQ(result, -EINTR);
-
-            LOGI("prefetcher->prepare() was cancelled early.");
-            abortPrepare(UNKNOWN_ERROR);
-            return;
-        }
     }
 
     Mutex::Autolock autoLock(mLock);
diff --git a/media/libstagefright/CachingDataSource.cpp b/media/libstagefright/CachingDataSource.cpp
deleted file mode 100644
index 1ca463e..0000000
--- a/media/libstagefright/CachingDataSource.cpp
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2009 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 <stdlib.h>
-#include <string.h>
-
-#include <media/stagefright/CachingDataSource.h>
-#include <media/stagefright/MediaDebug.h>
-
-namespace android {
-
-CachingDataSource::CachingDataSource(
-        const sp<DataSource> &source, size_t pageSize, int numPages)
-    : mSource(source),
-      mData(malloc(pageSize * numPages)),
-      mPageSize(pageSize),
-      mFirst(NULL),
-      mLast(NULL) {
-    for (int i = 0; i < numPages; ++i) {
-        Page *page = new Page;
-        page->mPrev = mLast;
-        page->mNext = NULL;
-
-        if (mLast == NULL) {
-            mFirst = page;
-        } else {
-            mLast->mNext = page;
-        }
-
-        mLast = page;
-
-        page->mOffset = -1;
-        page->mLength = 0;
-        page->mData = (char *)mData + mPageSize * i;
-    }
-}
-
-CachingDataSource::~CachingDataSource() {
-    Page *page = mFirst;
-    while (page != NULL) {
-        Page *next = page->mNext;
-        delete page;
-        page = next;
-    }
-    mFirst = mLast = NULL;
-
-    free(mData);
-    mData = NULL;
-}
-
-status_t CachingDataSource::initCheck() const {
-    return mSource->initCheck();
-}
-
-status_t CachingDataSource::getSize(off_t *size) {
-    return mSource->getSize(size);
-}
-
-uint32_t CachingDataSource::flags() {
-    return mSource->flags();
-}
-
-ssize_t CachingDataSource::readAt(off_t offset, void *data, size_t size) {
-    Mutex::Autolock autoLock(mLock);
-
-    size_t total = 0;
-    while (size > 0) {
-        Page *page = mFirst;
-        while (page != NULL) {
-            if (page->mOffset >= 0 && offset >= page->mOffset
-                && offset < page->mOffset + (off_t)page->mLength) {
-                break;
-            }
-            page = page->mNext;
-        }
-
-        if (page == NULL) {
-            page = allocate_page();
-            page->mOffset = offset - offset % mPageSize;
-            ssize_t n = mSource->readAt(page->mOffset, page->mData, mPageSize);
-            if (n < 0) {
-                page->mLength = 0;
-            } else {
-                page->mLength = (size_t)n;
-            }
-            mFirst->mPrev = page;
-            page->mNext = mFirst;
-            page->mPrev = NULL;
-            mFirst = page;
-
-            if (n < 0) {
-                return n;
-            }
-
-            if (offset >= page->mOffset + (off_t)page->mLength) {
-                break;
-            }
-        } else {
-            // Move "page" to the front in LRU order.
-            if (page->mNext != NULL) {
-                page->mNext->mPrev = page->mPrev;
-            } else {
-                mLast = page->mPrev;
-            }
-
-            if (page->mPrev != NULL) {
-                page->mPrev->mNext = page->mNext;
-            } else {
-                mFirst = page->mNext;
-            }
-
-            mFirst->mPrev = page;
-            page->mNext = mFirst;
-            page->mPrev = NULL;
-            mFirst = page;
-        }
-
-        size_t copy = page->mLength - (offset - page->mOffset);
-        if (copy > size) {
-            copy = size;
-        }
-        memcpy(data,(const char *)page->mData + (offset - page->mOffset),
-               copy);
-
-        total += copy;
-
-        if (page->mLength < mPageSize) {
-            // This was the final page. There is no more data beyond it.
-            break;
-        }
-
-        offset += copy;
-        size -= copy;
-        data = (char *)data + copy;
-    }
-
-    return total;
-}
-
-CachingDataSource::Page *CachingDataSource::allocate_page() {
-    // The last page is the least recently used, i.e. oldest.
-
-    Page *page = mLast;
-
-    page->mPrev->mNext = NULL;
-    mLast = page->mPrev;
-    page->mPrev = NULL;
-
-    return page;
-}
-
-}  // namespace android
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index b569a6b..6e4f9df 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -20,13 +20,13 @@
 #include "include/WAVExtractor.h"
 #include "include/OggExtractor.h"
 #include "include/MPEG2TSExtractor.h"
+#include "include/NuCachedSource2.h"
+#include "include/NuHTTPDataSource.h"
 
 #include "matroska/MatroskaExtractor.h"
 
-#include <media/stagefright/CachingDataSource.h>
 #include <media/stagefright/DataSource.h>
 #include <media/stagefright/FileSource.h>
-#include <media/stagefright/HTTPDataSource.h>
 #include <media/stagefright/MediaErrors.h>
 #include <utils/String8.h>
 
@@ -108,11 +108,11 @@
     if (!strncasecmp("file://", uri, 7)) {
         source = new FileSource(uri + 7);
     } else if (!strncasecmp("http://", uri, 7)) {
-        sp<HTTPDataSource> httpSource = new HTTPDataSource(uri, headers);
-        if (httpSource->connect() != OK) {
+        sp<NuHTTPDataSource> httpSource = new NuHTTPDataSource;
+        if (httpSource->connect(uri /* , headers */) != OK) {
             return NULL;
         }
-        source = new CachingDataSource(httpSource, 64 * 1024, 10);
+        source = new NuCachedSource2(httpSource);
     } else {
         // Assume it's a filename.
         source = new FileSource(uri);
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
deleted file mode 100644
index f72a6cc..0000000
--- a/media/libstagefright/HTTPDataSource.cpp
+++ /dev/null
@@ -1,457 +0,0 @@
-/*
- * Copyright (C) 2009 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 "HTTPDataSource"
-#include <utils/Log.h>
-
-#include "include/stagefright_string.h"
-#include "include/HTTPStream.h"
-
-#include <stdlib.h>
-
-#include <cutils/properties.h>
-#include <media/stagefright/HTTPDataSource.h>
-#include <media/stagefright/MediaDebug.h>
-
-namespace android {
-
-status_t HTTPDataSource::connectWithRedirectsAndRange(off_t rangeStart) {
-    string host = mStartingHost.string();
-    string path = mStartingPath.string();
-    int port = mStartingPort;
-
-    LOGV("Connecting to host '%s', port %d, path '%s'",
-         host.c_str(), port, path.c_str());
-
-    int numRedirectsRemaining = 5;
-    while (numRedirectsRemaining-- > 0) {
-        {
-            Mutex::Autolock autoLock(mStateLock);
-            if (mState == DISCONNECTED) {
-                return UNKNOWN_ERROR;
-            }
-        }
-
-        status_t err = mHttp->connect(host.c_str(), port);
-
-        if (err != OK) {
-            return err;
-        }
-
-        String8 request;
-        request.append("GET ");
-        request.append(path.c_str());
-        request.append(" HTTP/1.1\r\n");
-        request.append(mHeaders);
-        request.append("Host: ");
-        request.append(host.c_str());
-        request.append("\r\n");
-
-        if (rangeStart > 0) {
-            char range[128];
-            sprintf(range, "Range: bytes=%ld-\r\n", rangeStart);
-
-            request.append(range);
-        }
-
-        request.append("\r\n");
-
-        err = mHttp->send(request.string());
-
-        if (err != OK) {
-            return err;
-        }
-
-        int httpStatus;
-        err = mHttp->receive_header(&httpStatus);
-
-        if (err != OK) {
-            return err;
-        }
-
-        if (httpStatus >= 200 && httpStatus < 300) {
-            applyTimeoutResponse();
-            return OK;
-        }
-
-        if (httpStatus != 301 && httpStatus != 302) {
-            LOGE("HTTP request failed w/ http status %d", httpStatus);
-            return ERROR_IO;
-        }
-
-        string location;
-        CHECK(mHttp->find_header_value("Location", &location));
-
-        CHECK(string(location, 0, 7) == "http://");
-        location.erase(0, 7);
-        string::size_type slashPos = location.find('/');
-        if (slashPos == string::npos) {
-            slashPos = location.size();
-            location += '/';
-        }
-
-        mHttp->disconnect();
-
-        LOGV("Redirecting to %s\n", location.c_str());
-
-        host = string(location, 0, slashPos);
-
-        string::size_type colonPos = host.find(':');
-        if (colonPos != string::npos) {
-            const char *start = host.c_str() + colonPos + 1;
-            char *end;
-            long tmp = strtol(start, &end, 10);
-            CHECK(end > start && (*end == '\0'));
-
-            port = (tmp >= 0 && tmp < 65536) ? (int)tmp : 80;
-
-            host.erase(colonPos, host.size() - colonPos);
-        } else {
-            port = 80;
-        }
-
-        path = string(location, slashPos);
-
-        mStartingHost = host.c_str();
-        mStartingPath = path.c_str();
-        mStartingPort = port;
-    }
-
-    return ERROR_IO;
-}
-
-void HTTPDataSource::applyTimeoutResponse() {
-    string timeout;
-    if (mHttp->find_header_value("X-SocketTimeout", &timeout)) {
-        const char *s = timeout.c_str();
-        char *end;
-        long tmp = strtol(s, &end, 10);
-        if (end == s || *end != '\0') {
-            LOGW("Illegal X-SocketTimeout value given.");
-            return;
-        }
-
-        LOGI("overriding default timeout, new timeout is %ld seconds", tmp);
-        mHttp->setReceiveTimeout(tmp);
-    }
-}
-
-HTTPDataSource::HTTPDataSource(
-        const char *uri, const KeyedVector<String8, String8> *headers) {
-    CHECK(!strncasecmp("http://", uri, 7));
-
-    string host;
-    string path;
-    int port;
-
-    char *slash = strchr(uri + 7, '/');
-    if (slash == NULL) {
-        host = uri + 7;
-        path = "/";
-    } else {
-        host = string(uri + 7, slash - (uri + 7));
-        path = slash;
-    }
-
-    char *colon = strchr(host.c_str(), ':');
-    if (colon == NULL) {
-        port = 80;
-    } else {
-        char *end;
-        long tmp = strtol(colon + 1, &end, 10);
-        CHECK(end > colon + 1);
-        CHECK(tmp > 0 && tmp < 65536);
-        port = tmp;
-
-        host = string(host, 0, colon - host.c_str());
-    }
-
-    mStartingHost = host.c_str();
-    mStartingPath = path.c_str();
-    mStartingPort = port;
-
-    init(headers);
-}
-
-HTTPDataSource::HTTPDataSource(
-        const char *_host, int port, const char *_path,
-        const KeyedVector<String8, String8> *headers) {
-    mStartingHost = _host;
-    mStartingPath = _path;
-    mStartingPort = port;
-
-    init(headers);
-}
-
-void HTTPDataSource::init(const KeyedVector<String8, String8> *headers) {
-    mState = DISCONNECTED;
-    mHttp = new HTTPStream;
-
-    initHeaders(headers);
-
-    mBuffer = malloc(kBufferSize);
-
-    mNumRetriesLeft = kMaxNumRetries;
-}
-
-status_t HTTPDataSource::connect() {
-    {
-        Mutex::Autolock autoLock(mStateLock);
-
-        if (mState != DISCONNECTED) {
-            return ERROR_ALREADY_CONNECTED;
-        }
-
-        mState = CONNECTING;
-    }
-
-    mBufferLength = 0;
-    mBufferOffset = 0;
-    mContentLengthValid = false;
-
-    status_t err = connectWithRedirectsAndRange(0);
-
-    if (err != OK) {
-        Mutex::Autolock autoLock(mStateLock);
-
-        if (mState != CONNECTING) {
-            LOGV("connect() cancelled");
-        }
-        mState = DISCONNECTED;
-
-        return err;
-    }
-
-    string value;
-    if (mHttp->find_header_value("Content-Length", &value)) {
-        char *end;
-        mContentLength = strtoull(value.c_str(), &end, 10);
-        mContentLengthValid = true;
-    }
-
-    Mutex::Autolock autoLock(mStateLock);
-
-    if (mState != CONNECTING) {
-        // disconnect was called when we had just successfully connected.
-        LOGV("connect() cancelled (we had just succeeded connecting)");
-
-        mHttp->disconnect();
-        return UNKNOWN_ERROR;
-    }
-
-    mState = CONNECTED;
-
-    return OK;
-}
-
-void HTTPDataSource::disconnect() {
-    Mutex::Autolock autoLock(mStateLock);
-
-    if (mState == CONNECTING || mState == CONNECTED) {
-        mHttp->disconnect();
-        mState = DISCONNECTED;
-    }
-}
-
-status_t HTTPDataSource::initCheck() const {
-    Mutex::Autolock autoLock(mStateLock);
-
-    return (mState == CONNECTED) ? (status_t)OK : ERROR_NOT_CONNECTED;
-}
-
-status_t HTTPDataSource::getSize(off_t *size) {
-    *size = 0;
-
-    {
-        Mutex::Autolock autoLock(mStateLock);
-        if (mState != CONNECTED) {
-            return ERROR_NOT_CONNECTED;
-        }
-    }
-
-    if (!mContentLengthValid) {
-        return ERROR_UNSUPPORTED;
-    }
-
-    *size = mContentLength;
-
-    return OK;
-}
-
-HTTPDataSource::~HTTPDataSource() {
-    disconnect();
-
-    delete mHttp;
-    mHttp = NULL;
-
-    free(mBuffer);
-    mBuffer = NULL;
-}
-
-ssize_t HTTPDataSource::sendRangeRequest(size_t offset) {
-    status_t err = connectWithRedirectsAndRange(offset);
-
-    if (err != OK) {
-        return err;
-    }
-
-    string value;
-    if (!mHttp->find_header_value("Content-Length", &value)) {
-        return kBufferSize;
-    }
-
-    char *end;
-    unsigned long contentLength = strtoul(value.c_str(), &end, 10);
-
-    return contentLength;
-}
-
-ssize_t HTTPDataSource::readAt(off_t offset, void *data, size_t size) {
-    LOGV("readAt %ld, size %d", offset, size);
-
-rinse_repeat:
-    {
-        Mutex::Autolock autoLock(mStateLock);
-        if (mState != CONNECTED) {
-            return ERROR_NOT_CONNECTED;
-        }
-    }
-
-    if (offset >= mBufferOffset
-            && offset < (off_t)(mBufferOffset + mBufferLength)) {
-        size_t num_bytes_available = mBufferLength - (offset - mBufferOffset);
-
-        size_t copy = num_bytes_available;
-        if (copy > size) {
-            copy = size;
-        }
-
-        memcpy(data, (const char *)mBuffer + (offset - mBufferOffset), copy);
-
-        if (copy < size) {
-            LOGV("short read (1), returning %d vs. %d requested", copy, size);
-        }
-
-        return copy;
-    }
-
-    ssize_t contentLength = 0;
-    if (offset != (off_t)(mBufferOffset + mBufferLength)) {
-        LOGV("new range offset=%ld (old=%ld)",
-             offset, mBufferOffset + mBufferLength);
-
-        mHttp->disconnect();
-
-        contentLength = sendRangeRequest(offset);
-
-        if (contentLength > kBufferSize) {
-            contentLength = kBufferSize;
-        }
-    } else {
-        contentLength = kBufferSize;
-    }
-
-    mBufferOffset = offset;
-
-    if (mContentLengthValid
-            && mBufferOffset + contentLength >= (off_t)mContentLength) {
-        // If we never triggered a range request but know the content length,
-        // make sure to not read more data than there could be, otherwise
-        // we'd block indefinitely if the server doesn't close the connection.
-
-        contentLength = mContentLength - mBufferOffset;
-    }
-
-    if (contentLength <= 0) {
-        return contentLength;
-    }
-
-    ssize_t num_bytes_received = mHttp->receive(mBuffer, contentLength);
-
-    if (num_bytes_received < 0
-            || (mContentLengthValid && num_bytes_received < contentLength)) {
-        if (mNumRetriesLeft-- > 0) {
-            mHttp->disconnect();
-            mBufferLength = 0;
-            num_bytes_received = connectWithRedirectsAndRange(mBufferOffset);
-            if (num_bytes_received == OK) {
-                LOGI("retrying connection succeeded.");
-                goto rinse_repeat;
-            }
-            LOGE("retrying connection failed");
-        }
-
-        mBufferLength = 0;
-
-        return num_bytes_received;
-    }
-
-    mBufferLength = (size_t)num_bytes_received;
-
-    size_t copy = mBufferLength;
-    if (copy > size) {
-        copy = size;
-    }
-
-    memcpy(data, mBuffer, copy);
-
-    return copy;
-}
-
-void HTTPDataSource::initHeaders(
-        const KeyedVector<String8, String8> *overrides) {
-    mHeaders = String8();
-
-    mHeaders.append("User-Agent: stagefright/1.0 (Linux;Android ");
-
-#if (PROPERTY_VALUE_MAX < 8)
-#error "PROPERTY_VALUE_MAX must be at least 8"
-#endif
-
-    char value[PROPERTY_VALUE_MAX];
-    property_get("ro.build.version.release", value, "Unknown");
-    mHeaders.append(value);
-    mHeaders.append(")\r\n");
-
-    if (overrides == NULL) {
-        return;
-    }
-
-    for (size_t i = 0; i < overrides->size(); ++i) {
-        String8 line;
-        line.append(overrides->keyAt(i));
-        line.append(": ");
-        line.append(overrides->valueAt(i));
-        line.append("\r\n");
-
-        mHeaders.append(line);
-    }
-}
-
-uint32_t HTTPDataSource::flags() {
-    uint32_t f = kWantsPrefetching;
-
-    if (!strcasecmp(mStartingHost.string(), "localhost")
-            || !strcmp(mStartingHost.string(), "127.0.0.1")) {
-        f |= kStreamedFromLocalHost;
-    }
-
-    return f;
-}
-
-}  // namespace android
-
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
deleted file mode 100644
index b6ed56b..0000000
--- a/media/libstagefright/Prefetcher.cpp
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * Copyright (C) 2010 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_TAG "Prefetcher"
-//#define LOG_NDEBUG 0
-#include <utils/Log.h>
-
-#include "include/Prefetcher.h"
-
-#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaSource.h>
-#include <media/stagefright/MetaData.h>
-#include <utils/List.h>
-
-namespace android {
-
-struct PrefetchedSource : public MediaSource {
-    PrefetchedSource(
-            size_t index,
-            const sp<MediaSource> &source);
-
-    virtual status_t start(MetaData *params);
-    virtual status_t stop();
-
-    virtual status_t read(
-            MediaBuffer **buffer, const ReadOptions *options);
-
-    virtual sp<MetaData> getFormat();
-
-protected:
-    virtual ~PrefetchedSource();
-
-private:
-    friend struct Prefetcher;
-
-    Mutex mLock;
-    Condition mCondition;
-
-    sp<MediaSource> mSource;
-    size_t mIndex;
-    bool mStarted;
-    bool mReachedEOS;
-    status_t mFinalStatus;
-    int64_t mSeekTimeUs;
-    int64_t mCacheDurationUs;
-    size_t mCacheSizeBytes;
-    bool mPrefetcherStopped;
-    bool mCurrentlyPrefetching;
-
-    List<MediaBuffer *> mCachedBuffers;
-
-    // Returns true iff source is currently caching.
-    bool getCacheDurationUs(int64_t *durationUs, size_t *totalSize = NULL);
-
-    void updateCacheDuration_l();
-    void clearCache_l();
-
-    void cacheMore();
-    void onPrefetcherStopped();
-
-    PrefetchedSource(const PrefetchedSource &);
-    PrefetchedSource &operator=(const PrefetchedSource &);
-};
-
-Prefetcher::Prefetcher()
-    : mDone(false),
-      mThreadExited(false) {
-    startThread();
-}
-
-Prefetcher::~Prefetcher() {
-    stopThread();
-}
-
-sp<MediaSource> Prefetcher::addSource(const sp<MediaSource> &source) {
-    Mutex::Autolock autoLock(mLock);
-
-    sp<PrefetchedSource> psource =
-        new PrefetchedSource(mSources.size(), source);
-
-    mSources.add(psource);
-
-    return psource;
-}
-
-void Prefetcher::startThread() {
-    mThreadExited = false;
-    mDone = false;
-
-    int res = androidCreateThreadEtc(
-            ThreadWrapper, this, "Prefetcher",
-            ANDROID_PRIORITY_DEFAULT, 0, &mThread);
-
-    CHECK_EQ(res, 1);
-}
-
-void Prefetcher::stopThread() {
-    Mutex::Autolock autoLock(mLock);
-
-    while (!mThreadExited) {
-        mDone = true;
-        mCondition.signal();
-        mCondition.wait(mLock);
-    }
-}
-
-// static
-int Prefetcher::ThreadWrapper(void *me) {
-    static_cast<Prefetcher *>(me)->threadFunc();
-
-    return 0;
-}
-
-// Cache at most 1 min for each source.
-static int64_t kMaxCacheDurationUs = 60 * 1000000ll;
-
-// At the same time cache at most 5MB per source.
-static size_t kMaxCacheSizeBytes = 5 * 1024 * 1024;
-
-// If the amount of cached data drops below this,
-// fill the cache up to the max duration again.
-static int64_t kLowWaterDurationUs = 5000000ll;
-
-void Prefetcher::threadFunc() {
-    bool fillingCache = false;
-
-    for (;;) {
-        sp<PrefetchedSource> minSource;
-        int64_t minCacheDurationUs = -1;
-
-        {
-            Mutex::Autolock autoLock(mLock);
-            if (mDone) {
-                break;
-            }
-            mCondition.waitRelative(
-                    mLock, fillingCache ? 10000000ll : 1000000000ll);
-
-            ssize_t minIndex = -1;
-            for (size_t i = 0; i < mSources.size(); ++i) {
-                sp<PrefetchedSource> source = mSources[i].promote();
-
-                if (source == NULL) {
-                    continue;
-                }
-
-                int64_t cacheDurationUs;
-                size_t cacheSizeBytes;
-                if (!source->getCacheDurationUs(&cacheDurationUs, &cacheSizeBytes)) {
-                    continue;
-                }
-
-                if (cacheSizeBytes > kMaxCacheSizeBytes) {
-                    LOGI("max cache size reached");
-                    continue;
-                }
-
-                if (mSources.size() > 1 && cacheDurationUs >= kMaxCacheDurationUs) {
-                    LOGI("max duration reached, size = %d bytes", cacheSizeBytes);
-                    continue;
-                }
-
-                if (minIndex < 0 || cacheDurationUs < minCacheDurationUs) {
-                    minCacheDurationUs = cacheDurationUs;
-                    minIndex = i;
-                    minSource = source;
-                }
-            }
-
-            if (minIndex < 0) {
-                if (fillingCache) {
-                    LOGV("[%p] done filling the cache, above high water mark.",
-                         this);
-                    fillingCache = false;
-                }
-                continue;
-            }
-        }
-
-        if (!fillingCache && minCacheDurationUs < kLowWaterDurationUs) {
-            LOGI("[%p] cache below low water mark, filling cache.", this);
-            fillingCache = true;
-        }
-
-        if (fillingCache) {
-            // Make sure not to hold the lock while calling into the source.
-            // The lock guards the list of sources, not the individual sources
-            // themselves.
-            minSource->cacheMore();
-        }
-    }
-
-    Mutex::Autolock autoLock(mLock);
-    for (size_t i = 0; i < mSources.size(); ++i) {
-        sp<PrefetchedSource> source = mSources[i].promote();
-
-        if (source == NULL) {
-            continue;
-        }
-
-        source->onPrefetcherStopped();
-    }
-
-    mThreadExited = true;
-    mCondition.signal();
-}
-
-int64_t Prefetcher::getCachedDurationUs(bool *noMoreData) {
-    Mutex::Autolock autoLock(mLock);
-
-    int64_t minCacheDurationUs = -1;
-    ssize_t minIndex = -1;
-    bool anySourceActive = false;
-    for (size_t i = 0; i < mSources.size(); ++i) {
-        int64_t cacheDurationUs;
-        sp<PrefetchedSource> source = mSources[i].promote();
-        if (source == NULL) {
-            continue;
-        }
-
-        if (source->getCacheDurationUs(&cacheDurationUs)) {
-            anySourceActive = true;
-        }
-
-        if (minIndex < 0 || cacheDurationUs < minCacheDurationUs) {
-            minCacheDurationUs = cacheDurationUs;
-            minIndex = i;
-        }
-    }
-
-    if (noMoreData) {
-        *noMoreData = !anySourceActive;
-    }
-
-    return minCacheDurationUs < 0 ? 0 : minCacheDurationUs;
-}
-
-status_t Prefetcher::prepare(
-        bool (*continueFunc)(void *cookie), void *cookie) {
-    // Fill the cache.
-
-    int64_t duration;
-    bool noMoreData;
-    do {
-        usleep(100000);
-
-        if (continueFunc && !(*continueFunc)(cookie)) {
-            return -EINTR;
-        }
-
-        duration = getCachedDurationUs(&noMoreData);
-    } while (!noMoreData && duration < 2000000ll);
-
-    return OK;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-PrefetchedSource::PrefetchedSource(
-        size_t index,
-        const sp<MediaSource> &source)
-    : mSource(source),
-      mIndex(index),
-      mStarted(false),
-      mReachedEOS(false),
-      mSeekTimeUs(0),
-      mCacheDurationUs(0),
-      mCacheSizeBytes(0),
-      mPrefetcherStopped(false),
-      mCurrentlyPrefetching(false) {
-}
-
-PrefetchedSource::~PrefetchedSource() {
-    if (mStarted) {
-        stop();
-    }
-}
-
-status_t PrefetchedSource::start(MetaData *params) {
-    CHECK(!mStarted);
-
-    Mutex::Autolock autoLock(mLock);
-
-    status_t err = mSource->start(params);
-
-    if (err != OK) {
-        return err;
-    }
-
-    mStarted = true;
-
-    return OK;
-}
-
-status_t PrefetchedSource::stop() {
-    CHECK(mStarted);
-
-    Mutex::Autolock autoLock(mLock);
-
-    while (mCurrentlyPrefetching) {
-        mCondition.wait(mLock);
-    }
-
-    clearCache_l();
-
-    status_t err = mSource->stop();
-
-    mStarted = false;
-
-    return err;
-}
-
-status_t PrefetchedSource::read(
-        MediaBuffer **out, const ReadOptions *options) {
-    *out = NULL;
-
-    Mutex::Autolock autoLock(mLock);
-
-    CHECK(mStarted);
-
-    int64_t seekTimeUs;
-    if (options && options->getSeekTo(&seekTimeUs)) {
-        CHECK(seekTimeUs >= 0);
-
-        clearCache_l();
-
-        mReachedEOS = false;
-        mSeekTimeUs = seekTimeUs;
-    }
-
-    while (!mPrefetcherStopped && !mReachedEOS && mCachedBuffers.empty()) {
-        mCondition.wait(mLock);
-    }
-
-    if (mCachedBuffers.empty()) {
-        return mReachedEOS ? mFinalStatus : ERROR_END_OF_STREAM;
-    }
-
-    *out = *mCachedBuffers.begin();
-    mCachedBuffers.erase(mCachedBuffers.begin());
-    updateCacheDuration_l();
-    mCacheSizeBytes -= (*out)->size();
-
-    return OK;
-}
-
-sp<MetaData> PrefetchedSource::getFormat() {
-    return mSource->getFormat();
-}
-
-bool PrefetchedSource::getCacheDurationUs(
-        int64_t *durationUs, size_t *totalSize) {
-    Mutex::Autolock autoLock(mLock);
-
-    *durationUs = mCacheDurationUs;
-    if (totalSize != NULL) {
-        *totalSize = mCacheSizeBytes;
-    }
-
-    if (!mStarted || mReachedEOS) {
-        return false;
-    }
-
-    return true;
-}
-
-void PrefetchedSource::cacheMore() {
-    MediaSource::ReadOptions options;
-
-    Mutex::Autolock autoLock(mLock);
-
-    if (!mStarted) {
-        return;
-    }
-
-    mCurrentlyPrefetching = true;
-
-    if (mSeekTimeUs >= 0) {
-        options.setSeekTo(mSeekTimeUs);
-        mSeekTimeUs = -1;
-    }
-
-    // Ensure our object does not go away while we're not holding
-    // the lock.
-    sp<PrefetchedSource> me = this;
-
-    mLock.unlock();
-    MediaBuffer *buffer;
-    status_t err = mSource->read(&buffer, &options);
-    mLock.lock();
-
-    if (err != OK) {
-        mCurrentlyPrefetching = false;
-        mReachedEOS = true;
-        mFinalStatus = err;
-        mCondition.signal();
-
-        return;
-    }
-
-    CHECK(buffer != NULL);
-
-    MediaBuffer *copy = new MediaBuffer(buffer->range_length());
-    memcpy(copy->data(),
-           (const uint8_t *)buffer->data() + buffer->range_offset(),
-           buffer->range_length());
-
-    sp<MetaData> from = buffer->meta_data();
-    sp<MetaData> to = copy->meta_data();
-
-    int64_t timeUs;
-    if (from->findInt64(kKeyTime, &timeUs)) {
-        to->setInt64(kKeyTime, timeUs);
-    }
-
-    buffer->release();
-    buffer = NULL;
-
-    mCachedBuffers.push_back(copy);
-    updateCacheDuration_l();
-    mCacheSizeBytes += copy->size();
-
-    mCurrentlyPrefetching = false;
-    mCondition.signal();
-}
-
-void PrefetchedSource::updateCacheDuration_l() {
-    if (mCachedBuffers.size() < 2) {
-        mCacheDurationUs = 0;
-    } else {
-        int64_t firstTimeUs, lastTimeUs;
-        CHECK((*mCachedBuffers.begin())->meta_data()->findInt64(
-                    kKeyTime, &firstTimeUs));
-        CHECK((*--mCachedBuffers.end())->meta_data()->findInt64(
-                    kKeyTime, &lastTimeUs));
-
-        mCacheDurationUs = lastTimeUs - firstTimeUs;
-    }
-}
-
-void PrefetchedSource::clearCache_l() {
-    List<MediaBuffer *>::iterator it = mCachedBuffers.begin();
-    while (it != mCachedBuffers.end()) {
-        (*it)->release();
-
-        it = mCachedBuffers.erase(it);
-    }
-
-    updateCacheDuration_l();
-    mCacheSizeBytes = 0;
-}
-
-void PrefetchedSource::onPrefetcherStopped() {
-    Mutex::Autolock autoLock(mLock);
-    mPrefetcherStopped = true;
-    mCondition.signal();
-}
-
-}  // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 182aa06..2a9f21b 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -18,11 +18,11 @@
 
 #define AWESOME_PLAYER_H_
 
+#include "NuHTTPDataSource.h"
 #include "TimedEventQueue.h"
 
 #include <media/MediaPlayerInterface.h>
 #include <media/stagefright/DataSource.h>
-#include <media/stagefright/HTTPDataSource.h>
 #include <media/stagefright/OMXClient.h>
 #include <utils/threads.h>
 
@@ -33,8 +33,8 @@
 struct MediaBuffer;
 struct MediaExtractor;
 struct MediaSource;
-struct Prefetcher;
 struct TimeSource;
+struct NuCachedSource2;
 
 struct ALooper;
 struct ARTSPController;
@@ -101,6 +101,7 @@
         PREPARED            = 16,
         AT_EOS              = 32,
         PREPARE_CANCELLED   = 64,
+        CACHE_UNDERRUN      = 128,
     };
 
     mutable Mutex mLock;
@@ -169,8 +170,8 @@
     MediaBuffer *mLastVideoBuffer;
     MediaBuffer *mVideoBuffer;
 
-    sp<Prefetcher> mPrefetcher;
-    sp<HTTPDataSource> mConnectingDataSource;
+    sp<NuHTTPDataSource> mConnectingDataSource;
+    sp<NuCachedSource2> mCachedSource;
 
     sp<ALooper> mLooper;
     sp<ARTSPController> mRTSPController;
diff --git a/media/libstagefright/include/Prefetcher.h b/media/libstagefright/include/Prefetcher.h
deleted file mode 100644
index b411d1b..0000000
--- a/media/libstagefright/include/Prefetcher.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2010 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 PREFETCHER_H_
-
-#define PREFETCHER_H_
-
-#include <utils/RefBase.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
-
-namespace android {
-
-struct MediaSource;
-struct PrefetchedSource;
-
-struct Prefetcher : public RefBase {
-    Prefetcher();
-
-    // Given an existing MediaSource returns a new MediaSource
-    // that will benefit from prefetching/caching the original one.
-    sp<MediaSource> addSource(const sp<MediaSource> &source);
-
-    int64_t getCachedDurationUs(bool *noMoreData = NULL);
-
-    // If provided (non-NULL), "continueFunc" will be called repeatedly
-    // while preparing and preparation will finish early if it returns
-    // false. In this case "-EINTR" is returned as a result.
-    status_t prepare(
-            bool (*continueFunc)(void *cookie) = NULL,
-            void *cookie = NULL);
-
-protected:
-    virtual ~Prefetcher();
-
-private:
-    Mutex mLock;
-    Condition mCondition;
-
-    Vector<wp<PrefetchedSource> > mSources;
-    android_thread_id_t mThread;
-    bool mDone;
-    bool mThreadExited;
-
-    void startThread();
-    void stopThread();
-
-    static int ThreadWrapper(void *me);
-    void threadFunc();
-
-    Prefetcher(const Prefetcher &);
-    Prefetcher &operator=(const Prefetcher &);
-};
-
-}  // namespace android
-
-#endif  // PREFETCHER_H_