summaryrefslogtreecommitdiffstats
path: root/media/libstagefright
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2010-02-12 10:42:02 -0800
committerAndreas Huber <andih@google.com>2010-02-12 12:43:34 -0800
commit7b3396acc702451be9bafb19d7fe26d55d43a316 (patch)
treeeadd21b8b9142e7f0ece40c4f6b8b55323b5dd6d /media/libstagefright
parent328901bdc7c00ab361c5ef16d0d69c94a0458e95 (diff)
downloadframeworks_av-7b3396acc702451be9bafb19d7fe26d55d43a316.zip
frameworks_av-7b3396acc702451be9bafb19d7fe26d55d43a316.tar.gz
frameworks_av-7b3396acc702451be9bafb19d7fe26d55d43a316.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/libstagefright')
-rw-r--r--media/libstagefright/AwesomePlayer.cpp140
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp14
-rw-r--r--media/libstagefright/Prefetcher.cpp40
-rw-r--r--media/libstagefright/include/AwesomePlayer.h23
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);