Skip to content


Browse files Browse the repository at this point in the history
[MSE] Limit the number of samples stored in SourceBuffer

Reviewed by Philippe Normand.

Applications may append a lot of samples without triggering eviction algorithm (> 500K), which results in cleanup (on
player destruction) taking too long time.

This can easily happen in videos with a static image, for example a black screen, that are only focused on audio. Then
the video samples number can grow a lot because the samples themselves are not big and to achieve a big size, you can
need many of them. The result is that we have lots of objects if little data and it can take a long time to destruct them.

This change is no-op for non GStreamer ports and in GStreamer ports it allows to define an environment variable to limit
the number of samples.

Based on a patch by Eugene Mutavchi <>.

* Source/WebCore/platform/graphics/SourceBufferPrivate.cpp:
(WebCore::SourceBufferPrivate::platformEvictionThreshold const):
(WebCore::SourceBufferPrivate::hasTooManySamples const):
* Source/WebCore/platform/graphics/SourceBufferPrivate.h:
* Source/WebCore/platform/graphics/gstreamer/mse/SourceBufferPrivateGStreamer.cpp:
(WebCore::SourceBufferPrivateGStreamer::platformEvictionThreshold const):
* Source/WebCore/platform/graphics/gstreamer/mse/SourceBufferPrivateGStreamer.h:

Canonical link:
  • Loading branch information
calvaris committed Jun 21, 2023
1 parent 0079f01 commit 319ff9c
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 4 deletions.
19 changes: 18 additions & 1 deletion Source/WebCore/platform/graphics/SourceBufferPrivate.cpp
Expand Up @@ -507,6 +507,23 @@ void SourceBufferPrivate::removeCodedFrames(const MediaTime& start, const MediaT
updateBufferedFromTrackBuffers(trackBuffers, isEnded, WTFMove(completionHandler));

size_t SourceBufferPrivate::platformEvictionThreshold() const
// Default implementation of the virtual function.
return 0;

bool SourceBufferPrivate::hasTooManySamples() const
const size_t evictionThreshold = platformEvictionThreshold();
if (!evictionThreshold)
return false;
size_t currentSize = 0;
for (const auto& trackBuffer : m_trackBufferMap.values())
currentSize += trackBuffer->samples().size();
return currentSize > evictionThreshold;

void SourceBufferPrivate::evictCodedFrames(uint64_t newDataSize, uint64_t maximumBufferSize, const MediaTime& currentTime, bool isEnded)
// 3.5.13 Coded Frame Eviction Algorithm
Expand All @@ -518,7 +535,7 @@ void SourceBufferPrivate::evictCodedFrames(uint64_t newDataSize, uint64_t maximu
// This algorithm is run to free up space in this source buffer when new data is appended.
// 1. Let new data equal the data that is about to be appended to this SourceBuffer.
// 2. If the buffer full flag equals false, then abort these steps.
bool isBufferFull = isBufferFullFor(newDataSize, maximumBufferSize);
bool isBufferFull = isBufferFullFor(newDataSize, maximumBufferSize) || hasTooManySamples();
if (!isBufferFull)

Expand Down
2 changes: 2 additions & 0 deletions Source/WebCore/platform/graphics/SourceBufferPrivate.h
Expand Up @@ -97,6 +97,7 @@ class SourceBufferPrivate
virtual void setShouldGenerateTimestamps(bool flag) { m_shouldGenerateTimestamps = flag; }
WEBCORE_EXPORT virtual void removeCodedFrames(const MediaTime& start, const MediaTime& end, const MediaTime& currentMediaTime, bool isEnded, CompletionHandler<void()>&& = [] { });
WEBCORE_EXPORT virtual void evictCodedFrames(uint64_t newDataSize, uint64_t maximumBufferSize, const MediaTime& currentTime, bool isEnded);
WEBCORE_EXPORT virtual size_t platformEvictionThreshold() const;
WEBCORE_EXPORT virtual uint64_t totalTrackBufferSizeInBytes() const;
WEBCORE_EXPORT virtual void resetTimestampOffsetInTrackBuffers();
virtual void startChangingType() { m_pendingInitializationSegmentForChangeType = true; }
Expand Down Expand Up @@ -205,6 +206,7 @@ class SourceBufferPrivate
bool evictFrames(uint64_t newDataSize, uint64_t maximumBufferSize, const MediaTime& currentTime, bool isEnded);
bool isAttached() const;
Vector<PlatformTimeRanges> trackBuffersRanges() const;
bool hasTooManySamples() const;

bool m_hasAudio { false };
bool m_hasVideo { false };
Expand Down
Expand Up @@ -50,10 +50,7 @@
#include "NotImplemented.h"
#include "VideoTrackPrivateGStreamer.h"
#include "WebKitMediaSourceGStreamer.h"

#include <wtf/text/StringToIntegerConversion.h>

#define GST_CAT_DEFAULT webkit_mse_debug
Expand Down Expand Up @@ -380,6 +377,18 @@ size_t SourceBufferPrivateGStreamer::platformMaximumBufferSize() const
return 0;

size_t SourceBufferPrivateGStreamer::platformEvictionThreshold() const
static size_t evictionThreshold = 0;
static std::once_flag once;
std::call_once(once, []() {
auto stringView = StringView::fromLatin1(std::getenv("MSE_BUFFER_SAMPLES_EVICTION_THRESHOLD"));
if (!stringView.isEmpty())
evictionThreshold = parseInteger<size_t>(stringView, 10).value_or(0);
return evictionThreshold;


} // namespace WebCore
Expand Down
Expand Up @@ -95,6 +95,7 @@ class SourceBufferPrivateGStreamer final : public SourceBufferPrivate {

size_t platformMaximumBufferSize() const override;
size_t platformEvictionThreshold() const final;

SourceBufferPrivateGStreamer(MediaSourcePrivateGStreamer*, const ContentType&, MediaPlayerPrivateGStreamerMSE&);
Expand Down

0 comments on commit 319ff9c

Please sign in to comment.