From c39143b08b453dc46ea6ee63319ab6d0b9d46f1f Mon Sep 17 00:00:00 2001 From: Todd T Date: Mon, 9 Oct 2023 11:22:49 -0400 Subject: [PATCH] Add WORKERFS support (#581) * README.md update * Workflow update * Action update * Workflow update * Workflow update * Added workerLoadURL to FFMessageLoadConfig * Add WORKERFS support * Imported WORKERFS types * Import WORKERFS types * Action update * Type updates * Export update * Updated classes * Package together workflow update * Cleanup * Restore CI.yml to upstream * Restore README.md to upstream * Restore classes.ts changes that are not related tp WORKERFS * Restore types.ts changes unrelated to WORERFS * Restore const.ts changes unrelated to WORKERFS * Updated mount to support any enabled filesystems. --------- Co-authored-by: Todd --- build/ffmpeg-wasm.sh | 1 + packages/ffmpeg/src/classes.ts | 28 ++++++++++++++++++++++ packages/ffmpeg/src/const.ts | 4 +++- packages/ffmpeg/src/types.ts | 41 +++++++++++++++++++++++++++++++-- packages/ffmpeg/src/worker.ts | 21 +++++++++++++++++ packages/types/types/index.d.ts | 20 ++++++++++++++++ 6 files changed, 112 insertions(+), 3 deletions(-) diff --git a/build/ffmpeg-wasm.sh b/build/ffmpeg-wasm.sh index 7d4abd1..0fe38f1 100755 --- a/build/ffmpeg-wasm.sh +++ b/build/ffmpeg-wasm.sh @@ -39,6 +39,7 @@ CONF_FLAGS=( -sEXPORT_NAME="$EXPORT_NAME" # required in browser env, so that user can access this module from window object -sEXPORTED_FUNCTIONS=$(node src/bind/ffmpeg/export.js) # exported functions -sEXPORTED_RUNTIME_METHODS=$(node src/bind/ffmpeg/export-runtime.js) # exported built-in functions + -lworkerfs.js --pre-js src/bind/ffmpeg/bind.js # extra bindings, contains most of the ffmpeg.wasm javascript code # ffmpeg source code src/fftools/cmdutils.c diff --git a/packages/ffmpeg/src/classes.ts b/packages/ffmpeg/src/classes.ts index d9348b2..d429962 100644 --- a/packages/ffmpeg/src/classes.ts +++ b/packages/ffmpeg/src/classes.ts @@ -13,6 +13,10 @@ import { LogEventCallback, ProgressEventCallback, FileData, + WorkerFSMountData, + FFFSType, + FFFSMountOptions, + FFFSPath, } from "./types.js"; import { getMessageID } from "./utils.js"; import { ERROR_TERMINATED, ERROR_NOT_LOADED } from "./errors.js"; @@ -56,6 +60,8 @@ export class FFmpeg { this.loaded = true; this.#resolves[id](data); break; + case FFMessageType.MOUNT: + case FFMessageType.UNMOUNT: case FFMessageType.EXEC: case FFMessageType.WRITE_FILE: case FFMessageType.READ_FILE: @@ -292,6 +298,28 @@ export class FFmpeg { ) as Promise; }; + public mount = (fsType: FFFSType, options: FFFSMountOptions, mountPoint: FFFSPath, ): Promise => { + const trans: Transferable[] = []; + return this.#send( + { + type: FFMessageType.MOUNT, + data: { fsType, options, mountPoint }, + }, + trans + ) as Promise; + }; + + public unmount = (mountPoint: FFFSPath): Promise => { + const trans: Transferable[] = []; + return this.#send( + { + type: FFMessageType.UNMOUNT, + data: { mountPoint }, + }, + trans + ) as Promise; + }; + /** * Read data from ffmpeg.wasm. * diff --git a/packages/ffmpeg/src/const.ts b/packages/ffmpeg/src/const.ts index 119ad23..65b03a8 100644 --- a/packages/ffmpeg/src/const.ts +++ b/packages/ffmpeg/src/const.ts @@ -19,4 +19,6 @@ export enum FFMessageType { DOWNLOAD = "DOWNLOAD", PROGRESS = "PROGRESS", LOG = "LOG", -} + MOUNT = "MOUNT", + UNMOUNT = "UNMOUNT", +} \ No newline at end of file diff --git a/packages/ffmpeg/src/types.ts b/packages/ffmpeg/src/types.ts index 411cf29..45aef3f 100644 --- a/packages/ffmpeg/src/types.ts +++ b/packages/ffmpeg/src/types.ts @@ -64,6 +64,41 @@ export interface FFMessageDeleteDirData { path: FFFSPath; } +export enum FFFSType { + MEMFS = "MEMFS", + NODEFS = "NODEFS", + NODERAWFS = "NODERAWFS", + IDBFS = "IDBFS", + WORKERFS = "WORKERFS", + PROXYFS = "PROXYFS", +} + +export type WorkerFSFileEntry = + | File; + +export interface WorkerFSBlobEntry { + name: string; + data: Blob; +} + +export interface WorkerFSMountData { + blobs?: WorkerFSBlobEntry[]; + files?: WorkerFSFileEntry[]; +} + +export type FFFSMountOptions = + | WorkerFSMountData; + +export interface FFMessageMountData { + fsType: FFFSType; + options: FFFSMountOptions; + mountPoint: FFFSPath; +} + +export interface FFMessageUnmountData { + mountPoint: FFFSPath; +} + export type FFMessageData = | FFMessageLoadConfig | FFMessageExecData @@ -73,7 +108,9 @@ export type FFMessageData = | FFMessageRenameData | FFMessageCreateDirData | FFMessageListDirData - | FFMessageDeleteDirData; + | FFMessageDeleteDirData + | FFMessageMountData + | FFMessageUnmountData; export interface Message { type: string; @@ -134,4 +171,4 @@ export interface FFMessageEventCallback { type: string; data: CallbackData; }; -} +} \ No newline at end of file diff --git a/packages/ffmpeg/src/worker.ts b/packages/ffmpeg/src/worker.ts index 398bfa7..446e866 100644 --- a/packages/ffmpeg/src/worker.ts +++ b/packages/ffmpeg/src/worker.ts @@ -14,6 +14,8 @@ import type { FFMessageCreateDirData, FFMessageListDirData, FFMessageDeleteDirData, + FFMessageMountData, + FFMessageUnmountData, CallbackData, IsFirst, OK, @@ -137,6 +139,19 @@ const deleteDir = ({ path }: FFMessageDeleteDirData): OK => { return true; }; +const mount = ({ fsType, options, mountPoint }: FFMessageMountData): OK => { + let str = fsType as keyof typeof ffmpeg.FS.filesystems; + let fs = ffmpeg.FS.filesystems[str]; + if (!fs) return false; + ffmpeg.FS.mount(fs, options, mountPoint); + return true; +}; + +const unmount = ({ mountPoint }: FFMessageUnmountData): OK => { + ffmpeg.FS.unmount(mountPoint); + return true; +}; + self.onmessage = async ({ data: { id, type, data: _data }, }: FFMessageEvent): Promise => { @@ -173,6 +188,12 @@ self.onmessage = async ({ case FFMessageType.DELETE_DIR: data = deleteDir(_data as FFMessageDeleteDirData); break; + case FFMessageType.MOUNT: + data = mount(_data as FFMessageMountData); + break; + case FFMessageType.UNMOUNT: + data = unmount(_data as FFMessageUnmountData); + break; default: throw ERROR_UNKNOWN_MESSAGE_TYPE; } diff --git a/packages/types/types/index.d.ts b/packages/types/types/index.d.ts index 368615f..d3cd4fb 100644 --- a/packages/types/types/index.d.ts +++ b/packages/types/types/index.d.ts @@ -39,6 +39,23 @@ export interface Stat { blocks: number; } +export interface FSFilesystemWORKERFS { + +} + +export interface FSFilesystemMEMFS { + +} + +export interface FSFilesystems { + WORKERFS: FSFilesystemWORKERFS; + MEMFS: FSFilesystemMEMFS; +} + +export type FSFilesystem = +| FSFilesystemWORKERFS +| FSFilesystemMEMFS; + /** * Functions to interact with Emscripten FS library. * @@ -58,6 +75,9 @@ export interface FS { isFile: (mode: number) => boolean; /** mode is a numeric notation of permission, @see [Numeric Notation](https://en.wikipedia.org/wiki/File-system_permissions#Numeric_notation) */ isDir: (mode: number) => boolean; + mount: (fileSystemType: FSFilesystem, data: WorkerFSMountConfig, path: string) => void; + unmount: (path: string) => void; + filesystems: FSFilesystems; } /**