Display Subtitles via JavaScript
Go to file
2022-12-26 11:34:42 +03:00
.github/workflows ci: Add release workflow 2022-05-03 09:51:45 +03:00
assets Move Font Settings to assets directory 2020-02-13 22:06:48 -03:00
build Bump Fontconfig 2022-12-23 22:00:36 +03:00
lib Bump Fontconfig 2022-12-23 22:00:36 +03:00
src src/make: use -c to compile instead of -r 2022-12-26 11:34:42 +03:00
.dockerignore Ignore all files for build context 2022-12-23 23:41:37 +03:00
.editorconfig editorconfig: fix syntax error 2022-03-22 13:57:47 -03:00
.gitignore src: use a custom Makefile 2022-12-26 11:34:42 +03:00
.gitmodules fix brotli repo url in .gitmodules 2022-03-13 18:45:16 -03:00
Dockerfile Update emscripten 2.0.34 2022-12-23 20:13:09 +03:00
functions.mk make: replace submodule update with reset 2022-12-26 00:05:39 +03:00
LICENSE Bump copyright year 2021-08-03 19:31:02 +02:00
Makefile make: disable pthreads in global flags 2022-12-26 11:34:42 +03:00
package-lock.json Bump version to 4.1.1 2022-05-20 20:21:11 +03:00
package.json Bump version to 4.1.1 2022-05-20 20:21:11 +03:00
README.md readme: add missing documentation 2022-05-04 19:42:04 +03:00
run-buildah-build.sh Add run-buildah-build.sh script 2021-09-18 18:02:36 +00:00
run-common.sh build: fix invalid default container name for docker 2021-10-02 11:17:07 -03:00
run-docker-build.sh Add run-buildah-build.sh script 2021-09-18 18:02:36 +00:00

Actions Status

SubtitlesOctopus displays subtitles in .ass format and easily integrates with HTML5 videos. Since it uses libass, SubtitlesOctopus supports most SSA/ASS features and enables you to get consistent results in authoring and web-playback, provided libass is also used locally.

ONLINE DEMO / other examples with demo

Features

  • Supports most SSA/ASS features (everything libass supports)
  • Supports all OpenType- and TrueType-fonts (including woff2 fonts)
  • Works fast (because uses WebAssembly with fallback to asm.js if it's not available)
  • Uses Web Workers thus video and interface doesn't lag even on "heavy" subtitles (working in background)
  • Doesn't use DOM manipulations and render subtitles on single canvas
  • Fully compatible with libass' extensions (but beware of compatability to other ASS-renderers when using them)
  • Easy to use - just connect it to video element

Included Libraries

  • libass
  • expat
  • fontconfig
  • freetype
  • fribidi
  • harfbuzz
  • brotli

Usage

To start using SubtitlesOctopus you only need to instantiate a new instance of SubtitlesOctopus and specify its Options.

var options = {
    video: document.getElementById('video'), // HTML5 video element
    subUrl: '/test/test.ass', // Link to subtitles
    fonts: ['/test/font-1.ttf', '/test/font-2.ttf'], // Links to fonts (not required, default font already included in build)
    workerUrl: '/libassjs-worker.js', // Link to WebAssembly-based file "libassjs-worker.js"
    legacyWorkerUrl: '/libassjs-worker-legacy.js' // Link to non-WebAssembly worker
};
var instance = new SubtitlesOctopus(options);

After that SubtitlesOctopus automatically "connects" to your video and it starts to display subtitles. You can use it with any HTML5 player.

See other examples.

Using only with canvas

You're also able to use it without any video. However, that requires you to set the time the subtitles should render at yourself:

var options = {
    canvas: document.getElementById('canvas'), // canvas element
    subUrl: '/test/test.ass', // Link to subtitles
    fonts: ['/test/font-1.ttf', '/test/font-2.ttf'], // Links to fonts (not required, default font already included in build)
    workerUrl: '/libassjs-worker.js' // Link to file "libassjs-worker.js"
};
var instance = new SubtitlesOctopus(options);
// And then...
instance.setCurrentTime(15); // Render subtitles at 00:15 on your canvas

Changing subtitles

You're not limited to only display the subtitle file you referenced in your options. You're able to dynamically change subtitles on the fly. There's three methods that you can use for this specifically:

  • setTrackByUrl(url): works the same as the subUrl option. It will set the subtitle to display by its URL.
  • setTrack(content): works the same as the subContent option. It will set the subtitle to dispaly by its content.
  • freeTrack(): this simply removes the subtitles. You can use the two methods above to set a new subtitle file to be displayed.
var instance = new SubtitlesOctopus(options);

// ... we want to change the subtitles to the Railgun OP
instance.setTrackByUrl('/test/railgun_op.ass');

Cleaning up the object

After you're finished with rendering the subtitles. You need to call the instance.dispose() method to correctly dispose of the object.

var instance = new SubtitlesOctopus(options);

// After you've finished using it...

instance.dispose();

Options

When creating an instance of SubtitleOctopus, you can set the following options:

  • video: The video element to attach listeners to. (Optional)
  • canvas: The canvas to render the subtitles to. If none is given it will create a new canvas and insert it as a sibling of the video element (only if the video element exists). (Optional)
  • subUrl: The URL of the subtitle file to play. (Require either subUrl or subContent to be specified)
  • subContent: The content of the subtitle file to play. (Require either subContent or subUrl to be specified)
  • workerUrl: The URL of the worker. (Default: libassjs-worker.js)
  • fonts: An array of links to the fonts used in the subtitle. (Optional)
  • availableFonts: Object with all available fonts - Key is font name in lower case, value is link: {"arial": "/font1.ttf"} (Optional)
  • timeOffset: The amount of time the subtitles should be offset from the video. (Default: 0)
  • onReady: Function that's called when SubtitlesOctopus is ready. (Optional)
  • onError: Function called in case of critical error meaning the subtitles wouldn't be shown and you should use an alternative method (for instance it occurs if browser doesn't support web workers). (Optional)
  • debug: Whether performance info is printed in the console. (Default: false)
  • renderMode: Rendering mode. (If not set, the deprecated option lossyRender is evaluated)
    • js-blend - JS Blending
    • wasm-blend - WASM Blending, currently the default
    • lossy - Lossy Render Mode (EXPERIMENTAL)
  • targetFps: Target FPS (Default: 24)
  • libassMemoryLimit: libass bitmap cache memory limit in MiB (approximate) (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)
  • maxRenderHeight: The maximum rendering height of the subtitles canvas. Beyond this subtitles will be upscaled by the browser. (Default: 0 - no limit)
  • dropAllAnimations: Remove all animation tags, such as karaoke, move, fade, etc. (Default: false)
  • renderAhead: How many MiB (approximate) of subtitles to render ahead and store. (Default: 0 - don't render ahead)
  • resizeVariation: The resize threshold at which the cache of pre-rendered events is cleared. (Default: 0.2)

Rendering Modes

JS Blending

To use this mode set renderMode to js-blend upon instance creation. This will do all the processing of the bitmaps produced by libass outside of WebAssembly.

WASM Blending

To use this mode set renderMode to wasm-blend upon instance creation. This will blend the bitmaps of the different events together in WebAssembly, so the JavaScript-part only needs to process a single image. If WebAssembly-support is available this will be faster than the default mode, especially for many and/or complex simultaneous subtitles. Without WebAssembly-support it will fallback to asm.js and should at least not be slower than the default mode.

Lossy Render Mode (EXPERIMENTAL)

To use this mode set renderMode to lossy upon instance creation. The Lossy Render mode has been created by @no1d as a suggestion for fix browser freezing when rendering heavy subtitles (#46), it uses createImageBitmap to render the bitmap in the Worker, using Promises instead of direct render on canvas in the Main Thread. When the browser start to hang, it will not lock main thread, instead will run Async, so if the function createImageBitmap fail, it will not stop the rendering process at all and may cause some bitmap loss or simply will not draw anything in canvas, mostly on low end devices.

WARNING: Experimental, not stable and not working in some browsers

Render Ahead (WASM Blending with pre-rendering) (EXPERIMENTAL)

Upon creating the SubtitleOctopus instance, set renderAhead in the options to a positive value to use this mode. In this mode, SubtitleOctopus renders events in advance (using WASM blending) so that they are ready in time. The amount of pre-rendered events is controlled by the renderAhead option. Each pre-rendered event is provided with information about its start time, end time, and end time of the gap after (if any). This mode will analyse the events to avoid rendering empty sections or rerendering non-animated events. Resizing the video player clears the cache of pre-rendered events (the threshold is set by resizeVariation).

The renderMode and lossyRender options are ignored.

WARNING: Experimental, may stall on heavily animated subtitles This mode tries to render every transition - at worst, every frame - in advance. If the rendering of many frames takes too long and the cache of prepared frames gets depleted (e.g. during a long section with heavy animations), the current subtitle-frame will continue to be displayed until the prerendering can catch up again. Adjusting prescaleFactor, prescaleHeightLimit and maxRenderHeight to lower the resolution of the rendering canvas can work around this at the expense of visual quality.

Brotli Compressed Subtitles

The SubtitleOctopus allow the use of compressed subtitles in brotli format, saving bandwidth and reducing library startup time

To use, just run: brotli subFile.ass and use the .br result file with the subUrl option

How to build?

Dependencies

  • git
  • emscripten (Configure the enviroment)
  • make
  • python3
  • cmake
  • pkgconfig
  • patch
  • libtool
  • autotools (autoconf, automake, autopoint)
  • gettext
  • ragel - Required by Harfbuzz
  • itstool - Required by Fontconfig
  • python3-ply - Required by WebIDL
  • gperf - Required by Fontconfig
  • licensecheck

Get the Source

Run git clone --recursive https://github.com/jellyfin/JavascriptSubtitlesOctopus.git

Build inside a Container

Docker

  1. Install Docker
  2. ./run-docker-build.sh
  3. Artifacts are in /dist/js

Buildah

  1. Install Buildah and a suitable backend for buildah run like crun or runc
  2. ./run-buildah-build.sh
  3. Artifacts are in /dist/js

Build without Containers

  1. Install the dependency packages listed above
  2. make
    • If on macOS with libtool from brew, LIBTOOLIZE=glibtoolize make
  3. Artifacts are in /dist/js

Why "Octopus"?

How am I an Octopus? Ba da ba da ba!