diff options
author | Andreas Huber <andih@google.com> | 2010-02-12 10:42:02 -0800 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2010-02-12 12:43:34 -0800 |
commit | ba7ec917ea91364598de1ba7a29910cec08fd5de (patch) | |
tree | 32ad186603b602989b5f67f6a2eb8a7fcb680397 /media | |
parent | 965e37ec88609c36a3c5461ece459a96abb6f7ca (diff) | |
download | frameworks_base-ba7ec917ea91364598de1ba7a29910cec08fd5de.zip frameworks_base-ba7ec917ea91364598de1ba7a29910cec08fd5de.tar.gz frameworks_base-ba7ec917ea91364598de1ba7a29910cec08fd5de.tar.bz2 |
Squashed commit of the following:
commit 427e927298449826bb5b98327b0c05957aa051e6
Author: Andreas Huber <andih@google.com>
Date: Fri Feb 12 10:39:07 2010 -0800
Fixing a race condition in AwesomePlayer and support for suspend/resume.
commit 96201a04b6657b6bd69ec6100f4de66aebcaa0b4
Author: Andreas Huber <andih@google.com>
Date: Fri Feb 12 10:36:15 2010 -0800
Protect MPEG4Source's sanity by properly locking.
related-to-bug: 2231576
Diffstat (limited to 'media')
-rw-r--r-- | media/libstagefright/AwesomePlayer.cpp | 140 | ||||
-rw-r--r-- | media/libstagefright/MPEG4Extractor.cpp | 14 | ||||
-rw-r--r-- | media/libstagefright/Prefetcher.cpp | 40 | ||||
-rw-r--r-- | media/libstagefright/include/AwesomePlayer.h | 23 |
4 files changed, 190 insertions, 27 deletions
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 5d2127b..41e6911 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -169,7 +169,8 @@ AwesomePlayer::AwesomePlayer() mAudioPlayer(NULL), mFlags(0), mLastVideoBuffer(NULL), - mVideoBuffer(NULL) { + mVideoBuffer(NULL), + mSuspensionState(NULL) { CHECK_EQ(mClient.connect(), OK); DataSource::RegisterDefaultSniffers(); @@ -221,7 +222,11 @@ void AwesomePlayer::setListener(const wp<MediaPlayerBase> &listener) { status_t AwesomePlayer::setDataSource( const char *uri, const KeyedVector<String8, String8> *headers) { Mutex::Autolock autoLock(mLock); + return setDataSource_l(uri, headers); +} +status_t AwesomePlayer::setDataSource_l( + const char *uri, const KeyedVector<String8, String8> *headers) { reset_l(); mUri = uri; @@ -243,15 +248,22 @@ status_t AwesomePlayer::setDataSource( reset_l(); - sp<DataSource> source = new FileSource(fd, offset, length); + sp<DataSource> dataSource = new FileSource(fd, offset, length); - status_t err = source->initCheck(); + status_t err = dataSource->initCheck(); if (err != OK) { return err; } - sp<MediaExtractor> extractor = MediaExtractor::Create(source); + mFileSource = dataSource; + + return setDataSource_l(dataSource); +} + +status_t AwesomePlayer::setDataSource_l( + const sp<DataSource> &dataSource) { + sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource); if (extractor == NULL) { return UNKNOWN_ERROR; @@ -299,6 +311,26 @@ void AwesomePlayer::reset_l() { cancelPlayerEvents(); + if (mPrefetcher != NULL) { + CHECK_EQ(mPrefetcher->getStrongCount(), 1); + } + mPrefetcher.clear(); + + // Shutdown audio first, so that the respone to the reset request + // appears to happen instantaneously as far as the user is concerned + // If we did this later, audio would continue playing while we + // shutdown the video-related resources and the player appear to + // not be as responsive to a reset request. + mAudioSource.clear(); + + if (mTimeSource != mAudioPlayer) { + delete mTimeSource; + } + mTimeSource = NULL; + + delete mAudioPlayer; + mAudioPlayer = NULL; + mVideoRenderer.clear(); if (mLastVideoBuffer) { @@ -325,16 +357,6 @@ void AwesomePlayer::reset_l() { IPCThreadState::self()->flushCommands(); } - mAudioSource.clear(); - - if (mTimeSource != mAudioPlayer) { - delete mTimeSource; - } - mTimeSource = NULL; - - delete mAudioPlayer; - mAudioPlayer = NULL; - mDurationUs = -1; mFlags = 0; mVideoWidth = mVideoHeight = -1; @@ -344,10 +366,13 @@ void AwesomePlayer::reset_l() { mSeeking = false; mSeekTimeUs = 0; - mPrefetcher.clear(); - mUri.setTo(""); mUriHeaders.clear(); + + mFileSource.clear(); + + delete mSuspensionState; + mSuspensionState = NULL; } void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) { @@ -403,7 +428,10 @@ void AwesomePlayer::onStreamDone() { status_t AwesomePlayer::play() { Mutex::Autolock autoLock(mLock); + return play_l(); +} +status_t AwesomePlayer::play_l() { if (mFlags & PLAYING) { return OK; } @@ -579,7 +607,10 @@ status_t AwesomePlayer::getDuration(int64_t *durationUs) { status_t AwesomePlayer::getPosition(int64_t *positionUs) { Mutex::Autolock autoLock(mLock); + return getPosition_l(positionUs); +} +status_t AwesomePlayer::getPosition_l(int64_t *positionUs) { if (mVideoSource != NULL) { *positionUs = mVideoTimeUs; } else if (mAudioPlayer != NULL) { @@ -697,7 +728,11 @@ status_t AwesomePlayer::setVideoSource(sp<MediaSource> source) { void AwesomePlayer::onVideoEvent() { Mutex::Autolock autoLock(mLock); - + if (!mVideoEventPending) { + // The event has been cancelled in reset_l() but had already + // been scheduled for execution at that time. + return; + } mVideoEventPending = false; if (mSeeking) { @@ -985,6 +1020,7 @@ void AwesomePlayer::onPrepareAsyncEvent() { if (prefetcher != NULL) { prefetcher->prepare(); + prefetcher.clear(); } Mutex::Autolock autoLock(mLock); @@ -1006,5 +1042,75 @@ void AwesomePlayer::onPrepareAsyncEvent() { mPreparedCondition.broadcast(); } +status_t AwesomePlayer::suspend() { + LOGI("suspend"); + Mutex::Autolock autoLock(mLock); + + if (mSuspensionState != NULL) { + return INVALID_OPERATION; + } + + while (mFlags & PREPARING) { + mPreparedCondition.wait(mLock); + } + + SuspensionState *state = new SuspensionState; + state->mUri = mUri; + state->mUriHeaders = mUriHeaders; + state->mFileSource = mFileSource; + + state->mFlags = mFlags & (PLAYING | LOOPING); + getPosition_l(&state->mPositionUs); + + reset_l(); + + mSuspensionState = state; + + return OK; +} + +status_t AwesomePlayer::resume() { + LOGI("resume"); + Mutex::Autolock autoLock(mLock); + + if (mSuspensionState == NULL) { + return INVALID_OPERATION; + } + + SuspensionState *state = mSuspensionState; + mSuspensionState = NULL; + + status_t err; + if (state->mFileSource != NULL) { + err = setDataSource_l(state->mFileSource); + + if (err == OK) { + mFileSource = state->mFileSource; + } + } else { + err = setDataSource_l(state->mUri, &state->mUriHeaders); + } + + if (err != OK) { + delete state; + state = NULL; + + return err; + } + + seekTo_l(state->mPositionUs); + + mFlags = state->mFlags & LOOPING; + + if (state->mFlags & PLAYING) { + play_l(); + } + + delete state; + state = NULL; + + return OK; +} + } // namespace android diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp index 666ed08..16635d3 100644 --- a/media/libstagefright/MPEG4Extractor.cpp +++ b/media/libstagefright/MPEG4Extractor.cpp @@ -60,6 +60,8 @@ protected: virtual ~MPEG4Source(); private: + Mutex mLock; + sp<MetaData> mFormat; sp<DataSource> mDataSource; int32_t mTimescale; @@ -1300,6 +1302,8 @@ MPEG4Source::~MPEG4Source() { } status_t MPEG4Source::start(MetaData *params) { + Mutex::Autolock autoLock(mLock); + CHECK(!mStarted); int32_t val; @@ -1325,6 +1329,8 @@ status_t MPEG4Source::start(MetaData *params) { } status_t MPEG4Source::stop() { + Mutex::Autolock autoLock(mLock); + CHECK(mStarted); if (mBuffer != NULL) { @@ -1345,6 +1351,8 @@ status_t MPEG4Source::stop() { } sp<MetaData> MPEG4Source::getFormat() { + Mutex::Autolock autoLock(mLock); + return mFormat; } @@ -1369,6 +1377,8 @@ size_t MPEG4Source::parseNALSize(const uint8_t *data) const { status_t MPEG4Source::read( MediaBuffer **out, const ReadOptions *options) { + Mutex::Autolock autoLock(mLock); + CHECK(mStarted); *out = NULL; @@ -1428,6 +1438,7 @@ status_t MPEG4Source::read( return ERROR_IO; } + CHECK(mBuffer != NULL); mBuffer->set_range(0, size); mBuffer->meta_data()->clear(); mBuffer->meta_data()->setInt64( @@ -1461,8 +1472,10 @@ status_t MPEG4Source::read( } MediaBuffer *clone = mBuffer->clone(); + CHECK(clone != NULL); clone->set_range(mBuffer->range_offset() + mNALLengthSize, nal_size); + CHECK(mBuffer != NULL); mBuffer->set_range( mBuffer->range_offset() + mNALLengthSize + nal_size, mBuffer->range_length() - mNALLengthSize - nal_size); @@ -1521,6 +1534,7 @@ status_t MPEG4Source::read( } CHECK_EQ(srcOffset, size); + CHECK(mBuffer != NULL); mBuffer->set_range(0, dstOffset); mBuffer->meta_data()->clear(); mBuffer->meta_data()->setInt64( diff --git a/media/libstagefright/Prefetcher.cpp b/media/libstagefright/Prefetcher.cpp index 835e167..cb03979 100644 --- a/media/libstagefright/Prefetcher.cpp +++ b/media/libstagefright/Prefetcher.cpp @@ -31,7 +31,6 @@ namespace android { struct PrefetchedSource : public MediaSource { PrefetchedSource( - const sp<Prefetcher> &prefetcher, size_t index, const sp<MediaSource> &source); @@ -52,13 +51,13 @@ private: Mutex mLock; Condition mCondition; - sp<Prefetcher> mPrefetcher; sp<MediaSource> mSource; size_t mIndex; bool mStarted; bool mReachedEOS; int64_t mSeekTimeUs; int64_t mCacheDurationUs; + bool mPrefetcherStopped; List<MediaBuffer *> mCachedBuffers; @@ -69,6 +68,7 @@ private: void clearCache_l(); void cacheMore(); + void onPrefetcherStopped(); PrefetchedSource(const PrefetchedSource &); PrefetchedSource &operator=(const PrefetchedSource &); @@ -88,7 +88,7 @@ sp<MediaSource> Prefetcher::addSource(const sp<MediaSource> &source) { Mutex::Autolock autoLock(mLock); sp<PrefetchedSource> psource = - new PrefetchedSource(this, mSources.size(), source); + new PrefetchedSource(mSources.size(), source); mSources.add(psource); @@ -130,8 +130,6 @@ void Prefetcher::threadFunc() { for (;;) { Mutex::Autolock autoLock(mLock); if (mDone) { - mThreadExited = true; - mCondition.signal(); break; } mCondition.waitRelative(mLock, 10000000ll); @@ -169,6 +167,19 @@ void Prefetcher::threadFunc() { source->cacheMore(); } } + + 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) { @@ -219,16 +230,15 @@ status_t Prefetcher::prepare() { //////////////////////////////////////////////////////////////////////////////// PrefetchedSource::PrefetchedSource( - const sp<Prefetcher> &prefetcher, size_t index, const sp<MediaSource> &source) - : mPrefetcher(prefetcher), - mSource(source), + : mSource(source), mIndex(index), mStarted(false), mReachedEOS(false), mSeekTimeUs(0), - mCacheDurationUs(0) { + mCacheDurationUs(0), + mPrefetcherStopped(false) { } PrefetchedSource::~PrefetchedSource() { @@ -238,6 +248,8 @@ PrefetchedSource::~PrefetchedSource() { } status_t PrefetchedSource::start(MetaData *params) { + CHECK(!mStarted); + Mutex::Autolock autoLock(mLock); status_t err = mSource->start(params); @@ -252,6 +264,8 @@ status_t PrefetchedSource::start(MetaData *params) { } status_t PrefetchedSource::stop() { + CHECK(mStarted); + Mutex::Autolock autoLock(mLock); clearCache_l(); @@ -281,7 +295,7 @@ status_t PrefetchedSource::read( mSeekTimeUs = seekTimeUs; } - while (!mReachedEOS && mCachedBuffers.empty()) { + while (!mPrefetcherStopped && !mReachedEOS && mCachedBuffers.empty()) { mCondition.wait(mLock); } @@ -390,4 +404,10 @@ void PrefetchedSource::clearCache_l() { updateCacheDuration_l(); } +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 a19784b..ee2aca0 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -27,6 +27,7 @@ namespace android { struct AudioPlayer; +struct DataSource; struct MediaBuffer; struct MediaExtractor; struct MediaSource; @@ -78,6 +79,9 @@ struct AwesomePlayer { status_t getVideoDimensions(int32_t *width, int32_t *height) const; + status_t suspend(); + status_t resume(); + private: friend struct AwesomeEvent; @@ -103,6 +107,8 @@ private: String8 mUri; KeyedVector<String8, String8> mUriHeaders; + sp<DataSource> mFileSource; + sp<MediaSource> mVideoSource; sp<AwesomeRenderer> mVideoRenderer; @@ -140,12 +146,29 @@ private: void postBufferingEvent_l(); void postStreamDoneEvent_l(); void postCheckAudioStatusEvent_l(); + status_t getPosition_l(int64_t *positionUs); + status_t play_l(); MediaBuffer *mLastVideoBuffer; MediaBuffer *mVideoBuffer; sp<Prefetcher> mPrefetcher; + struct SuspensionState { + String8 mUri; + KeyedVector<String8, String8> mUriHeaders; + sp<DataSource> mFileSource; + + uint32_t mFlags; + int64_t mPositionUs; + + } *mSuspensionState; + + status_t setDataSource_l( + const char *uri, + const KeyedVector<String8, String8> *headers = NULL); + + status_t setDataSource_l(const sp<DataSource> &dataSource); status_t setDataSource_l(const sp<MediaExtractor> &extractor); void reset_l(); status_t seekTo_l(int64_t timeUs); |