summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei Jia <wjia@google.com>2015-02-25 23:10:06 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2015-02-25 23:10:07 +0000
commit212765f2d5ee6e533f3d032d6609125faa95bf48 (patch)
tree8e6701ad7c2b2af5f9200ab79960de1c724f7635
parent7c4820d23b68f748b8dfff3d4bb5b13e9d4811a8 (diff)
parent9816016afb2a13c6a866cd047d57020566a8b9a9 (diff)
downloadframeworks_av-212765f2d5ee6e533f3d032d6609125faa95bf48.zip
frameworks_av-212765f2d5ee6e533f3d032d6609125faa95bf48.tar.gz
frameworks_av-212765f2d5ee6e533f3d032d6609125faa95bf48.tar.bz2
Merge "mediaplayer: support dynamic playback rate"
-rw-r--r--include/media/IMediaPlayer.h1
-rw-r--r--include/media/MediaPlayerInterface.h1
-rw-r--r--include/media/mediaplayer.h2
-rw-r--r--media/libmedia/IMediaPlayer.cpp15
-rw-r--r--media/libmedia/mediaplayer.cpp19
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.cpp8
-rw-r--r--media/libmediaplayerservice/MediaPlayerService.h1
-rw-r--r--media/libmediaplayerservice/nuplayer/MediaClock.cpp80
-rw-r--r--media/libmediaplayerservice/nuplayer/MediaClock.h23
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp20
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.h3
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp5
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerDriver.h1
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp73
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h6
15 files changed, 190 insertions, 68 deletions
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index db62cd5..4153c25 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -56,6 +56,7 @@ public:
virtual status_t stop() = 0;
virtual status_t pause() = 0;
virtual status_t isPlaying(bool* state) = 0;
+ virtual status_t setPlaybackRate(float rate) = 0;
virtual status_t seekTo(int msec) = 0;
virtual status_t getCurrentPosition(int* msec) = 0;
virtual status_t getDuration(int* msec) = 0;
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 4a6bf28..482b85f 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -156,6 +156,7 @@ public:
virtual status_t stop() = 0;
virtual status_t pause() = 0;
virtual bool isPlaying() = 0;
+ virtual status_t setPlaybackRate(float rate) { return INVALID_OPERATION; }
virtual status_t seekTo(int msec) = 0;
virtual status_t getCurrentPosition(int *msec) = 0;
virtual status_t getDuration(int *msec) = 0;
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 5830933..808e893 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -220,6 +220,7 @@ public:
status_t stop();
status_t pause();
bool isPlaying();
+ status_t setPlaybackRate(float rate);
status_t getVideoWidth(int *w);
status_t getVideoHeight(int *h);
status_t seekTo(int msec);
@@ -274,6 +275,7 @@ private:
int mVideoWidth;
int mVideoHeight;
int mAudioSessionId;
+ float mPlaybackRate;
float mSendLevel;
struct sockaddr_in mRetransmitEndpoint;
bool mRetransmitEndpointValid;
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 7f3e5cc..dcd5670 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -39,6 +39,7 @@ enum {
START,
STOP,
IS_PLAYING,
+ SET_PLAYBACK_RATE,
PAUSE,
SEEK_TO,
GET_CURRENT_POSITION,
@@ -164,6 +165,15 @@ public:
return reply.readInt32();
}
+ status_t setPlaybackRate(float rate)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+ data.writeFloat(rate);
+ remote()->transact(SET_PLAYBACK_RATE, data, &reply);
+ return reply.readInt32();
+ }
+
status_t pause()
{
Parcel data, reply;
@@ -426,6 +436,11 @@ status_t BnMediaPlayer::onTransact(
reply->writeInt32(ret);
return NO_ERROR;
} break;
+ case SET_PLAYBACK_RATE: {
+ CHECK_INTERFACE(IMediaPlayer, data, reply);
+ reply->writeInt32(setPlaybackRate(data.readFloat()));
+ return NO_ERROR;
+ } break;
case PAUSE: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
reply->writeInt32(pause());
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 432ecda..d1d51cc 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -59,6 +59,7 @@ MediaPlayer::MediaPlayer()
mLoop = false;
mLeftVolume = mRightVolume = 1.0;
mVideoWidth = mVideoHeight = 0;
+ mPlaybackRate = 1.0;
mLockThreadId = 0;
mAudioSessionId = AudioSystem::newAudioUniqueId();
AudioSystem::acquireAudioSessionId(mAudioSessionId, -1);
@@ -378,6 +379,24 @@ bool MediaPlayer::isPlaying()
return false;
}
+status_t MediaPlayer::setPlaybackRate(float rate)
+{
+ ALOGV("setPlaybackRate: %f", rate);
+ if (rate <= 0.0) {
+ return BAD_VALUE;
+ }
+ Mutex::Autolock _l(mLock);
+ if (mPlayer != 0) {
+ if (mPlaybackRate == rate) {
+ return NO_ERROR;
+ }
+ mPlaybackRate = rate;
+ return mPlayer->setPlaybackRate(rate);
+ }
+ ALOGV("setPlaybackRate: no active player");
+ return INVALID_OPERATION;
+}
+
status_t MediaPlayer::getVideoWidth(int *w)
{
ALOGV("getVideoWidth");
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 694f1a4..0b18ae0 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -961,6 +961,14 @@ status_t MediaPlayerService::Client::isPlaying(bool* state)
return NO_ERROR;
}
+status_t MediaPlayerService::Client::setPlaybackRate(float rate)
+{
+ ALOGV("[%d] setPlaybackRate(%f)", mConnId, rate);
+ sp<MediaPlayerBase> p = getPlayer();
+ if (p == 0) return UNKNOWN_ERROR;
+ return p->setPlaybackRate(rate);
+}
+
status_t MediaPlayerService::Client::getCurrentPosition(int *msec)
{
ALOGV("getCurrentPosition");
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index fad3447..7320311 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -261,6 +261,7 @@ private:
virtual status_t stop();
virtual status_t pause();
virtual status_t isPlaying(bool* state);
+ virtual status_t setPlaybackRate(float rate);
virtual status_t seekTo(int msec);
virtual status_t getCurrentPosition(int* msec);
virtual status_t getDuration(int* msec);
diff --git a/media/libmediaplayerservice/nuplayer/MediaClock.cpp b/media/libmediaplayerservice/nuplayer/MediaClock.cpp
index 7bfff13..9152da1 100644
--- a/media/libmediaplayerservice/nuplayer/MediaClock.cpp
+++ b/media/libmediaplayerservice/nuplayer/MediaClock.cpp
@@ -20,19 +20,17 @@
#include "MediaClock.h"
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
namespace android {
-// Maximum time change between two updates.
-static const int64_t kMaxAnchorFluctuationUs = 1000ll;
-
MediaClock::MediaClock()
: mAnchorTimeMediaUs(-1),
mAnchorTimeRealUs(-1),
mMaxTimeMediaUs(INT64_MAX),
mStartingTimeMediaUs(-1),
- mPaused(false) {
+ mPlaybackRate(1.0) {
}
MediaClock::~MediaClock() {
@@ -58,14 +56,14 @@ void MediaClock::updateAnchor(
return;
}
+ Mutex::Autolock autoLock(mLock);
int64_t nowUs = ALooper::GetNowUs();
- int64_t nowMediaUs = anchorTimeMediaUs + nowUs - anchorTimeRealUs;
+ int64_t nowMediaUs =
+ anchorTimeMediaUs + (nowUs - anchorTimeRealUs) * (double)mPlaybackRate;
if (nowMediaUs < 0) {
ALOGW("reject anchor time since it leads to negative media time.");
return;
}
-
- Mutex::Autolock autoLock(mLock);
mAnchorTimeRealUs = nowUs;
mAnchorTimeMediaUs = nowMediaUs;
mMaxTimeMediaUs = maxTimeMediaUs;
@@ -76,60 +74,66 @@ void MediaClock::updateMaxTimeMedia(int64_t maxTimeMediaUs) {
mMaxTimeMediaUs = maxTimeMediaUs;
}
-void MediaClock::pause() {
+void MediaClock::setPlaybackRate(float rate) {
+ CHECK_GE(rate, 0.0);
Mutex::Autolock autoLock(mLock);
- if (mPaused) {
- return;
- }
-
- mPaused = true;
if (mAnchorTimeRealUs == -1) {
+ mPlaybackRate = rate;
return;
}
int64_t nowUs = ALooper::GetNowUs();
- mAnchorTimeMediaUs += nowUs - mAnchorTimeRealUs;
+ mAnchorTimeMediaUs += (nowUs - mAnchorTimeRealUs) * (double)mPlaybackRate;
if (mAnchorTimeMediaUs < 0) {
- ALOGW("anchor time should not be negative, set to 0.");
+ ALOGW("setRate: anchor time should not be negative, set to 0.");
mAnchorTimeMediaUs = 0;
}
mAnchorTimeRealUs = nowUs;
+ mPlaybackRate = rate;
}
-void MediaClock::resume() {
+status_t MediaClock::getMediaTime(
+ int64_t realUs, int64_t *outMediaUs, bool allowPastMaxTime) {
Mutex::Autolock autoLock(mLock);
- if (!mPaused) {
- return;
- }
+ return getMediaTime_l(realUs, outMediaUs, allowPastMaxTime);
+}
- mPaused = false;
+status_t MediaClock::getMediaTime_l(
+ int64_t realUs, int64_t *outMediaUs, bool allowPastMaxTime) {
if (mAnchorTimeRealUs == -1) {
- return;
+ return NO_INIT;
}
- mAnchorTimeRealUs = ALooper::GetNowUs();
+ int64_t mediaUs = mAnchorTimeMediaUs
+ + (realUs - mAnchorTimeRealUs) * (double)mPlaybackRate;
+ if (mediaUs > mMaxTimeMediaUs && !allowPastMaxTime) {
+ mediaUs = mMaxTimeMediaUs;
+ }
+ if (mediaUs < mStartingTimeMediaUs) {
+ mediaUs = mStartingTimeMediaUs;
+ }
+ if (mediaUs < 0) {
+ mediaUs = 0;
+ }
+ *outMediaUs = mediaUs;
+ return OK;
}
-int64_t MediaClock::getTimeMedia(int64_t realUs, bool allowPastMaxTime) {
+status_t MediaClock::getRealTimeFor(int64_t targetMediaUs, int64_t *outRealUs) {
Mutex::Autolock autoLock(mLock);
- if (mAnchorTimeRealUs == -1) {
- return -1ll;
+ if (mPlaybackRate == 0.0) {
+ return NO_INIT;
}
- if (mPaused) {
- realUs = mAnchorTimeRealUs;
- }
- int64_t currentMediaUs = mAnchorTimeMediaUs + realUs - mAnchorTimeRealUs;
- if (currentMediaUs > mMaxTimeMediaUs && !allowPastMaxTime) {
- currentMediaUs = mMaxTimeMediaUs;
- }
- if (currentMediaUs < mStartingTimeMediaUs) {
- currentMediaUs = mStartingTimeMediaUs;
- }
- if (currentMediaUs < 0) {
- currentMediaUs = 0;
+ int64_t nowUs = ALooper::GetNowUs();
+ int64_t nowMediaUs;
+ status_t status =
+ getMediaTime_l(nowUs, &nowMediaUs, true /* allowPastMaxTime */);
+ if (status != OK) {
+ return status;
}
- return currentMediaUs;
+ *outRealUs = (targetMediaUs - nowMediaUs) / (double)mPlaybackRate + nowUs;
+ return OK;
}
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/MediaClock.h b/media/libmediaplayerservice/nuplayer/MediaClock.h
index d005993..660764f 100644
--- a/media/libmediaplayerservice/nuplayer/MediaClock.h
+++ b/media/libmediaplayerservice/nuplayer/MediaClock.h
@@ -32,9 +32,8 @@ struct MediaClock : public RefBase {
void setStartingTimeMedia(int64_t startingTimeMediaUs);
void clearAnchor();
- // It's highly recommended to use timestamp of just rendered frame as
- // anchor time, especially in paused state. Such restriction will be
- // required when dynamic playback rate is supported in the future.
+ // It's required to use timestamp of just rendered frame as
+ // anchor time in paused state.
void updateAnchor(
int64_t anchorTimeMediaUs,
int64_t anchorTimeRealUs,
@@ -42,15 +41,25 @@ struct MediaClock : public RefBase {
void updateMaxTimeMedia(int64_t maxTimeMediaUs);
- void pause();
- void resume();
+ void setPlaybackRate(float rate);
- int64_t getTimeMedia(int64_t realUs, bool allowPastMaxTime = false);
+ // query media time corresponding to real time |realUs|, and save the
+ // result in |outMediaUs|.
+ status_t getMediaTime(int64_t realUs,
+ int64_t *outMediaUs,
+ bool allowPastMaxTime = false);
+ // query real time corresponding to media time |targetMediaUs|.
+ // The result is saved in |outRealUs|.
+ status_t getRealTimeFor(int64_t targetMediaUs, int64_t *outRealUs);
protected:
virtual ~MediaClock();
private:
+ status_t getMediaTime_l(int64_t realUs,
+ int64_t *outMediaUs,
+ bool allowPastMaxTime);
+
Mutex mLock;
int64_t mAnchorTimeMediaUs;
@@ -58,7 +67,7 @@ private:
int64_t mMaxTimeMediaUs;
int64_t mStartingTimeMediaUs;
- bool mPaused;
+ float mPlaybackRate;
DISALLOW_EVIL_CONSTRUCTORS(MediaClock);
};
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index fb8dbce..0d19fe9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -180,6 +180,7 @@ NuPlayer::NuPlayer()
mFlushingVideo(NONE),
mResumePending(false),
mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
+ mPlaybackRate(1.0),
mStarted(false),
mPaused(false),
mPausedByClient(false) {
@@ -314,6 +315,12 @@ void NuPlayer::start() {
(new AMessage(kWhatStart, id()))->post();
}
+void NuPlayer::setPlaybackRate(float rate) {
+ sp<AMessage> msg = new AMessage(kWhatSetRate, id());
+ msg->setFloat("rate", rate);
+ msg->post();
+}
+
void NuPlayer::pause() {
(new AMessage(kWhatPause, id()))->post();
}
@@ -604,6 +611,16 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
break;
}
+ case kWhatSetRate:
+ {
+ ALOGV("kWhatSetRate");
+ CHECK(msg->findFloat("rate", &mPlaybackRate));
+ if (mRenderer != NULL) {
+ mRenderer->setPlaybackRate(mPlaybackRate);
+ }
+ break;
+ }
+
case kWhatScanSources:
{
int32_t generation;
@@ -1048,6 +1065,9 @@ void NuPlayer::onStart() {
++mRendererGeneration;
notify->setInt32("generation", mRendererGeneration);
mRenderer = new Renderer(mAudioSink, notify, flags);
+ if (mPlaybackRate != 1.0) {
+ mRenderer->setPlaybackRate(mPlaybackRate);
+ }
mRendererLooper = new ALooper;
mRendererLooper->setName("NuPlayerRenderer");
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index 57eaf74..a2cb53e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -51,6 +51,7 @@ struct NuPlayer : public AHandler {
const sp<IGraphicBufferProducer> &bufferProducer);
void setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink);
+ void setPlaybackRate(float rate);
void start();
void pause();
@@ -104,6 +105,7 @@ private:
kWhatSetVideoNativeWindow = '=NaW',
kWhatSetAudioSink = '=AuS',
kWhatMoreDataQueued = 'more',
+ kWhatSetRate = 'setR',
kWhatStart = 'strt',
kWhatScanSources = 'scan',
kWhatVideoNotify = 'vidN',
@@ -175,6 +177,7 @@ private:
int32_t mVideoScalingMode;
+ float mPlaybackRate;
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 abfa4d3..5887e50 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -341,6 +341,11 @@ bool NuPlayerDriver::isPlaying() {
return mState == STATE_RUNNING && !mAtEOS;
}
+status_t NuPlayerDriver::setPlaybackRate(float rate) {
+ mPlayer->setPlaybackRate(rate);
+ return OK;
+}
+
status_t NuPlayerDriver::seekTo(int msec) {
ALOGD("seekTo(%p) %d ms", this, msec);
Mutex::Autolock autoLock(mLock);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index 5cba7d9..e53abcd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -47,6 +47,7 @@ struct NuPlayerDriver : public MediaPlayerInterface {
virtual status_t stop();
virtual status_t pause();
virtual bool isPlaying();
+ virtual status_t setPlaybackRate(float rate);
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 7f8680d..d21884b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -67,6 +67,7 @@ NuPlayer::Renderer::Renderer(
mVideoQueueGeneration(0),
mAudioDrainGeneration(0),
mVideoDrainGeneration(0),
+ mPlaybackRate(1.0),
mAudioFirstAnchorTimeMediaUs(-1),
mAnchorTimeMediaUs(-1),
mAnchorNumFramesWritten(-1),
@@ -121,6 +122,12 @@ void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) {
msg->post();
}
+void NuPlayer::Renderer::setPlaybackRate(float rate) {
+ sp<AMessage> msg = new AMessage(kWhatSetRate, id());
+ msg->setFloat("rate", rate);
+ msg->post();
+}
+
void NuPlayer::Renderer::flush(bool audio, bool notifyComplete) {
{
Mutex::Autolock autoLock(mLock);
@@ -172,12 +179,7 @@ void NuPlayer::Renderer::setVideoFrameRate(float fps) {
// Called on any threads.
status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) {
- int64_t currentTimeUs = mMediaClock->getTimeMedia(ALooper::GetNowUs());
- if (currentTimeUs == -1) {
- return NO_INIT;
- }
- *mediaUs = currentTimeUs;
- return OK;
+ return mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
}
void NuPlayer::Renderer::clearAudioFirstAnchorTime_l() {
@@ -361,6 +363,16 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
break;
}
+ case kWhatSetRate:
+ {
+ CHECK(msg->findFloat("rate", &mPlaybackRate));
+ int32_t ratePermille = (int32_t)(0.5f + 1000 * mPlaybackRate);
+ mPlaybackRate = ratePermille / 1000.0f;
+ mMediaClock->setPlaybackRate(mPlaybackRate);
+ mAudioSink->setPlaybackRatePermille(ratePermille);
+ break;
+ }
+
case kWhatFlush:
{
onFlush(msg);
@@ -541,10 +553,10 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
if (mAudioFirstAnchorTimeMediaUs >= 0) {
int64_t nowUs = ALooper::GetNowUs();
+ int64_t nowMediaUs =
+ mAudioFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs);
// we don't know how much data we are queueing for offloaded tracks.
- mMediaClock->updateAnchor(mAudioFirstAnchorTimeMediaUs,
- nowUs - getPlayedOutAudioDurationUs(nowUs),
- INT64_MAX);
+ mMediaClock->updateAnchor(nowMediaUs, nowUs, INT64_MAX);
}
if (hasEOS) {
@@ -670,21 +682,27 @@ bool NuPlayer::Renderer::onDrainAudioQueue() {
return !mAudioQueue.empty();
}
+int64_t NuPlayer::Renderer::getDurationUsIfPlayedAtSampleRate(uint32_t numFrames) {
+ int32_t sampleRate = offloadingAudio() ?
+ mCurrentOffloadInfo.sample_rate : mCurrentPcmInfo.mSampleRate;
+ // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
+ return (int64_t)((int32_t)numFrames * 1000000LL / sampleRate);
+}
+
+// Calculate duration of pending samples if played at normal rate (i.e., 1.0).
int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
- int64_t writtenAudioDurationUs =
- mNumFramesWritten * 1000LL * mAudioSink->msecsPerFrame();
+ int64_t writtenAudioDurationUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs);
}
int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
- int64_t currentPositionUs =
- mMediaClock->getTimeMedia(nowUs, true /* allowPastMaxTime */);
- if (currentPositionUs == -1) {
+ int64_t realUs;
+ if (mMediaClock->getRealTimeFor(mediaTimeUs, &realUs) != OK) {
// If failed to get current position, e.g. due to audio clock is
// not ready, then just play out video immediately without delay.
return nowUs;
}
- return (mediaTimeUs - currentPositionUs) + nowUs;
+ return realUs;
}
void NuPlayer::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) {
@@ -696,9 +714,8 @@ void NuPlayer::Renderer::onNewAudioMediaTime(int64_t mediaTimeUs) {
}
setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
int64_t nowUs = ALooper::GetNowUs();
- mMediaClock->updateAnchor(mediaTimeUs,
- nowUs + getPendingAudioPlayoutDurationUs(nowUs),
- mediaTimeUs);
+ int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
+ mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
mAnchorTimeMediaUs = mediaTimeUs;
}
@@ -828,9 +845,11 @@ void NuPlayer::Renderer::onDrainVideoQueue() {
ALOGV("video late by %lld us (%.2f secs)",
mVideoLateByUs, mVideoLateByUs / 1E6);
} else {
+ int64_t mediaUs = 0;
+ mMediaClock->getMediaTime(realTimeUs, &mediaUs);
ALOGV("rendering video at media time %.2f secs",
(mFlags & FLAG_REAL_TIME ? realTimeUs :
- mMediaClock->getTimeMedia(realTimeUs)) / 1E6);
+ mediaUs) / 1E6);
}
} else {
setVideoLateByUs(0);
@@ -1153,7 +1172,7 @@ void NuPlayer::Renderer::onPause() {
++mVideoDrainGeneration;
prepareForMediaRenderingStart_l();
mPaused = true;
- mMediaClock->pause();
+ mMediaClock->setPlaybackRate(0.0);
}
mDrainAudioQueuePending = false;
@@ -1181,7 +1200,7 @@ void NuPlayer::Renderer::onResume() {
{
Mutex::Autolock autoLock(mLock);
mPaused = false;
- mMediaClock->resume();
+ mMediaClock->setPlaybackRate(mPlaybackRate);
if (!mAudioQueue.empty()) {
postDrainAudioQueue_l();
@@ -1222,6 +1241,7 @@ bool NuPlayer::Renderer::getSyncQueues() {
// accessing getTimestamp() or getPosition() every time a data buffer with
// a media time is received.
//
+// Calculate duration of played samples if played at normal rate (i.e., 1.0).
int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) {
uint32_t numFramesPlayed;
int64_t numFramesPlayedAt;
@@ -1259,9 +1279,8 @@ int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) {
//ALOGD("getPosition: %d %lld", numFramesPlayed, numFramesPlayedAt);
}
- // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
//CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
- int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000LL * mAudioSink->msecsPerFrame())
+ int64_t durationUs = getDurationUsIfPlayedAtSampleRate(numFramesPlayed)
+ nowUs - numFramesPlayedAt;
if (durationUs < 0) {
// Occurs when numFramesPlayed position is very small and the following:
@@ -1400,6 +1419,10 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
&offloadInfo);
if (err == OK) {
+ if (mPlaybackRate != 1.0) {
+ mAudioSink->setPlaybackRatePermille(
+ (int32_t)(mPlaybackRate * 1000 + 0.5f));
+ }
// 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
@@ -1455,6 +1478,10 @@ status_t NuPlayer::Renderer::onOpenAudioSink(
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 faf3b3f..38843d5 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -48,6 +48,8 @@ struct NuPlayer::Renderer : public AHandler {
void queueEOS(bool audio, status_t finalResult);
+ void setPlaybackRate(float rate);
+
void flush(bool audio, bool notifyComplete);
void signalTimeDiscontinuity();
@@ -100,6 +102,7 @@ private:
kWhatPostDrainVideoQueue = 'pDVQ',
kWhatQueueBuffer = 'queB',
kWhatQueueEOS = 'qEOS',
+ kWhatSetRate = 'setR',
kWhatFlush = 'flus',
kWhatPause = 'paus',
kWhatResume = 'resm',
@@ -138,6 +141,7 @@ private:
int32_t mVideoDrainGeneration;
sp<MediaClock> mMediaClock;
+ float mPlaybackRate;
int64_t mAudioFirstAnchorTimeMediaUs;
int64_t mAnchorTimeMediaUs;
int64_t mAnchorNumFramesWritten;
@@ -243,6 +247,8 @@ private:
void startAudioOffloadPauseTimeout();
void cancelAudioOffloadPauseTimeout();
+ int64_t getDurationUsIfPlayedAtSampleRate(uint32_t numFrames);
+
DISALLOW_EVIL_CONSTRUCTORS(Renderer);
};