JASSUB: JavaScript SSA/ASS Subtitle Renderer

repository·main·Indexed 41 days ago

https://github.com/thaunknown/jassub

A high-performance JavaScript wrapper for libass that renders SSA/ASS subtitles in the browser using WebAssembly and WebGL hardware acceleration. Version 2.5.15 supports rendering via HTML5 video elements or standalone canvases, custom font management, and multi-threading via SharedArrayBuffer.

Tokens
2.6K
Snippets
8
Records
12
Agent score
53%

What's inside JASSUB

  1. Configure font management in JASSUB

    main

    JASSUB provides three ways to manage fonts to balance memory, bandwidth, and user experience (avoiding FOUT):

    1. fonts: An array of URLs or Uint8Array data. Use this to pre-load specific fonts immediately upon initialization. This is non-blocking.
    2. availableFonts: A map of font names to sources (URLs or Uint8Array). JASSUB loads these only when needed. Note that loading these asynchronously can cause a Flash of Unstyled Text (FOUT).
    3. queryFonts: Set to 'localandremote' to enable searching for fonts via the Google Fonts API if they aren't found in fonts or availableFonts.
    // Recommended configuration for best UX
    const instance = new JASSUB({
      fonts: fileAttachments, // e.g., extracted from MKV
      availableFonts: {
        'My Fallback Font Family Name': './fonts/MyFallbackFont.woff2'
      },
      defaultFont: 'My Fallback Font Family Name',
      queryFonts: 'localandremote'
    })
  2. Render subtitles using only a canvas

    main

    You can use JASSUB without a video element by providing a canvas instead. In this mode, you are responsible for manually triggering renders using instance.manualRender with the appropriate timing and dimensions.

    import JASSUB from 'jassub'
    
    const instance = new JASSUB({
      canvas: document.querySelector('canvas'),
      subUrl: './tracks/sub.ass'
    })
    
    await instance.ready
    
    instance.manualRender({
      expectedDisplayTime: performance.now(), 
      width: 1920, 
      height: 1080, 
      mediaTime: 10.20
    })
  3. Basic usage with a video element

    main

    To use JASSUB with a standard HTML5 video element, instantiate the JASSUB class and provide the video element and the subUrl pointing to your .ass or .ssa file.

    import JASSUB from 'jassub'
    
    const instance = new JASSUB({
      video: document.querySelector('video'),
      subUrl: './tracks/sub.ass'
    })
  4. Access the renderer via IPC

    main

    The instance.renderer object communicates with a remote worker via IPC. Because of this, all calls to instance.renderer are asynchronous. You must await them to ensure the command is serialized and executed correctly.

    // Always await renderer calls
    await instance.renderer.setDefaultFont('Gandhi Sans');
    
    // Setting properties is also an async IPC call
    await (instance.renderer.useLocalFonts = false);
  5. Override worker and WASM URLs for custom bundlers

    main

    If you are using a custom bundler that requires explicit paths for the worker and WASM files, you can pass workerUrl, wasmUrl, and modernWasmUrl (for SIMD) in the constructor options.

    import JASSUB from 'jassub'
    import workerUrl from 'jassub/dist/jassub-worker.js?worker&url'
    import wasmUrl from 'jassub/dist/jassub-worker.wasm?url' // non-SIMD fallback
    import modernWasmUrl from 'jassub/dist/jassub-worker-modern.wasm?url' // SIMD
    
    const instance = new JASSUB({
      video: document.querySelector('video'),
      subContent: subtitleString,
      workerUrl,
      wasmUrl,
      modernWasmUrl
    })
  6. Configure HTTP headers for multi-threading

    main

    To enable multi-threading via SharedArrayBuffer, it is highly recommended to serve your application with the following COOP/COEP headers:

    {
      "Cross-Origin-Embedder-Policy": "require-corp",
      "Cross-Origin-Opener-Policy": "same-origin"
    }

    If these headers are not present, JASSUB will automatically fallback to single-threaded mode.

  7. Use the JASSUB class API

    main

    The JASSUB class is the primary interface for interacting with the WASM engine. It provides methods for data processing, font management, canvas manipulation, and event handling.

    Data Processing

    • processData(data: EmbindString): Processes a complete data set.
    • processChunk(data: EmbindString, offset: number, length: number): Processes a specific chunk of data.
    • createTrackMem(data: EmbindString): Creates track memory from the provided data.

    Font Management

    • addFont(font: any, type: number, size: number): Adds a font to the engine.
    • reloadFonts(): Reloads the fonts.
    • setDefaultFont(font: any): Sets the default font.

    Canvas and Rendering

    • resizeCanvas(width: number, height: number, devicePixelRatio: number, extra: number): Resizes the internal canvas.
    • setMargin(top: number, right: number, bottom: number, left: number): Sets margins.
    • rawRender(x: number, y: number): Performs a raw render at the specified coordinates.
    • styleOverride(style: any): Applies style overrides.
    • disableStyleOverride(): Disables style overrides.

    Event and Style Management

    • getEvents(): Retrieves current events.
    • createEvent(event: any): Creates a new event.
    • setEvent(id: number, event: any): Sets data for a specific event.
    • removeEvent(id: number): Removes an event.
    • getStyles(): Retrieves current styles.
    • createStyle(style: any): Creates a new style.
    • setStyle(id: number, style: any): Sets data for a specific style.
    • removeStyle(id: number): Removes a style.

    Lifecycle and Configuration

    • quitLibrary(): Shuts down the library.
    • setLogLevel(level: number): Sets the logging level.
    • setMemoryLimits(limit: number): Sets memory limits.
    • setThreads(count: number): Configures the number of threads.
    • removeAllEvents(): Clears all events.
  8. Manage JASSUB instance lifecycle with ClassHandle

    main

    The JASSUB class implements the ClassHandle interface, which is used for manual memory management of the WASM objects.

    • delete(): Immediately destroys the instance.
    • deleteLater(): Schedules the instance for destruction.
    • isDeleted(): Returns whether the instance has already been destroyed.
    • clone(): Creates a clone of the current instance.
    • [Symbol.dispose](): Supports the explicit resource management pattern (using using in TypeScript/JavaScript).
  9. Initialize JASSUB via MainModuleFactory

    main

    To use JASSUB, you must first initialize the WebAssembly module using the MainModuleFactory. This function returns a Promise that resolves to a MainModule object, which contains the JASSUB class constructor.

    Note: The JASSUB constructor accepts three parameters:

    1. _0 (number): Likely related to memory or initial configuration.
    2. _1 (number): Likely related to memory or initial configuration.
    3. _2 (any): Additional configuration options.
    import MainModuleFactory from 'jassub';
    
    async function init() {
      const module = await MainModuleFactory();
      const jassubInstance = new module.JASSUB(0, 0, {});
    }
  10. Initialize JASSUB with JASSUBOptions

    main

    To use JASSUB, instantiate the JASSUB class with a JASSUBOptions object. You must provide either a video element or a canvas element, and either a subUrl (for subtitle files) or subContent (for raw subtitle text).

    If you provide a video element without a canvas, JASSUB will automatically create a canvas, style it to overlay the video, and insert it into the DOM immediately after the video element.

    import JASSUB from 'jassub';
    
    const jassub = new JASSUB({
      video: document.querySelector('video'),
      subUrl: 'path/to/subtitles.ass',
      // Optional configuration
      timeOffset: 0,
      debug: false,
      prescaleFactor: 1.0,
      availableFonts: {
        'liberation sans': new URL('./default.woff2', import.meta.url).href
      }
    });
  11. Configure JASSUBOptions

    main

    The JASSUBOptions object defines the behavior and assets for the subtitle renderer.

    Required Fields (Logical XOR groups)

    • Media Source: Must contain either video: HTMLVideoElement or canvas: HTMLCanvasElement.
    • Subtitle Source: Must contain either subUrl: string or subContent: string.

    Available Options

    OptionTypeDescription
    timeOffsetnumberOffset in seconds applied to the subtitle timing.
    debugbooleanEnables debug logging.
    prescaleFactornumberScaling factor for rendering resolution.
    prescaleHeightLimitnumberMaximum height used for prescaling calculations.
    maxRenderHeightnumberHard limit for the rendered height (0 = no limit).
    workerUrlstringCustom URL for the web worker.
    wasmUrlstringURL for the standard WASM file.
    modernWasmUrlstringURL for the SIMD-enabled WASM file.
    fontsArray<string | Uint8Array>Array of font data/URLs.
    availableFontsRecord<string, Uint8Array | string>Map of font family names to data/URLs.
    defaultFontstringThe font family to use if others are unavailable.
    queryFonts'local' | 'localandremote' | falseStrategy for finding fonts.
    libassMemoryLimitnumberMemory limit for libass.
    libassGlyphLimitnumberGlyph limit for libass.