Loading include/media/BufferingSettings.h +2 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,8 @@ struct BufferingSettings : public Parcelable { static const int kNoWatermark = -1; static bool IsValidBufferingMode(int mode); static bool IsTimeBasedBufferingMode(int mode); static bool IsSizeBasedBufferingMode(int mode); BufferingMode mInitialBufferingMode; // for prepare BufferingMode mRebufferingMode; // for playback Loading include/media/stagefright/Utils.h +4 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <utils/Errors.h> #include <utils/RefBase.h> #include <system/audio.h> #include <media/BufferingSettings.h> #include <media/MediaPlayerInterface.h> namespace android { Loading Loading @@ -90,6 +91,9 @@ void writeToAMessage(const sp<AMessage> &msg, const AVSyncSettings &sync, float void readFromAMessage( const sp<AMessage> &msg, AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */); void writeToAMessage(const sp<AMessage> &msg, const BufferingSettings &buffering); void readFromAMessage(const sp<AMessage> &msg, BufferingSettings *buffering /* nonnull */); AString nameForFd(int fd); } // namespace android Loading media/libmedia/BufferingSettings.cpp +10 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,16 @@ bool BufferingSettings::IsValidBufferingMode(int mode) { return (mode >= BUFFERING_MODE_NONE && mode < BUFFERING_MODE_COUNT); } // static bool BufferingSettings::IsTimeBasedBufferingMode(int mode) { return (mode == BUFFERING_MODE_TIME_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE); } // static bool BufferingSettings::IsSizeBasedBufferingMode(int mode) { return (mode == BUFFERING_MODE_SIZE_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE); } BufferingSettings::BufferingSettings() : mInitialBufferingMode(BUFFERING_MODE_NONE), mRebufferingMode(BUFFERING_MODE_NONE), Loading media/libmediaplayerservice/nuplayer/GenericSource.cpp +81 −27 Original line number Diff line number Diff line Loading @@ -38,11 +38,12 @@ namespace android { static int64_t kLowWaterMarkUs = 2000000ll; // 2secs static int64_t kHighWaterMarkUs = 5000000ll; // 5secs static int64_t kHighWaterMarkRebufferUs = 15000000ll; // 15secs static const ssize_t kLowWaterMarkBytes = 40000; static const ssize_t kHighWaterMarkBytes = 200000; static const int kLowWaterMarkMs = 2000; // 2secs static const int kHighWaterMarkMs = 5000; // 5secs static const int kHighWaterMarkRebufferMs = 15000; // 15secs static const int kLowWaterMarkKB = 40; static const int kHighWaterMarkKB = 200; NuPlayer::GenericSource::GenericSource( const sp<AMessage> ¬ify, Loading Loading @@ -237,6 +238,16 @@ status_t NuPlayer::GenericSource::initFromDataSource() { return OK; } status_t NuPlayer::GenericSource::getDefaultBufferingSettings( BufferingSettings* buffering /* nonnull */) { mBufferingMonitor->getDefaultBufferingSettings(buffering); return OK; } status_t NuPlayer::GenericSource::setBufferingSettings(const BufferingSettings& buffering) { return mBufferingMonitor->setBufferingSettings(buffering); } status_t NuPlayer::GenericSource::startSources() { // Start the selected A/V tracks now before we start buffering. // Widevine sources might re-initialize crypto when starting, if we delay Loading Loading @@ -1469,11 +1480,48 @@ NuPlayer::GenericSource::BufferingMonitor::BufferingMonitor(const sp<AMessage> & mFirstDequeuedBufferRealUs(-1ll), mFirstDequeuedBufferMediaUs(-1ll), mlastDequeuedBufferMediaUs(-1ll) { getDefaultBufferingSettings(&mSettings); } NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() { } void NuPlayer::GenericSource::BufferingMonitor::getDefaultBufferingSettings( BufferingSettings *buffering /* nonnull */) { buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY; buffering->mRebufferingMode = BUFFERING_MODE_TIME_THEN_SIZE; buffering->mInitialWatermarkMs = kHighWaterMarkMs; buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs; buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs; buffering->mRebufferingWatermarkLowKB = kLowWaterMarkKB; buffering->mRebufferingWatermarkHighKB = kHighWaterMarkKB; } status_t NuPlayer::GenericSource::BufferingMonitor::setBufferingSettings( const BufferingSettings &buffering) { Mutex::Autolock _l(mLock); if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode) || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode) && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs) || (buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode) && buffering.mRebufferingWatermarkLowKB > buffering.mRebufferingWatermarkHighKB)) { return BAD_VALUE; } mSettings = buffering; if (mSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) { mSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark; } if (!mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) { mSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark; mSettings.mRebufferingWatermarkHighMs = INT32_MAX; } if (!mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) { mSettings.mRebufferingWatermarkLowKB = BufferingSettings::kNoWatermark; mSettings.mRebufferingWatermarkHighKB = INT32_MAX; } return OK; } void NuPlayer::GenericSource::BufferingMonitor::prepare( const sp<NuCachedSource2> &cachedSource, int64_t durationUs, Loading Loading @@ -1702,7 +1750,9 @@ void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() { stopBufferingIfNecessary_l(); return; } else if (cachedDurationUs >= 0ll) { } if (cachedDurationUs >= 0ll) { if (mDurationUs > 0ll) { int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs; int percentage = 100.0 * cachedPosUs / mDurationUs; Loading @@ -1713,36 +1763,40 @@ void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() { notifyBufferingUpdate_l(percentage); } ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f); ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f); if (cachedDurationUs < kLowWaterMarkUs) { if (mPrepareBuffering) { if (cachedDurationUs > mSettings.mInitialWatermarkMs * 1000) { stopBufferingIfNecessary_l(); } } else if (mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) { if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) { // Take into account the data cached in downstream components to try to avoid // unnecessary pause. if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) { int64_t downStreamCacheUs = mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs int64_t downStreamCacheUs = mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs); if (downStreamCacheUs > 0) { cachedDurationUs += downStreamCacheUs; } } if (cachedDurationUs < kLowWaterMarkUs) { if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) { startBufferingIfNecessary_l(); } } else { int64_t highWaterMark = mPrepareBuffering ? kHighWaterMarkUs : kHighWaterMarkRebufferUs; if (cachedDurationUs > highWaterMark) { } else if (cachedDurationUs > mSettings.mRebufferingWatermarkHighMs * 1000) { stopBufferingIfNecessary_l(); } } } else if (cachedDataRemaining >= 0) { } else if (cachedDataRemaining >= 0 && mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) { ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes", cachedDataRemaining); if (cachedDataRemaining < kLowWaterMarkBytes) { if (cachedDataRemaining < (mSettings.mRebufferingWatermarkLowKB << 10)) { startBufferingIfNecessary_l(); } else if (cachedDataRemaining > kHighWaterMarkBytes) { } else if (cachedDataRemaining > (mSettings.mRebufferingWatermarkHighKB << 10)) { stopBufferingIfNecessary_l(); } } Loading media/libmediaplayerservice/nuplayer/GenericSource.h +8 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,10 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { status_t setDataSource(const sp<DataSource>& dataSource); virtual status_t getDefaultBufferingSettings( BufferingSettings* buffering /* nonnull */) override; virtual status_t setBufferingSettings(const BufferingSettings& buffering) override; virtual void prepareAsync(); virtual void start(); Loading Loading @@ -119,6 +123,9 @@ private: public: explicit BufferingMonitor(const sp<AMessage> ¬ify); void getDefaultBufferingSettings(BufferingSettings *buffering /* nonnull */); status_t setBufferingSettings(const BufferingSettings &buffering); // Set up state. void prepare(const sp<NuCachedSource2> &cachedSource, int64_t durationUs, Loading Loading @@ -167,6 +174,7 @@ private: mutable Mutex mLock; BufferingSettings mSettings; bool mOffloadAudio; int64_t mFirstDequeuedBufferRealUs; int64_t mFirstDequeuedBufferMediaUs; Loading Loading
include/media/BufferingSettings.h +2 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,8 @@ struct BufferingSettings : public Parcelable { static const int kNoWatermark = -1; static bool IsValidBufferingMode(int mode); static bool IsTimeBasedBufferingMode(int mode); static bool IsSizeBasedBufferingMode(int mode); BufferingMode mInitialBufferingMode; // for prepare BufferingMode mRebufferingMode; // for playback Loading
include/media/stagefright/Utils.h +4 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #include <utils/Errors.h> #include <utils/RefBase.h> #include <system/audio.h> #include <media/BufferingSettings.h> #include <media/MediaPlayerInterface.h> namespace android { Loading Loading @@ -90,6 +91,9 @@ void writeToAMessage(const sp<AMessage> &msg, const AVSyncSettings &sync, float void readFromAMessage( const sp<AMessage> &msg, AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */); void writeToAMessage(const sp<AMessage> &msg, const BufferingSettings &buffering); void readFromAMessage(const sp<AMessage> &msg, BufferingSettings *buffering /* nonnull */); AString nameForFd(int fd); } // namespace android Loading
media/libmedia/BufferingSettings.cpp +10 −0 Original line number Diff line number Diff line Loading @@ -28,6 +28,16 @@ bool BufferingSettings::IsValidBufferingMode(int mode) { return (mode >= BUFFERING_MODE_NONE && mode < BUFFERING_MODE_COUNT); } // static bool BufferingSettings::IsTimeBasedBufferingMode(int mode) { return (mode == BUFFERING_MODE_TIME_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE); } // static bool BufferingSettings::IsSizeBasedBufferingMode(int mode) { return (mode == BUFFERING_MODE_SIZE_ONLY || mode == BUFFERING_MODE_TIME_THEN_SIZE); } BufferingSettings::BufferingSettings() : mInitialBufferingMode(BUFFERING_MODE_NONE), mRebufferingMode(BUFFERING_MODE_NONE), Loading
media/libmediaplayerservice/nuplayer/GenericSource.cpp +81 −27 Original line number Diff line number Diff line Loading @@ -38,11 +38,12 @@ namespace android { static int64_t kLowWaterMarkUs = 2000000ll; // 2secs static int64_t kHighWaterMarkUs = 5000000ll; // 5secs static int64_t kHighWaterMarkRebufferUs = 15000000ll; // 15secs static const ssize_t kLowWaterMarkBytes = 40000; static const ssize_t kHighWaterMarkBytes = 200000; static const int kLowWaterMarkMs = 2000; // 2secs static const int kHighWaterMarkMs = 5000; // 5secs static const int kHighWaterMarkRebufferMs = 15000; // 15secs static const int kLowWaterMarkKB = 40; static const int kHighWaterMarkKB = 200; NuPlayer::GenericSource::GenericSource( const sp<AMessage> ¬ify, Loading Loading @@ -237,6 +238,16 @@ status_t NuPlayer::GenericSource::initFromDataSource() { return OK; } status_t NuPlayer::GenericSource::getDefaultBufferingSettings( BufferingSettings* buffering /* nonnull */) { mBufferingMonitor->getDefaultBufferingSettings(buffering); return OK; } status_t NuPlayer::GenericSource::setBufferingSettings(const BufferingSettings& buffering) { return mBufferingMonitor->setBufferingSettings(buffering); } status_t NuPlayer::GenericSource::startSources() { // Start the selected A/V tracks now before we start buffering. // Widevine sources might re-initialize crypto when starting, if we delay Loading Loading @@ -1469,11 +1480,48 @@ NuPlayer::GenericSource::BufferingMonitor::BufferingMonitor(const sp<AMessage> & mFirstDequeuedBufferRealUs(-1ll), mFirstDequeuedBufferMediaUs(-1ll), mlastDequeuedBufferMediaUs(-1ll) { getDefaultBufferingSettings(&mSettings); } NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() { } void NuPlayer::GenericSource::BufferingMonitor::getDefaultBufferingSettings( BufferingSettings *buffering /* nonnull */) { buffering->mInitialBufferingMode = BUFFERING_MODE_TIME_ONLY; buffering->mRebufferingMode = BUFFERING_MODE_TIME_THEN_SIZE; buffering->mInitialWatermarkMs = kHighWaterMarkMs; buffering->mRebufferingWatermarkLowMs = kLowWaterMarkMs; buffering->mRebufferingWatermarkHighMs = kHighWaterMarkRebufferMs; buffering->mRebufferingWatermarkLowKB = kLowWaterMarkKB; buffering->mRebufferingWatermarkHighKB = kHighWaterMarkKB; } status_t NuPlayer::GenericSource::BufferingMonitor::setBufferingSettings( const BufferingSettings &buffering) { Mutex::Autolock _l(mLock); if (buffering.IsSizeBasedBufferingMode(buffering.mInitialBufferingMode) || (buffering.IsTimeBasedBufferingMode(buffering.mRebufferingMode) && buffering.mRebufferingWatermarkLowMs > buffering.mRebufferingWatermarkHighMs) || (buffering.IsSizeBasedBufferingMode(buffering.mRebufferingMode) && buffering.mRebufferingWatermarkLowKB > buffering.mRebufferingWatermarkHighKB)) { return BAD_VALUE; } mSettings = buffering; if (mSettings.mInitialBufferingMode == BUFFERING_MODE_NONE) { mSettings.mInitialWatermarkMs = BufferingSettings::kNoWatermark; } if (!mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) { mSettings.mRebufferingWatermarkLowMs = BufferingSettings::kNoWatermark; mSettings.mRebufferingWatermarkHighMs = INT32_MAX; } if (!mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) { mSettings.mRebufferingWatermarkLowKB = BufferingSettings::kNoWatermark; mSettings.mRebufferingWatermarkHighKB = INT32_MAX; } return OK; } void NuPlayer::GenericSource::BufferingMonitor::prepare( const sp<NuCachedSource2> &cachedSource, int64_t durationUs, Loading Loading @@ -1702,7 +1750,9 @@ void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() { stopBufferingIfNecessary_l(); return; } else if (cachedDurationUs >= 0ll) { } if (cachedDurationUs >= 0ll) { if (mDurationUs > 0ll) { int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs; int percentage = 100.0 * cachedPosUs / mDurationUs; Loading @@ -1713,36 +1763,40 @@ void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() { notifyBufferingUpdate_l(percentage); } ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f); ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f); if (cachedDurationUs < kLowWaterMarkUs) { if (mPrepareBuffering) { if (cachedDurationUs > mSettings.mInitialWatermarkMs * 1000) { stopBufferingIfNecessary_l(); } } else if (mSettings.IsTimeBasedBufferingMode(mSettings.mRebufferingMode)) { if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) { // Take into account the data cached in downstream components to try to avoid // unnecessary pause. if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) { int64_t downStreamCacheUs = mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs int64_t downStreamCacheUs = mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs); if (downStreamCacheUs > 0) { cachedDurationUs += downStreamCacheUs; } } if (cachedDurationUs < kLowWaterMarkUs) { if (cachedDurationUs < mSettings.mRebufferingWatermarkLowMs * 1000) { startBufferingIfNecessary_l(); } } else { int64_t highWaterMark = mPrepareBuffering ? kHighWaterMarkUs : kHighWaterMarkRebufferUs; if (cachedDurationUs > highWaterMark) { } else if (cachedDurationUs > mSettings.mRebufferingWatermarkHighMs * 1000) { stopBufferingIfNecessary_l(); } } } else if (cachedDataRemaining >= 0) { } else if (cachedDataRemaining >= 0 && mSettings.IsSizeBasedBufferingMode(mSettings.mRebufferingMode)) { ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes", cachedDataRemaining); if (cachedDataRemaining < kLowWaterMarkBytes) { if (cachedDataRemaining < (mSettings.mRebufferingWatermarkLowKB << 10)) { startBufferingIfNecessary_l(); } else if (cachedDataRemaining > kHighWaterMarkBytes) { } else if (cachedDataRemaining > (mSettings.mRebufferingWatermarkHighKB << 10)) { stopBufferingIfNecessary_l(); } } Loading
media/libmediaplayerservice/nuplayer/GenericSource.h +8 −0 Original line number Diff line number Diff line Loading @@ -50,6 +50,10 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { status_t setDataSource(const sp<DataSource>& dataSource); virtual status_t getDefaultBufferingSettings( BufferingSettings* buffering /* nonnull */) override; virtual status_t setBufferingSettings(const BufferingSettings& buffering) override; virtual void prepareAsync(); virtual void start(); Loading Loading @@ -119,6 +123,9 @@ private: public: explicit BufferingMonitor(const sp<AMessage> ¬ify); void getDefaultBufferingSettings(BufferingSettings *buffering /* nonnull */); status_t setBufferingSettings(const BufferingSettings &buffering); // Set up state. void prepare(const sp<NuCachedSource2> &cachedSource, int64_t durationUs, Loading Loading @@ -167,6 +174,7 @@ private: mutable Mutex mLock; BufferingSettings mSettings; bool mOffloadAudio; int64_t mFirstDequeuedBufferRealUs; int64_t mFirstDequeuedBufferMediaUs; Loading