Skip to content

Using FFmpegKitNext on Web

Taner Sener edited this page Jul 28, 2026 · 1 revision

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.

1. Add the Local Package

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

2. Import the API

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();

3. Execute FFmpeg

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()}`);

4. Use the Virtual Filesystem

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`);

5. Use FFmpegKit Protocols

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.

6. Execute FFprobe and Read Media Information

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();

7. Sessions, Callbacks and Diagnostics

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();

8. Build Linkage

The Web build supports two linkage modes:

  • Dynamic linkage is the default. libffmpegkit.wasm loads 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.

Clone this wiki locally