Module/ffmpeg
Decode video via FFmpeg on a worker thread and render into Koya textures.
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().widthnumber - Video width in pixels.heightnumber - Video height in pixels.durationnumber 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): voidplay
Resume playback if paused.
play(windowId: number, key: string): voidpause
Pause playback while keeping resources.
pause(windowId: number, key: string): voidstop
Stop decoding and release native resources for that stream.
stop(windowId: number, key: string): voiddetails
Return basic metadata for the loaded source.
details(windowId: number, key: string): VideoDetails | undefinedExample #
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://..., andhttp(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.