diff --git a/packages/ffmpeg/src/classes.ts b/packages/ffmpeg/src/classes.ts index 48d9e2c4a4..9d38f3bfa1 100644 --- a/packages/ffmpeg/src/classes.ts +++ b/packages/ffmpeg/src/classes.ts @@ -1,5 +1,6 @@ -import { FFMessageType } from "./const.js"; +import { FFMessageType, MIME_TYPE_JAVASCRIPT, MIME_TYPE_WASM } from "./const.js"; import { + BinaryFileData, CallbackData, Callbacks, FSNode, @@ -20,6 +21,16 @@ import { import { getMessageID } from "./utils.js"; import { ERROR_TERMINATED, ERROR_NOT_LOADED } from "./errors.js"; +/** + * Convert binary file data (ArrayBuffer, Uint8Array, or Blob) to a Blob URL + * so the web worker can consume it as a regular URL string. + */ +const toBlobURL = (data: BinaryFileData, mimeType: string): string => { + const blob = + data instanceof Blob ? data : new Blob([data], { type: mimeType }); + return URL.createObjectURL(blob); +}; + type FFMessageOptions = { signal?: AbortSignal; }; @@ -185,7 +196,13 @@ export class FFmpeg { * @returns `true` if ffmpeg core is loaded for the first time. */ public load = ( - { classWorkerURL, ...config }: FFMessageLoadConfig = {}, + { + classWorkerURL, + coreData, + wasmData, + workerData, + ...config + }: FFMessageLoadConfig = {}, { signal }: FFMessageOptions = {} ): Promise => { if (!this.#worker) { @@ -200,6 +217,12 @@ export class FFmpeg { }); this.#registerHandlers(); } + // Convert binary data to Blob URLs so the worker can load them as + // regular URL strings. Binary data takes precedence over URL strings. + if (coreData) config.coreURL = toBlobURL(coreData, MIME_TYPE_JAVASCRIPT); + if (wasmData) config.wasmURL = toBlobURL(wasmData, MIME_TYPE_WASM); + if (workerData) + config.workerURL = toBlobURL(workerData, MIME_TYPE_JAVASCRIPT); return this.#send( { type: FFMessageType.LOAD, diff --git a/packages/ffmpeg/src/types.ts b/packages/ffmpeg/src/types.ts index 5ddf97d50e..7249fc4f81 100644 --- a/packages/ffmpeg/src/types.ts +++ b/packages/ffmpeg/src/types.ts @@ -1,5 +1,12 @@ export type FFFSPath = string; +/** + * Binary file data that can be passed directly instead of a URL. + * When provided, a Blob URL is created internally so the worker + * can consume it as a regular URL. + */ +export type BinaryFileData = ArrayBuffer | Uint8Array | Blob; + /** * ffmpeg-core loading configuration. */ @@ -23,6 +30,21 @@ export interface FFMessageLoadConfig { * @defaultValue `https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@${CORE_VERSION}/dist/umd/ffmpeg-core.worker.js`; */ workerURL?: string; + /** + * `ffmpeg-core.js` file content as binary data. When provided, takes + * precedence over `coreURL` and a Blob URL is created internally. + */ + coreData?: BinaryFileData; + /** + * `ffmpeg-core.wasm` file content as binary data. When provided, takes + * precedence over `wasmURL` and a Blob URL is created internally. + */ + wasmData?: BinaryFileData; + /** + * `ffmpeg-core.worker.js` file content as binary data. When provided, + * takes precedence over `workerURL` and a Blob URL is created internally. + */ + workerData?: BinaryFileData; /** * `ffmpeg.worker.js` URL. This worker is spawned when FFmpeg.load() is called, it is an essential worker and usually you don't need to update this config. *