-
Notifications
You must be signed in to change notification settings - Fork 25
Using FFmpegKitNext on Web
This page shows how to use FFmpegKitNext in a Web application after the ffmpeg-kit-next-web package has been built and added to the app.
The Web package supports modern browsers with WebAssembly, module Web Worker, SharedArrayBuffer and WebAssembly SIMD support.
ffmpeg-kit-next-web is not published to npm. Build the Web bundle locally, then depend on the generated package folder.
{
"dependencies": {
"ffmpeg-kit-next-web": "file:<path-to-repo>/prebuilt/bundle-web-wasm32/ffmpeg-kit-next"
}
}Serve the complete generated package folder as static assets. The worker and .wasm files are resolved relative to the package module.
The page that loads ffmpeg-kit-next-web must be cross-origin isolated:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Import from the package entry point.
import {
FFmpegKit,
FFmpegKitConfig,
FFprobeKit,
Packages,
ReturnCode,
SessionState
} from 'ffmpeg-kit-next-web';Most API calls boot the WebAssembly runtime automatically. Initialize explicitly only when you want to control the boot moment or suppress the native load confirmation.
await FFmpegKitConfig.init(false);Call uninit() when you want to terminate the worker and release the WebAssembly heap. A later API call starts a fresh runtime.
await FFmpegKitConfig.uninit();execute returns a promise that resolves with an FFmpegSession after the command finishes.
const session = await FFmpegKit.execute('-i file1.mp4 -c:v mpeg4 file2.mp4');
const returnCode = session.getReturnCode();
if (ReturnCode.isSuccess(returnCode)) {
// SUCCESS
} else if (ReturnCode.isCancel(returnCode)) {
// CANCEL
} else {
console.log(await session.getOutput());
}Use executeAsync for workflows where the promise should resolve as soon as the native execution starts. The complete callback receives the final session.
const session = await FFmpegKit.executeAsync('-i file1.mp4 -c:v mpeg4 file2.mp4', completedSession => {
console.log(`completed rc=${completedSession.getReturnCode()}`);
}, log => {
console.log(log.getMessage());
}, statistics => {
console.log(`time=${statistics.getTime()} size=${statistics.getSize()}`);
});
console.log(`started session ${session.getSessionId()}`);Write small inputs into MEMFS, or mount large File/Blob inputs read-only through WORKERFS.
import { mount, readFile, writeFile } from 'ffmpeg-kit-next-web';
await writeFile('input.mp4', new Uint8Array(await file.arrayBuffer()));
await FFmpegKit.execute('-i input.mp4 -c:v mpeg4 output.mp4');
const output = await readFile('output.mp4');
const url = URL.createObjectURL(new Blob([output], { type: 'video/mp4' }));For large browser File objects:
await mount('/mnt', { files: [file] });
await FFmpegKit.execute(`-i /mnt/${file.name} -c:v mpeg4 output.mp4`);ffkitmem: avoids staging finite byte arrays in MEMFS.
import { FFmpegKitInputBuffer, FFmpegKitOutputBuffer } from 'ffmpeg-kit-next-web';
const input = await FFmpegKitInputBuffer.fromByteArray(bytes, 'mp4');
const output = await FFmpegKitOutputBuffer.create('mp4');
try {
await FFmpegKit.execute(`-i ${input.getUrl()} -c:v mpeg4 ${output.getUrl()}`);
const result = await output.toByteArray();
} finally {
await input.close();
await output.close();
}Use ffkitstream: when data is produced or consumed incrementally. Pair streams with executeAsync and pump them while the command runs.
import { FFmpegKitStreamInput } from 'ffmpeg-kit-next-web';
const stream = await FFmpegKitStreamInput.create('mp4');
await FFmpegKit.executeAsync(`-i ${stream.getUrl()} -c:v mpeg4 output.mp4`);
let offset = 0;
while (offset < bytes.length) {
offset += await stream.write(bytes.subarray(offset));
}
await stream.closeInput();
await stream.close();Close every input, output and stream helper you create.
Use FFprobeKit for FFprobe commands and parsed media information.
const probeSession = await FFprobeKit.execute('-hide_banner -v error -show_format -show_streams input.mp4');
console.log(await probeSession.getOutput());
const mediaSession = await FFprobeKit.getMediaInformation('input.mp4');
const information = mediaSession.getMediaInformation();Session history is asynchronous on Web.
const sessions = await FFmpegKitConfig.getSessions();
const lastSession = await FFmpegKitConfig.getLastSession();
const runningSessions = await FFmpegKitConfig.getSessionsByState(SessionState.RUNNING);Global callbacks apply to all matching sessions. Calling a callback setter with no argument clears it.
FFmpegKitConfig.enableFFmpegSessionCompleteCallback(session => {
console.log(`FFmpeg session completed: ${session.getSessionId()}`);
});
FFmpegKitConfig.enableLogCallback(log => {
console.log(log.getMessage());
});
FFmpegKitConfig.enableStatisticsCallback(statistics => {
console.log(`frame=${statistics.getVideoFrameNumber()} speed=${statistics.getSpeed()}`);
});Read version and package information when reporting diagnostics.
const ffmpegVersion = await FFmpegKitConfig.getFFmpegVersion();
const ffmpegKitVersion = await FFmpegKitConfig.getVersion();
const buildDate = await FFmpegKitConfig.getBuildDate();
const packageName = await Packages.getPackageName();The Web build supports two linkage modes:
- Dynamic linkage is the default.
libffmpegkit.wasmloads FFmpeg side modules at runtime. - Static linkage is enabled with
--static. FFmpeg libraries are linked into one main WebAssembly module.
Choose the mode when building the local package. Application code imports the same JavaScript API in both modes.
Copyright (c) 2026 FFmpegKitNext
- Status
- Versions
- Changelog
- Project Layout
- Using
- Building
- External Libraries
- Patents
- License