summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/java/android/media/AudioManager.java2
-rw-r--r--media/java/android/media/MediaPlayer.java47
-rw-r--r--media/jni/android_media_MediaPlayer.cpp14
-rw-r--r--media/libmedia/IMediaPlayer.cpp32
-rw-r--r--media/libmedia/mediaplayer.cpp10
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp14
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h2
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.cpp10
-rw-r--r--media/libmediaplayerservice/StagefrightPlayer.h2
-rw-r--r--media/libstagefright/AwesomePlayer.cpp246
-rw-r--r--media/libstagefright/MPEG4Extractor.cpp14
-rw-r--r--media/libstagefright/Prefetcher.cpp40
-rw-r--r--media/libstagefright/include/AwesomePlayer.h41
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);