summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/stagefright/CachingDataSource.h2
-rw-r--r--include/media/stagefright/DataSource.h8
-rw-r--r--include/media/stagefright/HTTPDataSource.h6
-rw-r--r--media/libstagefright/Android.mk1
-rw-r--r--media/libstagefright/AwesomePlayer.cpp84
-rw-r--r--media/libstagefright/CachingDataSource.cpp4
-rw-r--r--media/libstagefright/HTTPDataSource.cpp60
-rw-r--r--media/libstagefright/Prefetcher.cpp381
-rw-r--r--media/libstagefright/include/AwesomePlayer.h18
-rw-r--r--media/libstagefright/include/Prefetcher.h63
10 files changed, 590 insertions, 37 deletions
diff --git a/include/media/stagefright/CachingDataSource.h b/include/media/stagefright/CachingDataSource.h
index b0fc4b2..30b7ad9 100644
--- a/include/media/stagefright/CachingDataSource.h
+++ b/include/media/stagefright/CachingDataSource.h
@@ -33,6 +33,8 @@ public:
virtual ssize_t readAt(off_t offset, void *data, size_t size);
+ virtual uint32_t flags();
+
protected:
virtual ~CachingDataSource();
diff --git a/include/media/stagefright/DataSource.h b/include/media/stagefright/DataSource.h
index f88666a..0c0ace0 100644
--- a/include/media/stagefright/DataSource.h
+++ b/include/media/stagefright/DataSource.h
@@ -31,6 +31,10 @@ class String8;
class DataSource : public RefBase {
public:
+ enum Flags {
+ kWantsPrefetching = 1,
+ };
+
static sp<DataSource> CreateFromURI(const char *uri);
DataSource() {}
@@ -45,6 +49,10 @@ public:
// May return ERROR_UNSUPPORTED.
virtual status_t getSize(off_t *size);
+ virtual uint32_t flags() {
+ return 0;
+ }
+
////////////////////////////////////////////////////////////////////////////
bool sniff(String8 *mimeType, float *confidence);
diff --git a/include/media/stagefright/HTTPDataSource.h b/include/media/stagefright/HTTPDataSource.h
index d5dc9e6..3075f1c 100644
--- a/include/media/stagefright/HTTPDataSource.h
+++ b/include/media/stagefright/HTTPDataSource.h
@@ -33,6 +33,10 @@ public:
virtual ssize_t readAt(off_t offset, void *data, size_t size);
+ virtual uint32_t flags() {
+ return kWantsPrefetching;
+ }
+
protected:
virtual ~HTTPDataSource();
@@ -52,6 +56,8 @@ private:
status_t mInitCheck;
+ ssize_t sendRangeRequest(size_t offset);
+
HTTPDataSource(const HTTPDataSource &);
HTTPDataSource &operator=(const HTTPDataSource &);
};
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 3813907..dbb52c6 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -31,6 +31,7 @@ LOCAL_SRC_FILES += \
MPEG4Extractor.cpp \
MPEG4Writer.cpp \
MediaExtractor.cpp \
+ Prefetcher.cpp \
SampleIterator.cpp \
SampleTable.cpp \
ShoutcastSource.cpp \
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index f6cd46a..42b9acc 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -19,6 +19,7 @@
#include <utils/Log.h>
#include "include/AwesomePlayer.h"
+#include "include/Prefetcher.h"
#include "include/SoftwareRenderer.h"
#include <binder/IPCThreadState.h>
@@ -118,6 +119,8 @@ AwesomePlayer::AwesomePlayer()
mVideoEventPending = false;
mStreamDoneEvent = new AwesomeEvent(this, 1);
mStreamDoneEventPending = false;
+ mBufferingEvent = new AwesomeEvent(this, 2);
+ mBufferingEventPending = false;
mQueue.start();
@@ -132,11 +135,16 @@ AwesomePlayer::~AwesomePlayer() {
mClient.disconnect();
}
-void AwesomePlayer::cancelPlayerEvents() {
+void AwesomePlayer::cancelPlayerEvents(bool keepBufferingGoing) {
mQueue.cancelEvent(mVideoEvent->eventID());
mVideoEventPending = false;
mQueue.cancelEvent(mStreamDoneEvent->eventID());
mStreamDoneEventPending = false;
+
+ if (!keepBufferingGoing) {
+ mQueue.cancelEvent(mBufferingEvent->eventID());
+ mBufferingEventPending = false;
+ }
}
void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) {
@@ -149,12 +157,22 @@ status_t AwesomePlayer::setDataSource(const char *uri) {
reset_l();
- sp<MediaExtractor> extractor = MediaExtractor::CreateFromURI(uri);
+ sp<DataSource> dataSource = DataSource::CreateFromURI(uri);
+
+ if (dataSource == NULL) {
+ return UNKNOWN_ERROR;
+ }
+
+ sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
if (extractor == NULL) {
return UNKNOWN_ERROR;
}
+ if (dataSource->flags() & DataSource::kWantsPrefetching) {
+ mPrefetcher = new Prefetcher;
+ }
+
return setDataSource_l(extractor);
}
@@ -182,8 +200,6 @@ status_t AwesomePlayer::setDataSource(
}
status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
- reset_l();
-
bool haveAudio = false;
bool haveVideo = false;
for (size_t i = 0; i < extractor->countTracks(); ++i) {
@@ -253,6 +269,8 @@ void AwesomePlayer::reset_l() {
mSeeking = false;
mSeekTimeUs = 0;
+
+ mPrefetcher.clear();
}
// static
@@ -278,13 +296,35 @@ void AwesomePlayer::AudioNotify(void *_me, int what) {
}
}
-void AwesomePlayer::notifyListener_l(int msg) {
+void AwesomePlayer::notifyListener_l(int msg, int ext1) {
if (mListener != NULL) {
sp<MediaPlayerBase> listener = mListener.promote();
if (listener != NULL) {
- listener->sendEvent(msg);
+ listener->sendEvent(msg, ext1);
+ }
+ }
+}
+
+void AwesomePlayer::onBufferingUpdate() {
+ Mutex::Autolock autoLock(mLock);
+ mBufferingEventPending = false;
+
+ if (mDurationUs >= 0) {
+ int64_t cachedDurationUs = mPrefetcher->getCachedDurationUs();
+ int64_t positionUs = 0;
+ if (mVideoRenderer != NULL) {
+ positionUs = mVideoTimeUs;
+ } else if (mAudioPlayer != NULL) {
+ positionUs = mAudioPlayer->getMediaTimeUs();
}
+
+ cachedDurationUs += positionUs;
+
+ double percentage = (double)cachedDurationUs / mDurationUs;
+ notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage * 100.0);
+
+ postBufferingEvent_l();
}
}
@@ -361,6 +401,8 @@ status_t AwesomePlayer::play() {
seekAudioIfNecessary_l();
}
+ postBufferingEvent_l();
+
return OK;
}
@@ -414,7 +456,7 @@ status_t AwesomePlayer::pause_l() {
return OK;
}
- cancelPlayerEvents();
+ cancelPlayerEvents(true /* keepBufferingGoing */);
if (mAudioPlayer != NULL) {
mAudioPlayer->pause();
@@ -518,11 +560,15 @@ status_t AwesomePlayer::getVideoDimensions(
return OK;
}
-status_t AwesomePlayer::setAudioSource(const sp<MediaSource> &source) {
+status_t AwesomePlayer::setAudioSource(sp<MediaSource> source) {
if (source == NULL) {
return UNKNOWN_ERROR;
}
+ if (mPrefetcher != NULL) {
+ source = mPrefetcher->addSource(source);
+ }
+
sp<MetaData> meta = source->getFormat();
const char *mime;
@@ -549,11 +595,15 @@ status_t AwesomePlayer::setAudioSource(const sp<MediaSource> &source) {
return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
}
-status_t AwesomePlayer::setVideoSource(const sp<MediaSource> &source) {
+status_t AwesomePlayer::setVideoSource(sp<MediaSource> source) {
if (source == NULL) {
return UNKNOWN_ERROR;
}
+ if (mPrefetcher != NULL) {
+ source = mPrefetcher->addSource(source);
+ }
+
mVideoSource = OMXCodec::Create(
mClient.interface(), source->getFormat(),
false, // createEncoder
@@ -580,9 +630,13 @@ void AwesomePlayer::onEvent(int32_t code) {
if (code == 1) {
onStreamDone();
return;
+ } else if (code == 2) {
+ onBufferingUpdate();
+ return;
}
Mutex::Autolock autoLock(mLock);
+
mVideoEventPending = false;
if (mSeeking) {
@@ -718,5 +772,17 @@ void AwesomePlayer::postStreamDoneEvent_l() {
mQueue.postEvent(mStreamDoneEvent);
}
+void AwesomePlayer::postBufferingEvent_l() {
+ if (mPrefetcher == NULL) {
+ return;
+ }
+
+ if (mBufferingEventPending) {
+ return;
+ }
+ mBufferingEventPending = true;
+ mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
+}
+
} // namespace android
diff --git a/media/libstagefright/CachingDataSource.cpp b/media/libstagefright/CachingDataSource.cpp
index 23f4897..8d04ead 100644
--- a/media/libstagefright/CachingDataSource.cpp
+++ b/media/libstagefright/CachingDataSource.cpp
@@ -65,6 +65,10 @@ status_t CachingDataSource::initCheck() const {
return mSource->initCheck();
}
+uint32_t CachingDataSource::flags() {
+ return mSource->flags();
+}
+
ssize_t CachingDataSource::readAt(off_t offset, void *data, size_t size) {
Mutex::Autolock autoLock(mLock);
diff --git a/media/libstagefright/HTTPDataSource.cpp b/media/libstagefright/HTTPDataSource.cpp
index 7e8bbc6..135a044 100644
--- a/media/libstagefright/HTTPDataSource.cpp
+++ b/media/libstagefright/HTTPDataSource.cpp
@@ -190,30 +190,12 @@ HTTPDataSource::~HTTPDataSource() {
mHttp = NULL;
}
-ssize_t HTTPDataSource::readAt(off_t offset, void *data, size_t size) {
- 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);
-
- return copy;
- }
-
- mBufferOffset = offset;
- mBufferLength = 0;
-
+ssize_t HTTPDataSource::sendRangeRequest(size_t offset) {
char host[128];
sprintf(host, "Host: %s\r\n", mHost);
char range[128];
- sprintf(range, "Range: bytes=%ld-%ld\r\n\r\n",
- mBufferOffset, mBufferOffset + kBufferSize - 1);
+ sprintf(range, "Range: bytes=%d-\r\n\r\n", offset);
int http_status;
@@ -251,12 +233,44 @@ ssize_t HTTPDataSource::readAt(off_t offset, void *data, size_t size) {
char *end;
unsigned long contentLength = strtoul(value.c_str(), &end, 10);
- ssize_t num_bytes_received = mHttp->receive(mBuffer, contentLength);
+ return contentLength;
+}
- if (num_bytes_received <= 0) {
- return num_bytes_received;
+ssize_t HTTPDataSource::readAt(off_t offset, void *data, size_t size) {
+ 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);
+
+ return copy;
}
+ ssize_t contentLength = 0;
+ if (mBufferLength <= 0 || offset != mBufferOffset + mBufferLength) {
+ mHttp->disconnect();
+ contentLength = sendRangeRequest(offset);
+
+ if (contentLength > kBufferSize) {
+ contentLength = kBufferSize;
+ }
+ } else {
+ contentLength = kBufferSize;
+ }
+
+ mBufferOffset = offset;
+
+ if (contentLength <= 0) {
+ return contentLength;
+ }
+
+ ssize_t num_bytes_received = mHttp->receive(mBuffer, contentLength);
+
mBufferLength = (size_t)num_bytes_received;
size_t copy = mBufferLength;
diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp
new file mode 100644
index 0000000..93e3fdc
--- /dev/null
+++ b/media/libstagefright/Prefetcher.cpp
@@ -0,0 +1,381 @@
+/*
+ * 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(
+ const sp<Prefetcher> &prefetcher,
+ 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<Prefetcher> mPrefetcher;
+ sp<MediaSource> mSource;
+ size_t mIndex;
+ bool mStarted;
+ bool mReachedEOS;
+ int64_t mSeekTimeUs;
+ int64_t mCacheDurationUs;
+
+ List<MediaBuffer *> mCachedBuffers;
+
+ // Returns true iff source is currently caching.
+ bool getCacheDurationUs(int64_t *durationUs);
+
+ void updateCacheDuration_l();
+ void clearCache_l();
+
+ void cacheMore();
+
+ 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(this, 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 about 10secs for each source.
+static int64_t kMaxCacheDurationUs = 10000000ll;
+
+void Prefetcher::threadFunc() {
+ for (;;) {
+ Mutex::Autolock autoLock(mLock);
+ if (mDone) {
+ mThreadExited = true;
+ mCondition.signal();
+ break;
+ }
+ mCondition.waitRelative(mLock, 10000000ll);
+
+ int64_t minCacheDurationUs = -1;
+ 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;
+ if (!source->getCacheDurationUs(&cacheDurationUs)) {
+ continue;
+ }
+
+ if (cacheDurationUs >= kMaxCacheDurationUs) {
+ continue;
+ }
+
+ if (minIndex < 0 || cacheDurationUs < minCacheDurationUs) {
+ minCacheDurationUs = cacheDurationUs;
+ minIndex = i;
+ }
+ }
+
+ if (minIndex < 0) {
+ continue;
+ }
+
+ sp<PrefetchedSource> source = mSources[minIndex].promote();
+ if (source != NULL) {
+ source->cacheMore();
+ }
+ }
+}
+
+int64_t Prefetcher::getCachedDurationUs() {
+ Mutex::Autolock autoLock(mLock);
+
+ int64_t minCacheDurationUs = -1;
+ ssize_t minIndex = -1;
+ 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)) {
+ continue;
+ }
+
+ if (cacheDurationUs >= kMaxCacheDurationUs) {
+ continue;
+ }
+
+ if (minIndex < 0 || cacheDurationUs < minCacheDurationUs) {
+ minCacheDurationUs = cacheDurationUs;
+ minIndex = i;
+ }
+ }
+
+ return minCacheDurationUs < 0 ? 0 : minCacheDurationUs;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+PrefetchedSource::PrefetchedSource(
+ const sp<Prefetcher> &prefetcher,
+ size_t index,
+ const sp<MediaSource> &source)
+ : mPrefetcher(prefetcher),
+ mSource(source),
+ mIndex(index),
+ mStarted(false),
+ mReachedEOS(false),
+ mSeekTimeUs(0),
+ mCacheDurationUs(0) {
+}
+
+PrefetchedSource::~PrefetchedSource() {
+ if (mStarted) {
+ stop();
+ }
+}
+
+status_t PrefetchedSource::start(MetaData *params) {
+ Mutex::Autolock autoLock(mLock);
+
+ status_t err = mSource->start(params);
+
+ if (err != OK) {
+ return err;
+ }
+
+ mStarted = true;
+
+ for (;;) {
+ // Buffer 2 secs on startup.
+ if (mReachedEOS || mCacheDurationUs > 2000000) {
+ break;
+ }
+
+ mCondition.wait(mLock);
+ }
+
+ return OK;
+}
+
+status_t PrefetchedSource::stop() {
+ Mutex::Autolock autoLock(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 (!mReachedEOS && mCachedBuffers.empty()) {
+ mCondition.wait(mLock);
+ }
+
+ if (mCachedBuffers.empty()) {
+ return ERROR_END_OF_STREAM;
+ }
+
+ *out = *mCachedBuffers.begin();
+ mCachedBuffers.erase(mCachedBuffers.begin());
+ updateCacheDuration_l();
+
+ return OK;
+}
+
+sp<MetaData> PrefetchedSource::getFormat() {
+ return mSource->getFormat();
+}
+
+bool PrefetchedSource::getCacheDurationUs(int64_t *durationUs) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (!mStarted || mReachedEOS) {
+ *durationUs = 0;
+
+ return false;
+ }
+
+ *durationUs = mCacheDurationUs;
+
+ return true;
+}
+
+void PrefetchedSource::cacheMore() {
+ Mutex::Autolock autoLock(mLock);
+
+ if (!mStarted) {
+ return;
+ }
+
+ MediaBuffer *buffer;
+ MediaSource::ReadOptions options;
+ if (mSeekTimeUs >= 0) {
+ options.setSeekTo(mSeekTimeUs);
+ mSeekTimeUs = -1;
+ }
+
+ status_t err = mSource->read(&buffer, &options);
+
+ if (err != OK) {
+ mReachedEOS = true;
+ 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();
+ 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();
+}
+
+} // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index b28a12c..c2e46c0 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -26,10 +26,11 @@
namespace android {
+struct AudioPlayer;
struct MediaBuffer;
struct MediaExtractor;
struct MediaSource;
-struct AudioPlayer;
+struct Prefetcher;
struct TimeSource;
struct AwesomeRenderer : public RefBase {
@@ -109,13 +110,18 @@ private:
bool mVideoEventPending;
sp<TimedEventQueue::Event> mStreamDoneEvent;
bool mStreamDoneEventPending;
+ sp<TimedEventQueue::Event> mBufferingEvent;
+ bool mBufferingEventPending;
void postVideoEvent_l(int64_t delayUs = -1);
+ void postBufferingEvent_l();
void postStreamDoneEvent_l();
MediaBuffer *mLastVideoBuffer;
MediaBuffer *mVideoBuffer;
+ sp<Prefetcher> mPrefetcher;
+
status_t setDataSource_l(const sp<MediaExtractor> &extractor);
void reset_l();
status_t seekTo_l(int64_t timeUs);
@@ -123,17 +129,19 @@ private:
void initRenderer_l();
void seekAudioIfNecessary_l();
- void cancelPlayerEvents();
+ void cancelPlayerEvents(bool keepBufferingGoing = false);
- status_t setAudioSource(const sp<MediaSource> &source);
- status_t setVideoSource(const sp<MediaSource> &source);
+ status_t setAudioSource(sp<MediaSource> source);
+ status_t setVideoSource(sp<MediaSource> source);
void onEvent(int32_t code);
static void AudioNotify(void *me, int what);
void onStreamDone();
- void notifyListener_l(int msg);
+ void notifyListener_l(int msg, int ext1 = 0);
+
+ void onBufferingUpdate();
AwesomePlayer(const AwesomePlayer &);
AwesomePlayer &operator=(const AwesomePlayer &);
diff --git a/media/libstagefright/include/Prefetcher.h b/media/libstagefright/include/Prefetcher.h
new file mode 100644
index 0000000..7a97785
--- /dev/null
+++ b/media/libstagefright/include/Prefetcher.h
@@ -0,0 +1,63 @@
+/*
+ * 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();
+
+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_