Skip to content

Commit

Permalink
WPE fix: Avoid pruning buffered ranges already enqueued for playback (D…
Browse files Browse the repository at this point in the history
…ash-Industry-Forum#4039)

In WPE WebKit, the buffered range of the currentTime has high chances to
have been internally enqueued for playback (an action that can't be
undone, there's no way to unenqueue other than flushing the whole playback
pipeline). If that range is pruned, an internal flush is triggered, but
in order to keep playing from the currentTime onwards, the needed samples
must be enqueued again at least since the previous sync sample. This
can cause a lot of stress to the video decoder and generate stuttering.

This patch solves the problem by avoiding pruning (deleting) ranges
belonging to the same buffered range where the currentTime (or seek
target) is.

This behaviour is protected by the streaming.buffer.avoidCurrentTimeRangePruning
setting, which is disabled by default and only triggers the new behaviour
when enabled on purpose by the webpage embedding dash.js.
  • Loading branch information
eocanha authored and eastkiki committed Oct 4, 2022
1 parent 4bc83ef commit b3f8c6b
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 2 deletions.
10 changes: 8 additions & 2 deletions src/core/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ import Events from './events/Events';
* longFormContentDurationThreshold: 600,
* stallThreshold: 0.5,
* useAppendWindow: true,
* setStallState: true
* setStallState: true,
* avoidCurrentTimeRangePruning: false
* },
* gaps: {
* jumpGaps: true,
Expand Down Expand Up @@ -304,6 +305,10 @@ import Events from './events/Events';
* Specifies if the appendWindow attributes of the MSE SourceBuffers should be set according to content duration from manifest.
* @property {boolean} [setStallState=true]
* Specifies if we fire manual waiting events once the stall threshold is reached
* @property {boolean} [avoidCurrentTimeRangePruning=false]
* Avoids pruning of the buffered range that contains the current playback time.
*
* That buffered range is likely to have been enqueued for playback. Pruning it causes a flush and reenqueue in WPE and WebKitGTK based browsers. This stresses the video decoder and can cause stuttering on embedded platforms.
*/

/**
Expand Down Expand Up @@ -801,7 +806,8 @@ function Settings() {
longFormContentDurationThreshold: 600,
stallThreshold: 0.3,
useAppendWindow: true,
setStallState: true
setStallState: true,
avoidCurrentTimeRangePruning: false
},
gaps: {
jumpGaps: true,
Expand Down
19 changes: 19 additions & 0 deletions src/streaming/controllers/BufferController.js
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,25 @@ function BufferController(config) {
if (currentTimeRequest) {
rangeStart = Math.max(currentTimeRequest.startTime + currentTimeRequest.duration, rangeStart);
}

// Never remove the contiguous range of targetTime in order to avoid flushes & reenqueues when the user doesn't want it
const avoidCurrentTimeRangePruning = settings.get().streaming.buffer.avoidCurrentTimeRangePruning;
if (avoidCurrentTimeRangePruning) {
for (let i = 0; i < ranges.length; i++) {
if (ranges.start(i) <= targetTime && targetTime <= ranges.end(i)
&& ranges.start(i) <= rangeStart && rangeStart <= ranges.end(i)) {
let oldRangeStart = rangeStart;
if (i + 1 < ranges.length) {
rangeStart = ranges.start(i+1);
} else {
rangeStart = ranges.end(i) + 1;
}
logger.debug('Buffered range [' + ranges.start(i) + ', ' + ranges.end(i) + '] overlaps with targetTime ' + targetTime + ' and range to be pruned [' + oldRangeStart + ', ' + endOfBuffer + '], using [' + rangeStart + ', ' + endOfBuffer +'] instead' + ((rangeStart < endOfBuffer) ? '' : ' (no actual pruning)'));
break;
}
}
}

if (rangeStart < endOfBuffer) {
return {
start: rangeStart,
Expand Down

0 comments on commit b3f8c6b

Please sign in to comment.