Skip to content

Commit 37f01ed

Browse files
committed
Rework the cache reset when resize the canvas
Compare the resolution of each frame with the current canvas size. Keep some frames within specified time regardless of the resolution. Discard distant frames if maximum time is specified.
1 parent 5ab8af3 commit 37f01ed

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
@@ -146,6 +146,15 @@ When creating an instance of SubtitleOctopus, you can set the following options:
146146
(Default: `0` - don't render ahead)
147147
- `resizeVariation`: The resize threshold at which the cache of pre-rendered events is cleared.
148148
(Default: `0.2`)
149+
- `renderAheadResetMinTime`: Minimum time in seconds to keep events in the cache after
150+
resizing the canvas (regardless of `resizeVariation`).
151+
(Default: `1`)
152+
- `renderAheadResetMaxTime`: Maximum time in seconds to keep events in the cache after
153+
resizing the canvas (within `resizeVariation`).
154+
(Default: `0`; `0` - no time limit)
155+
- `renderAheadResetMaxFill`: Maximum portion of the cache that can be used after
156+
resizing the canvas.
157+
(Default: `1`; `1` - the entire cache can be used)
149158

150159
### Rendering Modes
151160
#### JS Blending

src/subtitles-octopus.js

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@ var FRAMETIME_ULP = 0.001;
33
// minimum time difference between subtitle events
44
var EVENTTIME_ULP = 0.01;
55

6+
/**
7+
* Returns `value` if it is a non-negative number, or `defaultValue` instead.
8+
* @param {number} value - Test value.
9+
* @param {number} defaultValue - Default value.
10+
* @returns {number} `value` if it is a non-negative number, or default value instead.
11+
*/
12+
function nonNegative(value, defaultValue) {
13+
return value == null || value < 0 ? defaultValue : value;
14+
}
15+
616
var SubtitlesOctopus = function (options) {
717
var supportsWebAssembly = false;
818
try {
@@ -28,6 +38,9 @@ var SubtitlesOctopus = function (options) {
2838
self.maxRenderHeight = options.maxRenderHeight || 0; // 0 - no limit
2939
self.resizeVariation = options.resizeVariation || 0.2; // by how many a size can vary before it would cause clearance of prerendered buffer
3040
self.renderAhead = options.renderAhead || 0; // how many MiB to render ahead and store; 0 to disable (approximate)
41+
self.renderAheadResetMinTime = nonNegative(options.renderAheadResetMinTime, 1);
42+
self.renderAheadResetMaxTime = nonNegative(options.renderAheadResetMaxTime, 0); // 0 - no time limit
43+
self.renderAheadResetMaxFill = Math.min(nonNegative(options.renderAheadResetMaxFill, 1), 1);
3144
self.isOurCanvas = false; // (internal) we created canvas and manage it
3245
self.video = options.video; // HTML video element (optional if canvas specified)
3346
self.canvasParent = null; // (internal) HTML canvas parent element
@@ -414,28 +427,47 @@ var SubtitlesOctopus = function (options) {
414427
self.rafId = 0;
415428
}
416429

430+
/**
431+
* Compare rects with a given relative (to 2nd rect) threshold.
432+
* @param {Object} rect1 - Rect 1.
433+
* @param {number} rect1.width - Rect 1 width.
434+
* @param {number} rect1.height - Rect 2 height.
435+
* @param {Object} rect2 - Rect 2.
436+
* @param {number} rect2.width - Rect 2 width.
437+
* @param {number} rect2.height - Rect 2 height.
438+
* @param {number} threshold - Relative threshold.
439+
* @returns {boolean} Rects are equal (or not) within a given relative (to 2nd rect) threshold.
440+
*/
441+
function fuzzyEqualRect(rect1, rect2, threshold) {
442+
return (Math.abs(rect1.width - rect2.width) < threshold * rect2.width &&
443+
Math.abs(rect1.height - rect2.height) < threshold * rect2.height);
444+
}
445+
417446
self.resetRenderAheadCache = function (isResizing) {
418447
if (self.renderAhead > 0) {
419448
var newCache = [];
420449
if (isResizing && self.oneshotState.prevHeight && self.oneshotState.prevWidth) {
421450
if (self.oneshotState.prevHeight == self.canvas.height &&
422451
self.oneshotState.prevWidth == self.canvas.width) return;
423-
var timeLimit = 10, sizeLimit = self.renderAhead * 0.3;
424-
if (self.canvas.height >= self.oneshotState.prevHeight * (1.0 - self.resizeVariation) &&
425-
self.canvas.height <= self.oneshotState.prevHeight * (1.0 + self.resizeVariation) &&
426-
self.canvas.width >= self.oneshotState.prevWidth * (1.0 - self.resizeVariation) &&
427-
self.canvas.width <= self.oneshotState.prevWidth * (1.0 + self.resizeVariation)) {
428-
console.debug('viewport changes are small, leaving more of prerendered buffer');
429-
timeLimit = 30;
430-
sizeLimit = self.renderAhead * 0.5;
431-
}
432-
var stopTime = self.video.currentTime + self.timeOffset + timeLimit;
452+
453+
var tm = self.video.currentTime + self.timeOffset;
454+
var minTime = tm + self.renderAheadResetMinTime;
455+
var maxTime = self.renderAheadResetMaxTime > 0 ? tm + self.renderAheadResetMaxTime : Infinity;
456+
var sizeLimit = self.renderAhead * self.renderAheadResetMaxFill;
433457
var size = 0;
458+
434459
for (var i = 0; i < self.renderedItems.length; i++) {
435460
var item = self.renderedItems[i];
436-
if (item.emptyFinish < 0 || item.emptyFinish >= stopTime) break;
461+
462+
if (item.emptyFinish < 0 || item.eventFinish >= maxTime) break;
463+
464+
if (item.eventFinish >= minTime &&
465+
!fuzzyEqualRect(item.viewport, self.canvas, self.resizeVariation)) continue;
466+
437467
size += item.size;
468+
438469
if (size >= sizeLimit) break;
470+
439471
newCache.push(item);
440472
}
441473
}

0 commit comments

Comments
 (0)