Bug 1216460 - [2.2] Refactor SourceBuffer frame eviction and threshold defaults. r=jya
authorEugen Sawin <esawin@mozilla.com>
Fri, 18 Mar 2016 22:26:56 +0100
changeset 289946 9ffa65c64e14209ebd0ce7a44b7254a6c5fc6b9e
parent 289945 6495286a5790d50950cb6c2b9afdae0ef1fe4538
child 289947 602b90a3250ad6603ec839cbb1ba8e4ce1751e5d
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya
bugs1216460
milestone48.0a1
Bug 1216460 - [2.2] Refactor SourceBuffer frame eviction and threshold defaults. r=jya * Move eviction handling out of SourceBuffer into TrackBuffersManager * Separate audio and video eviction thresholds * Reduce default audio eviction threshold to 15MB
dom/media/mediasource/SourceBuffer.cpp
dom/media/mediasource/SourceBuffer.h
dom/media/mediasource/SourceBufferContentManager.h
dom/media/mediasource/SourceBufferResource.h
dom/media/mediasource/TrackBuffersManager.cpp
dom/media/mediasource/TrackBuffersManager.h
--- a/dom/media/mediasource/SourceBuffer.cpp
+++ b/dom/media/mediasource/SourceBuffer.cpp
@@ -290,18 +290,16 @@ SourceBuffer::SourceBuffer(MediaSource* 
   : DOMEventTargetHelper(aMediaSource->GetParentObject())
   , mMediaSource(aMediaSource)
   , mUpdating(false)
   , mActive(false)
   , mType(aType)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aMediaSource);
-  mEvictionThreshold = Preferences::GetUint("media.mediasource.eviction_threshold",
-                                            100 * (1 << 20));
   bool generateTimestamps = false;
   if (aType.LowerCaseEqualsLiteral("audio/mpeg") ||
       aType.LowerCaseEqualsLiteral("audio/aac")) {
     generateTimestamps = true;
   }
   mAttributes = new SourceBufferAttributes(generateTimestamps);
 
   mContentManager =
@@ -519,34 +517,33 @@ SourceBuffer::PrepareAppend(const uint8_
   // evict data before that range across all SourceBuffers it knows
   // about.
   // TODO: Make the eviction threshold smaller for audio-only streams.
   // TODO: Drive evictions off memory pressure notifications.
   // TODO: Consider a global eviction threshold  rather than per TrackBuffer.
   TimeUnit newBufferStartTime;
   // Attempt to evict the amount of data we are about to add by lowering the
   // threshold.
-  uint32_t toEvict =
-    (mEvictionThreshold > aLength) ? mEvictionThreshold - aLength : aLength;
   Result evicted =
     mContentManager->EvictData(TimeUnit::FromSeconds(mMediaSource->GetDecoder()->GetCurrentTime()),
-                               toEvict, &newBufferStartTime);
+                               aLength, &newBufferStartTime);
   if (evicted == Result::DATA_EVICTED) {
     MSE_DEBUG("AppendData Evict; current buffered start=%f",
               GetBufferedStart());
 
     // We notify that we've evicted from the time range 0 through to
     // the current start point.
     mMediaSource->NotifyEvicted(0.0, newBufferStartTime.ToSeconds());
   }
 
   // See if we have enough free space to append our new data.
   // As we can only evict once we have playable data, we must give a chance
   // to the DASH player to provide a complete media segment.
-  if (aLength > mEvictionThreshold || evicted == Result::BUFFER_FULL) {
+  if (aLength > mContentManager->EvictionThreshold() ||
+      evicted == Result::BUFFER_FULL) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     return nullptr;
   }
 
   RefPtr<MediaByteBuffer> data = new MediaByteBuffer();
   if (!data->AppendElements(aData, aLength, fallible)) {
     aRv.Throw(NS_ERROR_DOM_QUOTA_EXCEEDED_ERR);
     return nullptr;
--- a/dom/media/mediasource/SourceBuffer.h
+++ b/dom/media/mediasource/SourceBuffer.h
@@ -248,18 +248,16 @@ private:
                                                   uint32_t aLength,
                                                   ErrorResult& aRv);
 
   void AppendDataCompletedWithSuccess(bool aHasActiveTracks);
   void AppendDataErrored(nsresult aError);
 
   RefPtr<MediaSource> mMediaSource;
 
-  uint32_t mEvictionThreshold;
-
   RefPtr<SourceBufferContentManager> mContentManager;
   RefPtr<SourceBufferAttributes> mAttributes;
 
   bool mUpdating;
 
   mozilla::Atomic<bool> mActive;
 
   MozPromiseRequestHolder<SourceBufferContentManager::AppendPromise> mPendingAppend;
--- a/dom/media/mediasource/SourceBufferContentManager.h
+++ b/dom/media/mediasource/SourceBufferContentManager.h
@@ -102,16 +102,17 @@ public:
   virtual AppendState GetAppendState()
   {
     return AppendState::WAITING_FOR_SEGMENT;
   }
 
   virtual void SetGroupStartTimestamp(const media::TimeUnit& aGroupStartTimestamp) {}
   virtual void RestartGroupStartTimestamp() {}
   virtual media::TimeUnit GroupEndTimestamp() = 0;
+  virtual int64_t EvictionThreshold() const = 0;
 
 protected:
   virtual ~SourceBufferContentManager() { }
 };
 
 } // namespace mozilla
 
 #endif /* MOZILLA_SOURCEBUFFERCONTENTMANAGER_H_ */
--- a/dom/media/mediasource/SourceBufferResource.h
+++ b/dom/media/mediasource/SourceBufferResource.h
@@ -106,19 +106,19 @@ public:
   // Used by SourceBuffer.
   void AppendData(MediaByteBuffer* aData);
   void Ended();
   bool IsEnded()
   {
     ReentrantMonitorAutoEnter mon(mMonitor);
     return mEnded;
   }
-  // Remove data from resource if it holds more than the threshold
-  // number of bytes. Returns amount evicted.
-  uint32_t EvictData(uint64_t aPlaybackOffset, int64_t aThreshold,
+  // Remove data from resource if it holds more than the threshold reduced by
+  // the given number of bytes. Returns amount evicted.
+  uint32_t EvictData(uint64_t aPlaybackOffset, int64_t aThresholdReduct,
                      ErrorResult& aRv);
 
   // Remove data from resource before the given offset.
   void EvictBefore(uint64_t aOffset, ErrorResult& aRv);
 
   // Remove all data from the resource
   uint32_t EvictAll();
 
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -94,18 +94,20 @@ TrackBuffersManager::TrackBuffersManager
   , mNewMediaSegmentStarted(false)
   , mActiveTrack(false)
   , mType(aType)
   , mParser(ContainerParser::CreateForMIMEType(aType))
   , mProcessedInput(0)
   , mTaskQueue(aParentDecoder->GetDemuxer()->GetTaskQueue())
   , mSourceBufferAttributes(aAttributes)
   , mParentDecoder(new nsMainThreadPtrHolder<MediaSourceDecoder>(aParentDecoder, false /* strict */))
-  , mEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold",
-                                            100 * (1 << 20)))
+  , mVideoEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold.video",
+                                                 100 * 1024 * 1024))
+  , mAudioEvictionThreshold(Preferences::GetUint("media.mediasource.eviction_threshold.audio",
+                                                 15 * 1024 * 1024))
   , mEvictionOccurred(false)
   , mMonitor("TrackBuffersManager")
   , mAppendRunning(false)
 {
   MOZ_ASSERT(NS_IsMainThread(), "Must be instanciated on the main thread");
 }
 
 TrackBuffersManager::~TrackBuffersManager()
@@ -197,19 +199,23 @@ TrackBuffersManager::RangeRemoval(TimeUn
 }
 
 TrackBuffersManager::EvictDataResult
 TrackBuffersManager::EvictData(TimeUnit aPlaybackTime,
                                int64_t aThresholdReduct,
                                TimeUnit* aBufferStartTime)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  MSE_DEBUG("");
+
+  const int64_t toEvict = GetSize() -
+    std::max(EvictionThreshold() - aThresholdReduct, aThresholdReduct);
 
-  int64_t toEvict = GetSize() - aThreshold;
+  MSE_DEBUG("buffered=%lldkb, eviction threshold=%ukb, evict=%lldkb",
+            GetSize() / 1024, EvictionThreshold() / 1024, toEvict / 1024);
+
   if (toEvict <= 0) {
     return EvictDataResult::NO_DATA_EVICTED;
   }
   if (toEvict <= 512*1024) {
     // Don't bother evicting less than 512KB.
     return EvictDataResult::CANT_EVICT;
   }
 
@@ -346,16 +352,25 @@ TrackBuffersManager::CompleteResetParser
 
   // 8. Set append state to WAITING_FOR_SEGMENT.
   SetAppendState(AppendState::WAITING_FOR_SEGMENT);
 
   // Reject our promise immediately.
   mAppendPromise.RejectIfExists(NS_ERROR_ABORT, __func__);
 }
 
+int64_t
+TrackBuffersManager::EvictionThreshold() const
+{
+  if (HasVideo()) {
+    return mVideoEvictionThreshold;
+  }
+  return mAudioEvictionThreshold;
+}
+
 void
 TrackBuffersManager::DoEvictData(const TimeUnit& aPlaybackTime,
                                  int64_t aSizeToEvict)
 {
   MOZ_ASSERT(OnTaskQueue());
 
   // Video is what takes the most space, only evict there if we have video.
   const auto& track = HasVideo() ? mVideoTracks : mAudioTracks;
@@ -496,17 +511,17 @@ TrackBuffersManager::CodedFrameRemoval(T
   }
 
   UpdateBufferedRanges();
 
   // Update our reported total size.
   mSizeSourceBuffer = mVideoTracks.mSizeBuffer + mAudioTracks.mSizeBuffer;
 
   // 4. If buffer full flag equals true and this object is ready to accept more bytes, then set the buffer full flag to false.
-  if (mBufferFull && mSizeSourceBuffer < mEvictionThreshold) {
+  if (mBufferFull && mSizeSourceBuffer < EvictionThreshold()) {
     mBufferFull = false;
   }
   mEvictionOccurred = true;
 
   return dataRemoved;
 }
 
 void
@@ -1232,17 +1247,17 @@ TrackBuffersManager::CompleteCodedFrameP
 
   UpdateBufferedRanges();
 
   // 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.
-  if (mSizeSourceBuffer >= mEvictionThreshold) {
+  if (mSizeSourceBuffer >= EvictionThreshold()) {
     mBufferFull = true;
     mEvictionOccurred = false;
   }
 
   // 5. If the input buffer does not contain a complete media segment, then jump to the need more data step below.
   if (mParser->MediaSegmentRange().IsEmpty()) {
     ResolveProcessing(true, __func__);
     return;
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -72,16 +72,17 @@ public:
   AppendState GetAppendState() override
   {
     return mAppendState;
   }
 
   void SetGroupStartTimestamp(const media::TimeUnit& aGroupStartTimestamp) override;
   void RestartGroupStartTimestamp() override;
   media::TimeUnit GroupEndTimestamp() override;
+  int64_t EvictionThreshold() const override;
 
   // Interface for MediaSourceDemuxer
   MediaInfo GetMetadata();
   const TrackBuffer& GetTrackBuffer(TrackInfo::TrackType aTrack);
   const media::TimeIntervals& Buffered(TrackInfo::TrackType);
   media::TimeIntervals SafeBuffered(TrackInfo::TrackType) const;
   bool IsEnded() const
   {
@@ -339,17 +340,18 @@ private:
   RefPtr<dom::SourceBufferAttributes> mSourceBufferAttributes;
   nsMainThreadPtrHandle<MediaSourceDecoder> mParentDecoder;
 
   // Set to true if mediasource state changed to ended.
   Atomic<bool> mEnded;
 
   // Global size of this source buffer content.
   Atomic<int64_t> mSizeSourceBuffer;
-  uint32_t mEvictionThreshold;
+  int64_t mVideoEvictionThreshold;
+  int64_t mAudioEvictionThreshold;
   Atomic<bool> mEvictionOccurred;
 
   // Monitor to protect following objects accessed across multipple threads.
   // mMonitor is also notified if the value of mAppendRunning becomes false.
   mutable Monitor mMonitor;
   // Set to true while a BufferAppend is running or is pending.
   Atomic<bool> mAppendRunning;
   // Stable audio and video track time ranges.