OSDN Git Service

NuPlayer: query current position from NuPlayerRenderer.
authorRonghua Wu <ronghuawu@google.com>
Wed, 8 Oct 2014 22:13:29 +0000 (15:13 -0700)
committerRonghua Wu <ronghuawu@google.com>
Mon, 13 Oct 2014 23:24:49 +0000 (16:24 -0700)
Bug: 17653702
Change-Id: Ie0b1f92420b071a0cfcd389f5e7917a54d332541

media/libmediaplayerservice/nuplayer/NuPlayer.cpp
media/libmediaplayerservice/nuplayer/NuPlayer.h
media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h

index 1c73995..eb5821b 100644 (file)
@@ -151,7 +151,6 @@ private:
 NuPlayer::NuPlayer()
     : mUIDValid(false),
       mSourceFlags(0),
-      mCurrentPositionUs(0),
       mVideoIsAVC(false),
       mOffloadAudio(false),
       mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
@@ -169,7 +168,6 @@ NuPlayer::NuPlayer()
       mFlushingVideo(NONE),
       mSkipRenderingAudioUntilMediaTimeUs(-1ll),
       mSkipRenderingVideoUntilMediaTimeUs(-1ll),
-      mVideoLateByUs(0ll),
       mNumFramesTotal(0ll),
       mNumFramesDropped(0ll),
       mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW),
@@ -546,8 +544,11 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
                     // the extractor may not yet be started and will assert.
                     // If the video decoder is not set (perhaps audio only in this case)
                     // do not perform a seek as it is not needed.
-                    mDeferredActions.push_back(
-                            new SeekAction(mCurrentPositionUs, false /* needNotify */));
+                    int64_t currentPositionUs = 0;
+                    if (getCurrentPosition(&currentPositionUs) == OK) {
+                        mDeferredActions.push_back(
+                                new SeekAction(currentPositionUs, false /* needNotify */));
+                    }
                 }
 
                 // If there is a new surface texture, instantiate decoders
@@ -581,7 +582,6 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
             mVideoEOS = false;
             mSkipRenderingAudioUntilMediaTimeUs = -1;
             mSkipRenderingVideoUntilMediaTimeUs = -1;
-            mVideoLateByUs = 0;
             mNumFramesTotal = 0;
             mNumFramesDropped = 0;
             mStarted = true;
@@ -889,22 +889,6 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) {
                         && (mVideoEOS || mVideoDecoder == NULL)) {
                     notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
                 }
-            } else if (what == Renderer::kWhatPosition) {
-                int64_t positionUs;
-                CHECK(msg->findInt64("positionUs", &positionUs));
-                mCurrentPositionUs = positionUs;
-
-                CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs));
-
-                if (mDriver != NULL) {
-                    sp<NuPlayerDriver> driver = mDriver.promote();
-                    if (driver != NULL) {
-                        driver->notifyPosition(positionUs);
-
-                        driver->notifyFrameStats(
-                                mNumFramesTotal, mNumFramesDropped);
-                    }
-                }
             } else if (what == Renderer::kWhatFlushComplete) {
                 int32_t audio;
                 CHECK(msg->findInt32("audio", &audio));
@@ -1053,10 +1037,6 @@ void NuPlayer::handleFlushComplete(bool audio, bool isDecoder) {
         case FLUSHING_DECODER:
         {
             *state = FLUSHED;
-
-            if (!audio) {
-                mVideoLateByUs = 0;
-            }
             break;
         }
 
@@ -1066,7 +1046,6 @@ void NuPlayer::handleFlushComplete(bool audio, bool isDecoder) {
 
             ALOGV("initiating %s decoder shutdown", audio ? "audio" : "video");
             if (!audio) {
-                mVideoLateByUs = 0;
                 // Widevine source reads must stop before releasing the video decoder.
                 if (mSource != NULL && mSourceFlags & Source::FLAG_SECURE) {
                     mSource->stop();
@@ -1487,7 +1466,7 @@ status_t NuPlayer::feedDecoderInputData(bool audio, const sp<AMessage> &msg) {
         dropAccessUnit = false;
         if (!audio
                 && !(mSourceFlags & Source::FLAG_SECURE)
-                && mVideoLateByUs > 100000ll
+                && mRenderer->getVideoLateByUs() > 100000ll
                 && mVideoIsAVC
                 && !IsAVCReferenceFrame(accessUnit)) {
             dropAccessUnit = true;
@@ -1822,6 +1801,20 @@ status_t NuPlayer::selectTrack(size_t trackIndex, bool select) {
     return err;
 }
 
+status_t NuPlayer::getCurrentPosition(int64_t *mediaUs) {
+    sp<Renderer> renderer = mRenderer;
+    if (renderer == NULL) {
+        return NO_INIT;
+    }
+
+    return renderer->getCurrentPosition(mediaUs);
+}
+
+void NuPlayer::getStats(int64_t *numFramesTotal, int64_t *numFramesDropped) {
+    *numFramesTotal = mNumFramesTotal;
+    *numFramesDropped = mNumFramesDropped;
+}
+
 sp<MetaData> NuPlayer::getFileMeta() {
     return mSource->getFileFormatMeta();
 }
@@ -1879,7 +1872,6 @@ void NuPlayer::performSeek(int64_t seekTimeUs, bool needNotify) {
     if (mDriver != NULL) {
         sp<NuPlayerDriver> driver = mDriver.promote();
         if (driver != NULL) {
-            driver->notifyPosition(seekTimeUs);
             if (needNotify) {
                 driver->notifySeekComplete();
             }
index 1b9a756..c61510c 100644 (file)
@@ -67,6 +67,8 @@ struct NuPlayer : public AHandler {
     status_t getTrackInfo(Parcel* reply) const;
     status_t getSelectedTrack(int32_t type, Parcel* reply) const;
     status_t selectTrack(size_t trackIndex, bool select);
+    status_t getCurrentPosition(int64_t *mediaUs);
+    void getStats(int64_t *mNumFramesTotal, int64_t *mNumFramesDropped);
 
     sp<MetaData> getFileMeta();
 
@@ -126,7 +128,6 @@ private:
     sp<Source> mSource;
     uint32_t mSourceFlags;
     sp<NativeWindowWrapper> mNativeWindow;
-    int64_t mCurrentPositionUs;
     sp<MediaPlayerBase::AudioSink> mAudioSink;
     sp<Decoder> mVideoDecoder;
     bool mVideoIsAVC;
@@ -179,7 +180,6 @@ private:
     int64_t mSkipRenderingAudioUntilMediaTimeUs;
     int64_t mSkipRenderingVideoUntilMediaTimeUs;
 
-    int64_t mVideoLateByUs;
     int64_t mNumFramesTotal, mNumFramesDropped;
 
     int32_t mVideoScalingMode;
index c57955d..6a80313 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/Utils.h>
 
@@ -38,10 +39,7 @@ NuPlayerDriver::NuPlayerDriver()
       mSetSurfaceInProgress(false),
       mDurationUs(-1),
       mPositionUs(-1),
-      mNotifyTimeRealUs(-1),
-      mPauseStartedTimeUs(-1),
-      mNumFramesTotal(0),
-      mNumFramesDropped(0),
+      mSeekInProgress(false),
       mLooper(new ALooper),
       mPlayerFlags(0),
       mAtEOS(false),
@@ -276,14 +274,6 @@ status_t NuPlayerDriver::start() {
                 mPositionUs = -1;
             } else {
                 mPlayer->resume();
-                if (mNotifyTimeRealUs != -1) {
-                    // Pause time must be set if here by setPauseStartedTimeIfNeeded().
-                    //CHECK(mPauseStartedTimeUs != -1);
-
-                    // if no seek occurs, adjust our notify time so that getCurrentPosition()
-                    // is continuous if read immediately after calling start().
-                    mNotifyTimeRealUs += ALooper::GetNowUs() - mPauseStartedTimeUs;
-                }
             }
             break;
         }
@@ -293,7 +283,6 @@ status_t NuPlayerDriver::start() {
     }
 
     mState = STATE_RUNNING;
-    mPauseStartedTimeUs = -1;
 
     return OK;
 }
@@ -322,7 +311,6 @@ status_t NuPlayerDriver::stop() {
         default:
             return INVALID_OPERATION;
     }
-    setPauseStartedTimeIfNeeded();
 
     return OK;
 }
@@ -336,7 +324,6 @@ status_t NuPlayerDriver::pause() {
             return OK;
 
         case STATE_RUNNING:
-            setPauseStartedTimeIfNeeded();
             mState = STATE_PAUSED;
             notifyListener_l(MEDIA_PAUSED);
             mPlayer->pause();
@@ -374,6 +361,7 @@ status_t NuPlayerDriver::seekTo(int msec) {
         case STATE_PAUSED:
         {
             mAtEOS = false;
+            mSeekInProgress = true;
             // seeks can take a while, so we essentially paused
             notifyListener_l(MEDIA_PAUSED);
             mPlayer->seekToAsync(seekTimeUs, true /* needNotify */);
@@ -385,44 +373,23 @@ status_t NuPlayerDriver::seekTo(int msec) {
     }
 
     mPositionUs = seekTimeUs;
-    mNotifyTimeRealUs = -1;
     return OK;
 }
 
 status_t NuPlayerDriver::getCurrentPosition(int *msec) {
-    Mutex::Autolock autoLock(mLock);
+    int64_t tempUs = 0;
+    status_t ret = mPlayer->getCurrentPosition(&tempUs);
 
-    if (mPositionUs < 0) {
-        // mPositionUs is the media time.
-        // It is negative under these cases
-        // (1) == -1 after reset, or very first playback, no stream notification yet.
-        // (2) == -1 start after end of stream, no stream notification yet.
-        // (3) == large negative # after ~292,471 years of continuous playback.
-
-        //CHECK_EQ(mPositionUs, -1);
-        *msec = 0;
-    } else if (mNotifyTimeRealUs == -1) {
-        // A seek has occurred just occurred, no stream notification yet.
-        // mPositionUs (>= 0) is the new media position.
-        *msec = mPositionUs / 1000;
+    Mutex::Autolock autoLock(mLock);
+    // We need to check mSeekInProgress here because mPlayer->seekToAsync is an async call, which
+    // means getCurrentPosition can be called before seek is completed. Iow, renderer may return a
+    // position value that's different the seek to position.
+    if (ret != OK || mSeekInProgress) {
+        tempUs = (mPositionUs <= 0) ? 0 : mPositionUs;
     } else {
-        // mPosition must be valid (i.e. >= 0) by the first check above.
-        // We're either playing or have pause time set: mPauseStartedTimeUs is >= 0
-        //LOG_ALWAYS_FATAL_IF(
-        //        !isPlaying() && mPauseStartedTimeUs < 0,
-        //        "Player in non-playing mState(%d) and mPauseStartedTimeUs(%lld) < 0",
-        //        mState, (long long)mPauseStartedTimeUs);
-        ALOG_ASSERT(mNotifyTimeRealUs >= 0);
-        int64_t nowUs =
-                (isPlaying() ?  ALooper::GetNowUs() : mPauseStartedTimeUs);
-        *msec = (mPositionUs + nowUs - mNotifyTimeRealUs + 500ll) / 1000;
-        // It is possible for *msec to be negative if the media position is > 596 hours.
-        // but we turn on this checking in NDEBUG == 0 mode.
-        ALOG_ASSERT(*msec >= 0);
-        ALOGV("getCurrentPosition nowUs(%lld)", (long long)nowUs);
+        mPositionUs = tempUs;
     }
-    ALOGV("getCurrentPosition returning(%d) mPositionUs(%lld) mNotifyRealTimeUs(%lld)",
-            *msec, (long long)mPositionUs, (long long)mNotifyTimeRealUs);
+    *msec = (int)divRound(tempUs, (int64_t)(1000));
     return OK;
 }
 
@@ -605,17 +572,10 @@ void NuPlayerDriver::notifyDuration(int64_t durationUs) {
     mDurationUs = durationUs;
 }
 
-void NuPlayerDriver::notifyPosition(int64_t positionUs) {
-    Mutex::Autolock autoLock(mLock);
-    if (isPlaying()) {
-        mPositionUs = positionUs;
-        mNotifyTimeRealUs = ALooper::GetNowUs();
-    }
-}
-
 void NuPlayerDriver::notifySeekComplete() {
     ALOGV("notifySeekComplete(%p)", this);
     Mutex::Autolock autoLock(mLock);
+    mSeekInProgress = false;
     notifySeekComplete_l();
 }
 
@@ -636,26 +596,21 @@ void NuPlayerDriver::notifySeekComplete_l() {
     notifyListener_l(wasSeeking ? MEDIA_SEEK_COMPLETE : MEDIA_PREPARED);
 }
 
-void NuPlayerDriver::notifyFrameStats(
-        int64_t numFramesTotal, int64_t numFramesDropped) {
-    Mutex::Autolock autoLock(mLock);
-    mNumFramesTotal = numFramesTotal;
-    mNumFramesDropped = numFramesDropped;
-}
-
 status_t NuPlayerDriver::dump(
         int fd, const Vector<String16> & /* args */) const {
-    Mutex::Autolock autoLock(mLock);
+    int64_t numFramesTotal;
+    int64_t numFramesDropped;
+    mPlayer->getStats(&numFramesTotal, &numFramesDropped);
 
     FILE *out = fdopen(dup(fd), "w");
 
     fprintf(out, " NuPlayer\n");
     fprintf(out, "  numFramesTotal(%" PRId64 "), numFramesDropped(%" PRId64 "), "
                  "percentageDropped(%.2f)\n",
-                 mNumFramesTotal,
-                 mNumFramesDropped,
-                 mNumFramesTotal == 0
-                    ? 0.0 : (double)mNumFramesDropped / mNumFramesTotal);
+                 numFramesTotal,
+                 numFramesDropped,
+                 numFramesTotal == 0
+                    ? 0.0 : (double)numFramesDropped / numFramesTotal);
 
     fclose(out);
     out = NULL;
@@ -690,7 +645,6 @@ void NuPlayerDriver::notifyListener_l(
         case MEDIA_ERROR:
         {
             mAtEOS = true;
-            setPauseStartedTimeIfNeeded();
             break;
         }
 
@@ -758,10 +712,4 @@ void NuPlayerDriver::notifyFlagsChanged(uint32_t flags) {
     mPlayerFlags = flags;
 }
 
-void NuPlayerDriver::setPauseStartedTimeIfNeeded() {
-    if (mPauseStartedTimeUs == -1) {
-        mPauseStartedTimeUs = ALooper::GetNowUs();
-    }
-}
-
 }  // namespace android
index f2bd431..5cba7d9 100644 (file)
@@ -68,10 +68,8 @@ struct NuPlayerDriver : public MediaPlayerInterface {
     void notifyResetComplete();
     void notifySetSurfaceComplete();
     void notifyDuration(int64_t durationUs);
-    void notifyPosition(int64_t positionUs);
     void notifySeekComplete();
     void notifySeekComplete_l();
-    void notifyFrameStats(int64_t numFramesTotal, int64_t numFramesDropped);
     void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
     void notifyFlagsChanged(uint32_t flags);
 
@@ -106,10 +104,7 @@ private:
     bool mSetSurfaceInProgress;
     int64_t mDurationUs;
     int64_t mPositionUs;
-    int64_t mNotifyTimeRealUs;
-    int64_t mPauseStartedTimeUs;
-    int64_t mNumFramesTotal;
-    int64_t mNumFramesDropped;
+    bool mSeekInProgress;
     // <<<
 
     sp<ALooper> mLooper;
@@ -125,7 +120,6 @@ private:
 
     status_t prepare_l();
     void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0, const Parcel *in = NULL);
-    void setPauseStartedTimeIfNeeded();
 
     DISALLOW_EVIL_CONSTRUCTORS(NuPlayerDriver);
 };
index e5c64f6..7b9dbb7 100644 (file)
@@ -25,6 +25,7 @@
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/AUtils.h>
 #include <media/stagefright/MediaErrors.h>
 #include <media/stagefright/MetaData.h>
 
@@ -63,22 +64,21 @@ NuPlayer::Renderer::Renderer(
       mDrainVideoQueuePending(false),
       mAudioQueueGeneration(0),
       mVideoQueueGeneration(0),
-      mFirstAnchorTimeMediaUs(-1),
-      mAnchorTimeMediaUs(-1),
-      mAnchorTimeRealUs(-1),
-      mFlushingAudio(false),
-      mFlushingVideo(false),
+      mAudioFirstAnchorTimeMediaUs(-1),
+      mVideoAnchorTimeMediaUs(-1),
+      mVideoAnchorTimeRealUs(-1),
+      mVideoLateByUs(0ll),
       mHasAudio(false),
       mHasVideo(false),
+      mPauseStartedTimeRealUs(-1),
+      mFlushingAudio(false),
+      mFlushingVideo(false),
       mSyncQueues(false),
       mPaused(false),
-      mPauseStartedTimeRealUs(-1),
       mVideoSampleReceived(false),
       mVideoRenderingStarted(false),
       mVideoRenderingStartGeneration(0),
       mAudioRenderingStartGeneration(0),
-      mLastPositionUpdateUs(-1ll),
-      mVideoLateByUs(0ll),
       mAudioOffloadPauseTimeoutGeneration(0),
       mAudioOffloadTornDown(false) {
     readProperties();
@@ -137,9 +137,9 @@ void NuPlayer::Renderer::signalTimeDiscontinuity() {
     Mutex::Autolock autoLock(mLock);
     // CHECK(mAudioQueue.empty());
     // CHECK(mVideoQueue.empty());
-    mFirstAnchorTimeMediaUs = -1;
-    mAnchorTimeMediaUs = -1;
-    mAnchorTimeRealUs = -1;
+    setAudioFirstAnchorTime(-1);
+    setVideoAnchorTime(-1, -1);
+    setVideoLateByUs(0);
     mSyncQueues = false;
 }
 
@@ -165,6 +165,78 @@ void NuPlayer::Renderer::setVideoFrameRate(float fps) {
     msg->post();
 }
 
+status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) {
+    return getCurrentPosition(mediaUs, ALooper::GetNowUs());
+}
+
+status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs, int64_t nowUs) {
+    Mutex::Autolock autoLock(mTimeLock);
+    if (!mHasAudio && !mHasVideo) {
+        return NO_INIT;
+    }
+
+    int64_t positionUs = 0;
+    if (!mHasAudio) {
+        if (mVideoAnchorTimeMediaUs < 0) {
+            return NO_INIT;
+        }
+        positionUs = (nowUs - mVideoAnchorTimeRealUs) + mVideoAnchorTimeMediaUs;
+
+        if (mPauseStartedTimeRealUs != -1) {
+            positionUs -= (nowUs - mPauseStartedTimeRealUs);
+        }
+    } else {
+        if (mAudioFirstAnchorTimeMediaUs < 0) {
+            return NO_INIT;
+        }
+        positionUs = mAudioFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs);
+    }
+    *mediaUs = (positionUs <= 0) ? 0 : positionUs;
+    return OK;
+}
+
+void NuPlayer::Renderer::setHasMedia(bool audio) {
+    Mutex::Autolock autoLock(mTimeLock);
+    if (audio) {
+        mHasAudio = true;
+    } else {
+        mHasVideo = true;
+    }
+}
+
+void NuPlayer::Renderer::setAudioFirstAnchorTime(int64_t mediaUs) {
+    Mutex::Autolock autoLock(mTimeLock);
+    mAudioFirstAnchorTimeMediaUs = mediaUs;
+}
+
+void NuPlayer::Renderer::setAudioFirstAnchorTimeIfNeeded(int64_t mediaUs) {
+    Mutex::Autolock autoLock(mTimeLock);
+    if (mAudioFirstAnchorTimeMediaUs == -1) {
+        mAudioFirstAnchorTimeMediaUs = mediaUs;
+    }
+}
+
+void NuPlayer::Renderer::setVideoAnchorTime(int64_t mediaUs, int64_t realUs) {
+    Mutex::Autolock autoLock(mTimeLock);
+    mVideoAnchorTimeMediaUs = mediaUs;
+    mVideoAnchorTimeRealUs = realUs;
+}
+
+void NuPlayer::Renderer::setVideoLateByUs(int64_t lateUs) {
+    Mutex::Autolock autoLock(mTimeLock);
+    mVideoLateByUs = lateUs;
+}
+
+int64_t NuPlayer::Renderer::getVideoLateByUs() {
+    Mutex::Autolock autoLock(mTimeLock);
+    return mVideoLateByUs;
+}
+
+void NuPlayer::Renderer::setPauseStartedTimeRealUs(int64_t realUs) {
+    Mutex::Autolock autoLock(mTimeLock);
+    mPauseStartedTimeRealUs = realUs;
+}
+
 void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatStopAudioSink:
@@ -388,16 +460,7 @@ size_t NuPlayer::Renderer::fillAudioBuffer(void *buffer, size_t size) {
             int64_t mediaTimeUs;
             CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
             ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
-            if (mFirstAnchorTimeMediaUs == -1) {
-                mFirstAnchorTimeMediaUs = mediaTimeUs;
-            }
-
-            int64_t nowUs = ALooper::GetNowUs();
-            mAnchorTimeMediaUs =
-                mFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs);
-            mAnchorTimeRealUs = nowUs;
-
-            notifyPosition();
+            setAudioFirstAnchorTimeIfNeeded(mediaTimeUs);
         }
 
         size_t copy = entry->mBuffer->size() - entry->mOffset;
@@ -468,15 +531,8 @@ bool NuPlayer::Renderer::onDrainAudioQueue() {
             int64_t mediaTimeUs;
             CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
             ALOGV("rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
-            if (mFirstAnchorTimeMediaUs == -1) {
-                mFirstAnchorTimeMediaUs = mediaTimeUs;
-            }
-            mAnchorTimeMediaUs = mediaTimeUs;
-
-            int64_t nowUs = ALooper::GetNowUs();
-            mAnchorTimeRealUs = nowUs + getPendingAudioPlayoutDurationUs(nowUs);
 
-            notifyPosition();
+            setAudioFirstAnchorTimeIfNeeded(mediaTimeUs);
         }
 
         size_t copy = entry->mBuffer->size() - entry->mOffset;
@@ -534,6 +590,14 @@ int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
     return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs);
 }
 
+int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
+    int64_t currentPositionUs;
+    if (getCurrentPosition(&currentPositionUs, nowUs) != OK) {
+        currentPositionUs = 0;
+    }
+    return (mediaTimeUs - currentPositionUs) + nowUs;
+}
+
 void NuPlayer::Renderer::postDrainVideoQueue() {
     if (mDrainVideoQueuePending
             || mSyncQueues
@@ -568,21 +632,11 @@ void NuPlayer::Renderer::postDrainVideoQueue() {
         int64_t mediaTimeUs;
         CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
 
-        if (mFirstAnchorTimeMediaUs == -1 && !mHasAudio) {
-            mFirstAnchorTimeMediaUs = mediaTimeUs;
-        }
-        if (mAnchorTimeMediaUs < 0) {
-            if (!mHasAudio) {
-                mAnchorTimeMediaUs = mediaTimeUs;
-                mAnchorTimeRealUs = nowUs;
-                if (!mPaused || mVideoSampleReceived) {
-                    notifyPosition();
-                }
-            }
+        if (mVideoAnchorTimeMediaUs < 0) {
+            setVideoAnchorTime(mediaTimeUs, nowUs);
             realTimeUs = nowUs;
         } else {
-            realTimeUs =
-                (mediaTimeUs - mAnchorTimeMediaUs) + mAnchorTimeRealUs;
+            realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
         }
     }
 
@@ -618,10 +672,11 @@ void NuPlayer::Renderer::onDrainVideoQueue() {
         mVideoQueue.erase(mVideoQueue.begin());
         entry = NULL;
 
-        mVideoLateByUs = 0ll;
+        setVideoLateByUs(0);
         return;
     }
 
+    int64_t nowUs = -1;
     int64_t realTimeUs;
     if (mFlags & FLAG_REAL_TIME) {
         CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
@@ -629,13 +684,17 @@ void NuPlayer::Renderer::onDrainVideoQueue() {
         int64_t mediaTimeUs;
         CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
 
-        realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs;
+        nowUs = ALooper::GetNowUs();
+        realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
     }
 
     bool tooLate = false;
 
     if (!mPaused) {
-        mVideoLateByUs = ALooper::GetNowUs() - realTimeUs;
+        if (nowUs == -1) {
+            nowUs = ALooper::GetNowUs();
+        }
+        setVideoLateByUs(nowUs - realTimeUs);
         tooLate = (mVideoLateByUs > 40000);
 
         if (tooLate) {
@@ -644,13 +703,14 @@ void NuPlayer::Renderer::onDrainVideoQueue() {
         } else {
             ALOGV("rendering video at media time %.2f secs",
                     (mFlags & FLAG_REAL_TIME ? realTimeUs :
-                    (realTimeUs + mAnchorTimeMediaUs - mAnchorTimeRealUs)) / 1E6);
+                    (realTimeUs + mVideoAnchorTimeMediaUs - mVideoAnchorTimeRealUs)) / 1E6);
         }
     } else {
-        mVideoLateByUs = 0ll;
-        if (!mHasAudio && !mVideoSampleReceived) {
-            mAnchorTimeMediaUs = -1;
-            mAnchorTimeRealUs = -1;
+        setVideoLateByUs(0);
+        if (!mVideoSampleReceived) {
+            // This will ensure that the first frame after a flush won't be used as anchor
+            // when renderer is in paused state, because resume can happen any time after seek.
+            setVideoAnchorTime(-1, -1);
         }
     }
 
@@ -693,10 +753,9 @@ void NuPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) {
     int32_t audio;
     CHECK(msg->findInt32("audio", &audio));
 
-    if (audio) {
-        mHasAudio = true;
-    } else {
-        mHasVideo = true;
+    setHasMedia(audio);
+
+    if (mHasVideo) {
         if (mVideoScheduler == NULL) {
             mVideoScheduler = new VideoFrameScheduler();
             mVideoScheduler->init();
@@ -837,9 +896,7 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
     {
          Mutex::Autolock autoLock(mLock);
          syncQueuesDone_l();
-         if (!mHasAudio) {
-             mPauseStartedTimeRealUs = -1;
-         }
+         setPauseStartedTimeRealUs(-1);
     }
 
     ALOGV("flushing %s", audio ? "audio" : "video");
@@ -852,7 +909,7 @@ void NuPlayer::Renderer::onFlush(const sp<AMessage> &msg) {
             prepareForMediaRenderingStart();
 
             if (offloadingAudio()) {
-                mFirstAnchorTimeMediaUs = -1;
+                setAudioFirstAnchorTime(-1);
             }
         }
 
@@ -943,42 +1000,6 @@ void NuPlayer::Renderer::onDisableOffloadAudio() {
     ++mAudioQueueGeneration;
 }
 
-void NuPlayer::Renderer::notifyPosition() {
-    // notifyPosition() must be called only after setting mAnchorTimeRealUs
-    // and mAnchorTimeMediaUs, and must not be paused as it extrapolates position.
-    //CHECK_GE(mAnchorTimeRealUs, 0);
-    //CHECK_GE(mAnchorTimeMediaUs, 0);
-    //CHECK(!mPaused || !mHasAudio);  // video-only does display in paused mode.
-
-    int64_t nowUs = ALooper::GetNowUs();
-
-    if (mLastPositionUpdateUs >= 0
-            && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs) {
-        return;
-    }
-    mLastPositionUpdateUs = nowUs;
-
-    int64_t positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs;
-
-    //ALOGD("notifyPosition: positionUs(%lld) nowUs(%lld) mAnchorTimeRealUs(%lld)"
-    //        " mAnchorTimeMediaUs(%lld) mFirstAnchorTimeMediaUs(%lld)",
-    //        (long long)positionUs, (long long)nowUs, (long long)mAnchorTimeRealUs,
-    //        (long long)mAnchorTimeMediaUs, (long long)mFirstAnchorTimeMediaUs);
-
-    // Due to adding the latency to mAnchorTimeRealUs in onDrainAudioQueue(),
-    // positionUs may be less than the first media time.  This is avoided
-    // here to prevent potential retrograde motion of the position bar
-    // when starting up after a seek.
-    if (positionUs < mFirstAnchorTimeMediaUs) {
-        positionUs = mFirstAnchorTimeMediaUs;
-    }
-    sp<AMessage> notify = mNotify->dup();
-    notify->setInt32("what", kWhatPosition);
-    notify->setInt64("positionUs", positionUs);
-    notify->setInt64("videoLateByUs", mVideoLateByUs);
-    notify->post();
-}
-
 void NuPlayer::Renderer::onPause() {
     if (mPaused) {
         ALOGW("Renderer::onPause() called while already paused!");
@@ -990,9 +1011,7 @@ void NuPlayer::Renderer::onPause() {
         ++mVideoQueueGeneration;
         prepareForMediaRenderingStart();
         mPaused = true;
-        if (!mHasAudio) {
-            mPauseStartedTimeRealUs = ALooper::GetNowUs();
-        }
+        setPauseStartedTimeRealUs(ALooper::GetNowUs());
     }
 
     mDrainAudioQueuePending = false;
@@ -1021,9 +1040,11 @@ void NuPlayer::Renderer::onResume() {
 
     Mutex::Autolock autoLock(mLock);
     mPaused = false;
-    if (!mHasAudio && mPauseStartedTimeRealUs != -1) {
-        mAnchorTimeRealUs += ALooper::GetNowUs() - mPauseStartedTimeRealUs;
-        mPauseStartedTimeRealUs = -1;
+    if (mPauseStartedTimeRealUs != -1) {
+        int64_t newAnchorRealUs =
+            mVideoAnchorTimeRealUs + ALooper::GetNowUs() - mPauseStartedTimeRealUs;
+        setVideoAnchorTime(mVideoAnchorTimeMediaUs, newAnchorRealUs);
+        setPauseStartedTimeRealUs(-1);
     }
 
     if (!mAudioQueue.empty()) {
@@ -1045,7 +1066,6 @@ void NuPlayer::Renderer::onSetVideoFrameRate(float fps) {
 // TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs()
 // as it acquires locks and may query the audio driver.
 //
-// Some calls are not needed since notifyPosition() doesn't always deliver a message.
 // Some calls could conceivably retrieve extrapolated data instead of
 // accessing getTimestamp() or getPosition() every time a data buffer with
 // a media time is received.
@@ -1113,15 +1133,11 @@ void NuPlayer::Renderer::onAudioOffloadTearDown(AudioOffloadTearDownReason reaso
     }
     mAudioOffloadTornDown = true;
 
-    int64_t firstAudioTimeUs;
-    {
-        Mutex::Autolock autoLock(mLock);
-        firstAudioTimeUs = mFirstAnchorTimeMediaUs;
+    int64_t currentPositionUs;
+    if (getCurrentPosition(&currentPositionUs) != OK) {
+        currentPositionUs = 0;
     }
 
-    int64_t currentPositionUs =
-        firstAudioTimeUs + getPlayedOutAudioDurationUs(ALooper::GetNowUs());
-
     mAudioSink->stop();
     mAudioSink->flush();
 
index d27c238..db1dab6 100644 (file)
@@ -59,6 +59,17 @@ struct NuPlayer::Renderer : public AHandler {
 
     void setVideoFrameRate(float fps);
 
+    // Following setters and getters are protected by mTimeLock.
+    status_t getCurrentPosition(int64_t *mediaUs);
+    status_t getCurrentPosition(int64_t *mediaUs, int64_t nowUs);
+    void setHasMedia(bool audio);
+    void setAudioFirstAnchorTime(int64_t mediaUs);
+    void setAudioFirstAnchorTimeIfNeeded(int64_t mediaUs);
+    void setVideoAnchorTime(int64_t mediaUs, int64_t realUs);
+    void setVideoLateByUs(int64_t lateUs);
+    int64_t getVideoLateByUs();
+    void setPauseStartedTimeRealUs(int64_t realUs);
+
     enum {
         kWhatEOS                 = 'eos ',
         kWhatFlushComplete       = 'fluC',
@@ -117,27 +128,33 @@ private:
     int32_t mAudioQueueGeneration;
     int32_t mVideoQueueGeneration;
 
-    int64_t mFirstAnchorTimeMediaUs;
-    int64_t mAnchorTimeMediaUs;
-    int64_t mAnchorTimeRealUs;
+    Mutex mTimeLock;
+    // |mTimeLock| protects the following 7 member vars that are related to time.
+    // Note: those members are only written on Renderer thread, so reading on Renderer thread
+    // doesn't need to be protected. Otherwise accessing those members must be protected by
+    // |mTimeLock|.
+    // TODO: move those members to a seperated media clock class.
+    int64_t mAudioFirstAnchorTimeMediaUs;
+    int64_t mVideoAnchorTimeMediaUs;
+    int64_t mVideoAnchorTimeRealUs;
+    int64_t mVideoLateByUs;
+    bool mHasAudio;
+    bool mHasVideo;
+    int64_t mPauseStartedTimeRealUs;
 
     Mutex mFlushLock;  // protects the following 2 member vars.
     bool mFlushingAudio;
     bool mFlushingVideo;
 
-    bool mHasAudio;
-    bool mHasVideo;
     bool mSyncQueues;
 
     bool mPaused;
-    int64_t mPauseStartedTimeRealUs;
     bool mVideoSampleReceived;
     bool mVideoRenderingStarted;
     int32_t mVideoRenderingStartGeneration;
     int32_t mAudioRenderingStartGeneration;
 
     int64_t mLastPositionUpdateUs;
-    int64_t mVideoLateByUs;
 
     int32_t mAudioOffloadPauseTimeoutGeneration;
     bool mAudioOffloadTornDown;
@@ -149,6 +166,8 @@ private:
     int64_t getPlayedOutAudioDurationUs(int64_t nowUs);
     void postDrainAudioQueue_l(int64_t delayUs = 0);
 
+    int64_t getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs);
+
     void onDrainVideoQueue();
     void postDrainVideoQueue();