From e9fc7c51a74467633c9d8d6486369f8e3c3b496f Mon Sep 17 00:00:00 2001 From: Vasily Date: Sat, 29 Jan 2022 18:10:50 +0100 Subject: [PATCH 1/2] Add options to scale canvas relative to video JSO struggles on complex subtitles and higher resolutions, scaling the sub-canvas down if the canvas gets larger than a size deemed good enough can be used to somewhat work around this at the expense of introducing some blurriness. Scaling up is also possible but probably less useful. This was ported from jellyfin's fork and jellyfin-web uses this on at least some devices. However the option names were changed to better match their actual function. [Vasily ] Original implementation together with a hard canvas height limit in https://github.com/jellyfin/JavascriptSubtitlesOctopus/commit/345d7010b1d31f933f1b2cc3a17d83a09b5e5c2e https://github.com/jellyfin/JavascriptSubtitlesOctopus/commit/bcf4b5fc62140a3ab37ce5e3f6c329c3094cb7d8 [Dmitry Lyzo ] Rebased for upstream; removed default hardHeightLimit and added docs [Oneric ] Simplified scaling logic (identical results for positive values); fixed zero and negativity bugs in scaling logic; changed option names for clarity; split prescaling from hard height limit. Co-Authored-By: Dmitry Lyzo Co-Authored-By: Oneric --- README.md | 5 +++++ src/subtitles-octopus.js | 28 ++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 30feddf4..f95f4817 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,11 @@ When creating an instance of SubtitleOctopus, you can set the following options: (Default: `0` - no limit) - `libassGlyphLimit`: libass glyph cache memory limit in MiB (approximate) (Default: `0` - no limit) +- `prescaleFactor`: Scale down (`< 1.0`) the subtitles canvas to improve + performance at the expense of quality, or scale it up (`> 1.0`). + (Default: `1.0` - no scaling; must be a number > 0) +- `prescaleHeightLimit`: The height beyond which the subtitles canvas won't be prescaled. + (Default: `1080`) ### Rendering Modes #### JS Blending diff --git a/src/subtitles-octopus.js b/src/subtitles-octopus.js index 0418f8b8..7b79c253 100644 --- a/src/subtitles-octopus.js +++ b/src/subtitles-octopus.js @@ -17,6 +17,8 @@ var SubtitlesOctopus = function (options) { self.libassMemoryLimit = options.libassMemoryLimit || 0; self.libassGlyphLimit = options.libassGlyphLimit || 0; self.targetFps = options.targetFps || 24; + self.prescaleFactor = options.prescaleFactor || 1.0; + self.prescaleHeightLimit = options.prescaleHeightLimit || 1080; self.isOurCanvas = false; // (internal) we created canvas and manage it self.video = options.video; // HTML video element (optional if canvas specified) self.canvasParent = null; // (internal) HTML canvas parent element @@ -404,14 +406,36 @@ var SubtitlesOctopus = function (options) { } }; + function _computeCanvasSize(width, height) { + var scalefactor = self.prescaleFactor <= 0 ? 1.0 : self.prescaleFactor; + + if (height <= 0 || width <= 0) { + width = 0; + height = 0; + } else { + var sgn = scalefactor < 1 ? -1 : 1; + var newH = height; + if (sgn * newH * scalefactor <= sgn * self.prescaleHeightLimit) + newH *= scalefactor; + else if (sgn * newH < sgn * self.prescaleHeightLimit) + newH = self.prescaleHeightLimit; + + width *= newH / height; + height = newH; + } + + return {'width': width, 'height': height}; + } + self.resize = function (width, height, top, left) { var videoSize = null; top = top || 0; left = left || 0; if ((!width || !height) && self.video) { videoSize = self.getVideoPosition(); - width = videoSize.width * self.pixelRatio; - height = videoSize.height * self.pixelRatio; + var newSize = _computeCanvasSize(videoSize.width * self.pixelRatio, videoSize.height * self.pixelRatio); + width = newSize.width; + height = newSize.height; var offset = self.canvasParent.getBoundingClientRect().top - self.video.getBoundingClientRect().top; top = videoSize.y - offset; left = videoSize.x; From 5ebf13d6c0a6e76c61b07308a03118003f62f218 Mon Sep 17 00:00:00 2001 From: Vasily Date: Sat, 29 Jan 2022 18:38:38 +0100 Subject: [PATCH 2/2] Add option to limit canvas size JSO struggles with complex subtitles on HiDPI canvasses, so limiting the size can make sense if such subtitles are expected. This was ported from jellyfin's fork and jellyfin-web uses this on at least some devices. In the original implementation prescaleHeightLimit would override maxRenderHeight if it was larger. This undocumentend behaviour was dropped here as it seemed unintuitive and unhelpful. [Vasily ] Original implementation together with prescaling in https://github.com/jellyfin/JavascriptSubtitlesOctopus/commit/345d7010b1d31f933f1b2cc3a17d83a09b5e5c2e https://github.com/jellyfin/JavascriptSubtitlesOctopus/commit/4c5f018a07d5c51b089ef21ccf1f81a0355e6c8c [Dmitry Lyzo] Rebased for upstream; seperated from the prescaling; removed default height limit and added docs [Oneric] Renamed hardHeightLimit to maxRenderHeight; split from prescaling. Co-Authored-By: Dmitry Lyzo --- README.md | 3 +++ src/subtitles-octopus.js | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/README.md b/README.md index f95f4817..6c45ffd7 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,9 @@ When creating an instance of SubtitleOctopus, you can set the following options: (Default: `1.0` - no scaling; must be a number > 0) - `prescaleHeightLimit`: The height beyond which the subtitles canvas won't be prescaled. (Default: `1080`) +- `maxRenderHeight`: The maximum rendering height of the subtitles canvas. + Beyond this subtitles will be upscaled by the browser. + (Default: `0` - no limit) ### Rendering Modes #### JS Blending diff --git a/src/subtitles-octopus.js b/src/subtitles-octopus.js index 7b79c253..64981e04 100644 --- a/src/subtitles-octopus.js +++ b/src/subtitles-octopus.js @@ -19,6 +19,7 @@ var SubtitlesOctopus = function (options) { self.targetFps = options.targetFps || 24; self.prescaleFactor = options.prescaleFactor || 1.0; self.prescaleHeightLimit = options.prescaleHeightLimit || 1080; + self.maxRenderHeight = options.maxRenderHeight || 0; // 0 - no limit self.isOurCanvas = false; // (internal) we created canvas and manage it self.video = options.video; // HTML video element (optional if canvas specified) self.canvasParent = null; // (internal) HTML canvas parent element @@ -420,6 +421,9 @@ var SubtitlesOctopus = function (options) { else if (sgn * newH < sgn * self.prescaleHeightLimit) newH = self.prescaleHeightLimit; + if (self.maxRenderHeight > 0 && newH > self.maxRenderHeight) + newH = self.maxRenderHeight; + width *= newH / height; height = newH; }