diff options
author | Andreas Huber <andih@google.com> | 2010-09-03 13:20:33 -0700 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2010-09-03 13:44:42 -0700 |
commit | 87ab9cdd0fde6bfb1205805c6a13423aafadeaaa (patch) | |
tree | ec5f210cc652e9ca96ea174fdc890b7bec147084 /media | |
parent | 12da9d7472ae87b841575d5358e19f143d12f900 (diff) | |
download | frameworks_base-87ab9cdd0fde6bfb1205805c6a13423aafadeaaa.zip frameworks_base-87ab9cdd0fde6bfb1205805c6a13423aafadeaaa.tar.gz frameworks_base-87ab9cdd0fde6bfb1205805c6a13423aafadeaaa.tar.bz2 |
Properly buffer a certain amount of data on streaming sources before finishing prepare().
Change-Id: I39bf3c6dafcbe003b51dea4795742dcd8548f207
related-to-bug: 2875110
Diffstat (limited to 'media')
-rw-r--r-- | media/libstagefright/AwesomePlayer.cpp | 204 | ||||
-rw-r--r-- | media/libstagefright/include/AwesomePlayer.h | 3 |
2 files changed, 119 insertions, 88 deletions
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index 2681dc3..c13726b 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -50,6 +50,9 @@ namespace android { +static int64_t kLowWaterMarkUs = 2000000ll; // 2secs +static int64_t kHighWaterMarkUs = 10000000ll; // 10secs + struct AwesomeEvent : public TimedEventQueue::Event { AwesomeEvent( AwesomePlayer *player, @@ -450,6 +453,25 @@ void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) { } } +// Returns true iff cached duration is available/applicable. +bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) { + off_t totalSize; + + if (mRTSPController != NULL) { + *durationUs = mRTSPController->getQueueDurationUs(eos); + return true; + } else if (mCachedSource != NULL && mDurationUs >= 0 + && mCachedSource->getSize(&totalSize) == OK) { + int64_t bitrate = totalSize * 8000000ll / mDurationUs; // in bits/sec + + size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos); + *durationUs = cachedDataRemaining * 8000000ll / bitrate; + return true; + } + + return false; +} + void AwesomePlayer::onBufferingUpdate() { Mutex::Autolock autoLock(mLock); if (!mBufferingEventPending) { @@ -457,78 +479,82 @@ void AwesomePlayer::onBufferingUpdate() { } mBufferingEventPending = false; - int kLowWaterMarkSecs = 2; - int kHighWaterMarkSecs = 10; - - if (mRTSPController != NULL) { + if (mCachedSource != NULL) { bool eos; - int64_t queueDurationUs = mRTSPController->getQueueDurationUs(&eos); + size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos); - LOGV("queueDurationUs = %.2f secs", queueDurationUs / 1E6); + if (eos) { + notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); + } else { + off_t size; + if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) { + int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec - if ((mFlags & PLAYING) && !eos - && (queueDurationUs < kLowWaterMarkSecs * 1000000ll)) { - LOGI("rtsp cache is running low, pausing."); - mFlags |= CACHE_UNDERRUN; - pause_l(); - notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); - } else if ((mFlags & CACHE_UNDERRUN) - && (eos || queueDurationUs > kHighWaterMarkSecs * 1000000ll)) { - LOGI("rtsp cache has filled up, resuming."); - mFlags &= ~CACHE_UNDERRUN; - play_l(); - notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); - } + size_t cachedSize = mCachedSource->cachedSize(); + int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate; - postBufferingEvent_l(); - return; - } + int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; + if (percentage > 100) { + percentage = 100; + } - if (mCachedSource == NULL) { - return; + notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); + } else { + // We don't know the bitrate of the stream, use absolute size + // limits to maintain the cache. + + const size_t kLowWaterMarkBytes = 400000; + const size_t kHighWaterMarkBytes = 1000000; + + if ((mFlags & PLAYING) && !eos + && (cachedDataRemaining < kLowWaterMarkBytes)) { + LOGI("cache is running low (< %d) , pausing.", + kLowWaterMarkBytes); + mFlags |= CACHE_UNDERRUN; + pause_l(); + notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); + } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) { + if (mFlags & CACHE_UNDERRUN) { + LOGI("cache has filled up (> %d), resuming.", + kHighWaterMarkBytes); + mFlags &= ~CACHE_UNDERRUN; + play_l(); + notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); + } else if (mFlags & PREPARING) { + LOGV("cache has filled up (> %d), prepare is done", + kHighWaterMarkBytes); + finishAsyncPrepare_l(); + } + } + } + } } + int64_t cachedDurationUs; bool eos; - size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos); - - size_t lowWatermark = 400000; - size_t highWatermark = 1000000; - - if (eos) { - notifyListener_l(MEDIA_BUFFERING_UPDATE, 100); - } else { - off_t size; - if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) { - int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec - - size_t cachedSize = mCachedSource->cachedSize(); - int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate; - - int percentage = 100.0 * (double)cachedDurationUs / mDurationUs; - if (percentage > 100) { - percentage = 100; + if (getCachedDuration_l(&cachedDurationUs, &eos)) { + if ((mFlags & PLAYING) && !eos + && (cachedDurationUs < kLowWaterMarkUs)) { + LOGI("cache is running low (%.2f secs) , pausing.", + cachedDurationUs / 1E6); + mFlags |= CACHE_UNDERRUN; + pause_l(); + notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); + } else if (eos || cachedDurationUs > kHighWaterMarkUs) { + if (mFlags & CACHE_UNDERRUN) { + LOGI("cache has filled up (%.2f secs), resuming.", + cachedDurationUs / 1E6); + mFlags &= ~CACHE_UNDERRUN; + play_l(); + notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); + } else if (mFlags & PREPARING) { + LOGV("cache has filled up (%.2f secs), prepare is done", + cachedDurationUs / 1E6); + finishAsyncPrepare_l(); } - - notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage); - - lowWatermark = kLowWaterMarkSecs * bitrate / 8; - highWatermark = kHighWaterMarkSecs * bitrate / 8; } } - if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) { - LOGI("cache is running low (< %d) , pausing.", lowWatermark); - mFlags |= CACHE_UNDERRUN; - pause_l(); - notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START); - } else if ((mFlags & CACHE_UNDERRUN) - && (eos || cachedDataRemaining > highWatermark)) { - LOGI("cache has filled up (> %d), resuming.", highWatermark); - mFlags &= ~CACHE_UNDERRUN; - play_l(); - notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END); - } - postBufferingEvent_l(); } @@ -1437,45 +1463,49 @@ bool AwesomePlayer::ContinuePreparation(void *cookie) { } void AwesomePlayer::onPrepareAsyncEvent() { - { - Mutex::Autolock autoLock(mLock); + Mutex::Autolock autoLock(mLock); - if (mFlags & PREPARE_CANCELLED) { - LOGI("prepare was cancelled before doing anything"); - abortPrepare(UNKNOWN_ERROR); - return; - } + if (mFlags & PREPARE_CANCELLED) { + LOGI("prepare was cancelled before doing anything"); + abortPrepare(UNKNOWN_ERROR); + return; + } - if (mUri.size() > 0) { - status_t err = finishSetDataSource_l(); + if (mUri.size() > 0) { + status_t err = finishSetDataSource_l(); - if (err != OK) { - abortPrepare(err); - return; - } + if (err != OK) { + abortPrepare(err); + return; } + } - if (mVideoTrack != NULL && mVideoSource == NULL) { - status_t err = initVideoDecoder(); + if (mVideoTrack != NULL && mVideoSource == NULL) { + status_t err = initVideoDecoder(); - if (err != OK) { - abortPrepare(err); - return; - } + if (err != OK) { + abortPrepare(err); + return; } + } - if (mAudioTrack != NULL && mAudioSource == NULL) { - status_t err = initAudioDecoder(); + if (mAudioTrack != NULL && mAudioSource == NULL) { + status_t err = initAudioDecoder(); - if (err != OK) { - abortPrepare(err); - return; - } + if (err != OK) { + abortPrepare(err); + return; } } - Mutex::Autolock autoLock(mLock); + if (mCachedSource != NULL || mRTSPController != NULL) { + postBufferingEvent_l(); + } else { + finishAsyncPrepare_l(); + } +} +void AwesomePlayer::finishAsyncPrepare_l() { if (mIsAsyncPrepare) { if (mVideoWidth < 0 || mVideoHeight < 0) { notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0); @@ -1491,8 +1521,6 @@ void AwesomePlayer::onPrepareAsyncEvent() { mFlags |= PREPARED; mAsyncPrepareEvent = NULL; mPreparedCondition.broadcast(); - - postBufferingEvent_l(); } status_t AwesomePlayer::suspend() { diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 55e2c36..f47deb8 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -238,6 +238,9 @@ private: void onCheckAudioStatus(); void onPrepareAsyncEvent(); void abortPrepare(status_t err); + void finishAsyncPrepare_l(); + + bool getCachedDuration_l(int64_t *durationUs, bool *eos); status_t finishSetDataSource_l(); |