Loading media/libmediaplayerservice/nuplayer/GenericSource.cpp +364 −198 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ 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; Loading @@ -66,11 +67,8 @@ NuPlayer::GenericSource::GenericSource( mFd(-1), mDrmManagerClient(NULL), mBitrate(-1ll), mPollBufferingGeneration(0), mPendingReadBufferTypes(0), mBuffering(false), mPrepareBuffering(false), mPrevBufferPercentage(-1) { mPendingReadBufferTypes(0) { mBufferingMonitor = new BufferingMonitor(notify); resetDataSource(); DataSource::RegisterDefaultSniffers(); } Loading @@ -91,6 +89,13 @@ void NuPlayer::GenericSource::resetDataSource() { mDrmManagerClient = NULL; mStarted = false; mStopRead = true; if (mBufferingMonitorLooper != NULL) { mBufferingMonitorLooper->unregisterHandler(mBufferingMonitor->id()); mBufferingMonitorLooper->stop(); mBufferingMonitorLooper = NULL; } mBufferingMonitor->stop(); } status_t NuPlayer::GenericSource::setDataSource( Loading Loading @@ -338,6 +343,10 @@ bool NuPlayer::GenericSource::isStreaming() const { return mIsStreaming; } void NuPlayer::GenericSource::setOffloadAudio(bool offload) { mBufferingMonitor->setOffloadAudio(offload); } NuPlayer::GenericSource::~GenericSource() { if (mLooper != NULL) { mLooper->unregisterHandler(id()); Loading Loading @@ -466,10 +475,18 @@ void NuPlayer::GenericSource::finishPrepareAsync() { } if (mIsStreaming) { mPrepareBuffering = true; if (mBufferingMonitorLooper == NULL) { mBufferingMonitor->prepare(mCachedSource, mWVMExtractor, mDurationUs, mBitrate, mIsStreaming); mBufferingMonitorLooper = new ALooper; mBufferingMonitorLooper->setName("GSBMonitor"); mBufferingMonitorLooper->start(); mBufferingMonitorLooper->registerHandler(mBufferingMonitor); } ensureCacheIsFetching(); restartPollBuffering(); mBufferingMonitor->ensureCacheIsFetching(); mBufferingMonitor->restartPollBuffering(); } else { notifyPrepared(); } Loading @@ -492,7 +509,7 @@ void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { } mBitrate = -1; cancelPollBuffering(); mBufferingMonitor->cancelPollBuffering(); } notifyPrepared(err); } Loading Loading @@ -571,182 +588,6 @@ status_t NuPlayer::GenericSource::feedMoreTSData() { return OK; } void NuPlayer::GenericSource::schedulePollBuffering() { sp<AMessage> msg = new AMessage(kWhatPollBuffering, this); msg->setInt32("generation", mPollBufferingGeneration); msg->post(1000000ll); } void NuPlayer::GenericSource::cancelPollBuffering() { mBuffering = false; ++mPollBufferingGeneration; mPrevBufferPercentage = -1; } void NuPlayer::GenericSource::restartPollBuffering() { if (mIsStreaming) { cancelPollBuffering(); onPollBuffering(); } } void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) { // Buffering percent could go backward as it's estimated from remaining // data and last access time. This could cause the buffering position // drawn on media control to jitter slightly. Remember previously reported // percentage and don't allow it to go backward. if (percentage < mPrevBufferPercentage) { percentage = mPrevBufferPercentage; } else if (percentage > 100) { percentage = 100; } mPrevBufferPercentage = percentage; ALOGV("notifyBufferingUpdate: buffering %d%%", percentage); sp<AMessage> msg = dupNotify(); msg->setInt32("what", kWhatBufferingUpdate); msg->setInt32("percentage", percentage); msg->post(); } void NuPlayer::GenericSource::startBufferingIfNecessary() { ALOGV("startBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d", mPrepareBuffering, mBuffering); if (mPrepareBuffering) { return; } if (!mBuffering) { mBuffering = true; ensureCacheIsFetching(); sendCacheStats(); sp<AMessage> notify = dupNotify(); notify->setInt32("what", kWhatPauseOnBufferingStart); notify->post(); } } void NuPlayer::GenericSource::stopBufferingIfNecessary() { ALOGV("stopBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d", mPrepareBuffering, mBuffering); if (mPrepareBuffering) { mPrepareBuffering = false; notifyPrepared(); return; } if (mBuffering) { mBuffering = false; sendCacheStats(); sp<AMessage> notify = dupNotify(); notify->setInt32("what", kWhatResumeOnBufferingEnd); notify->post(); } } void NuPlayer::GenericSource::sendCacheStats() { int32_t kbps = 0; status_t err = UNKNOWN_ERROR; if (mWVMExtractor != NULL) { err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps); } else if (mCachedSource != NULL) { err = mCachedSource->getEstimatedBandwidthKbps(&kbps); } if (err == OK) { sp<AMessage> notify = dupNotify(); notify->setInt32("what", kWhatCacheStats); notify->setInt32("bandwidth", kbps); notify->post(); } } void NuPlayer::GenericSource::ensureCacheIsFetching() { if (mCachedSource != NULL) { mCachedSource->resumeFetchingIfNecessary(); } } void NuPlayer::GenericSource::onPollBuffering() { status_t finalStatus = UNKNOWN_ERROR; int64_t cachedDurationUs = -1ll; ssize_t cachedDataRemaining = -1; ALOGW_IF(mWVMExtractor != NULL && mCachedSource != NULL, "WVMExtractor and NuCachedSource both present"); if (mWVMExtractor != NULL) { cachedDurationUs = mWVMExtractor->getCachedDurationUs(&finalStatus); } else if (mCachedSource != NULL) { cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); if (finalStatus == OK) { off64_t size; int64_t bitrate = 0ll; if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) { bitrate = size * 8000000ll / mDurationUs; } else if (mBitrate > 0) { bitrate = mBitrate; } if (bitrate > 0) { cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate; } } } if (finalStatus != OK) { ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus); if (finalStatus == ERROR_END_OF_STREAM) { notifyBufferingUpdate(100); } stopBufferingIfNecessary(); return; } else if (cachedDurationUs >= 0ll) { if (mDurationUs > 0ll) { int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs; int percentage = 100.0 * cachedPosUs / mDurationUs; if (percentage > 100) { percentage = 100; } notifyBufferingUpdate(percentage); } ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f); if (cachedDurationUs < kLowWaterMarkUs) { startBufferingIfNecessary(); } else if (cachedDurationUs > kHighWaterMarkUs) { stopBufferingIfNecessary(); } } else if (cachedDataRemaining >= 0) { ALOGV("onPollBuffering: cachedDataRemaining %zd bytes", cachedDataRemaining); if (cachedDataRemaining < kLowWaterMarkBytes) { startBufferingIfNecessary(); } else if (cachedDataRemaining > kHighWaterMarkBytes) { stopBufferingIfNecessary(); } } schedulePollBuffering(); } void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatPrepareAsync: Loading Loading @@ -834,17 +675,7 @@ void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { case kWhatStart: case kWhatResume: { restartPollBuffering(); break; } case kWhatPollBuffering: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation == mPollBufferingGeneration) { onPollBuffering(); } mBufferingMonitor->restartPollBuffering(); break; } Loading Loading @@ -1045,6 +876,10 @@ sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const { status_t NuPlayer::GenericSource::dequeueAccessUnit( bool audio, sp<ABuffer> *accessUnit) { if (!mStarted) { return -EWOULDBLOCK; } Track *track = audio ? &mAudioTrack : &mVideoTrack; if (track->mSource == NULL) { Loading Loading @@ -1091,6 +926,7 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); if (audio) { mAudioLastDequeueTimeUs = timeUs; mBufferingMonitor->updateDequeuedBufferTime(timeUs); } else { mVideoLastDequeueTimeUs = timeUs; } Loading Loading @@ -1377,6 +1213,8 @@ void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) { } status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) { mBufferingMonitor->updateDequeuedBufferTime(-1ll); // If the Widevine source is stopped, do not attempt to read any // more buffers. if (mStopRead) { Loading @@ -1403,8 +1241,8 @@ status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) { // If currently buffering, post kWhatBufferingEnd first, so that // NuPlayer resumes. Otherwise, if cache hits high watermark // before new polling happens, no one will resume the playback. stopBufferingIfNecessary(); restartPollBuffering(); mBufferingMonitor->stopBufferingIfNecessary(); mBufferingMonitor->restartPollBuffering(); return OK; } Loading Loading @@ -1585,8 +1423,10 @@ void NuPlayer::GenericSource::readBuffer( CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); if (trackType == MEDIA_TRACK_TYPE_AUDIO) { mAudioTimeUs = timeUs; mBufferingMonitor->updateQueuedTime(true /* isAudio */, timeUs); } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) { mVideoTimeUs = timeUs; mBufferingMonitor->updateQueuedTime(false /* isAudio */, timeUs); } queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track); Loading Loading @@ -1630,4 +1470,330 @@ void NuPlayer::GenericSource::queueDiscontinuityIfNeeded( } } NuPlayer::GenericSource::BufferingMonitor::BufferingMonitor(const sp<AMessage> ¬ify) : mNotify(notify), mDurationUs(-1ll), mBitrate(-1ll), mIsStreaming(false), mAudioTimeUs(0), mVideoTimeUs(0), mPollBufferingGeneration(0), mPrepareBuffering(false), mBuffering(false), mPrevBufferPercentage(-1), mOffloadAudio(false), mFirstDequeuedBufferRealUs(-1ll), mFirstDequeuedBufferMediaUs(-1ll), mlastDequeuedBufferMediaUs(-1ll) { } NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() { } void NuPlayer::GenericSource::BufferingMonitor::prepare( const sp<NuCachedSource2> &cachedSource, const sp<WVMExtractor> &wvmExtractor, int64_t durationUs, int64_t bitrate, bool isStreaming) { Mutex::Autolock _l(mLock); prepare_l(cachedSource, wvmExtractor, durationUs, bitrate, isStreaming); } void NuPlayer::GenericSource::BufferingMonitor::stop() { Mutex::Autolock _l(mLock); prepare_l(NULL /* cachedSource */, NULL /* wvmExtractor */, -1 /* durationUs */, -1 /* bitrate */, false /* isStreaming */); } void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering() { Mutex::Autolock _l(mLock); cancelPollBuffering_l(); } void NuPlayer::GenericSource::BufferingMonitor::restartPollBuffering() { Mutex::Autolock _l(mLock); if (mIsStreaming) { cancelPollBuffering_l(); onPollBuffering_l(); } } void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary() { Mutex::Autolock _l(mLock); stopBufferingIfNecessary_l(); } void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching() { Mutex::Autolock _l(mLock); ensureCacheIsFetching_l(); } void NuPlayer::GenericSource::BufferingMonitor::updateQueuedTime(bool isAudio, int64_t timeUs) { Mutex::Autolock _l(mLock); if (isAudio) { mAudioTimeUs = timeUs; } else { mVideoTimeUs = timeUs; } } void NuPlayer::GenericSource::BufferingMonitor::setOffloadAudio(bool offload) { Mutex::Autolock _l(mLock); mOffloadAudio = offload; } void NuPlayer::GenericSource::BufferingMonitor::updateDequeuedBufferTime(int64_t mediaUs) { Mutex::Autolock _l(mLock); if (mediaUs < 0) { mFirstDequeuedBufferRealUs = -1ll; mFirstDequeuedBufferMediaUs = -1ll; } else if (mFirstDequeuedBufferRealUs < 0) { mFirstDequeuedBufferRealUs = ALooper::GetNowUs(); mFirstDequeuedBufferMediaUs = mediaUs; } mlastDequeuedBufferMediaUs = mediaUs; } void NuPlayer::GenericSource::BufferingMonitor::prepare_l( const sp<NuCachedSource2> &cachedSource, const sp<WVMExtractor> &wvmExtractor, int64_t durationUs, int64_t bitrate, bool isStreaming) { ALOGW_IF(wvmExtractor != NULL && cachedSource != NULL, "WVMExtractor and NuCachedSource are both present when " "BufferingMonitor::prepare_l is called, ignore NuCachedSource"); mCachedSource = cachedSource; mWVMExtractor = wvmExtractor; mDurationUs = durationUs; mBitrate = bitrate; mIsStreaming = isStreaming; mAudioTimeUs = 0; mVideoTimeUs = 0; mPrepareBuffering = true; cancelPollBuffering_l(); mOffloadAudio = false; mFirstDequeuedBufferRealUs = -1ll; mFirstDequeuedBufferMediaUs = -1ll; mlastDequeuedBufferMediaUs = -1ll; } void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering_l() { mBuffering = false; ++mPollBufferingGeneration; mPrevBufferPercentage = -1; } void NuPlayer::GenericSource::BufferingMonitor::notifyBufferingUpdate_l(int32_t percentage) { // Buffering percent could go backward as it's estimated from remaining // data and last access time. This could cause the buffering position // drawn on media control to jitter slightly. Remember previously reported // percentage and don't allow it to go backward. if (percentage < mPrevBufferPercentage) { percentage = mPrevBufferPercentage; } else if (percentage > 100) { percentage = 100; } mPrevBufferPercentage = percentage; ALOGV("notifyBufferingUpdate_l: buffering %d%%", percentage); sp<AMessage> msg = mNotify->dup(); msg->setInt32("what", kWhatBufferingUpdate); msg->setInt32("percentage", percentage); msg->post(); } void NuPlayer::GenericSource::BufferingMonitor::startBufferingIfNecessary_l() { ALOGD("startBufferingIfNecessary_l: mPrepareBuffering=%d, mBuffering=%d", mPrepareBuffering, mBuffering); if (mPrepareBuffering) { return; } if (!mBuffering) { mBuffering = true; ensureCacheIsFetching_l(); sendCacheStats_l(); sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatPauseOnBufferingStart); notify->post(); } } void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary_l() { ALOGD("stopBufferingIfNecessary_l: mPrepareBuffering=%d, mBuffering=%d", mPrepareBuffering, mBuffering); if (mPrepareBuffering) { mPrepareBuffering = false; sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatPrepared); notify->setInt32("err", OK); notify->post(); return; } if (mBuffering) { mBuffering = false; sendCacheStats_l(); sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatResumeOnBufferingEnd); notify->post(); } } void NuPlayer::GenericSource::BufferingMonitor::sendCacheStats_l() { int32_t kbps = 0; status_t err = UNKNOWN_ERROR; if (mWVMExtractor != NULL) { err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps); } else if (mCachedSource != NULL) { err = mCachedSource->getEstimatedBandwidthKbps(&kbps); } if (err == OK) { sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatCacheStats); notify->setInt32("bandwidth", kbps); notify->post(); } } void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching_l() { if (mCachedSource != NULL) { mCachedSource->resumeFetchingIfNecessary(); } } void NuPlayer::GenericSource::BufferingMonitor::schedulePollBuffering_l() { sp<AMessage> msg = new AMessage(kWhatPollBuffering, this); msg->setInt32("generation", mPollBufferingGeneration); // Enquires buffering status every second. msg->post(1000000ll); } int64_t NuPlayer::GenericSource::BufferingMonitor::getLastReadPosition_l() { if (mAudioTimeUs > 0) { return mAudioTimeUs; } else if (mVideoTimeUs > 0) { return mVideoTimeUs; } else { return 0; } } void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() { status_t finalStatus = UNKNOWN_ERROR; int64_t cachedDurationUs = -1ll; ssize_t cachedDataRemaining = -1; if (mWVMExtractor != NULL) { cachedDurationUs = mWVMExtractor->getCachedDurationUs(&finalStatus); } else if (mCachedSource != NULL) { cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); if (finalStatus == OK) { off64_t size; int64_t bitrate = 0ll; if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) { // |bitrate| uses bits/second unit, while size is number of bytes. bitrate = size * 8000000ll / mDurationUs; } else if (mBitrate > 0) { bitrate = mBitrate; } if (bitrate > 0) { cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate; } } } if (finalStatus != OK) { ALOGV("onPollBuffering_l: EOS (finalStatus = %d)", finalStatus); if (finalStatus == ERROR_END_OF_STREAM) { notifyBufferingUpdate_l(100); } stopBufferingIfNecessary_l(); return; } else if (cachedDurationUs >= 0ll) { if (mDurationUs > 0ll) { int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs; int percentage = 100.0 * cachedPosUs / mDurationUs; if (percentage > 100) { percentage = 100; } notifyBufferingUpdate_l(percentage); } ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f); if (cachedDurationUs < kLowWaterMarkUs) { // Take into account the data cached in downstream components to try to avoid // unnecessary pause. if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) { int64_t downStreamCacheUs = mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs); if (downStreamCacheUs > 0) { cachedDurationUs += downStreamCacheUs; } } if (cachedDurationUs < kLowWaterMarkUs) { startBufferingIfNecessary_l(); } } else { int64_t highWaterMark = mPrepareBuffering ? kHighWaterMarkUs : kHighWaterMarkRebufferUs; if (cachedDurationUs > highWaterMark) { stopBufferingIfNecessary_l(); } } } else if (cachedDataRemaining >= 0) { ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes", cachedDataRemaining); if (cachedDataRemaining < kLowWaterMarkBytes) { startBufferingIfNecessary_l(); } else if (cachedDataRemaining > kHighWaterMarkBytes) { stopBufferingIfNecessary_l(); } } schedulePollBuffering_l(); } void NuPlayer::GenericSource::BufferingMonitor::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatPollBuffering: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); Mutex::Autolock _l(mLock); if (generation == mPollBufferingGeneration) { onPollBuffering_l(); } break; } default: TRESPASS(); break; } } } // namespace android media/libmediaplayerservice/nuplayer/GenericSource.h +81 −14 Original line number Diff line number Diff line Loading @@ -77,6 +77,8 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual bool isStreaming() const; virtual void setOffloadAudio(bool offload); protected: virtual ~GenericSource(); Loading Loading @@ -111,6 +113,83 @@ private: sp<AnotherPacketSource> mPackets; }; // Helper to monitor buffering status. The polling happens every second. // When necessary, it will send out buffering events to the player. struct BufferingMonitor : public AHandler { public: BufferingMonitor(const sp<AMessage> ¬ify); // Set up state. void prepare(const sp<NuCachedSource2> &cachedSource, const sp<WVMExtractor> &wvmExtractor, int64_t durationUs, int64_t bitrate, bool isStreaming); // Stop and reset buffering monitor. void stop(); // Cancel the current monitor task. void cancelPollBuffering(); // Restart the monitor task. void restartPollBuffering(); // Stop buffering task and send out corresponding events. void stopBufferingIfNecessary(); // Make sure data source is getting data. void ensureCacheIsFetching(); // Update media time of just extracted buffer from data source. void updateQueuedTime(bool isAudio, int64_t timeUs); // Set the offload mode. void setOffloadAudio(bool offload); // Update media time of last dequeued buffer which is sent to the decoder. void updateDequeuedBufferTime(int64_t mediaUs); protected: virtual ~BufferingMonitor(); virtual void onMessageReceived(const sp<AMessage> &msg); private: enum { kWhatPollBuffering, }; sp<AMessage> mNotify; sp<NuCachedSource2> mCachedSource; sp<WVMExtractor> mWVMExtractor; int64_t mDurationUs; int64_t mBitrate; bool mIsStreaming; int64_t mAudioTimeUs; int64_t mVideoTimeUs; int32_t mPollBufferingGeneration; bool mPrepareBuffering; bool mBuffering; int32_t mPrevBufferPercentage; mutable Mutex mLock; bool mOffloadAudio; int64_t mFirstDequeuedBufferRealUs; int64_t mFirstDequeuedBufferMediaUs; int64_t mlastDequeuedBufferMediaUs; void prepare_l(const sp<NuCachedSource2> &cachedSource, const sp<WVMExtractor> &wvmExtractor, int64_t durationUs, int64_t bitrate, bool isStreaming); void cancelPollBuffering_l(); void notifyBufferingUpdate_l(int32_t percentage); void startBufferingIfNecessary_l(); void stopBufferingIfNecessary_l(); void sendCacheStats_l(); void ensureCacheIsFetching_l(); int64_t getLastReadPosition_l(); void onPollBuffering_l(); void schedulePollBuffering_l(); }; Vector<sp<IMediaSource> > mSources; Track mAudioTrack; int64_t mAudioTimeUs; Loading Loading @@ -147,17 +226,15 @@ private: bool mStarted; bool mStopRead; int64_t mBitrate; int32_t mPollBufferingGeneration; sp<BufferingMonitor> mBufferingMonitor; uint32_t mPendingReadBufferTypes; bool mBuffering; bool mPrepareBuffering; int32_t mPrevBufferPercentage; sp<ABuffer> mGlobalTimedText; mutable Mutex mReadBufferLock; mutable Mutex mDisconnectLock; sp<ALooper> mLooper; sp<ALooper> mBufferingMonitorLooper; void resetDataSource(); Loading Loading @@ -212,16 +289,6 @@ private: void queueDiscontinuityIfNeeded( bool seeking, bool formatChange, media_track_type trackType, Track *track); void schedulePollBuffering(); void cancelPollBuffering(); void restartPollBuffering(); void onPollBuffering(); void notifyBufferingUpdate(int32_t percentage); void startBufferingIfNecessary(); void stopBufferingIfNecessary(); void sendCacheStats(); void ensureCacheIsFetching(); DISALLOW_EVIL_CONSTRUCTORS(GenericSource); }; Loading media/libmediaplayerservice/nuplayer/NuPlayer.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -1564,10 +1564,14 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<DecoderBase> *decoder) { determineAudioModeChange(); if (mOffloadAudio) { mSource->setOffloadAudio(true /* offload */); const bool hasVideo = (mSource->getFormat(false /*audio */) != NULL); format->setInt32("has-video", hasVideo); *decoder = new DecoderPassThrough(notify, mSource, mRenderer); } else { mSource->setOffloadAudio(false /* offload */); *decoder = new Decoder(notify, mSource, mPID, mRenderer); } } else { Loading media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -223,6 +223,11 @@ status_t NuPlayer::DecoderPassThrough::fetchInputData(sp<AMessage> &reply) { status_t err = dequeueAccessUnit(&accessUnit); if (err == -EWOULDBLOCK) { // Flush out the aggregate buffer to try to avoid underrun. accessUnit = aggregateBuffer(NULL /* accessUnit */); if (accessUnit != NULL) { break; } return err; } else if (err != OK) { if (err == INFO_DISCONTINUITY) { Loading media/libmediaplayerservice/nuplayer/NuPlayerSource.h +2 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
media/libmediaplayerservice/nuplayer/GenericSource.cpp +364 −198 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ 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; Loading @@ -66,11 +67,8 @@ NuPlayer::GenericSource::GenericSource( mFd(-1), mDrmManagerClient(NULL), mBitrate(-1ll), mPollBufferingGeneration(0), mPendingReadBufferTypes(0), mBuffering(false), mPrepareBuffering(false), mPrevBufferPercentage(-1) { mPendingReadBufferTypes(0) { mBufferingMonitor = new BufferingMonitor(notify); resetDataSource(); DataSource::RegisterDefaultSniffers(); } Loading @@ -91,6 +89,13 @@ void NuPlayer::GenericSource::resetDataSource() { mDrmManagerClient = NULL; mStarted = false; mStopRead = true; if (mBufferingMonitorLooper != NULL) { mBufferingMonitorLooper->unregisterHandler(mBufferingMonitor->id()); mBufferingMonitorLooper->stop(); mBufferingMonitorLooper = NULL; } mBufferingMonitor->stop(); } status_t NuPlayer::GenericSource::setDataSource( Loading Loading @@ -338,6 +343,10 @@ bool NuPlayer::GenericSource::isStreaming() const { return mIsStreaming; } void NuPlayer::GenericSource::setOffloadAudio(bool offload) { mBufferingMonitor->setOffloadAudio(offload); } NuPlayer::GenericSource::~GenericSource() { if (mLooper != NULL) { mLooper->unregisterHandler(id()); Loading Loading @@ -466,10 +475,18 @@ void NuPlayer::GenericSource::finishPrepareAsync() { } if (mIsStreaming) { mPrepareBuffering = true; if (mBufferingMonitorLooper == NULL) { mBufferingMonitor->prepare(mCachedSource, mWVMExtractor, mDurationUs, mBitrate, mIsStreaming); mBufferingMonitorLooper = new ALooper; mBufferingMonitorLooper->setName("GSBMonitor"); mBufferingMonitorLooper->start(); mBufferingMonitorLooper->registerHandler(mBufferingMonitor); } ensureCacheIsFetching(); restartPollBuffering(); mBufferingMonitor->ensureCacheIsFetching(); mBufferingMonitor->restartPollBuffering(); } else { notifyPrepared(); } Loading @@ -492,7 +509,7 @@ void NuPlayer::GenericSource::notifyPreparedAndCleanup(status_t err) { } mBitrate = -1; cancelPollBuffering(); mBufferingMonitor->cancelPollBuffering(); } notifyPrepared(err); } Loading Loading @@ -571,182 +588,6 @@ status_t NuPlayer::GenericSource::feedMoreTSData() { return OK; } void NuPlayer::GenericSource::schedulePollBuffering() { sp<AMessage> msg = new AMessage(kWhatPollBuffering, this); msg->setInt32("generation", mPollBufferingGeneration); msg->post(1000000ll); } void NuPlayer::GenericSource::cancelPollBuffering() { mBuffering = false; ++mPollBufferingGeneration; mPrevBufferPercentage = -1; } void NuPlayer::GenericSource::restartPollBuffering() { if (mIsStreaming) { cancelPollBuffering(); onPollBuffering(); } } void NuPlayer::GenericSource::notifyBufferingUpdate(int32_t percentage) { // Buffering percent could go backward as it's estimated from remaining // data and last access time. This could cause the buffering position // drawn on media control to jitter slightly. Remember previously reported // percentage and don't allow it to go backward. if (percentage < mPrevBufferPercentage) { percentage = mPrevBufferPercentage; } else if (percentage > 100) { percentage = 100; } mPrevBufferPercentage = percentage; ALOGV("notifyBufferingUpdate: buffering %d%%", percentage); sp<AMessage> msg = dupNotify(); msg->setInt32("what", kWhatBufferingUpdate); msg->setInt32("percentage", percentage); msg->post(); } void NuPlayer::GenericSource::startBufferingIfNecessary() { ALOGV("startBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d", mPrepareBuffering, mBuffering); if (mPrepareBuffering) { return; } if (!mBuffering) { mBuffering = true; ensureCacheIsFetching(); sendCacheStats(); sp<AMessage> notify = dupNotify(); notify->setInt32("what", kWhatPauseOnBufferingStart); notify->post(); } } void NuPlayer::GenericSource::stopBufferingIfNecessary() { ALOGV("stopBufferingIfNecessary: mPrepareBuffering=%d, mBuffering=%d", mPrepareBuffering, mBuffering); if (mPrepareBuffering) { mPrepareBuffering = false; notifyPrepared(); return; } if (mBuffering) { mBuffering = false; sendCacheStats(); sp<AMessage> notify = dupNotify(); notify->setInt32("what", kWhatResumeOnBufferingEnd); notify->post(); } } void NuPlayer::GenericSource::sendCacheStats() { int32_t kbps = 0; status_t err = UNKNOWN_ERROR; if (mWVMExtractor != NULL) { err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps); } else if (mCachedSource != NULL) { err = mCachedSource->getEstimatedBandwidthKbps(&kbps); } if (err == OK) { sp<AMessage> notify = dupNotify(); notify->setInt32("what", kWhatCacheStats); notify->setInt32("bandwidth", kbps); notify->post(); } } void NuPlayer::GenericSource::ensureCacheIsFetching() { if (mCachedSource != NULL) { mCachedSource->resumeFetchingIfNecessary(); } } void NuPlayer::GenericSource::onPollBuffering() { status_t finalStatus = UNKNOWN_ERROR; int64_t cachedDurationUs = -1ll; ssize_t cachedDataRemaining = -1; ALOGW_IF(mWVMExtractor != NULL && mCachedSource != NULL, "WVMExtractor and NuCachedSource both present"); if (mWVMExtractor != NULL) { cachedDurationUs = mWVMExtractor->getCachedDurationUs(&finalStatus); } else if (mCachedSource != NULL) { cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); if (finalStatus == OK) { off64_t size; int64_t bitrate = 0ll; if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) { bitrate = size * 8000000ll / mDurationUs; } else if (mBitrate > 0) { bitrate = mBitrate; } if (bitrate > 0) { cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate; } } } if (finalStatus != OK) { ALOGV("onPollBuffering: EOS (finalStatus = %d)", finalStatus); if (finalStatus == ERROR_END_OF_STREAM) { notifyBufferingUpdate(100); } stopBufferingIfNecessary(); return; } else if (cachedDurationUs >= 0ll) { if (mDurationUs > 0ll) { int64_t cachedPosUs = getLastReadPosition() + cachedDurationUs; int percentage = 100.0 * cachedPosUs / mDurationUs; if (percentage > 100) { percentage = 100; } notifyBufferingUpdate(percentage); } ALOGV("onPollBuffering: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f); if (cachedDurationUs < kLowWaterMarkUs) { startBufferingIfNecessary(); } else if (cachedDurationUs > kHighWaterMarkUs) { stopBufferingIfNecessary(); } } else if (cachedDataRemaining >= 0) { ALOGV("onPollBuffering: cachedDataRemaining %zd bytes", cachedDataRemaining); if (cachedDataRemaining < kLowWaterMarkBytes) { startBufferingIfNecessary(); } else if (cachedDataRemaining > kHighWaterMarkBytes) { stopBufferingIfNecessary(); } } schedulePollBuffering(); } void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatPrepareAsync: Loading Loading @@ -834,17 +675,7 @@ void NuPlayer::GenericSource::onMessageReceived(const sp<AMessage> &msg) { case kWhatStart: case kWhatResume: { restartPollBuffering(); break; } case kWhatPollBuffering: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation == mPollBufferingGeneration) { onPollBuffering(); } mBufferingMonitor->restartPollBuffering(); break; } Loading Loading @@ -1045,6 +876,10 @@ sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const { status_t NuPlayer::GenericSource::dequeueAccessUnit( bool audio, sp<ABuffer> *accessUnit) { if (!mStarted) { return -EWOULDBLOCK; } Track *track = audio ? &mAudioTrack : &mVideoTrack; if (track->mSource == NULL) { Loading Loading @@ -1091,6 +926,7 @@ status_t NuPlayer::GenericSource::dequeueAccessUnit( CHECK((*accessUnit)->meta()->findInt64("timeUs", &timeUs)); if (audio) { mAudioLastDequeueTimeUs = timeUs; mBufferingMonitor->updateDequeuedBufferTime(timeUs); } else { mVideoLastDequeueTimeUs = timeUs; } Loading Loading @@ -1377,6 +1213,8 @@ void NuPlayer::GenericSource::onSeek(sp<AMessage> msg) { } status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) { mBufferingMonitor->updateDequeuedBufferTime(-1ll); // If the Widevine source is stopped, do not attempt to read any // more buffers. if (mStopRead) { Loading @@ -1403,8 +1241,8 @@ status_t NuPlayer::GenericSource::doSeek(int64_t seekTimeUs) { // If currently buffering, post kWhatBufferingEnd first, so that // NuPlayer resumes. Otherwise, if cache hits high watermark // before new polling happens, no one will resume the playback. stopBufferingIfNecessary(); restartPollBuffering(); mBufferingMonitor->stopBufferingIfNecessary(); mBufferingMonitor->restartPollBuffering(); return OK; } Loading Loading @@ -1585,8 +1423,10 @@ void NuPlayer::GenericSource::readBuffer( CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs)); if (trackType == MEDIA_TRACK_TYPE_AUDIO) { mAudioTimeUs = timeUs; mBufferingMonitor->updateQueuedTime(true /* isAudio */, timeUs); } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) { mVideoTimeUs = timeUs; mBufferingMonitor->updateQueuedTime(false /* isAudio */, timeUs); } queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track); Loading Loading @@ -1630,4 +1470,330 @@ void NuPlayer::GenericSource::queueDiscontinuityIfNeeded( } } NuPlayer::GenericSource::BufferingMonitor::BufferingMonitor(const sp<AMessage> ¬ify) : mNotify(notify), mDurationUs(-1ll), mBitrate(-1ll), mIsStreaming(false), mAudioTimeUs(0), mVideoTimeUs(0), mPollBufferingGeneration(0), mPrepareBuffering(false), mBuffering(false), mPrevBufferPercentage(-1), mOffloadAudio(false), mFirstDequeuedBufferRealUs(-1ll), mFirstDequeuedBufferMediaUs(-1ll), mlastDequeuedBufferMediaUs(-1ll) { } NuPlayer::GenericSource::BufferingMonitor::~BufferingMonitor() { } void NuPlayer::GenericSource::BufferingMonitor::prepare( const sp<NuCachedSource2> &cachedSource, const sp<WVMExtractor> &wvmExtractor, int64_t durationUs, int64_t bitrate, bool isStreaming) { Mutex::Autolock _l(mLock); prepare_l(cachedSource, wvmExtractor, durationUs, bitrate, isStreaming); } void NuPlayer::GenericSource::BufferingMonitor::stop() { Mutex::Autolock _l(mLock); prepare_l(NULL /* cachedSource */, NULL /* wvmExtractor */, -1 /* durationUs */, -1 /* bitrate */, false /* isStreaming */); } void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering() { Mutex::Autolock _l(mLock); cancelPollBuffering_l(); } void NuPlayer::GenericSource::BufferingMonitor::restartPollBuffering() { Mutex::Autolock _l(mLock); if (mIsStreaming) { cancelPollBuffering_l(); onPollBuffering_l(); } } void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary() { Mutex::Autolock _l(mLock); stopBufferingIfNecessary_l(); } void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching() { Mutex::Autolock _l(mLock); ensureCacheIsFetching_l(); } void NuPlayer::GenericSource::BufferingMonitor::updateQueuedTime(bool isAudio, int64_t timeUs) { Mutex::Autolock _l(mLock); if (isAudio) { mAudioTimeUs = timeUs; } else { mVideoTimeUs = timeUs; } } void NuPlayer::GenericSource::BufferingMonitor::setOffloadAudio(bool offload) { Mutex::Autolock _l(mLock); mOffloadAudio = offload; } void NuPlayer::GenericSource::BufferingMonitor::updateDequeuedBufferTime(int64_t mediaUs) { Mutex::Autolock _l(mLock); if (mediaUs < 0) { mFirstDequeuedBufferRealUs = -1ll; mFirstDequeuedBufferMediaUs = -1ll; } else if (mFirstDequeuedBufferRealUs < 0) { mFirstDequeuedBufferRealUs = ALooper::GetNowUs(); mFirstDequeuedBufferMediaUs = mediaUs; } mlastDequeuedBufferMediaUs = mediaUs; } void NuPlayer::GenericSource::BufferingMonitor::prepare_l( const sp<NuCachedSource2> &cachedSource, const sp<WVMExtractor> &wvmExtractor, int64_t durationUs, int64_t bitrate, bool isStreaming) { ALOGW_IF(wvmExtractor != NULL && cachedSource != NULL, "WVMExtractor and NuCachedSource are both present when " "BufferingMonitor::prepare_l is called, ignore NuCachedSource"); mCachedSource = cachedSource; mWVMExtractor = wvmExtractor; mDurationUs = durationUs; mBitrate = bitrate; mIsStreaming = isStreaming; mAudioTimeUs = 0; mVideoTimeUs = 0; mPrepareBuffering = true; cancelPollBuffering_l(); mOffloadAudio = false; mFirstDequeuedBufferRealUs = -1ll; mFirstDequeuedBufferMediaUs = -1ll; mlastDequeuedBufferMediaUs = -1ll; } void NuPlayer::GenericSource::BufferingMonitor::cancelPollBuffering_l() { mBuffering = false; ++mPollBufferingGeneration; mPrevBufferPercentage = -1; } void NuPlayer::GenericSource::BufferingMonitor::notifyBufferingUpdate_l(int32_t percentage) { // Buffering percent could go backward as it's estimated from remaining // data and last access time. This could cause the buffering position // drawn on media control to jitter slightly. Remember previously reported // percentage and don't allow it to go backward. if (percentage < mPrevBufferPercentage) { percentage = mPrevBufferPercentage; } else if (percentage > 100) { percentage = 100; } mPrevBufferPercentage = percentage; ALOGV("notifyBufferingUpdate_l: buffering %d%%", percentage); sp<AMessage> msg = mNotify->dup(); msg->setInt32("what", kWhatBufferingUpdate); msg->setInt32("percentage", percentage); msg->post(); } void NuPlayer::GenericSource::BufferingMonitor::startBufferingIfNecessary_l() { ALOGD("startBufferingIfNecessary_l: mPrepareBuffering=%d, mBuffering=%d", mPrepareBuffering, mBuffering); if (mPrepareBuffering) { return; } if (!mBuffering) { mBuffering = true; ensureCacheIsFetching_l(); sendCacheStats_l(); sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatPauseOnBufferingStart); notify->post(); } } void NuPlayer::GenericSource::BufferingMonitor::stopBufferingIfNecessary_l() { ALOGD("stopBufferingIfNecessary_l: mPrepareBuffering=%d, mBuffering=%d", mPrepareBuffering, mBuffering); if (mPrepareBuffering) { mPrepareBuffering = false; sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatPrepared); notify->setInt32("err", OK); notify->post(); return; } if (mBuffering) { mBuffering = false; sendCacheStats_l(); sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatResumeOnBufferingEnd); notify->post(); } } void NuPlayer::GenericSource::BufferingMonitor::sendCacheStats_l() { int32_t kbps = 0; status_t err = UNKNOWN_ERROR; if (mWVMExtractor != NULL) { err = mWVMExtractor->getEstimatedBandwidthKbps(&kbps); } else if (mCachedSource != NULL) { err = mCachedSource->getEstimatedBandwidthKbps(&kbps); } if (err == OK) { sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatCacheStats); notify->setInt32("bandwidth", kbps); notify->post(); } } void NuPlayer::GenericSource::BufferingMonitor::ensureCacheIsFetching_l() { if (mCachedSource != NULL) { mCachedSource->resumeFetchingIfNecessary(); } } void NuPlayer::GenericSource::BufferingMonitor::schedulePollBuffering_l() { sp<AMessage> msg = new AMessage(kWhatPollBuffering, this); msg->setInt32("generation", mPollBufferingGeneration); // Enquires buffering status every second. msg->post(1000000ll); } int64_t NuPlayer::GenericSource::BufferingMonitor::getLastReadPosition_l() { if (mAudioTimeUs > 0) { return mAudioTimeUs; } else if (mVideoTimeUs > 0) { return mVideoTimeUs; } else { return 0; } } void NuPlayer::GenericSource::BufferingMonitor::onPollBuffering_l() { status_t finalStatus = UNKNOWN_ERROR; int64_t cachedDurationUs = -1ll; ssize_t cachedDataRemaining = -1; if (mWVMExtractor != NULL) { cachedDurationUs = mWVMExtractor->getCachedDurationUs(&finalStatus); } else if (mCachedSource != NULL) { cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus); if (finalStatus == OK) { off64_t size; int64_t bitrate = 0ll; if (mDurationUs > 0 && mCachedSource->getSize(&size) == OK) { // |bitrate| uses bits/second unit, while size is number of bytes. bitrate = size * 8000000ll / mDurationUs; } else if (mBitrate > 0) { bitrate = mBitrate; } if (bitrate > 0) { cachedDurationUs = cachedDataRemaining * 8000000ll / bitrate; } } } if (finalStatus != OK) { ALOGV("onPollBuffering_l: EOS (finalStatus = %d)", finalStatus); if (finalStatus == ERROR_END_OF_STREAM) { notifyBufferingUpdate_l(100); } stopBufferingIfNecessary_l(); return; } else if (cachedDurationUs >= 0ll) { if (mDurationUs > 0ll) { int64_t cachedPosUs = getLastReadPosition_l() + cachedDurationUs; int percentage = 100.0 * cachedPosUs / mDurationUs; if (percentage > 100) { percentage = 100; } notifyBufferingUpdate_l(percentage); } ALOGV("onPollBuffering_l: cachedDurationUs %.1f sec", cachedDurationUs / 1000000.0f); if (cachedDurationUs < kLowWaterMarkUs) { // Take into account the data cached in downstream components to try to avoid // unnecessary pause. if (mOffloadAudio && mFirstDequeuedBufferRealUs >= 0) { int64_t downStreamCacheUs = mlastDequeuedBufferMediaUs - mFirstDequeuedBufferMediaUs - (ALooper::GetNowUs() - mFirstDequeuedBufferRealUs); if (downStreamCacheUs > 0) { cachedDurationUs += downStreamCacheUs; } } if (cachedDurationUs < kLowWaterMarkUs) { startBufferingIfNecessary_l(); } } else { int64_t highWaterMark = mPrepareBuffering ? kHighWaterMarkUs : kHighWaterMarkRebufferUs; if (cachedDurationUs > highWaterMark) { stopBufferingIfNecessary_l(); } } } else if (cachedDataRemaining >= 0) { ALOGV("onPollBuffering_l: cachedDataRemaining %zd bytes", cachedDataRemaining); if (cachedDataRemaining < kLowWaterMarkBytes) { startBufferingIfNecessary_l(); } else if (cachedDataRemaining > kHighWaterMarkBytes) { stopBufferingIfNecessary_l(); } } schedulePollBuffering_l(); } void NuPlayer::GenericSource::BufferingMonitor::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatPollBuffering: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); Mutex::Autolock _l(mLock); if (generation == mPollBufferingGeneration) { onPollBuffering_l(); } break; } default: TRESPASS(); break; } } } // namespace android
media/libmediaplayerservice/nuplayer/GenericSource.h +81 −14 Original line number Diff line number Diff line Loading @@ -77,6 +77,8 @@ struct NuPlayer::GenericSource : public NuPlayer::Source { virtual bool isStreaming() const; virtual void setOffloadAudio(bool offload); protected: virtual ~GenericSource(); Loading Loading @@ -111,6 +113,83 @@ private: sp<AnotherPacketSource> mPackets; }; // Helper to monitor buffering status. The polling happens every second. // When necessary, it will send out buffering events to the player. struct BufferingMonitor : public AHandler { public: BufferingMonitor(const sp<AMessage> ¬ify); // Set up state. void prepare(const sp<NuCachedSource2> &cachedSource, const sp<WVMExtractor> &wvmExtractor, int64_t durationUs, int64_t bitrate, bool isStreaming); // Stop and reset buffering monitor. void stop(); // Cancel the current monitor task. void cancelPollBuffering(); // Restart the monitor task. void restartPollBuffering(); // Stop buffering task and send out corresponding events. void stopBufferingIfNecessary(); // Make sure data source is getting data. void ensureCacheIsFetching(); // Update media time of just extracted buffer from data source. void updateQueuedTime(bool isAudio, int64_t timeUs); // Set the offload mode. void setOffloadAudio(bool offload); // Update media time of last dequeued buffer which is sent to the decoder. void updateDequeuedBufferTime(int64_t mediaUs); protected: virtual ~BufferingMonitor(); virtual void onMessageReceived(const sp<AMessage> &msg); private: enum { kWhatPollBuffering, }; sp<AMessage> mNotify; sp<NuCachedSource2> mCachedSource; sp<WVMExtractor> mWVMExtractor; int64_t mDurationUs; int64_t mBitrate; bool mIsStreaming; int64_t mAudioTimeUs; int64_t mVideoTimeUs; int32_t mPollBufferingGeneration; bool mPrepareBuffering; bool mBuffering; int32_t mPrevBufferPercentage; mutable Mutex mLock; bool mOffloadAudio; int64_t mFirstDequeuedBufferRealUs; int64_t mFirstDequeuedBufferMediaUs; int64_t mlastDequeuedBufferMediaUs; void prepare_l(const sp<NuCachedSource2> &cachedSource, const sp<WVMExtractor> &wvmExtractor, int64_t durationUs, int64_t bitrate, bool isStreaming); void cancelPollBuffering_l(); void notifyBufferingUpdate_l(int32_t percentage); void startBufferingIfNecessary_l(); void stopBufferingIfNecessary_l(); void sendCacheStats_l(); void ensureCacheIsFetching_l(); int64_t getLastReadPosition_l(); void onPollBuffering_l(); void schedulePollBuffering_l(); }; Vector<sp<IMediaSource> > mSources; Track mAudioTrack; int64_t mAudioTimeUs; Loading Loading @@ -147,17 +226,15 @@ private: bool mStarted; bool mStopRead; int64_t mBitrate; int32_t mPollBufferingGeneration; sp<BufferingMonitor> mBufferingMonitor; uint32_t mPendingReadBufferTypes; bool mBuffering; bool mPrepareBuffering; int32_t mPrevBufferPercentage; sp<ABuffer> mGlobalTimedText; mutable Mutex mReadBufferLock; mutable Mutex mDisconnectLock; sp<ALooper> mLooper; sp<ALooper> mBufferingMonitorLooper; void resetDataSource(); Loading Loading @@ -212,16 +289,6 @@ private: void queueDiscontinuityIfNeeded( bool seeking, bool formatChange, media_track_type trackType, Track *track); void schedulePollBuffering(); void cancelPollBuffering(); void restartPollBuffering(); void onPollBuffering(); void notifyBufferingUpdate(int32_t percentage); void startBufferingIfNecessary(); void stopBufferingIfNecessary(); void sendCacheStats(); void ensureCacheIsFetching(); DISALLOW_EVIL_CONSTRUCTORS(GenericSource); }; Loading
media/libmediaplayerservice/nuplayer/NuPlayer.cpp +4 −0 Original line number Diff line number Diff line Loading @@ -1564,10 +1564,14 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<DecoderBase> *decoder) { determineAudioModeChange(); if (mOffloadAudio) { mSource->setOffloadAudio(true /* offload */); const bool hasVideo = (mSource->getFormat(false /*audio */) != NULL); format->setInt32("has-video", hasVideo); *decoder = new DecoderPassThrough(notify, mSource, mRenderer); } else { mSource->setOffloadAudio(false /* offload */); *decoder = new Decoder(notify, mSource, mPID, mRenderer); } } else { Loading
media/libmediaplayerservice/nuplayer/NuPlayerDecoderPassThrough.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -223,6 +223,11 @@ status_t NuPlayer::DecoderPassThrough::fetchInputData(sp<AMessage> &reply) { status_t err = dequeueAccessUnit(&accessUnit); if (err == -EWOULDBLOCK) { // Flush out the aggregate buffer to try to avoid underrun. accessUnit = aggregateBuffer(NULL /* accessUnit */); if (accessUnit != NULL) { break; } return err; } else if (err != OK) { if (err == INFO_DISCONTINUITY) { Loading
media/libmediaplayerservice/nuplayer/NuPlayerSource.h +2 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes