From c23f12af0394aa2f6651968a3c8840f1af317aa1 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Mon, 8 Feb 2010 14:40:30 -0800 Subject: Properly implement asynchronous preparation of media playback. related-to-bug: 2413002 --- media/libmediaplayerservice/StagefrightPlayer.cpp | 23 +----- media/libstagefright/AwesomePlayer.cpp | 98 ++++++++++++++++++----- media/libstagefright/Prefetcher.cpp | 27 ++++--- media/libstagefright/include/AwesomePlayer.h | 12 ++- media/libstagefright/include/Prefetcher.h | 4 +- 5 files changed, 108 insertions(+), 56 deletions(-) diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp index f42d55b..1bfcf65 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.cpp +++ b/media/libmediaplayerservice/StagefrightPlayer.cpp @@ -49,30 +49,11 @@ status_t StagefrightPlayer::setVideoSurface(const sp &surface) { } status_t StagefrightPlayer::prepare() { - LOGV("prepare"); - - int32_t width, height; - if (mPlayer->getVideoDimensions(&width, &height) != OK) { - width = height = 0; - } - - sendEvent(MEDIA_SET_VIDEO_SIZE, width, height); - - return OK; + return mPlayer->prepare(); } status_t StagefrightPlayer::prepareAsync() { - LOGV("prepareAsync"); - - status_t err = prepare(); - - if (err != OK) { - return err; - } - - sendEvent(MEDIA_PREPARED); - - return OK; + return mPlayer->prepareAsync(); } status_t StagefrightPlayer::start() { diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 2b403f8..d25f7f6 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -37,21 +37,23 @@ namespace android { struct AwesomeEvent : public TimedEventQueue::Event { - AwesomeEvent(AwesomePlayer *player, int32_t code) + AwesomeEvent( + AwesomePlayer *player, + void (AwesomePlayer::*method)()) : mPlayer(player), - mCode(code) { + mMethod(method) { } protected: virtual ~AwesomeEvent() {} virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) { - mPlayer->onEvent(mCode); + (mPlayer->*mMethod)(); } private: AwesomePlayer *mPlayer; - int32_t mCode; + void (AwesomePlayer::*mMethod)(); AwesomeEvent(const AwesomeEvent &); AwesomeEvent &operator=(const AwesomeEvent &); @@ -115,13 +117,16 @@ AwesomePlayer::AwesomePlayer() DataSource::RegisterDefaultSniffers(); - mVideoEvent = new AwesomeEvent(this, 0); + mVideoEvent = new AwesomeEvent(this, &AwesomePlayer::onVideoEvent); mVideoEventPending = false; - mStreamDoneEvent = new AwesomeEvent(this, 1); + mStreamDoneEvent = new AwesomeEvent(this, &AwesomePlayer::onStreamDone); mStreamDoneEventPending = false; - mBufferingEvent = new AwesomeEvent(this, 2); + mBufferingEvent = new AwesomeEvent(this, &AwesomePlayer::onBufferingUpdate); mBufferingEventPending = false; - mCheckAudioStatusEvent = new AwesomeEvent(this, 3); + + mCheckAudioStatusEvent = new AwesomeEvent( + this, &AwesomePlayer::onCheckAudioStatus); + mAudioStatusEventPending = false; mQueue.start(); @@ -287,12 +292,12 @@ void AwesomePlayer::reset_l() { mPrefetcher.clear(); } -void AwesomePlayer::notifyListener_l(int msg, int ext1) { +void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) { if (mListener != NULL) { sp listener = mListener.promote(); if (listener != NULL) { - listener->sendEvent(msg, ext1); + listener->sendEvent(msg, ext1, ext2); } } } @@ -623,18 +628,7 @@ status_t AwesomePlayer::setVideoSource(sp source) { return mVideoSource != NULL ? OK : UNKNOWN_ERROR; } -void AwesomePlayer::onEvent(int32_t code) { - if (code == 1) { - onStreamDone(); - return; - } else if (code == 2) { - onBufferingUpdate(); - return; - } else if (code == 3) { - onCheckAudioStatus(); - return; - } - +void AwesomePlayer::onVideoEvent() { Mutex::Autolock autoLock(mLock); mVideoEventPending = false; @@ -819,5 +813,65 @@ void AwesomePlayer::onCheckAudioStatus() { postCheckAudioStatusEvent_l(); } +status_t AwesomePlayer::prepare() { + Mutex::Autolock autoLock(mLock); + + status_t err = prepareAsync_l(); + + if (err != OK) { + return err; + } + + while (mAsyncPrepareEvent != NULL) { + mPreparedCondition.wait(mLock); + } + + return OK; +} + +status_t AwesomePlayer::prepareAsync() { + Mutex::Autolock autoLock(mLock); + return prepareAsync_l(); +} + +status_t AwesomePlayer::prepareAsync_l() { + if (mAsyncPrepareEvent != NULL) { + return UNKNOWN_ERROR; // async prepare already pending. + } + + mAsyncPrepareEvent = new AwesomeEvent( + this, &AwesomePlayer::onPrepareAsyncEvent); + + mQueue.postEvent(mAsyncPrepareEvent); + + return OK; +} + +void AwesomePlayer::onPrepareAsyncEvent() { + sp prefetcher; + + { + Mutex::Autolock autoLock(mLock); + prefetcher = mPrefetcher; + } + + if (prefetcher != NULL) { + prefetcher->prepare(); + } + + Mutex::Autolock autoLock(mLock); + + if (mVideoWidth < 0 || mVideoHeight < 0) { + notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0); + } else { + notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight); + } + + notifyListener_l(MEDIA_PREPARED); + + mAsyncPrepareEvent = NULL; + mPreparedCondition.signal(); +} + } // namespace android diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp index 862998a..835e167 100644 --- a/media/libstagefright/Prefetcher.cpp +++ b/media/libstagefright/Prefetcher.cpp @@ -171,7 +171,7 @@ void Prefetcher::threadFunc() { } } -int64_t Prefetcher::getCachedDurationUs() { +int64_t Prefetcher::getCachedDurationUs(bool *noMoreData) { Mutex::Autolock autoLock(mLock); int64_t minCacheDurationUs = -1; @@ -197,9 +197,25 @@ int64_t Prefetcher::getCachedDurationUs() { } } + if (noMoreData) { + *noMoreData = minCacheDurationUs < 0; + } + return minCacheDurationUs < 0 ? 0 : minCacheDurationUs; } +status_t Prefetcher::prepare() { + // Buffer about 2 secs worth of data on prepare. + + int64_t duration; + bool noMoreData; + do { + duration = getCachedDurationUs(&noMoreData); + } while (!noMoreData && duration < 2000000); + + return OK; +} + //////////////////////////////////////////////////////////////////////////////// PrefetchedSource::PrefetchedSource( @@ -232,15 +248,6 @@ status_t PrefetchedSource::start(MetaData *params) { mStarted = true; - for (;;) { - // Buffer 2 secs on startup. - if (mReachedEOS || mCacheDurationUs > 2000000) { - break; - } - - mCondition.wait(mLock); - } - return OK; } diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 75e71e6..651b910 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -57,6 +57,10 @@ struct AwesomePlayer { void reset(); + status_t prepare(); + status_t prepareAsync(); + status_t prepareAsync_l(); + status_t play(); status_t pause(); @@ -121,6 +125,9 @@ private: sp mCheckAudioStatusEvent; bool mAudioStatusEventPending; + sp mAsyncPrepareEvent; + Condition mPreparedCondition; + void postVideoEvent_l(int64_t delayUs = -1); void postBufferingEvent_l(); void postStreamDoneEvent_l(); @@ -143,13 +150,14 @@ private: status_t setAudioSource(sp source); status_t setVideoSource(sp source); - void onEvent(int32_t code); void onStreamDone(); - void notifyListener_l(int msg, int ext1 = 0); + void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0); + void onVideoEvent(); void onBufferingUpdate(); void onCheckAudioStatus(); + void onPrepareAsyncEvent(); AwesomePlayer(const AwesomePlayer &); AwesomePlayer &operator=(const AwesomePlayer &); diff --git a/media/libstagefright/include/Prefetcher.h b/media/libstagefright/include/Prefetcher.h index 7a97785..d227864 100644 --- a/media/libstagefright/include/Prefetcher.h +++ b/media/libstagefright/include/Prefetcher.h @@ -34,7 +34,9 @@ struct Prefetcher : public RefBase { // that will benefit from prefetching/caching the original one. sp addSource(const sp &source); - int64_t getCachedDurationUs(); + int64_t getCachedDurationUs(bool *noMoreData = NULL); + + status_t prepare(); protected: virtual ~Prefetcher(); -- cgit v1.1