v0.7.1 (build 925)

FFmpeg-based video playback that decodes on a worker thread and streams frames into a Koya texture. Designed for simple usage: you load a source, bind a texture key, and render it in UI.

Import #

import * as ff from 'Module/ffmpeg';

Types #

VideoDetails
Metadata returned by details().
  • width number - Video width in pixels.
  • height number - Video height in pixels.
  • duration number optional - Duration in seconds, if available.

Functions #

load
Start decoding a source and publish frames to the given texture key.
load(windowId: number, key: string, path: string): void
play
Resume playback if paused.
play(windowId: number, key: string): void
pause
Pause playback while keeping resources.
pause(windowId: number, key: string): void
stop
Stop decoding and release native resources for that stream.
stop(windowId: number, key: string): void
details
Return basic metadata for the loaded source.
details(windowId: number, key: string): VideoDetails | undefined

Example #

Load a video file, bind it to a texture key, and display it in a panel element. This is the typical pattern for embedding video playback in a Koya UI.

import * as Compositor from 'Koya/Compositor';
import * as UI from 'Helix/UserInterface';
import * as ff from 'Module/ffmpeg';

export default async function () {
  const win = await Compositor.createWindow({ role: 'window', title: 'FFmpeg', size: { x: 720, y: 480 } });

  const key = '/ram/video/example';
  await ff.load(win, key, '/rom/video.mp4');
  const info = await ff.details(win, key);
  const W = info?.width || 640, H = info?.height || 360;

  const root = await UI.createElement(win, { layout: { type: 'row', gap: 8 } });
  await UI.attachRoot(win, root);
  const panel = await UI.createElement(win, {
    renderable: {
      type: 'panel',
      texture: key,
      aabb: { min: { x: 0, y: 0 }, max: { x: W, y: H } }
    },
    item: { width: W, height: H }
  });
  await UI.attach(win, root, panel);
}

Notes #

  • Sources: Supports /rom/... assets, file://..., and http(s)://... if FFmpeg is built with network support.
  • Timing: The worker paces frames from stream timestamps. Rendering just uploads the most recent frame at render_begin.
  • Render requests: When a frame is due, the worker requests a window render. If the window no longer exists, decoding stops for that stream.
  • Cleanup: Use ff.stop(...) to stop a stream. All streams are stopped automatically on engine shutdown.
  • Memory/IO: /rom/... assets are read via the engine's asset system and fed to FFmpeg through in-memory IO. No temp files are created.
  • Texture cleanup (JS): To free a texture key explicitly, call Koya/Image.destroy(windowId, key).
  • Resource usage: Be mindful that while a video is playing, the renderer will continue to render frames even if it's not being drawn by a renderable. Make sure you stop or pause videos when not visible.

Troubleshooting #

  • Playback speed: If too fast/slow, verify the source's reported frame rate/timestamps.
  • No video: Call ff.load(...) before creating the UI element that uses the texture key, or rebuild the element after loading.