Skip to content

Commit 03971c5

Browse files
committed
Rework the cache reset when resize the canvas
Compare the resolution of each frame with the current canvas size. Compare the subtitle display end time, not the gap end time. Keep some frames within specified time regardless of the resolution. Discard distant frames if maximum time is specified.
1 parent 5b330a7 commit 03971c5

File tree

2 files changed

+52
-11
lines changed

2 files changed

+52
-11
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,15 @@ When creating an instance of SubtitleOctopus, you can set the following options:
148148
(Default: `0` - don't render ahead)
149149
- `resizeVariation`: The resize threshold at which the cache of pre-rendered events is cleared.
150150
(Default: `0.2`)
151+
- `renderAheadResetMinTime`: Minimum time in seconds to keep events in the cache after
152+
resizing the canvas (regardless of `resizeVariation`).
153+
(Default: `1`)
154+
- `renderAheadResetMaxTime`: Maximum time in seconds to keep events in the cache after
155+
resizing the canvas (within `resizeVariation`).
156+
(Default: `0`; `0` - no time limit)
157+
- `renderAheadResetMaxFill`: Maximum portion of the cache that can be used after
158+
resizing the canvas.
159+
(Default: `1`; `1` - the entire cache can be used)
151160

152161
### Rendering Modes
153162
#### JS Blending

src/subtitles-octopus.js

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ var EVENTTIME_ULP = 0.01;
55
// maximum time offset for the next request in seconds
66
var MAX_REQUEST_OFFSET = 1;
77

8+
/**
9+
* Returns `value` if it is a non-negative number, or `defaultValue` instead.
10+
* @param {number} value - Test value.
11+
* @param {number} defaultValue - Default value.
12+
* @returns {number} `value` if it is a non-negative number, or default value instead.
13+
*/
14+
function nonNegative(value, defaultValue) {
15+
return value == null || value < 0 ? defaultValue : value;
16+
}
17+
818
var SubtitlesOctopus = function (options) {
919
var supportsWebAssembly = false;
1020
try {
@@ -30,6 +40,9 @@ var SubtitlesOctopus = function (options) {
3040
self.maxRenderHeight = options.maxRenderHeight || 0; // 0 - no limit
3141
self.resizeVariation = options.resizeVariation || 0.2; // by how many a size can vary before it would cause clearance of prerendered buffer
3242
self.renderAhead = options.renderAhead || 0; // how many MiB to render ahead and store; 0 to disable (approximate)
43+
self.renderAheadResetMinTime = nonNegative(options.renderAheadResetMinTime, 1);
44+
self.renderAheadResetMaxTime = nonNegative(options.renderAheadResetMaxTime, 0); // 0 - no time limit
45+
self.renderAheadResetMaxFill = Math.min(nonNegative(options.renderAheadResetMaxFill, 1), 1);
3346
self.isOurCanvas = false; // (internal) we created canvas and manage it
3447
self.video = options.video; // HTML video element (optional if canvas specified)
3548
self.canvasParent = null; // (internal) HTML canvas parent element
@@ -504,28 +517,47 @@ var SubtitlesOctopus = function (options) {
504517
self.rafId = 0;
505518
}
506519

520+
/**
521+
* Compare rects with a given relative (to 2nd rect) threshold.
522+
* @param {Object} rect1 - Rect 1.
523+
* @param {number} rect1.width - Rect 1 width.
524+
* @param {number} rect1.height - Rect 2 height.
525+
* @param {Object} rect2 - Rect 2.
526+
* @param {number} rect2.width - Rect 2 width.
527+
* @param {number} rect2.height - Rect 2 height.
528+
* @param {number} threshold - Relative threshold.
529+
* @returns {boolean} Rects are equal (or not) within a given relative (to 2nd rect) threshold.
530+
*/
531+
function fuzzyEqualRect(rect1, rect2, threshold) {
532+
return (Math.abs(rect1.width - rect2.width) < threshold * rect2.width &&
533+
Math.abs(rect1.height - rect2.height) < threshold * rect2.height);
534+
}
535+
507536
self.resetRenderAheadCache = function (isResizing) {
508537
if (self.renderAhead > 0) {
509538
var newCache = [];
510539
if (isResizing && self.oneshotState.prevHeight && self.oneshotState.prevWidth) {
511540
if (self.oneshotState.prevHeight === targetHeight &&
512541
self.oneshotState.prevWidth === targetWidth) return;
513-
var timeLimit = 10, sizeLimit = self.renderAhead * 0.3;
514-
if (targetHeight >= self.oneshotState.prevHeight * (1.0 - self.resizeVariation) &&
515-
targetHeight <= self.oneshotState.prevHeight * (1.0 + self.resizeVariation) &&
516-
targetWidth >= self.oneshotState.prevWidth * (1.0 - self.resizeVariation) &&
517-
targetWidth <= self.oneshotState.prevWidth * (1.0 + self.resizeVariation)) {
518-
console.debug('viewport changes are small, leaving more of prerendered buffer');
519-
timeLimit = 30;
520-
sizeLimit = self.renderAhead * 0.5;
521-
}
522-
var stopTime = self.video.currentTime + self.timeOffset + timeLimit;
542+
543+
var tm = self.video.currentTime + self.timeOffset;
544+
var minTime = tm + self.renderAheadResetMinTime;
545+
var maxTime = self.renderAheadResetMaxTime > 0 ? tm + self.renderAheadResetMaxTime : Infinity;
546+
var sizeLimit = self.renderAhead * self.renderAheadResetMaxFill;
523547
var size = 0;
548+
524549
for (var i = 0; i < self.renderedItems.length; i++) {
525550
var item = self.renderedItems[i];
526-
if (item.emptyFinish < 0 || stopTime < item.emptyFinish) break;
551+
552+
if (item.emptyFinish < 0 || maxTime < item.eventFinish) break;
553+
554+
if (item.eventFinish >= minTime &&
555+
!fuzzyEqualRect(item.viewport, self.canvas, self.resizeVariation)) continue;
556+
527557
size += item.size;
558+
528559
if (size >= sizeLimit) break;
560+
529561
newCache.push(item);
530562
}
531563
}

0 commit comments

Comments
 (0)