diff options
Diffstat (limited to 'media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp')
-rw-r--r-- | media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp | 334 |
1 files changed, 273 insertions, 61 deletions
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index d03601f..239296e 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -16,25 +16,31 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "NuPlayerDriver" +#include <inttypes.h> #include <utils/Log.h> #include "NuPlayerDriver.h" #include "NuPlayer.h" +#include "NuPlayerSource.h" #include <media/stagefright/foundation/ADebug.h> #include <media/stagefright/foundation/ALooper.h> +#include <media/stagefright/MetaData.h> namespace android { NuPlayerDriver::NuPlayerDriver() - : mResetInProgress(false), + : mState(STATE_IDLE), + mIsAsyncPrepare(false), + mAsyncResult(UNKNOWN_ERROR), + mSetSurfaceInProgress(false), mDurationUs(-1), mPositionUs(-1), mNumFramesTotal(0), mNumFramesDropped(0), mLooper(new ALooper), - mState(UNINITIALIZED), + mPlayerFlags(0), mAtEOS(false), mStartupSeekTimeUs(-1) { mLooper->setName("NuPlayerDriver Looper"); @@ -66,60 +72,143 @@ status_t NuPlayerDriver::setUID(uid_t uid) { status_t NuPlayerDriver::setDataSource( const char *url, const KeyedVector<String8, String8> *headers) { - CHECK_EQ((int)mState, (int)UNINITIALIZED); + Mutex::Autolock autoLock(mLock); - mPlayer->setDataSource(url, headers); + if (mState != STATE_IDLE) { + return INVALID_OPERATION; + } - mState = STOPPED; + mState = STATE_SET_DATASOURCE_PENDING; - return OK; + mPlayer->setDataSourceAsync(url, headers); + + while (mState == STATE_SET_DATASOURCE_PENDING) { + mCondition.wait(mLock); + } + + return mAsyncResult; } status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) { - CHECK_EQ((int)mState, (int)UNINITIALIZED); + Mutex::Autolock autoLock(mLock); - mPlayer->setDataSource(fd, offset, length); + if (mState != STATE_IDLE) { + return INVALID_OPERATION; + } - mState = STOPPED; + mState = STATE_SET_DATASOURCE_PENDING; - return OK; + mPlayer->setDataSourceAsync(fd, offset, length); + + while (mState == STATE_SET_DATASOURCE_PENDING) { + mCondition.wait(mLock); + } + + return mAsyncResult; } status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) { - CHECK_EQ((int)mState, (int)UNINITIALIZED); + Mutex::Autolock autoLock(mLock); - mPlayer->setDataSource(source); + if (mState != STATE_IDLE) { + return INVALID_OPERATION; + } - mState = STOPPED; + mState = STATE_SET_DATASOURCE_PENDING; - return OK; + mPlayer->setDataSourceAsync(source); + + while (mState == STATE_SET_DATASOURCE_PENDING) { + mCondition.wait(mLock); + } + + return mAsyncResult; } status_t NuPlayerDriver::setVideoSurfaceTexture( - const sp<ISurfaceTexture> &surfaceTexture) { - mPlayer->setVideoSurfaceTexture(surfaceTexture); + const sp<IGraphicBufferProducer> &bufferProducer) { + Mutex::Autolock autoLock(mLock); + + if (mSetSurfaceInProgress) { + return INVALID_OPERATION; + } + + switch (mState) { + case STATE_SET_DATASOURCE_PENDING: + case STATE_RESET_IN_PROGRESS: + return INVALID_OPERATION; + + default: + break; + } + + mSetSurfaceInProgress = true; + + mPlayer->setVideoSurfaceTextureAsync(bufferProducer); + + while (mSetSurfaceInProgress) { + mCondition.wait(mLock); + } return OK; } status_t NuPlayerDriver::prepare() { - sendEvent(MEDIA_SET_VIDEO_SIZE, 0, 0); - return OK; + Mutex::Autolock autoLock(mLock); + return prepare_l(); } -status_t NuPlayerDriver::prepareAsync() { - status_t err = prepare(); +status_t NuPlayerDriver::prepare_l() { + switch (mState) { + case STATE_UNPREPARED: + mState = STATE_PREPARING; + + // Make sure we're not posting any notifications, success or + // failure information is only communicated through our result + // code. + mIsAsyncPrepare = false; + mPlayer->prepareAsync(); + while (mState == STATE_PREPARING) { + mCondition.wait(mLock); + } + return (mState == STATE_PREPARED) ? OK : UNKNOWN_ERROR; + default: + return INVALID_OPERATION; + }; +} - notifyListener(MEDIA_PREPARED); +status_t NuPlayerDriver::prepareAsync() { + Mutex::Autolock autoLock(mLock); - return err; + switch (mState) { + case STATE_UNPREPARED: + mState = STATE_PREPARING; + mIsAsyncPrepare = true; + mPlayer->prepareAsync(); + return OK; + default: + return INVALID_OPERATION; + }; } status_t NuPlayerDriver::start() { + Mutex::Autolock autoLock(mLock); + switch (mState) { - case UNINITIALIZED: - return INVALID_OPERATION; - case STOPPED: + case STATE_UNPREPARED: + { + status_t err = prepare_l(); + + if (err != OK) { + return err; + } + + CHECK_EQ(mState, STATE_PREPARED); + + // fall through + } + + case STATE_PREPARED: { mAtEOS = false; mPlayer->start(); @@ -133,21 +222,23 @@ status_t NuPlayerDriver::start() { mStartupSeekTimeUs = -1; } - break; } - case PLAYING: - return OK; - default: - { - CHECK_EQ((int)mState, (int)PAUSED); + case STATE_RUNNING: + break; + + case STATE_PAUSED: + { mPlayer->resume(); break; } + + default: + return INVALID_OPERATION; } - mState = PLAYING; + mState = STATE_RUNNING; return OK; } @@ -157,52 +248,55 @@ status_t NuPlayerDriver::stop() { } status_t NuPlayerDriver::pause() { + Mutex::Autolock autoLock(mLock); + switch (mState) { - case UNINITIALIZED: - return INVALID_OPERATION; - case STOPPED: + case STATE_PAUSED: + case STATE_PREPARED: return OK; - case PLAYING: + + case STATE_RUNNING: + notifyListener(MEDIA_PAUSED); mPlayer->pause(); break; + default: - { - CHECK_EQ((int)mState, (int)PAUSED); - return OK; - } + return INVALID_OPERATION; } - mState = PAUSED; + mState = STATE_PAUSED; return OK; } bool NuPlayerDriver::isPlaying() { - return mState == PLAYING && !mAtEOS; + return mState == STATE_RUNNING && !mAtEOS; } status_t NuPlayerDriver::seekTo(int msec) { + Mutex::Autolock autoLock(mLock); + int64_t seekTimeUs = msec * 1000ll; switch (mState) { - case UNINITIALIZED: - return INVALID_OPERATION; - case STOPPED: + case STATE_PREPARED: { mStartupSeekTimeUs = seekTimeUs; break; } - case PLAYING: - case PAUSED: + + case STATE_RUNNING: + case STATE_PAUSED: { mAtEOS = false; + // seeks can take a while, so we essentially paused + notifyListener(MEDIA_PAUSED); mPlayer->seekToAsync(seekTimeUs); break; } default: - TRESPASS(); - break; + return INVALID_OPERATION; } return OK; @@ -224,27 +318,48 @@ status_t NuPlayerDriver::getDuration(int *msec) { Mutex::Autolock autoLock(mLock); if (mDurationUs < 0) { - *msec = 0; - } else { - *msec = (mDurationUs + 500ll) / 1000; + return UNKNOWN_ERROR; } + *msec = (mDurationUs + 500ll) / 1000; + return OK; } status_t NuPlayerDriver::reset() { Mutex::Autolock autoLock(mLock); - mResetInProgress = true; + switch (mState) { + case STATE_IDLE: + return OK; + + case STATE_SET_DATASOURCE_PENDING: + case STATE_RESET_IN_PROGRESS: + return INVALID_OPERATION; + + case STATE_PREPARING: + { + CHECK(mIsAsyncPrepare); + + notifyListener(MEDIA_PREPARED); + break; + } + + default: + break; + } + + notifyListener(MEDIA_STOPPED); + + mState = STATE_RESET_IN_PROGRESS; mPlayer->resetAsync(); - while (mResetInProgress) { + while (mState == STATE_RESET_IN_PROGRESS) { mCondition.wait(mLock); } mDurationUs = -1; mPositionUs = -1; - mState = UNINITIALIZED; mStartupSeekTimeUs = -1; return OK; @@ -277,6 +392,24 @@ status_t NuPlayerDriver::invoke(const Parcel &request, Parcel *reply) { int mode = request.readInt32(); return mPlayer->setVideoScalingMode(mode); } + + case INVOKE_ID_GET_TRACK_INFO: + { + return mPlayer->getTrackInfo(reply); + } + + case INVOKE_ID_SELECT_TRACK: + { + int trackIndex = request.readInt32(); + return mPlayer->selectTrack(trackIndex, true /* select */); + } + + case INVOKE_ID_UNSELECT_TRACK: + { + int trackIndex = request.readInt32(); + return mPlayer->selectTrack(trackIndex, false /* select */); + } + default: { return INVALID_OPERATION; @@ -298,13 +431,45 @@ status_t NuPlayerDriver::getParameter(int key, Parcel *reply) { status_t NuPlayerDriver::getMetadata( const media::Metadata::Filter& ids, Parcel *records) { - return INVALID_OPERATION; + Mutex::Autolock autoLock(mLock); + + using media::Metadata; + + Metadata meta(records); + + meta.appendBool( + Metadata::kPauseAvailable, + mPlayerFlags & NuPlayer::Source::FLAG_CAN_PAUSE); + + meta.appendBool( + Metadata::kSeekBackwardAvailable, + mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_BACKWARD); + + meta.appendBool( + Metadata::kSeekForwardAvailable, + mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK_FORWARD); + + meta.appendBool( + Metadata::kSeekAvailable, + mPlayerFlags & NuPlayer::Source::FLAG_CAN_SEEK); + + return OK; } void NuPlayerDriver::notifyResetComplete() { Mutex::Autolock autoLock(mLock); - CHECK(mResetInProgress); - mResetInProgress = false; + + CHECK_EQ(mState, STATE_RESET_IN_PROGRESS); + mState = STATE_IDLE; + mCondition.broadcast(); +} + +void NuPlayerDriver::notifySetSurfaceComplete() { + Mutex::Autolock autoLock(mLock); + + CHECK(mSetSurfaceInProgress); + mSetSurfaceInProgress = false; + mCondition.broadcast(); } @@ -335,7 +500,7 @@ status_t NuPlayerDriver::dump(int fd, const Vector<String16> &args) const { FILE *out = fdopen(dup(fd), "w"); fprintf(out, " NuPlayer\n"); - fprintf(out, " numFramesTotal(%lld), numFramesDropped(%lld), " + fprintf(out, " numFramesTotal(%" PRId64 "), numFramesDropped(%" PRId64 "), " "percentageDropped(%.2f)\n", mNumFramesTotal, mNumFramesDropped, @@ -348,12 +513,59 @@ status_t NuPlayerDriver::dump(int fd, const Vector<String16> &args) const { return OK; } -void NuPlayerDriver::notifyListener(int msg, int ext1, int ext2) { +void NuPlayerDriver::notifyListener( + int msg, int ext1, int ext2, const Parcel *in) { if (msg == MEDIA_PLAYBACK_COMPLETE || msg == MEDIA_ERROR) { mAtEOS = true; } - sendEvent(msg, ext1, ext2); + sendEvent(msg, ext1, ext2, in); +} + +void NuPlayerDriver::notifySetDataSourceCompleted(status_t err) { + Mutex::Autolock autoLock(mLock); + + CHECK_EQ(mState, STATE_SET_DATASOURCE_PENDING); + + mAsyncResult = err; + mState = (err == OK) ? STATE_UNPREPARED : STATE_IDLE; + mCondition.broadcast(); +} + +void NuPlayerDriver::notifyPrepareCompleted(status_t err) { + Mutex::Autolock autoLock(mLock); + + if (mState != STATE_PREPARING) { + // We were preparing asynchronously when the client called + // reset(), we sent a premature "prepared" notification and + // then initiated the reset. This notification is stale. + CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE); + return; + } + + CHECK_EQ(mState, STATE_PREPARING); + + mAsyncResult = err; + + if (err == OK) { + if (mIsAsyncPrepare) { + notifyListener(MEDIA_PREPARED); + } + mState = STATE_PREPARED; + } else { + if (mIsAsyncPrepare) { + notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); + } + mState = STATE_UNPREPARED; + } + + mCondition.broadcast(); +} + +void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) { + Mutex::Autolock autoLock(mLock); + + mPlayerFlags = flags; } } // namespace android |