Skip to content
Permalink
Browse files
[MSE] Ensure we are not removing the current time during automatic ev…
…iction

https://bugs.webkit.org/show_bug.cgi?id=247052

Reviewed by Alicia Boya Garcia.

In certain cases, depending on the sync frame positions, we could end up removing the current time, which would lead to
playback stopping. Now we ensure that the previous sync frame to current time is taking into account when calculating
the maximumRangeEnd.

* LayoutTests/media/media-source/media-source-append-buffer-full-evict-prior-to-end-expected.txt: Added.
* LayoutTests/media/media-source/media-source-append-buffer-full-evict-prior-to-end.html: Added.
* Source/WebCore/platform/graphics/SourceBufferPrivate.cpp:
(WebCore::SourceBufferPrivate::findPreviousSyncSamplePresentationTime):
(WebCore::SourceBufferPrivate::evictCodedFrames):
* Source/WebCore/platform/graphics/SourceBufferPrivate.h:

Canonical link: https://commits.webkit.org/256939@main
  • Loading branch information
calvaris committed Nov 22, 2022
1 parent 4f29db8 commit 6d7afcf0850ffbb4b6f06f3063ca131fbbf281cd
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 1 deletion.
@@ -0,0 +1,23 @@

EVENT(sourceopen)
EVENT(updateend)
EXPECTED (video.currentTime == '18') OK
Appending PTS=0, DTS=0, sync
Appending PTS=3, DTS=1
Appending PTS=1, DTS=2
Appending PTS=2, DTS=3
Appending PTS=4, DTS=4
Appending PTS=5, DTS=5, sync
Appending PTS=8, DTS=6
Appending PTS=6, DTS=7
Appending PTS=7, DTS=8
Appending PTS=9, DTS=9
Appending PTS=10, DTS=10, sync
Appending PTS=13, DTS=11
Appending PTS=11, DTS=12
Appending PTS=12, DTS=13
Appending PTS=14, DTS=14
EXPECTED (exception != 'QuotaExceededError: The quota has been exceeded.') OK
EXPECTED (bufferedRanges() == '[ 10...15 ]') OK
END OF TEST

@@ -0,0 +1,96 @@
<!DOCTYPE html>
<html>
<head>
<title>mock-media-source</title>
<script src="mock-media-source.js"></script>
<script src="../video-test.js"></script>
<script>
var source;
var sourceBuffer;
var initSegment;
var exception;

function bufferedRanges() {
var bufferedRanges = '[ ';
var timeRanges = sourceBuffer.buffered;
for (var i = 0 ; i < timeRanges.length ; i++) {
if (i)
bufferedRanges += ', ';
bufferedRanges += timeRanges.start(i) + '...' + timeRanges.end(i);
}
bufferedRanges += ' ]';
return bufferedRanges;
}

function doBufferedRangesContain(time) {
var timeRanges = sourceBuffer.buffered;
for (var i = 0 ; i < timeRanges.length ; i++) {
if (timeRanges.start(i) <= time && time <= timeRanges.end(i))
return true;
}
return false;
}

async function appendSample(dts, pts) {
const flag = dts % 5 == 0 ? SAMPLE_FLAG.SYNC : SAMPLE_FLAG.NONE;
consoleWrite('Appending PTS=' + pts + ', DTS=' + dts + (flag == SAMPLE_FLAG.SYNC ? ', sync' : ''));
sourceBuffer.appendBuffer(makeASample(pts, dts, 1, 1, 1, flag, 1));
await waitFor(sourceBuffer, 'updateend', true);
}

async function appendDtsRange(firstDts, lastDts) {
if (firstDts >= lastDts)
return null;

var resultException = null;
try {
for (var dts = firstDts; dts <= lastDts; dts += 5) {
await appendSample(dts + 0, dts + 0);
await appendSample(dts + 1, dts + 3);
await appendSample(dts + 2, dts + 1);
await appendSample(dts + 3, dts + 2);
await appendSample(dts + 4, dts + 4);
}
} catch (e) {
resultException = e;
sourceBuffer.abort();
}
return resultException;
}

if (window.internals)
internals.initializeMockMediaSource();

window.addEventListener('load', async() => {
findMediaElement();
source = new MediaSource();

const videoSource = document.createElement('source');
videoSource.type = 'video/mock; codecs=mock';
videoSource.src = URL.createObjectURL(source);
video.appendChild(videoSource);

await waitFor(source, 'sourceopen');
sourceBuffer = source.addSourceBuffer("video/mock; codecs=mock");
initSegment = makeAInit(350, [makeATrack(1, 'mock', TRACK_KIND.VIDEO)]);
sourceBuffer.appendBuffer(initSegment);
await waitFor(sourceBuffer, 'updateend');
waitFor(sourceBuffer, 'error');

internals.settings.setMaximumSourceBufferSize(500);

video.currentTime = 18;
testExpected('video.currentTime', 18, '==');
exception = await appendDtsRange(0, 14);

testExpected('exception', 'QuotaExceededError: The quota has been exceeded.', '!=');
testExpected('bufferedRanges()', '[ 10...15 ]', '==');

endTest();
});
</script>
</head>
<body>
<video></video>
</body>
</html>
@@ -357,6 +357,21 @@ static PlatformTimeRanges removeSamplesFromTrackBuffer(const DecodeOrderSampleMa
return trackBuffer.removeSamples(samples, logPrefix);
}

MediaTime SourceBufferPrivate::findPreviousSyncSamplePresentationTime(const MediaTime& time)
{
MediaTime previousSyncSamplePresentationTime = time;
for (auto& trackBufferKeyValue : m_trackBufferMap) {
TrackBuffer& trackBuffer = trackBufferKeyValue.value;
auto sampleIterator = trackBuffer.samples().decodeOrder().findSyncSamplePriorToPresentationTime(time);
if (sampleIterator == trackBuffer.samples().decodeOrder().rend())
continue;
const MediaTime& samplePresentationTime = sampleIterator->first.second;
if (samplePresentationTime < time)
previousSyncSamplePresentationTime = samplePresentationTime;
}
return previousSyncSamplePresentationTime;
}

void SourceBufferPrivate::removeCodedFrames(const MediaTime& start, const MediaTime& end, const MediaTime& currentTime, bool isEnded, CompletionHandler<void()>&& completionHandler)
{
ASSERT(start < end);
@@ -437,7 +452,7 @@ void SourceBufferPrivate::evictCodedFrames(uint64_t newDataSize, uint64_t maximu
unsigned timeChunkAsMilliseconds = evictionAlgorithmInitialTimeChunk;
do {
const MediaTime timeChunk = MediaTime(timeChunkAsMilliseconds, 1000);
const MediaTime maximumRangeEnd = currentTime - timeChunk;
const MediaTime maximumRangeEnd = std::min(currentTime - timeChunk, findPreviousSyncSamplePresentationTime(currentTime));

do {
MediaTime rangeStart = buffered.minimumBufferedTime();
@@ -164,6 +164,7 @@ class SourceBufferPrivate
void provideMediaData(TrackBuffer&, const AtomString& trackID);
void setBufferedDirty(bool);
void trySignalAllSamplesInTrackEnqueued(TrackBuffer&, const AtomString& trackID);
MediaTime findPreviousSyncSamplePresentationTime(const MediaTime&);

bool m_isAttached { false };
bool m_hasAudio { false };

0 comments on commit 6d7afcf

Please sign in to comment.