From 3a474aa67fc31505740526dd249d96204c08bf79 Mon Sep 17 00:00:00 2001 From: Lajos Molnar Date: Fri, 24 Apr 2015 17:10:07 -0700 Subject: stagefright: support setting/getting playback/sync config in MediaSync Bug: 18249558 Bug: 19666434 Bug: 20057497 Change-Id: I5868b17423d7c20cfaf4a399f3eb67bfba440605 --- media/libmedia/AudioTrack.cpp | 11 ++ media/libmedia/IMediaPlayer.cpp | 108 ++++++++++- media/libmedia/mediaplayer.cpp | 54 ++++-- media/libmediaplayerservice/MediaPlayerService.cpp | 86 +++++++-- media/libmediaplayerservice/MediaPlayerService.h | 14 +- media/libmediaplayerservice/StagefrightPlayer.cpp | 8 + media/libmediaplayerservice/StagefrightPlayer.h | 2 + media/libmediaplayerservice/nuplayer/NuPlayer.cpp | 176 ++++++++++++++++-- media/libmediaplayerservice/nuplayer/NuPlayer.h | 18 +- .../nuplayer/NuPlayerDriver.cpp | 29 ++- .../nuplayer/NuPlayerDriver.h | 5 +- .../nuplayer/NuPlayerRenderer.cpp | 197 ++++++++++++++++++--- .../nuplayer/NuPlayerRenderer.h | 27 ++- media/libstagefright/AudioPlayer.cpp | 17 +- media/libstagefright/AwesomePlayer.cpp | 70 +++++++- media/libstagefright/MediaSync.cpp | 151 ++++++++++++++-- media/libstagefright/Utils.cpp | 34 ++++ media/libstagefright/include/AwesomePlayer.h | 4 + 18 files changed, 907 insertions(+), 104 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 36281c4..76d9169 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -393,6 +393,7 @@ status_t AudioTrack::set( return BAD_VALUE; } mSampleRate = sampleRate; + mOriginalSampleRate = sampleRate; mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT; // Make copy of input parameter offloadInfo so that in the future: @@ -759,6 +760,15 @@ uint32_t AudioTrack::getSampleRate() const return mSampleRate; } +uint32_t AudioTrack::getOriginalSampleRate() const +{ + if (mIsTimed) { + return 0; + } + + return mOriginalSampleRate; +} + status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) { AutoMutex lock(mLock); @@ -1106,6 +1116,7 @@ status_t AudioTrack::createTrack_l() } if (mSampleRate == 0) { mSampleRate = afSampleRate; + mOriginalSampleRate = afSampleRate; } // Client decides whether the track is TIMED (see below), but can only express a preference // for FAST. Server will perform additional tests. diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index 0091078..bde35f2 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -21,6 +21,9 @@ #include +#include +#include + #include #include #include @@ -41,7 +44,10 @@ enum { START, STOP, IS_PLAYING, - SET_PLAYBACK_RATE, + SET_PLAYBACK_SETTINGS, + GET_PLAYBACK_SETTINGS, + SET_SYNC_SETTINGS, + GET_SYNC_SETTINGS, PAUSE, SEEK_TO, GET_CURRENT_POSITION, @@ -175,15 +181,63 @@ public: return reply.readInt32(); } - status_t setPlaybackRate(float rate) + status_t setPlaybackSettings(const AudioPlaybackRate& rate) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeFloat(rate.mSpeed); + data.writeFloat(rate.mPitch); + data.writeInt32((int32_t)rate.mFallbackMode); + data.writeInt32((int32_t)rate.mStretchMode); + remote()->transact(SET_PLAYBACK_SETTINGS, data, &reply); + return reply.readInt32(); + } + + status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(GET_PLAYBACK_SETTINGS, data, &reply); + status_t err = reply.readInt32(); + if (err == OK) { + *rate = AUDIO_PLAYBACK_RATE_DEFAULT; + rate->mSpeed = reply.readFloat(); + rate->mPitch = reply.readFloat(); + rate->mFallbackMode = (AudioTimestretchFallbackMode)reply.readInt32(); + rate->mStretchMode = (AudioTimestretchStretchMode)reply.readInt32(); + } + return err; + } + + status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); - data.writeFloat(rate); - remote()->transact(SET_PLAYBACK_RATE, data, &reply); + data.writeInt32((int32_t)sync.mSource); + data.writeInt32((int32_t)sync.mAudioAdjustMode); + data.writeFloat(sync.mTolerance); + data.writeFloat(videoFpsHint); + remote()->transact(SET_SYNC_SETTINGS, data, &reply); return reply.readInt32(); } + status_t getSyncSettings(AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(GET_SYNC_SETTINGS, data, &reply); + status_t err = reply.readInt32(); + if (err == OK) { + AVSyncSettings settings; + settings.mSource = (AVSyncSource)reply.readInt32(); + settings.mAudioAdjustMode = (AVSyncAudioAdjustMode)reply.readInt32(); + settings.mTolerance = reply.readFloat(); + *sync = settings; + *videoFps = reply.readFloat(); + } + return err; + } + status_t pause() { Parcel data, reply; @@ -453,9 +507,51 @@ status_t BnMediaPlayer::onTransact( reply->writeInt32(ret); return NO_ERROR; } break; - case SET_PLAYBACK_RATE: { + case SET_PLAYBACK_SETTINGS: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT; + rate.mSpeed = data.readFloat(); + rate.mPitch = data.readFloat(); + rate.mFallbackMode = (AudioTimestretchFallbackMode)data.readInt32(); + rate.mStretchMode = (AudioTimestretchStretchMode)data.readInt32(); + reply->writeInt32(setPlaybackSettings(rate)); + return NO_ERROR; + } break; + case GET_PLAYBACK_SETTINGS: { CHECK_INTERFACE(IMediaPlayer, data, reply); - reply->writeInt32(setPlaybackRate(data.readFloat())); + AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT; + status_t err = getPlaybackSettings(&rate); + reply->writeInt32(err); + if (err == OK) { + reply->writeFloat(rate.mSpeed); + reply->writeFloat(rate.mPitch); + reply->writeInt32((int32_t)rate.mFallbackMode); + reply->writeInt32((int32_t)rate.mStretchMode); + } + return NO_ERROR; + } break; + case SET_SYNC_SETTINGS: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + AVSyncSettings sync; + sync.mSource = (AVSyncSource)data.readInt32(); + sync.mAudioAdjustMode = (AVSyncAudioAdjustMode)data.readInt32(); + sync.mTolerance = data.readFloat(); + float videoFpsHint = data.readFloat(); + reply->writeInt32(setSyncSettings(sync, videoFpsHint)); + return NO_ERROR; + } break; + case GET_SYNC_SETTINGS: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + AVSyncSettings sync; + float videoFps; + status_t err = getSyncSettings(&sync, &videoFps); + reply->writeInt32(err); + if (err == OK) { + reply->writeInt32((int32_t)sync.mSource); + reply->writeInt32((int32_t)sync.mAudioAdjustMode); + reply->writeFloat(sync.mTolerance); + reply->writeFloat(videoFps); + } return NO_ERROR; } break; case PAUSE: { diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 9a276ae..81a5e8c 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -32,7 +32,9 @@ #include #include +#include #include +#include #include #include @@ -60,7 +62,6 @@ MediaPlayer::MediaPlayer() mLoop = false; mLeftVolume = mRightVolume = 1.0; mVideoWidth = mVideoHeight = 0; - mPlaybackRate = 1.0; mLockThreadId = 0; mAudioSessionId = AudioSystem::newAudioUniqueId(); AudioSystem::acquireAudioSessionId(mAudioSessionId, -1); @@ -389,6 +390,9 @@ bool MediaPlayer::isPlaying() if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) { ALOGE("internal/external state mismatch corrected"); mCurrentState = MEDIA_PLAYER_PAUSED; + } else if ((mCurrentState & MEDIA_PLAYER_PAUSED) && temp) { + ALOGE("internal/external state mismatch corrected"); + mCurrentState = MEDIA_PLAYER_STARTED; } return temp; } @@ -396,22 +400,50 @@ bool MediaPlayer::isPlaying() return false; } -status_t MediaPlayer::setPlaybackRate(float rate) +status_t MediaPlayer::setPlaybackSettings(const AudioPlaybackRate& rate) { - ALOGV("setPlaybackRate: %f", rate); - if (rate <= 0.0) { + ALOGV("setPlaybackSettings: %f %f %d %d", + rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode); + // Negative speed and pitch does not make sense. Further validation will + // be done by the respective mediaplayers. + if (rate.mSpeed < 0.f || rate.mPitch < 0.f) { return BAD_VALUE; } Mutex::Autolock _l(mLock); - if (mPlayer != 0) { - if (mPlaybackRate == rate) { - return NO_ERROR; + if (mPlayer == 0) return INVALID_OPERATION; + status_t err = mPlayer->setPlaybackSettings(rate); + if (err == OK) { + if (rate.mSpeed == 0.f && mCurrentState == MEDIA_PLAYER_STARTED) { + mCurrentState = MEDIA_PLAYER_PAUSED; + } else if (rate.mSpeed != 0.f && mCurrentState == MEDIA_PLAYER_PAUSED) { + mCurrentState = MEDIA_PLAYER_STARTED; } - mPlaybackRate = rate; - return mPlayer->setPlaybackRate(rate); } - ALOGV("setPlaybackRate: no active player"); - return INVALID_OPERATION; + return err; +} + +status_t MediaPlayer::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) +{ + Mutex::Autolock _l(mLock); + if (mPlayer == 0) return INVALID_OPERATION; + return mPlayer->getPlaybackSettings(rate); +} + +status_t MediaPlayer::setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) +{ + ALOGV("setSyncSettings: %u %u %f %f", + sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint); + Mutex::Autolock _l(mLock); + if (mPlayer == 0) return INVALID_OPERATION; + return mPlayer->setSyncSettings(sync, videoFpsHint); +} + +status_t MediaPlayer::getSyncSettings( + AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) +{ + Mutex::Autolock _l(mLock); + if (mPlayer == 0) return INVALID_OPERATION; + return mPlayer->getSyncSettings(sync, videoFps); } status_t MediaPlayer::getVideoWidth(int *w) diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 9567eff..891a9e9 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -981,12 +981,52 @@ status_t MediaPlayerService::Client::isPlaying(bool* state) return NO_ERROR; } -status_t MediaPlayerService::Client::setPlaybackRate(float rate) +status_t MediaPlayerService::Client::setPlaybackSettings(const AudioPlaybackRate& rate) { - ALOGV("[%d] setPlaybackRate(%f)", mConnId, rate); + ALOGV("[%d] setPlaybackSettings(%f, %f, %d, %d)", + mConnId, rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode); sp p = getPlayer(); if (p == 0) return UNKNOWN_ERROR; - return p->setPlaybackRate(rate); + return p->setPlaybackSettings(rate); +} + +status_t MediaPlayerService::Client::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) +{ + sp p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + status_t ret = p->getPlaybackSettings(rate); + if (ret == NO_ERROR) { + ALOGV("[%d] getPlaybackSettings(%f, %f, %d, %d)", + mConnId, rate->mSpeed, rate->mPitch, rate->mFallbackMode, rate->mStretchMode); + } else { + ALOGV("[%d] getPlaybackSettings returned %d", mConnId, ret); + } + return ret; +} + +status_t MediaPlayerService::Client::setSyncSettings( + const AVSyncSettings& sync, float videoFpsHint) +{ + ALOGV("[%d] setSyncSettings(%u, %u, %f, %f)", + mConnId, sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint); + sp p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + return p->setSyncSettings(sync, videoFpsHint); +} + +status_t MediaPlayerService::Client::getSyncSettings( + AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) +{ + sp p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + status_t ret = p->getSyncSettings(sync, videoFps); + if (ret == NO_ERROR) { + ALOGV("[%d] getSyncSettings(%u, %u, %f, %f)", + mConnId, sync->mSource, sync->mAudioAdjustMode, sync->mTolerance, *videoFps); + } else { + ALOGV("[%d] getSyncSettings returned %d", mConnId, ret); + } + return ret; } status_t MediaPlayerService::Client::getCurrentPosition(int *msec) @@ -1311,7 +1351,7 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid, mStreamType = AUDIO_STREAM_MUSIC; mLeftVolume = 1.0; mRightVolume = 1.0; - mPlaybackRatePermille = 1000; + mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT; mSampleRateHz = 0; mMsecsPerFrame = 0; mAuxEffectId = 0; @@ -1634,7 +1674,7 @@ status_t MediaPlayerService::AudioOutput::open( mSampleRateHz = sampleRate; mFlags = flags; - mMsecsPerFrame = mPlaybackRatePermille / (float) sampleRate; + mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate); uint32_t pos; if (t->getPosition(&pos) == OK) { mBytesWritten = uint64_t(pos) * t->frameSize(); @@ -1643,7 +1683,7 @@ status_t MediaPlayerService::AudioOutput::open( status_t res = NO_ERROR; if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) { - res = t->setSampleRate(mPlaybackRatePermille * mSampleRateHz / 1000); + res = t->setPlaybackRate(mPlaybackRate); if (res == NO_ERROR) { t->setAuxEffectSendLevel(mSendLevel); res = t->attachAuxEffect(mAuxEffectId); @@ -1739,22 +1779,38 @@ void MediaPlayerService::AudioOutput::setVolume(float left, float right) } } -status_t MediaPlayerService::AudioOutput::setPlaybackRatePermille(int32_t ratePermille) +status_t MediaPlayerService::AudioOutput::setPlaybackRate(const AudioPlaybackRate &rate) { - ALOGV("setPlaybackRatePermille(%d)", ratePermille); - status_t res = NO_ERROR; - if (mTrack != 0) { - res = mTrack->setSampleRate(ratePermille * mSampleRateHz / 1000); - } else { - res = NO_INIT; + ALOGV("setPlaybackRate(%f %f %d %d)", + rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode); + if (mTrack == 0) { + // remember rate so that we can set it when the track is opened + mPlaybackRate = rate; + return OK; + } + status_t res = mTrack->setPlaybackRate(rate); + if (res != NO_ERROR) { + return res; } - mPlaybackRatePermille = ratePermille; + // rate.mSpeed is always greater than 0 if setPlaybackRate succeeded + CHECK_GT(rate.mSpeed, 0.f); + mPlaybackRate = rate; if (mSampleRateHz != 0) { - mMsecsPerFrame = mPlaybackRatePermille / (float) mSampleRateHz; + mMsecsPerFrame = 1E3f / (rate.mSpeed * mSampleRateHz); } return res; } +status_t MediaPlayerService::AudioOutput::getPlaybackRate(AudioPlaybackRate *rate) +{ + ALOGV("setPlaybackRate"); + if (mTrack == 0) { + return NO_INIT; + } + *rate = mTrack->getPlaybackRate(); + return NO_ERROR; +} + status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level) { ALOGV("setAuxEffectSendLevel(%f)", level); diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 1a3ce92..5103841 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -34,7 +34,9 @@ namespace android { +struct AudioPlaybackRate; class AudioTrack; +struct AVSyncSettings; class IDataSource; class IMediaRecorder; class IMediaMetadataRetriever; @@ -109,7 +111,9 @@ class MediaPlayerService : public BnMediaPlayerService void setAudioAttributes(const audio_attributes_t * attributes); void setVolume(float left, float right); - virtual status_t setPlaybackRatePermille(int32_t ratePermille); + virtual status_t setPlaybackRate(const AudioPlaybackRate& rate); + virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */); + status_t setAuxEffectSendLevel(float level); status_t attachAuxEffect(int effectId); virtual status_t dump(int fd, const Vector& args) const; @@ -139,7 +143,7 @@ class MediaPlayerService : public BnMediaPlayerService const audio_attributes_t *mAttributes; float mLeftVolume; float mRightVolume; - int32_t mPlaybackRatePermille; + AudioPlaybackRate mPlaybackRate; uint32_t mSampleRateHz; // sample rate of the content, as set in open() float mMsecsPerFrame; int mSessionId; @@ -262,7 +266,11 @@ private: virtual status_t stop(); virtual status_t pause(); virtual status_t isPlaying(bool* state); - virtual status_t setPlaybackRate(float rate); + virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate); + virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */); + virtual status_t setSyncSettings(const AVSyncSettings& rate, float videoFpsHint); + virtual status_t getSyncSettings(AVSyncSettings* rate /* nonnull */, + float* videoFps /* nonnull */); virtual status_t seekTo(int msec); virtual status_t getCurrentPosition(int* msec); virtual status_t getDuration(int* msec); diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp index b37aee3..3fedd9b 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.cpp +++ b/media/libmediaplayerservice/StagefrightPlayer.cpp @@ -188,6 +188,14 @@ status_t StagefrightPlayer::getParameter(int key, Parcel *reply) { return mPlayer->getParameter(key, reply); } +status_t StagefrightPlayer::setPlaybackSettings(const AudioPlaybackRate &rate) { + return mPlayer->setPlaybackSettings(rate); +} + +status_t StagefrightPlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) { + return mPlayer->getPlaybackSettings(rate); +} + status_t StagefrightPlayer::getMetadata( const media::Metadata::Filter& /* ids */, Parcel *records) { using media::Metadata; diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h index e6c30ff..96013df 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.h +++ b/media/libmediaplayerservice/StagefrightPlayer.h @@ -60,6 +60,8 @@ public: virtual void setAudioSink(const sp &audioSink); virtual status_t setParameter(int key, const Parcel &request); virtual status_t getParameter(int key, Parcel *reply); + virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate); + virtual status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); virtual status_t getMetadata( const media::Metadata::Filter& ids, Parcel *records); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index b670d68..cb8579b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -37,6 +37,9 @@ #include +#include +#include + #include #include #include @@ -180,7 +183,8 @@ NuPlayer::NuPlayer() mFlushingVideo(NONE), mResumePending(false), mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW), - mPlaybackRate(1.0), + mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT), + mVideoFpsHint(-1.f), mStarted(false), mPaused(false), mPausedByClient(false) { @@ -331,10 +335,61 @@ void NuPlayer::start() { (new AMessage(kWhatStart, this))->post(); } -void NuPlayer::setPlaybackRate(float rate) { - sp msg = new AMessage(kWhatSetRate, this); - msg->setFloat("rate", rate); - msg->post(); +status_t NuPlayer::setPlaybackSettings(const AudioPlaybackRate &rate) { + // do some cursory validation of the settings here. audio modes are + // only validated when set on the audiosink. + if ((rate.mSpeed != 0.f && rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN) + || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX + || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN + || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) { + return BAD_VALUE; + } + sp msg = new AMessage(kWhatConfigPlayback, this); + writeToAMessage(msg, rate); + sp response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + } + return err; +} + +status_t NuPlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) { + sp msg = new AMessage(kWhatGetPlaybackSettings, this); + sp response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + if (err == OK) { + readFromAMessage(response, rate); + } + } + return err; +} + +status_t NuPlayer::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) { + sp msg = new AMessage(kWhatConfigSync, this); + writeToAMessage(msg, sync, videoFpsHint); + sp response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + } + return err; +} + +status_t NuPlayer::getSyncSettings( + AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) { + sp msg = new AMessage(kWhatGetSyncSettings, this); + sp response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + if (err == OK) { + readFromAMessage(response, sync, videoFps); + } + } + return err; } void NuPlayer::pause() { @@ -627,12 +682,28 @@ void NuPlayer::onMessageReceived(const sp &msg) { break; } - case kWhatSetRate: + case kWhatConfigPlayback: { - ALOGV("kWhatSetRate"); - CHECK(msg->findFloat("rate", &mPlaybackRate)); + sp replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + AudioPlaybackRate rate /* sanitized */; + readFromAMessage(msg, &rate); + status_t err = OK; if (mRenderer != NULL) { - mRenderer->setPlaybackRate(mPlaybackRate); + err = mRenderer->setPlaybackSettings(rate); + } + if (err == OK) { + if (rate.mSpeed == 0.f) { + onPause(); + // save all other settings (using non-paused speed) + // so we can restore them on start + AudioPlaybackRate newRate = rate; + newRate.mSpeed = mPlaybackSettings.mSpeed; + mPlaybackSettings = newRate; + } else { /* rate.mSpeed != 0.f */ + onResume(); + mPlaybackSettings = rate; + } } if (mVideoDecoder != NULL) { @@ -640,11 +711,86 @@ void NuPlayer::onMessageReceived(const sp &msg) { int32_t rate; if (meta != NULL && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) { sp params = new AMessage(); - params->setFloat("operating-rate", rate * mPlaybackRate); + params->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed); mVideoDecoder->setParameters(params); } } + sp response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatGetPlaybackSettings: + { + sp replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + AudioPlaybackRate rate = mPlaybackSettings; + status_t err = OK; + if (mRenderer != NULL) { + err = mRenderer->getPlaybackSettings(&rate); + } + if (err == OK) { + // get playback settings used by renderer, as it may be + // slightly off due to audiosink not taking small changes. + mPlaybackSettings = rate; + if (mPaused) { + rate.mSpeed = 0.f; + } + } + sp response = new AMessage; + if (err == OK) { + writeToAMessage(response, rate); + } + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatConfigSync: + { + sp replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + ALOGV("kWhatConfigSync"); + AVSyncSettings sync; + float videoFpsHint; + readFromAMessage(msg, &sync, &videoFpsHint); + status_t err = OK; + if (mRenderer != NULL) { + err = mRenderer->setSyncSettings(sync, videoFpsHint); + } + if (err == OK) { + mSyncSettings = sync; + mVideoFpsHint = videoFpsHint; + } + sp response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatGetSyncSettings: + { + sp replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + AVSyncSettings sync = mSyncSettings; + float videoFps = mVideoFpsHint; + status_t err = OK; + if (mRenderer != NULL) { + err = mRenderer->getSyncSettings(&sync, &videoFps); + if (err == OK) { + mSyncSettings = sync; + mVideoFpsHint = videoFps; + } + } + sp response = new AMessage; + if (err == OK) { + writeToAMessage(response, sync, videoFps); + } + response->setInt32("err", err); + response->postReply(replyID); break; } @@ -1114,8 +1260,12 @@ void NuPlayer::onStart() { mRendererLooper->setName("NuPlayerRenderer"); mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO); mRendererLooper->registerHandler(mRenderer); - if (mPlaybackRate != 1.0) { - mRenderer->setPlaybackRate(mPlaybackRate); + + status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings); + if (err != OK) { + mSource->stop(); + notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); + return; } sp meta = getFileMeta(); @@ -1282,7 +1432,7 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp *decoder) { sp meta = getFileMeta(); int32_t rate; if (meta != NULL && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) { - format->setFloat("operating-rate", rate * mPlaybackRate); + format->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed); } } diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 14bdb01..88e929d 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -18,6 +18,7 @@ #define NU_PLAYER_H_ +#include #include #include #include @@ -26,6 +27,8 @@ namespace android { struct ABuffer; struct AMessage; +struct AudioPlaybackRate; +struct AVSyncSettings; class IDataSource; class MetaData; struct NuPlayerDriver; @@ -54,7 +57,11 @@ struct NuPlayer : public AHandler { const sp &bufferProducer); void setAudioSink(const sp &sink); - void setPlaybackRate(float rate); + status_t setPlaybackSettings(const AudioPlaybackRate &rate); + status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); + status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint); + status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */); + void start(); void pause(); @@ -108,7 +115,10 @@ private: kWhatSetVideoNativeWindow = '=NaW', kWhatSetAudioSink = '=AuS', kWhatMoreDataQueued = 'more', - kWhatSetRate = 'setR', + kWhatConfigPlayback = 'cfPB', + kWhatConfigSync = 'cfSy', + kWhatGetPlaybackSettings = 'gPbS', + kWhatGetSyncSettings = 'gSyS', kWhatStart = 'strt', kWhatScanSources = 'scan', kWhatVideoNotify = 'vidN', @@ -180,7 +190,9 @@ private: int32_t mVideoScalingMode; - float mPlaybackRate; + AudioPlaybackRate mPlaybackSettings; + AVSyncSettings mSyncSettings; + float mVideoFpsHint; bool mStarted; // Actual pause state, either as requested by client or due to buffering. diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 04a324c..231f2e1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -360,9 +360,32 @@ bool NuPlayerDriver::isPlaying() { return mState == STATE_RUNNING && !mAtEOS; } -status_t NuPlayerDriver::setPlaybackRate(float rate) { - mPlayer->setPlaybackRate(rate); - return OK; +status_t NuPlayerDriver::setPlaybackSettings(const AudioPlaybackRate &rate) { + Mutex::Autolock autoLock(mLock); + status_t err = mPlayer->setPlaybackSettings(rate); + if (err == OK) { + if (rate.mSpeed == 0.f && mState == STATE_RUNNING) { + mState = STATE_PAUSED; + // try to update position + (void)mPlayer->getCurrentPosition(&mPositionUs); + notifyListener_l(MEDIA_PAUSED); + } else if (rate.mSpeed != 0.f && mState == STATE_PAUSED) { + mState = STATE_RUNNING; + } + } + return err; +} + +status_t NuPlayerDriver::getPlaybackSettings(AudioPlaybackRate *rate) { + return mPlayer->getPlaybackSettings(rate); +} + +status_t NuPlayerDriver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) { + return mPlayer->setSyncSettings(sync, videoFpsHint); +} + +status_t NuPlayerDriver::getSyncSettings(AVSyncSettings *sync, float *videoFps) { + return mPlayer->getSyncSettings(sync, videoFps); } status_t NuPlayerDriver::seekTo(int msec) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index 65f170e..9da7fc1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -49,7 +49,10 @@ struct NuPlayerDriver : public MediaPlayerInterface { virtual status_t stop(); virtual status_t pause(); virtual bool isPlaying(); - virtual status_t setPlaybackRate(float rate); + virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate); + virtual status_t getPlaybackSettings(AudioPlaybackRate *rate); + virtual status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint); + virtual status_t getSyncSettings(AVSyncSettings *sync, float *videoFps); virtual status_t seekTo(int msec); virtual status_t getCurrentPosition(int *msec); virtual status_t getDuration(int *msec); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index f229452..ae01cfc 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -66,7 +66,7 @@ NuPlayer::Renderer::Renderer( mVideoQueueGeneration(0), mAudioDrainGeneration(0), mVideoDrainGeneration(0), - mPlaybackRate(1.0), + mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT), mAudioFirstAnchorTimeMediaUs(-1), mAnchorTimeMediaUs(-1), mAnchorNumFramesWritten(-1), @@ -89,6 +89,8 @@ NuPlayer::Renderer::Renderer( mLastAudioBufferDrained(0), mWakeLock(new AWakeLock()) { mMediaClock = new MediaClock; + mPlaybackRate = mPlaybackSettings.mSpeed; + mMediaClock->setPlaybackRate(mPlaybackRate); } NuPlayer::Renderer::~Renderer() { @@ -121,10 +123,111 @@ void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) { msg->post(); } -void NuPlayer::Renderer::setPlaybackRate(float rate) { - sp msg = new AMessage(kWhatSetRate, this); - msg->setFloat("rate", rate); - msg->post(); +status_t NuPlayer::Renderer::setPlaybackSettings(const AudioPlaybackRate &rate) { + sp msg = new AMessage(kWhatConfigPlayback, this); + writeToAMessage(msg, rate); + sp response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + } + return err; +} + +status_t NuPlayer::Renderer::onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */) { + if (rate.mSpeed == 0.f) { + onPause(); + // don't call audiosink's setPlaybackRate if pausing, as pitch does not + // have to correspond to the any non-0 speed (e.g old speed). Keep + // settings nonetheless, using the old speed, in case audiosink changes. + AudioPlaybackRate newRate = rate; + newRate.mSpeed = mPlaybackSettings.mSpeed; + mPlaybackSettings = newRate; + return OK; + } + + if (mAudioSink != NULL) { + status_t err = mAudioSink->setPlaybackRate(rate); + if (err != OK) { + return err; + } + } + mPlaybackSettings = rate; + mPlaybackRate = rate.mSpeed; + mMediaClock->setPlaybackRate(mPlaybackRate); + return OK; +} + +status_t NuPlayer::Renderer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) { + sp msg = new AMessage(kWhatGetPlaybackSettings, this); + sp response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + if (err == OK) { + readFromAMessage(response, rate); + } + } + return err; +} + +status_t NuPlayer::Renderer::onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) { + if (mAudioSink != NULL) { + status_t err = mAudioSink->getPlaybackRate(rate); + if (err == OK) { + if (!isAudioPlaybackRateEqual(*rate, mPlaybackSettings)) { + ALOGW("correcting mismatch in internal/external playback rate"); + } + // get playback settings used by audiosink, as it may be + // slightly off due to audiosink not taking small changes. + mPlaybackSettings = *rate; + if (mPaused) { + rate->mSpeed = 0.f; + } + } + return err; + } + *rate = mPlaybackSettings; + return OK; +} + +status_t NuPlayer::Renderer::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) { + sp msg = new AMessage(kWhatConfigSync, this); + writeToAMessage(msg, sync, videoFpsHint); + sp response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + } + return err; +} + +status_t NuPlayer::Renderer::onConfigSync(const AVSyncSettings &sync, float videoFpsHint __unused) { + if (sync.mSource != AVSYNC_SOURCE_DEFAULT) { + return BAD_VALUE; + } + // TODO: support sync sources + return INVALID_OPERATION; +} + +status_t NuPlayer::Renderer::getSyncSettings(AVSyncSettings *sync, float *videoFps) { + sp msg = new AMessage(kWhatGetSyncSettings, this); + sp response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + if (err == OK) { + readFromAMessage(response, sync, videoFps); + } + } + return err; +} + +status_t NuPlayer::Renderer::onGetSyncSettings( + AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) { + *sync = mSyncSettings; + *videoFps = -1.f; + return OK; } void NuPlayer::Renderer::flush(bool audio, bool notifyComplete) { @@ -365,13 +468,63 @@ void NuPlayer::Renderer::onMessageReceived(const sp &msg) { break; } - case kWhatSetRate: + case kWhatConfigPlayback: { - CHECK(msg->findFloat("rate", &mPlaybackRate)); - int32_t ratePermille = (int32_t)(0.5f + 1000 * mPlaybackRate); - mPlaybackRate = ratePermille / 1000.0f; - mMediaClock->setPlaybackRate(mPlaybackRate); - mAudioSink->setPlaybackRatePermille(ratePermille); + sp replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + AudioPlaybackRate rate; + readFromAMessage(msg, &rate); + status_t err = onConfigPlayback(rate); + sp response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatGetPlaybackSettings: + { + sp replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT; + status_t err = onGetPlaybackSettings(&rate); + sp response = new AMessage; + if (err == OK) { + writeToAMessage(response, rate); + } + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatConfigSync: + { + sp replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + AVSyncSettings sync; + float videoFpsHint; + readFromAMessage(msg, &sync, &videoFpsHint); + status_t err = onConfigSync(sync, videoFpsHint); + sp response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatGetSyncSettings: + { + sp replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + ALOGV("kWhatGetSyncSettings"); + AVSyncSettings sync; + float videoFps = -1.f; + status_t err = onGetSyncSettings(&sync, &videoFps); + sp response = new AMessage; + if (err == OK) { + writeToAMessage(response, sync, videoFps); + } + response->setInt32("err", err); + response->postReply(replyID); break; } @@ -1176,7 +1329,6 @@ void NuPlayer::Renderer::onEnableOffloadAudio() { void NuPlayer::Renderer::onPause() { if (mPaused) { - ALOGW("Renderer::onPause() called while already paused!"); return; } @@ -1214,6 +1366,12 @@ void NuPlayer::Renderer::onResume() { { Mutex::Autolock autoLock(mLock); mPaused = false; + + // configure audiosink as we did not do it when pausing + if (mAudioSink != NULL) { + mAudioSink->setPlaybackRate(mPlaybackSettings); + } + mMediaClock->setPlaybackRate(mPlaybackRate); if (!mAudioQueue.empty()) { @@ -1433,10 +1591,10 @@ status_t NuPlayer::Renderer::onOpenAudioSink( &offloadInfo); if (err == OK) { - if (mPlaybackRate != 1.0) { - mAudioSink->setPlaybackRatePermille( - (int32_t)(mPlaybackRate * 1000 + 0.5f)); - } + err = mAudioSink->setPlaybackRate(mPlaybackSettings); + } + + if (err == OK) { // If the playback is offloaded to h/w, we pass // the HAL some metadata information. // We don't want to do this for PCM because it @@ -1486,16 +1644,15 @@ status_t NuPlayer::Renderer::onOpenAudioSink( NULL, NULL, (audio_output_flags_t)pcmFlags); + if (err == OK) { + err = mAudioSink->setPlaybackRate(mPlaybackSettings); + } if (err != OK) { ALOGW("openAudioSink: non offloaded open failed status: %d", err); mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER; return err; } mCurrentPcmInfo = info; - if (mPlaybackRate != 1.0) { - mAudioSink->setPlaybackRatePermille( - (int32_t)(mPlaybackRate * 1000 + 0.5f)); - } mAudioSink->start(); } if (audioSinkChanged) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 38843d5..928b71b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -18,6 +18,9 @@ #define NUPLAYER_RENDERER_H_ +#include +#include + #include "NuPlayer.h" namespace android { @@ -48,7 +51,10 @@ struct NuPlayer::Renderer : public AHandler { void queueEOS(bool audio, status_t finalResult); - void setPlaybackRate(float rate); + status_t setPlaybackSettings(const AudioPlaybackRate &rate /* sanitized */); + status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); + status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint); + status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */); void flush(bool audio, bool notifyComplete); @@ -102,7 +108,10 @@ private: kWhatPostDrainVideoQueue = 'pDVQ', kWhatQueueBuffer = 'queB', kWhatQueueEOS = 'qEOS', - kWhatSetRate = 'setR', + kWhatConfigPlayback = 'cfPB', + kWhatConfigSync = 'cfSy', + kWhatGetPlaybackSettings = 'gPbS', + kWhatGetSyncSettings = 'gSyS', kWhatFlush = 'flus', kWhatPause = 'paus', kWhatResume = 'resm', @@ -141,7 +150,12 @@ private: int32_t mVideoDrainGeneration; sp mMediaClock; - float mPlaybackRate; + float mPlaybackRate; // audio track rate + + AudioPlaybackRate mPlaybackSettings; + AVSyncSettings mSyncSettings; + float mVideoFpsHint; + int64_t mAudioFirstAnchorTimeMediaUs; int64_t mAnchorTimeMediaUs; int64_t mAnchorNumFramesWritten; @@ -217,6 +231,11 @@ private: void onAudioSinkChanged(); void onDisableOffloadAudio(); void onEnableOffloadAudio(); + status_t onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */); + status_t onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); + status_t onConfigSync(const AVSyncSettings &sync, float videoFpsHint); + status_t onGetSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */); + void onPause(); void onResume(); void onSetVideoFrameRate(float fps); @@ -252,6 +271,6 @@ private: DISALLOW_EVIL_CONSTRUCTORS(Renderer); }; -} // namespace android +} // namespace android #endif // NUPLAYER_RENDERER_H_ diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index e24824b..dd9d393 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -408,11 +408,22 @@ void AudioPlayer::notifyAudioEOS() { } } -status_t AudioPlayer::setPlaybackRatePermille(int32_t ratePermille) { +status_t AudioPlayer::setPlaybackRate(const AudioPlaybackRate &rate) { if (mAudioSink.get() != NULL) { - return mAudioSink->setPlaybackRatePermille(ratePermille); + return mAudioSink->setPlaybackRate(rate); } else if (mAudioTrack != 0){ - return mAudioTrack->setSampleRate(ratePermille * mSampleRate / 1000); + return mAudioTrack->setPlaybackRate(rate); + } else { + return NO_INIT; + } +} + +status_t AudioPlayer::getPlaybackRate(AudioPlaybackRate *rate /* nonnull */) { + if (mAudioSink.get() != NULL) { + return mAudioSink->getPlaybackRate(rate); + } else if (mAudioTrack != 0) { + *rate = mAudioTrack->getPlaybackRate(); + return OK; } else { return NO_INIT; } diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index c14625d..df01e7c 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -241,6 +241,8 @@ AwesomePlayer::AwesomePlayer() mClockEstimator = new WindowedLinearFitEstimator(); + mPlaybackSettings = AUDIO_PLAYBACK_RATE_DEFAULT; + reset(); } @@ -1009,6 +1011,10 @@ status_t AwesomePlayer::play_l() { return err; } } + + if (mAudioPlayer != NULL) { + mAudioPlayer->setPlaybackRate(mPlaybackSettings); + } } if (mTimeSource == NULL && mAudioPlayer == NULL) { @@ -1131,6 +1137,10 @@ status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) { } if (err == OK) { + err = mAudioPlayer->setPlaybackRate(mPlaybackSettings); + } + + if (err == OK) { modifyFlags(AUDIO_RUNNING, SET); mWatchForAudioEOS = true; @@ -2553,14 +2563,6 @@ status_t AwesomePlayer::setParameter(int key, const Parcel &request) { { return setCacheStatCollectFreq(request); } - case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE: - { - if (mAudioPlayer != NULL) { - return mAudioPlayer->setPlaybackRatePermille(request.readInt32()); - } else { - return NO_INIT; - } - } default: { return ERROR_UNSUPPORTED; @@ -2597,6 +2599,58 @@ status_t AwesomePlayer::getParameter(int key, Parcel *reply) { } } +status_t AwesomePlayer::setPlaybackSettings(const AudioPlaybackRate &rate) { + Mutex::Autolock autoLock(mLock); + // cursory sanity check for non-audio and paused cases + if ((rate.mSpeed != 0.f && rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN) + || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX + || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN + || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) { + return BAD_VALUE; + } + + status_t err = OK; + if (rate.mSpeed == 0.f) { + if (mFlags & PLAYING) { + modifyFlags(CACHE_UNDERRUN, CLEAR); // same as pause + err = pause_l(); + } + if (err == OK) { + // save settings (using old speed) in case player is resumed + AudioPlaybackRate newRate = rate; + newRate.mSpeed = mPlaybackSettings.mSpeed; + mPlaybackSettings = newRate; + } + return err; + } + if (mAudioPlayer != NULL) { + err = mAudioPlayer->setPlaybackRate(rate); + } + if (err == OK) { + mPlaybackSettings = rate; + if (!(mFlags & PLAYING)) { + play_l(); + } + } + return err; +} + +status_t AwesomePlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) { + if (mAudioPlayer != NULL) { + status_t err = mAudioPlayer->getPlaybackRate(rate); + if (err == OK) { + mPlaybackSettings = *rate; + Mutex::Autolock autoLock(mLock); + if (!(mFlags & PLAYING)) { + rate->mSpeed = 0.f; + } + } + return err; + } + *rate = mPlaybackSettings; + return OK; +} + status_t AwesomePlayer::getTrackInfo(Parcel *reply) const { Mutex::Autolock autoLock(mLock); size_t trackCount = mExtractor->countTracks(); diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp index 4350b59..85027ce 100644 --- a/media/libstagefright/MediaSync.cpp +++ b/media/libstagefright/MediaSync.cpp @@ -56,6 +56,10 @@ MediaSync::MediaSync() mPlaybackRate(0.0) { mMediaClock = new MediaClock; + // initialize settings + mPlaybackSettings = AUDIO_PLAYBACK_RATE_DEFAULT; + mPlaybackSettings.mSpeed = mPlaybackRate; + mLooper = new ALooper; mLooper->setName("MediaSync"); mLooper->start(false, false, ANDROID_PRIORITY_AUDIO); @@ -84,6 +88,11 @@ status_t MediaSync::configureSurface(const sp &output) { return INVALID_OPERATION; } + if (output == NULL && mSyncSettings.mSource == AVSYNC_SOURCE_VSYNC) { + ALOGE("configureSurface: output surface is used as sync source and cannot be removed."); + return INVALID_OPERATION; + } + if (output != NULL) { IGraphicBufferProducer::QueueBufferOutput queueBufferOutput; sp listener(new OutputListener(this)); @@ -105,8 +114,7 @@ status_t MediaSync::configureSurface(const sp &output) { } // |audioTrack| is used only for querying information. -status_t MediaSync::configureAudioTrack( - const sp &audioTrack, uint32_t nativeSampleRateInHz) { +status_t MediaSync::configureAudioTrack(const sp &audioTrack) { Mutex::Autolock lock(mMutex); // TODO: support audio track change. @@ -115,15 +123,35 @@ status_t MediaSync::configureAudioTrack( return INVALID_OPERATION; } - if (audioTrack != NULL && nativeSampleRateInHz <= 0) { - ALOGE("configureAudioTrack: native sample rate should be positive."); - return BAD_VALUE; + if (audioTrack == NULL && mSyncSettings.mSource == AVSYNC_SOURCE_AUDIO) { + ALOGE("configureAudioTrack: audioTrack is used as sync source and cannot be removed."); + return INVALID_OPERATION; } - mAudioTrack = audioTrack; - mNativeSampleRateInHz = nativeSampleRateInHz; + if (audioTrack != NULL) { + // check if audio track supports the playback settings + if (mPlaybackSettings.mSpeed != 0.f + && audioTrack->setPlaybackRate(mPlaybackSettings) != OK) { + ALOGE("playback settings are not supported by the audio track"); + return INVALID_OPERATION; + } + uint32_t nativeSampleRateInHz = audioTrack->getOriginalSampleRate(); + if (nativeSampleRateInHz <= 0) { + ALOGE("configureAudioTrack: native sample rate should be positive."); + return BAD_VALUE; + } + mAudioTrack = audioTrack; + mNativeSampleRateInHz = nativeSampleRateInHz; + (void)setPlaybackSettings_l(mPlaybackSettings); + } + else { + mAudioTrack = NULL; + mNativeSampleRateInHz = 0; + } - return NO_ERROR; + // potentially resync to new source + resync_l(); + return OK; } status_t MediaSync::createInputSurface( @@ -158,21 +186,27 @@ status_t MediaSync::createInputSurface( return status; } -status_t MediaSync::setPlaybackRate(float rate) { - if (rate < 0.0) { - return BAD_VALUE; +void MediaSync::resync_l() { + AVSyncSource src = mSyncSettings.mSource; + if (src == AVSYNC_SOURCE_DEFAULT) { + if (mAudioTrack != NULL) { + src = AVSYNC_SOURCE_AUDIO; + } else { + src = AVSYNC_SOURCE_SYSTEM_CLOCK; + } } - Mutex::Autolock lock(mMutex); + // TODO: resync ourselves to the current clock (e.g. on sync source change) + updatePlaybackRate_l(mPlaybackRate); +} +void MediaSync::updatePlaybackRate_l(float rate) { if (rate > mPlaybackRate) { mNextBufferItemMediaUs = -1; } mPlaybackRate = rate; mMediaClock->setPlaybackRate(rate); onDrainVideo_l(); - - return OK; } sp MediaSync::getMediaClock() { @@ -264,6 +298,95 @@ void MediaSync::setName(const AString &name) { mInput->setConsumerName(String8(name.c_str())); } +status_t MediaSync::setVideoFrameRateHint(float rate) { + // ignored until we add the FrameScheduler + return rate >= 0.f ? OK : BAD_VALUE; +} + +float MediaSync::getVideoFrameRate() { + // we don't know the frame rate + return -1.f; +} + +status_t MediaSync::setSyncSettings(const AVSyncSettings &syncSettings) { + // validate settings + if (syncSettings.mSource >= AVSYNC_SOURCE_MAX + || syncSettings.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX + || syncSettings.mTolerance < 0.f + || syncSettings.mTolerance >= AVSYNC_TOLERANCE_MAX) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + + // verify that we have the sync source + switch (syncSettings.mSource) { + case AVSYNC_SOURCE_AUDIO: + if (mAudioTrack == NULL) { + ALOGE("setSyncSettings: audio sync source requires an audio track"); + return BAD_VALUE; + } + break; + case AVSYNC_SOURCE_VSYNC: + if (mOutput == NULL) { + ALOGE("setSyncSettings: vsync sync source requires an output surface"); + return BAD_VALUE; + } + break; + default: + break; + } + + mSyncSettings = syncSettings; + resync_l(); + return OK; +} + +void MediaSync::getSyncSettings(AVSyncSettings *syncSettings) { + Mutex::Autolock lock(mMutex); + *syncSettings = mSyncSettings; +} + +status_t MediaSync::setPlaybackSettings(const AudioPlaybackRate &rate) { + Mutex::Autolock lock(mMutex); + + status_t err = setPlaybackSettings_l(rate); + if (err == OK) { + // TODO: adjust rate if using VSYNC as source + updatePlaybackRate_l(rate.mSpeed); + } + return err; +} + +status_t MediaSync::setPlaybackSettings_l(const AudioPlaybackRate &rate) { + if (rate.mSpeed < 0.f || rate.mPitch < 0.f) { + // We don't validate other audio settings. + // They will be validated when/if audiotrack is set. + return BAD_VALUE; + } + + if (mAudioTrack != NULL) { + if (rate.mSpeed == 0.f) { + mAudioTrack->pause(); + } else { + status_t err = mAudioTrack->setPlaybackRate(rate); + if (err != OK) { + return BAD_VALUE; + } + + // ignore errors + (void)mAudioTrack->start(); + } + } + mPlaybackSettings = rate; + return OK; +} + +void MediaSync::getPlaybackSettings(AudioPlaybackRate *rate) { + Mutex::Autolock lock(mMutex); + *rate = mPlaybackSettings; +} + int64_t MediaSync::getRealTime(int64_t mediaTimeUs, int64_t nowUs) { int64_t realUs; if (mMediaClock->getRealTimeFor(mediaTimeUs, &realUs) != OK) { diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 7b089b0..413628d 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -901,5 +901,39 @@ bool operator <(const HLSTime &t0, const HLSTime &t1) { || (t0.mSeq == t1.mSeq && t0.mTimeUs < t1.mTimeUs); } +void writeToAMessage(sp msg, const AudioPlaybackRate &rate) { + msg->setFloat("speed", rate.mSpeed); + msg->setFloat("pitch", rate.mPitch); + msg->setInt32("audio-fallback-mode", rate.mFallbackMode); + msg->setInt32("audio-stretch-mode", rate.mStretchMode); +} + +void readFromAMessage(const sp &msg, AudioPlaybackRate *rate /* nonnull */) { + *rate = AUDIO_PLAYBACK_RATE_DEFAULT; + CHECK(msg->findFloat("speed", &rate->mSpeed)); + CHECK(msg->findFloat("pitch", &rate->mPitch)); + CHECK(msg->findInt32("audio-fallback-mode", (int32_t *)&rate->mFallbackMode)); + CHECK(msg->findInt32("audio-stretch-mode", (int32_t *)&rate->mStretchMode)); +} + +void writeToAMessage(sp msg, const AVSyncSettings &sync, float videoFpsHint) { + msg->setInt32("sync-source", sync.mSource); + msg->setInt32("audio-adjust-mode", sync.mAudioAdjustMode); + msg->setFloat("tolerance", sync.mTolerance); + msg->setFloat("video-fps", videoFpsHint); +} + +void readFromAMessage( + const sp &msg, + AVSyncSettings *sync /* nonnull */, + float *videoFps /* nonnull */) { + AVSyncSettings settings; + CHECK(msg->findInt32("sync-source", (int32_t *)&settings.mSource)); + CHECK(msg->findInt32("audio-adjust-mode", (int32_t *)&settings.mAudioAdjustMode)); + CHECK(msg->findFloat("tolerance", &settings.mTolerance)); + CHECK(msg->findFloat("video-fps", videoFps)); + *sync = settings; +} + } // namespace android diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 8bba804..758b2c9 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -21,6 +21,7 @@ #include "HTTPBase.h" #include "TimedEventQueue.h" +#include #include #include #include @@ -93,6 +94,8 @@ struct AwesomePlayer { status_t setParameter(int key, const Parcel &request); status_t getParameter(int key, Parcel *reply); + status_t setPlaybackSettings(const AudioPlaybackRate &rate); + status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); status_t invoke(const Parcel &request, Parcel *reply); status_t setCacheStatCollectFreq(const Parcel &request); @@ -180,6 +183,7 @@ private: sp mOmxSource; sp mAudioSource; AudioPlayer *mAudioPlayer; + AudioPlaybackRate mPlaybackSettings; int64_t mDurationUs; int32_t mDisplayWidth; -- cgit v1.1