diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/libstagefright/MediaSync.cpp | 78 |
1 files changed, 65 insertions, 13 deletions
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp index ec956c4..8030a36 100644 --- a/media/libstagefright/MediaSync.cpp +++ b/media/libstagefright/MediaSync.cpp @@ -179,6 +179,42 @@ sp<const MediaClock> MediaSync::getMediaClock() { return mMediaClock; } +status_t MediaSync::getPlayTimeForPendingAudioFrames(int64_t *outTimeUs) { + Mutex::Autolock lock(mMutex); + // User should check the playback rate if it doesn't want to receive a + // huge number for play time. + if (mPlaybackRate == 0.0f) { + *outTimeUs = INT64_MAX; + return OK; + } + + uint32_t numFramesPlayed = 0; + if (mAudioTrack != NULL) { + status_t res = mAudioTrack->getPosition(&numFramesPlayed); + if (res != OK) { + return res; + } + } + + int64_t numPendingFrames = mNumFramesWritten - numFramesPlayed; + if (numPendingFrames < 0) { + numPendingFrames = 0; + ALOGW("getPlayTimeForPendingAudioFrames: pending frame count is negative."); + } + double timeUs = numPendingFrames * 1000000.0 + / (mNativeSampleRateInHz * (double)mPlaybackRate); + if (timeUs > (double)INT64_MAX) { + // Overflow. + *outTimeUs = INT64_MAX; + ALOGW("getPlayTimeForPendingAudioFrames: play time for pending audio frames " + "is too high, possibly due to super low playback rate(%f)", mPlaybackRate); + } else { + *outTimeUs = (int64_t)timeUs; + } + + return OK; +} + status_t MediaSync::updateQueuedAudioData( size_t sizeInBytes, int64_t presentationTimeUs) { if (sizeInBytes == 0) { @@ -195,13 +231,14 @@ status_t MediaSync::updateQueuedAudioData( int64_t numFrames = sizeInBytes / mAudioTrack->frameSize(); int64_t maxMediaTimeUs = presentationTimeUs + getDurationIfPlayedAtNativeSampleRate_l(numFrames); - mNumFramesWritten += numFrames; int64_t nowUs = ALooper::GetNowUs(); - int64_t nowMediaUs = maxMediaTimeUs + int64_t nowMediaUs = presentationTimeUs - getDurationIfPlayedAtNativeSampleRate_l(mNumFramesWritten) + getPlayedOutAudioDurationMedia_l(nowUs); + mNumFramesWritten += numFrames; + int64_t oldRealTime = -1; if (mNextBufferItemMediaUs != -1) { oldRealTime = getRealTime(mNextBufferItemMediaUs, nowUs); @@ -212,12 +249,13 @@ status_t MediaSync::updateQueuedAudioData( if (oldRealTime != -1) { int64_t newRealTime = getRealTime(mNextBufferItemMediaUs, nowUs); - if (newRealTime < oldRealTime) { - mNextBufferItemMediaUs = -1; - onDrainVideo_l(); + if (newRealTime >= oldRealTime) { + return OK; } } + mNextBufferItemMediaUs = -1; + onDrainVideo_l(); return OK; } @@ -316,12 +354,12 @@ void MediaSync::onDrainVideo_l() { return; } - int64_t nowUs = ALooper::GetNowUs(); - while (!mBufferItems.empty()) { + int64_t nowUs = ALooper::GetNowUs(); BufferItem *bufferItem = &*mBufferItems.begin(); int64_t itemMediaUs = bufferItem->mTimestamp / 1000; int64_t itemRealUs = getRealTime(itemMediaUs, nowUs); + if (itemRealUs <= nowUs) { if (mHasAudio) { if (nowUs - itemRealUs <= kMaxAllowedVideoLateTimeUs) { @@ -341,15 +379,13 @@ void MediaSync::onDrainVideo_l() { } mBufferItems.erase(mBufferItems.begin()); - - if (mBufferItems.empty()) { - mNextBufferItemMediaUs = -1; - } + mNextBufferItemMediaUs = -1; } else { if (mNextBufferItemMediaUs == -1 - || mNextBufferItemMediaUs != itemMediaUs) { + || mNextBufferItemMediaUs > itemMediaUs) { sp<AMessage> msg = new AMessage(kWhatDrainVideo, this); msg->post(itemRealUs - nowUs); + mNextBufferItemMediaUs = itemMediaUs; } break; } @@ -395,7 +431,9 @@ void MediaSync::onFrameAvailableFromInput() { } mBufferItems.push_back(bufferItem); - onDrainVideo_l(); + if (mBufferItems.size() == 1) { + onDrainVideo_l(); + } } void MediaSync::renderOneBufferItem_l( const BufferItem &bufferItem) { @@ -499,6 +537,20 @@ void MediaSync::onMessageReceived(const sp<AMessage> &msg) { case kWhatDrainVideo: { Mutex::Autolock lock(mMutex); + if (mNextBufferItemMediaUs != -1) { + int64_t nowUs = ALooper::GetNowUs(); + int64_t itemRealUs = getRealTime(mNextBufferItemMediaUs, nowUs); + + // The message could arrive earlier than expected due to + // various reasons, e.g., media clock has been changed because + // of new anchor time or playback rate. In such cases, the + // message needs to be re-posted. + if (itemRealUs > nowUs) { + msg->post(itemRealUs - nowUs); + break; + } + } + onDrainVideo_l(); break; } |