Skip to content

Commit 05ef61d

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 85598b5 commit 05ef61d

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
@@ -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
@@ -500,28 +513,47 @@ var SubtitlesOctopus = function (options) {
500513
self.rafId = 0;
501514
}
502515

516+
/**
517+
* Compare rects with a given relative (to 2nd rect) threshold.
518+
* @param {Object} rect1 - Rect 1.
519+
* @param {number} rect1.width - Rect 1 width.
520+
* @param {number} rect1.height - Rect 2 height.
521+
* @param {Object} rect2 - Rect 2.
522+
* @param {number} rect2.width - Rect 2 width.
523+
* @param {number} rect2.height - Rect 2 height.
524+
* @param {number} threshold - Relative threshold.
525+
* @returns {boolean} Rects are equal (or not) within a given relative (to 2nd rect) threshold.
526+
*/
527+
function fuzzyEqualRect(rect1, rect2, threshold) {
528+
return (Math.abs(rect1.width - rect2.width) < threshold * rect2.width &&
529+
Math.abs(rect1.height - rect2.height) < threshold * rect2.height);
530+
}
531+
503532
self.resetRenderAheadCache = function (isResizing) {
504533
if (self.renderAhead > 0) {
505534
var newCache = [];
506535
if (isResizing && self.oneshotState.prevHeight && self.oneshotState.prevWidth) {
507536
if (self.oneshotState.prevHeight === targetHeight &&
508537
self.oneshotState.prevWidth === targetWidth) return;
509-
var timeLimit = 10, sizeLimit = self.renderAhead * 0.3;
510-
if (targetHeight >= self.oneshotState.prevHeight * (1.0 - self.resizeVariation) &&
511-
targetHeight <= self.oneshotState.prevHeight * (1.0 + self.resizeVariation) &&
512-
targetWidth >= self.oneshotState.prevWidth * (1.0 - self.resizeVariation) &&
513-
targetWidth <= self.oneshotState.prevWidth * (1.0 + self.resizeVariation)) {
514-
console.debug('viewport changes are small, leaving more of prerendered buffer');
515-
timeLimit = 30;
516-
sizeLimit = self.renderAhead * 0.5;
517-
}
518-
var stopTime = self.video.currentTime + self.timeOffset + timeLimit;
538+
539+
var tm = self.video.currentTime + self.timeOffset;
540+
var minTime = tm + self.renderAheadResetMinTime;
541+
var maxTime = self.renderAheadResetMaxTime > 0 ? tm + self.renderAheadResetMaxTime : Infinity;
542+
var sizeLimit = self.renderAhead * self.renderAheadResetMaxFill;
519543
var size = 0;
544+
520545
for (var i = 0; i < self.renderedItems.length; i++) {
521546
var item = self.renderedItems[i];
522-
if (item.emptyFinish < 0 || stopTime < item.emptyFinish) break;
547+
548+
if (item.emptyFinish < 0 || maxTime < item.eventFinish) break;
549+
550+
if (item.eventFinish >= minTime &&
551+
!fuzzyEqualRect(item.viewport, self.canvas, self.resizeVariation)) continue;
552+
523553
size += item.size;
554+
524555
if (size >= sizeLimit) break;
556+
525557
newCache.push(item);
526558
}
527559
}

0 commit comments

Comments
 (0)