From 4708ca920e6a7aabda46d48927f0e488739e0e7d Mon Sep 17 00:00:00 2001 From: trav90 Date: Thu, 4 May 2017 02:29:08 -0500 Subject: [PATCH] Add eviction support to TrackBuffersManager We evict data in two steps. Up to playback time, or tail data. --- dom/media/mediasource/TrackBuffersManager.cpp | 95 ++++++++++++++++++- dom/media/mediasource/TrackBuffersManager.h | 7 ++ 2 files changed, 99 insertions(+), 3 deletions(-) diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index d62389fba6..16ed1d5a59 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -129,7 +129,20 @@ TrackBuffersManager::EvictData(TimeUnit aPlaybackTime, uint32_t aThreshold, TimeUnit* aBufferStartTime) { - // TODO. + MOZ_ASSERT(NS_IsMainThread()); + + int64_t toEvict = GetSize() - aThreshold; + if (toEvict <= 0) { + return EvictDataResult::NO_DATA_EVICTED; + } + MSE_DEBUG("Reaching our size limit, schedule eviction of %lld bytes", toEvict); + + nsCOMPtr task = + NS_NewRunnableMethodWithArgs( + this, &TrackBuffersManager::DoEvictData, + aPlaybackTime, toEvict); + GetTaskQueue()->Dispatch(task.forget()); + return EvictDataResult::NO_DATA_EVICTED; } @@ -182,8 +195,7 @@ TrackBuffersManager::Buffered() int64_t TrackBuffersManager::GetSize() { - // TODO - return 0; + return mSizeSourceBuffer; } void @@ -280,6 +292,70 @@ TrackBuffersManager::CompleteResetParserState() mAbort = false; } +void +TrackBuffersManager::DoEvictData(const TimeUnit& aPlaybackTime, + uint32_t aSizeToEvict) +{ + MOZ_ASSERT(OnTaskQueue()); + + // Remove any data we've already played, up to 5s behind. + TimeUnit lowerLimit = aPlaybackTime - TimeUnit::FromSeconds(5); + TimeUnit to; + // Video is what takes the most space, only evict there if we have video. + const auto& track = HasVideo() ? mVideoTracks : mAudioTracks; + const auto& buffer = track.mBuffers.LastElement(); + uint32_t lastKeyFrameIndex = 0; + int64_t toEvict = aSizeToEvict; + uint32_t partialEvict = 0; + for (uint32_t i = 0; i < buffer.Length(); i++) { + const auto& frame = buffer[i]; + if (frame->mKeyframe) { + lastKeyFrameIndex = i; + toEvict -= partialEvict; + if (toEvict < 0) { + break; + } + partialEvict = 0; + } + if (frame->mTime >= lowerLimit.ToMicroseconds()) { + break; + } + partialEvict += sizeof(*frame) + frame->Size(); + } + if (lastKeyFrameIndex > 0) { + CodedFrameRemoval( + TimeInterval(TimeUnit::FromMicroseconds(0), + TimeUnit::FromMicroseconds(buffer[lastKeyFrameIndex-1]->mTime))); + } + if (toEvict <= 0) { + return; + } + + // Still some to remove. Remove data starting from the end, up to 5s ahead + // of our playtime. + TimeUnit upperLimit = aPlaybackTime + TimeUnit::FromSeconds(5); + for (int32_t i = buffer.Length() - 1; i >= 0; i--) { + const auto& frame = buffer[i]; + if (frame->mKeyframe) { + lastKeyFrameIndex = i; + toEvict -= partialEvict; + if (toEvict < 0) { + break; + } + partialEvict = 0; + } + if (frame->mTime <= upperLimit.ToMicroseconds()) { + break; + } + partialEvict += sizeof(*frame) + frame->Size(); + } + if (lastKeyFrameIndex < buffer.Length()) { + CodedFrameRemoval( + TimeInterval(TimeUnit::FromMicroseconds(buffer[lastKeyFrameIndex+1]->mTime), + TimeUnit::FromInfinity())); + } +} + void TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval) { @@ -332,6 +408,7 @@ TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval) TimeInterval(TimeUnit::FromMicroseconds(frame->mTime), TimeUnit::FromMicroseconds(frame->mTime + frame->mDuration))); } + track->mSizeBuffer -= sizeof(*frame) + frame->Size(); data.RemoveElementAt(i); } } @@ -346,6 +423,7 @@ TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval) removedInterval = removedInterval.Span( TimeInterval(TimeUnit::FromMicroseconds(frame->mTime), TimeUnit::FromMicroseconds(frame->mTime + frame->mDuration))); + track->mSizeBuffer -= sizeof(*frame) + frame->Size(); data.RemoveElementAt(i); } } @@ -369,6 +447,9 @@ TrackBuffersManager::CodedFrameRemoval(TimeInterval aInterval) MSE_DEBUG("after video ranges=%s", DumpTimeRanges(mVideoTracks.mBufferedRanges).get()); MSE_DEBUG("after audio ranges=%s", DumpTimeRanges(mAudioTracks.mBufferedRanges).get()); + // Update our reported total size. + mSizeSourceBuffer = mVideoTracks.mSizeBuffer + mAudioTracks.mSizeBuffer; + mRangeRemovalPromise.ResolveIfExists(true, __func__); } @@ -884,6 +965,9 @@ TrackBuffersManager::CompleteCodedFrameProcessing() mAudioBufferedRanges = mAudioTracks.mBufferedRanges; } + // Update our reported total size. + mSizeSourceBuffer = mVideoTracks.mSizeBuffer + mAudioTracks.mSizeBuffer; + // Return to step 6.4 of Segment Parser Loop algorithm // 4. If this SourceBuffer is full and cannot accept more media data, then set the buffer full flag to true. // TODO @@ -1039,6 +1123,7 @@ TrackBuffersManager::ProcessFrame(MediaRawData* aSample, TimeInterval(TimeUnit::FromMicroseconds(sample->mTime), TimeUnit::FromMicroseconds(sample->mTime + sample->mDuration))); } + trackBuffer.mSizeBuffer -= sizeof(*sample) + sample->Size(); data.RemoveElementAt(i); } } @@ -1057,6 +1142,7 @@ TrackBuffersManager::ProcessFrame(MediaRawData* aSample, TimeInterval(TimeUnit::FromMicroseconds(sample->mTime), TimeUnit::FromMicroseconds(sample->mTime + sample->mDuration))); } + trackBuffer.mSizeBuffer -= sizeof(*sample) + sample->Size(); data.RemoveElementAt(i); } } @@ -1073,6 +1159,7 @@ TrackBuffersManager::ProcessFrame(MediaRawData* aSample, removedInterval = removedInterval.Span( TimeInterval(TimeUnit::FromMicroseconds(sample->mTime), TimeUnit::FromMicroseconds(sample->mTime + sample->mDuration))); + trackBuffer.mSizeBuffer -= sizeof(*aSample) + sample->Size(); data.RemoveElementAt(i); } // Update our buffered range to exclude the range just removed. @@ -1087,6 +1174,8 @@ TrackBuffersManager::ProcessFrame(MediaRawData* aSample, } else { data.AppendElement(aSample); } + trackBuffer.mSizeBuffer += sizeof(*aSample) + aSample->Size(); + // 17. Set last decode timestamp for track buffer to decode timestamp. trackBuffer.mLastDecodeTimestamp = Some(decodeTimestamp); // 18. Set last frame duration for track buffer to frame duration. diff --git a/dom/media/mediasource/TrackBuffersManager.h b/dom/media/mediasource/TrackBuffersManager.h index c037b1865e..e806205790 100644 --- a/dom/media/mediasource/TrackBuffersManager.h +++ b/dom/media/mediasource/TrackBuffersManager.h @@ -159,10 +159,13 @@ private: OnDemuxFailed(TrackType::kAudioTrack, aFailure); } + void DoEvictData(const TimeUnit& aPlaybackTime, uint32_t aThreshold); + struct TrackData { TrackData() : mNumTracks(0) , mNeedRandomAccessPoint(true) + , mSizeBuffer(0) {} uint32_t mNumTracks; Maybe mLastDecodeTimestamp; @@ -176,6 +179,7 @@ private: // We only manage a single track of each type at this time. nsTArray mBuffers; TimeIntervals mBufferedRanges; + uint32_t mSizeBuffer; }; bool ProcessFrame(MediaRawData* aSample, TrackData& aTrackData); MediaPromiseRequestHolder mProcessingRequest; @@ -223,6 +227,9 @@ private: // Set to true if mediasource state changed to ended. Atomic mEnded; + // Global size of this source buffer content. + Atomic mSizeSourceBuffer; + // Monitor to protect following objects accessed across multiple threads. mutable Monitor mMonitor; // Set by the main thread, but only when all our tasks are completes