diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/java/android/media/AudioManager.java | 2 | ||||
-rw-r--r-- | media/java/android/media/MediaPlayer.java | 47 | ||||
-rw-r--r-- | media/jni/android_media_MediaPlayer.cpp | 14 | ||||
-rw-r--r-- | media/libmedia/IMediaPlayer.cpp | 32 | ||||
-rw-r--r-- | media/libmedia/mediaplayer.cpp | 10 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.cpp | 14 | ||||
-rw-r--r-- | media/libmediaplayerservice/MediaPlayerService.h | 2 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightPlayer.cpp | 10 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightPlayer.h | 2 | ||||
-rw-r--r-- | media/libstagefright/AwesomePlayer.cpp | 246 | ||||
-rw-r--r-- | media/libstagefright/MPEG4Extractor.cpp | 14 | ||||
-rw-r--r-- | media/libstagefright/Prefetcher.cpp | 40 | ||||
-rw-r--r-- | media/libstagefright/include/AwesomePlayer.h | 41 |
13 files changed, 422 insertions, 52 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 171881f..70c27c2 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -751,6 +751,8 @@ public class AudioManager { */ public boolean isWiredHeadsetOn() { if (AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,"") + == AudioSystem.DEVICE_STATE_UNAVAILABLE && + AudioSystem.getDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,"") == AudioSystem.DEVICE_STATE_UNAVAILABLE) { return false; } else { diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 89ee7d3..e8b89e0 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -1064,6 +1064,53 @@ public class MediaPlayer private native void _reset(); /** + * Suspends the MediaPlayer. The only methods that may be called while + * suspended are {@link #reset()}, {@link #release()} and {@link #resume()}. + * MediaPlayer will release its hardware resources as far as + * possible and reasonable. A successfully suspended MediaPlayer will + * cease sending events. + * If suspension is successful, this method returns true, otherwise + * false is returned and the player's state is not affected. + * @hide + */ + public boolean suspend() { + if (native_suspend_resume(true) < 0) { + return false; + } + + stayAwake(false); + + // make sure none of the listeners get called anymore + mEventHandler.removeCallbacksAndMessages(null); + + return true; + } + + /** + * Resumes the MediaPlayer. Only to be called after a previous (successful) + * call to {@link #suspend()}. + * MediaPlayer will return to a state close to what it was in before + * suspension. + * @hide + */ + public boolean resume() { + if (native_suspend_resume(false) < 0) { + return false; + } + + if (isPlaying()) { + stayAwake(true); + } + + return true; + } + + /** + * @hide + */ + private native int native_suspend_resume(boolean isSuspend); + + /** * Sets the audio stream type for this MediaPlayer. See {@link AudioManager} * for a list of stream types. * diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index 2773e5c..8ed3730 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -692,6 +692,19 @@ android_media_MediaPlayer_snoop(JNIEnv* env, jobject thiz, jobject data, jint ki return ret; } +static jint +android_media_MediaPlayer_native_suspend_resume( + JNIEnv *env, jobject thiz, jboolean isSuspend) { + LOGV("suspend_resume(%d)", isSuspend); + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL ) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return UNKNOWN_ERROR; + } + + return isSuspend ? mp->suspend() : mp->resume(); +} + // ---------------------------------------------------------------------------- static JNINativeMethod gMethods[] = { @@ -724,6 +737,7 @@ static JNINativeMethod gMethods[] = { {"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup}, {"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize}, {"snoop", "([SI)I", (void *)android_media_MediaPlayer_snoop}, + {"native_suspend_resume", "(Z)I", (void *)android_media_MediaPlayer_native_suspend_resume}, }; static const char* const kClassPathName = "android/media/MediaPlayer"; diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index 9c127d4..ed792b3 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -43,6 +43,8 @@ enum { INVOKE, SET_METADATA_FILTER, GET_METADATA, + SUSPEND, + RESUME, }; class BpMediaPlayer: public BpInterface<IMediaPlayer> @@ -199,6 +201,26 @@ public: remote()->transact(GET_METADATA, request, reply); return reply->readInt32(); } + + status_t suspend() { + Parcel request; + request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + + Parcel reply; + remote()->transact(SUSPEND, request, &reply); + + return reply.readInt32(); + } + + status_t resume() { + Parcel request; + request.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + + Parcel reply; + remote()->transact(RESUME, request, &reply); + + return reply.readInt32(); + } }; IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer"); @@ -299,6 +321,16 @@ status_t BnMediaPlayer::onTransact( reply->writeInt32(setMetadataFilter(data)); return NO_ERROR; } break; + case SUSPEND: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + reply->writeInt32(suspend()); + return NO_ERROR; + } break; + case RESUME: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + reply->writeInt32(resume()); + return NO_ERROR; + } break; case GET_METADATA: { CHECK_INTERFACE(IMediaPlayer, data, reply); const status_t retcode = getMetadata(data.readInt32(), data.readInt32(), reply); diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 01cd8ce..2157814 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -167,6 +167,16 @@ status_t MediaPlayer::invoke(const Parcel& request, Parcel *reply) return INVALID_OPERATION; } +status_t MediaPlayer::suspend() { + Mutex::Autolock _l(mLock); + return mPlayer->suspend(); +} + +status_t MediaPlayer::resume() { + Mutex::Autolock _l(mLock); + return mPlayer->resume(); +} + status_t MediaPlayer::setMetadataFilter(const Parcel& filter) { LOGD("setMetadataFilter"); diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 55b06f4..b4fc035 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -970,6 +970,20 @@ status_t MediaPlayerService::Client::getMetadata( return OK; } +status_t MediaPlayerService::Client::suspend() { + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + + return p->suspend(); +} + +status_t MediaPlayerService::Client::resume() { + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + + return p->resume(); +} + status_t MediaPlayerService::Client::prepareAsync() { LOGV("[%d] prepareAsync", mConnId); diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index c9cae35..2408c62 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -222,6 +222,8 @@ private: virtual status_t getMetadata(bool update_only, bool apply_filter, Parcel *reply); + virtual status_t suspend(); + virtual status_t resume(); sp<MediaPlayerBase> createPlayer(player_type playerType); diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp index 1bfcf65..7776b4e 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.cpp +++ b/media/libmediaplayerservice/StagefrightPlayer.cpp @@ -136,6 +136,16 @@ player_type StagefrightPlayer::playerType() { return STAGEFRIGHT_PLAYER; } +status_t StagefrightPlayer::suspend() { + LOGV("suspend"); + return mPlayer->suspend(); +} + +status_t StagefrightPlayer::resume() { + LOGV("resume"); + return mPlayer->resume(); +} + status_t StagefrightPlayer::invoke(const Parcel &request, Parcel *reply) { return INVALID_OPERATION; } diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h index 9e6674a..4446582 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.h +++ b/media/libmediaplayerservice/StagefrightPlayer.h @@ -50,6 +50,8 @@ public: virtual player_type playerType(); virtual status_t invoke(const Parcel &request, Parcel *reply); virtual void setAudioSink(const sp<AudioSink> &audioSink); + virtual status_t suspend(); + virtual status_t resume(); private: AwesomePlayer *mPlayer; diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 5d2127b..1c9f4fd 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -84,6 +84,7 @@ private: struct AwesomeLocalRenderer : public AwesomeRenderer { AwesomeLocalRenderer( + bool previewOnly, const char *componentName, OMX_COLOR_FORMATTYPE colorFormat, const sp<ISurface> &surface, @@ -91,15 +92,18 @@ struct AwesomeLocalRenderer : public AwesomeRenderer { size_t decodedWidth, size_t decodedHeight) : mTarget(NULL), mLibHandle(NULL) { - init(componentName, + init(previewOnly, componentName, colorFormat, surface, displayWidth, displayHeight, decodedWidth, decodedHeight); } virtual void render(MediaBuffer *buffer) { - mTarget->render( - (const uint8_t *)buffer->data() + buffer->range_offset(), - buffer->range_length(), NULL); + render((const uint8_t *)buffer->data() + buffer->range_offset(), + buffer->range_length()); + } + + void render(const void *data, size_t size) { + mTarget->render(data, size, NULL); } protected: @@ -118,6 +122,7 @@ private: void *mLibHandle; void init( + bool previewOnly, const char *componentName, OMX_COLOR_FORMATTYPE colorFormat, const sp<ISurface> &surface, @@ -129,31 +134,39 @@ private: }; void AwesomeLocalRenderer::init( + bool previewOnly, const char *componentName, OMX_COLOR_FORMATTYPE colorFormat, const sp<ISurface> &surface, size_t displayWidth, size_t displayHeight, size_t decodedWidth, size_t decodedHeight) { - mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW); - - if (mLibHandle) { - typedef VideoRenderer *(*CreateRendererFunc)( - const sp<ISurface> &surface, - const char *componentName, - OMX_COLOR_FORMATTYPE colorFormat, - size_t displayWidth, size_t displayHeight, - size_t decodedWidth, size_t decodedHeight); - - CreateRendererFunc func = - (CreateRendererFunc)dlsym( - mLibHandle, - "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20" - "OMX_COLOR_FORMATTYPEjjjj"); - - if (func) { - mTarget = - (*func)(surface, componentName, colorFormat, - displayWidth, displayHeight, decodedWidth, decodedHeight); + if (!previewOnly) { + // We will stick to the vanilla software-color-converting renderer + // for "previewOnly" mode, to avoid unneccessarily switching overlays + // more often than necessary. + + mLibHandle = dlopen("libstagefrighthw.so", RTLD_NOW); + + if (mLibHandle) { + typedef VideoRenderer *(*CreateRendererFunc)( + const sp<ISurface> &surface, + const char *componentName, + OMX_COLOR_FORMATTYPE colorFormat, + size_t displayWidth, size_t displayHeight, + size_t decodedWidth, size_t decodedHeight); + + CreateRendererFunc func = + (CreateRendererFunc)dlsym( + mLibHandle, + "_Z14createRendererRKN7android2spINS_8ISurfaceEEEPKc20" + "OMX_COLOR_FORMATTYPEjjjj"); + + if (func) { + mTarget = + (*func)(surface, componentName, colorFormat, + displayWidth, displayHeight, + decodedWidth, decodedHeight); + } } } @@ -166,10 +179,12 @@ void AwesomeLocalRenderer::init( AwesomePlayer::AwesomePlayer() : mTimeSource(NULL), + mVideoRendererIsPreview(false), mAudioPlayer(NULL), mFlags(0), mLastVideoBuffer(NULL), - mVideoBuffer(NULL) { + mVideoBuffer(NULL), + mSuspensionState(NULL) { CHECK_EQ(mClient.connect(), OK); DataSource::RegisterDefaultSniffers(); @@ -221,7 +236,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 +262,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 +325,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 +371,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 +380,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 +442,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; } @@ -504,6 +546,7 @@ void AwesomePlayer::initRenderer_l() { // Other decoders are instantiated locally and as a consequence // allocate their buffers in local address space. mVideoRenderer = new AwesomeLocalRenderer( + false, // previewOnly component, (OMX_COLOR_FORMATTYPE)format, mISurface, @@ -579,7 +622,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 +743,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) { @@ -730,6 +780,7 @@ void AwesomePlayer::onVideoEvent() { LOGV("VideoSource signalled format change."); if (mVideoRenderer != NULL) { + mVideoRendererIsPreview = false; initRenderer_l(); } continue; @@ -808,7 +859,9 @@ void AwesomePlayer::onVideoEvent() { return; } - if (mVideoRenderer == NULL) { + if (mVideoRendererIsPreview || mVideoRenderer == NULL) { + mVideoRendererIsPreview = false; + initRenderer_l(); } @@ -985,6 +1038,7 @@ void AwesomePlayer::onPrepareAsyncEvent() { if (prefetcher != NULL) { prefetcher->prepare(); + prefetcher.clear(); } Mutex::Autolock autoLock(mLock); @@ -1006,5 +1060,113 @@ 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); + + if (mLastVideoBuffer) { + size_t size = mLastVideoBuffer->range_length(); + if (size) { + state->mLastVideoFrameSize = size; + state->mLastVideoFrame = malloc(size); + memcpy(state->mLastVideoFrame, + (const uint8_t *)mLastVideoBuffer->data() + + mLastVideoBuffer->range_offset(), + size); + + state->mVideoWidth = mVideoWidth; + state->mVideoHeight = mVideoHeight; + + sp<MetaData> meta = mVideoSource->getFormat(); + CHECK(meta->findInt32(kKeyColorFormat, &state->mColorFormat)); + CHECK(meta->findInt32(kKeyWidth, &state->mDecodedWidth)); + CHECK(meta->findInt32(kKeyHeight, &state->mDecodedHeight)); + } + } + + 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->mLastVideoFrame && mISurface != NULL) { + mVideoRenderer = + new AwesomeLocalRenderer( + true, // previewOnly + "", + (OMX_COLOR_FORMATTYPE)state->mColorFormat, + mISurface, + state->mVideoWidth, + state->mVideoHeight, + state->mDecodedWidth, + state->mDecodedHeight); + + mVideoRendererIsPreview = true; + + ((AwesomeLocalRenderer *)mVideoRenderer.get())->render( + state->mLastVideoFrame, state->mLastVideoFrameSize); + } + + 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..114d4c6 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -21,12 +21,14 @@ #include "TimedEventQueue.h" #include <media/MediaPlayerInterface.h> +#include <media/stagefright/DataSource.h> #include <media/stagefright/OMXClient.h> #include <utils/threads.h> namespace android { struct AudioPlayer; +struct DataSource; struct MediaBuffer; struct MediaExtractor; struct MediaSource; @@ -78,6 +80,9 @@ struct AwesomePlayer { status_t getVideoDimensions(int32_t *width, int32_t *height) const; + status_t suspend(); + status_t resume(); + private: friend struct AwesomeEvent; @@ -103,8 +108,11 @@ private: String8 mUri; KeyedVector<String8, String8> mUriHeaders; + sp<DataSource> mFileSource; + sp<MediaSource> mVideoSource; sp<AwesomeRenderer> mVideoRenderer; + bool mVideoRendererIsPreview; sp<MediaSource> mAudioSource; AudioPlayer *mAudioPlayer; @@ -140,12 +148,45 @@ 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; + + void *mLastVideoFrame; + size_t mLastVideoFrameSize; + int32_t mColorFormat; + int32_t mVideoWidth, mVideoHeight; + int32_t mDecodedWidth, mDecodedHeight; + + SuspensionState() + : mLastVideoFrame(NULL) { + } + + ~SuspensionState() { + if (mLastVideoFrame) { + free(mLastVideoFrame); + mLastVideoFrame = NULL; + } + } + } *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); |