Complete basic rewrite
This commit is contained in:
		
							parent
							
								
									2f18a2d806
								
							
						
					
					
						commit
						a136b8b1bb
					
				@ -37,11 +37,11 @@ RUN bash -x /src/build.sh
 | 
			
		||||
 | 
			
		||||
# Build ffmpeg.wasm
 | 
			
		||||
FROM ffmpeg-builder AS ffmpeg-wasm-builder
 | 
			
		||||
COPY src/bind /src/wasm/bind
 | 
			
		||||
COPY src/fftools /src/wasm/fftools
 | 
			
		||||
COPY src/bind /src/src/bind
 | 
			
		||||
COPY src/fftools /src/src/fftools
 | 
			
		||||
COPY build/ffmpeg-wasm.sh build.sh
 | 
			
		||||
RUN mkdir -p /src/dist/umd && bash -x /src/build.sh -o dist/umd/ffmpeg.js
 | 
			
		||||
RUN mkdir -p /src/dist/esm && bash -x /src/build.sh -sEXPORT_ES6 -o dist/esm/ffmpeg.js
 | 
			
		||||
RUN mkdir -p /src/dist/umd && bash -x /src/build.sh -o dist/umd/ffmpeg-core.js
 | 
			
		||||
RUN mkdir -p /src/dist/esm && bash -x /src/build.sh -sEXPORT_ES6 -o dist/esm/ffmpeg-core.js
 | 
			
		||||
 | 
			
		||||
# Export ffmpeg-core.wasm to dist/, use `docker buildx build -o . .` to get assets
 | 
			
		||||
FROM scratch AS exportor
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								Makefile
									
									
									
									
									
								
							@ -9,13 +9,13 @@ PROD_CFLAGS := -O3 -msimd128
 | 
			
		||||
PROD_MT_CFLAGS := $(PROD_CFLAGS) $(MT_FLAGS)
 | 
			
		||||
 | 
			
		||||
clean:
 | 
			
		||||
	rm -rf ./packages/ffmpeg$(PKG_SUFFIX)/dist
 | 
			
		||||
	rm -rf ./packages/ffmpeg$(PKG_SUFFIX)/types
 | 
			
		||||
	rm -rf ./packages/core$(PKG_SUFFIX)/dist
 | 
			
		||||
	rm -rf ./packages/core$(PKG_SUFFIX)/types
 | 
			
		||||
 | 
			
		||||
.PHONY: build
 | 
			
		||||
build:
 | 
			
		||||
	make clean PKG_SUFFIX="$(PKG_SUFFIX)"
 | 
			
		||||
	cp -r src/types/ffmpeg packages/ffmpeg$(PKG_SUFFIX)/types
 | 
			
		||||
	cp -r src/types/ffmpeg-core packages/core$(PKG_SUFFIX)/types
 | 
			
		||||
	EXTRA_CFLAGS="$(EXTRA_CFLAGS)" \
 | 
			
		||||
	EXTRA_LDFLAGS="$(EXTRA_LDFLAGS)" \
 | 
			
		||||
	FFMPEG_ST="$(FFMPEG_ST)" \
 | 
			
		||||
@ -25,7 +25,7 @@ build:
 | 
			
		||||
			--build-arg EXTRA_LDFLAGS \
 | 
			
		||||
			--build-arg FFMPEG_MT \
 | 
			
		||||
			--build-arg FFMPEG_ST \
 | 
			
		||||
			-o ./packages/ffmpeg$(PKG_SUFFIX) \
 | 
			
		||||
			-o ./packages/core$(PKG_SUFFIX) \
 | 
			
		||||
			$(EXTRA_ARGS) \
 | 
			
		||||
			.
 | 
			
		||||
 | 
			
		||||
@ -49,3 +49,6 @@ prd:
 | 
			
		||||
 | 
			
		||||
prd-mt:
 | 
			
		||||
	make build-mt EXTRA_CFLAGS="$(PROD_MT_CFLAGS)"
 | 
			
		||||
 | 
			
		||||
test:
 | 
			
		||||
	npm run test
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
  "version": "0.0.1",
 | 
			
		||||
  "description": "browser example",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "start": "npx http-server ../../"
 | 
			
		||||
    "start": "npx http-server -c-1 ../../"
 | 
			
		||||
  },
 | 
			
		||||
  "author": "Jerome Wu <jeromewus@gmail.com>",
 | 
			
		||||
  "license": "MIT"
 | 
			
		||||
 | 
			
		||||
@ -11,20 +11,32 @@
 | 
			
		||||
    <p id="message"></p>
 | 
			
		||||
    <script>
 | 
			
		||||
      const { fetchFile } = FFmpegUtil;
 | 
			
		||||
      const { FFmpeg } = FFmpegWASM;
 | 
			
		||||
      let ffmpeg = null;
 | 
			
		||||
 | 
			
		||||
      const transcode = async ({ target: { files } }) => {
 | 
			
		||||
        const message = document.getElementById('message');
 | 
			
		||||
        if (ffmpeg === null) {
 | 
			
		||||
          ffmpeg = await createFFmpeg();
 | 
			
		||||
          ffmpeg.setProgress((progress) => { console.log(progress * 100); });
 | 
			
		||||
          ffmpeg = new FFmpeg();
 | 
			
		||||
          ffmpeg.on(FFmpeg.DOWNLOAD, ({ url, total, received, done }) => {
 | 
			
		||||
              console.log(`downloading ${url}, progress: ${received / total * 100} %, done: ${done}`);
 | 
			
		||||
          });
 | 
			
		||||
          ffmpeg.on(FFmpeg.PROGRESS, (p) => {
 | 
			
		||||
              message.innerHTML = `${p * 100} %`;
 | 
			
		||||
          });
 | 
			
		||||
          ffmpeg.on(FFmpeg.LOG, ({ message }) => {
 | 
			
		||||
              console.log(message);
 | 
			
		||||
          });
 | 
			
		||||
          await ffmpeg.load({
 | 
			
		||||
            coreURL: "/packages/core/dist/umd/ffmpeg-core.js",
 | 
			
		||||
          });
 | 
			
		||||
        }
 | 
			
		||||
        const { name } = files[0];
 | 
			
		||||
        ffmpeg.FS.writeFile(name, await fetchFile(files[0]));
 | 
			
		||||
        await ffmpeg.writeFile(name, await fetchFile(files[0]));
 | 
			
		||||
        message.innerHTML = 'Start transcoding';
 | 
			
		||||
        await ffmpeg.exec('-i', name,  'output.mp4');
 | 
			
		||||
        await ffmpeg.exec(['-i', name,  'output.mp4']);
 | 
			
		||||
        message.innerHTML = 'Complete transcoding';
 | 
			
		||||
        const data = ffmpeg.FS.readFile('output.mp4');
 | 
			
		||||
        const data = await ffmpeg.readFile('output.mp4');
 | 
			
		||||
 | 
			
		||||
        const video = document.getElementById('output-video');
 | 
			
		||||
        video.src = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
 | 
			
		||||
 | 
			
		||||
@ -3,11 +3,11 @@
 | 
			
		||||
# ex:
 | 
			
		||||
#     bash ffmpeg-wasm.sh -o ffmpeg.js
 | 
			
		||||
 | 
			
		||||
EXPORT_NAME="createFFmpeg"
 | 
			
		||||
EXPORT_NAME="createFFmpegCore"
 | 
			
		||||
 | 
			
		||||
CONF_FLAGS=(
 | 
			
		||||
  -I. 
 | 
			
		||||
  -I./wasm/fftools 
 | 
			
		||||
  -I./src/fftools 
 | 
			
		||||
  -I$INSTALL_DIR/include 
 | 
			
		||||
  -L$INSTALL_DIR/lib 
 | 
			
		||||
  -Llibavcodec 
 | 
			
		||||
@ -35,17 +35,17 @@ CONF_FLAGS=(
 | 
			
		||||
  ${FFMPEG_MT:+ -sPTHREAD_POOL_SIZE=32}    # use 32 threads
 | 
			
		||||
  ${FFMPEG_ST:+ -sINITIAL_MEMORY=32MB -sALLOW_MEMORY_GROWTH} # Use just enough memory as memory usage can grow
 | 
			
		||||
  -sEXPORT_NAME="$EXPORT_NAME"             # required in browser env, so that user can access this module from window.createFFmpeg
 | 
			
		||||
  -sEXPORTED_FUNCTIONS=$(node wasm/bind/ffmpeg/export.js) # exported functions
 | 
			
		||||
  -sEXPORTED_RUNTIME_METHODS=$(node wasm/bind/ffmpeg/export-runtime.js) # exported built-in functions
 | 
			
		||||
  --pre-js wasm/bind/ffmpeg/bind.js        # extra bindings, contains most of the ffmpeg.wasm javascript code
 | 
			
		||||
  -sEXPORTED_FUNCTIONS=$(node src/bind/ffmpeg/export.js) # exported functions
 | 
			
		||||
  -sEXPORTED_RUNTIME_METHODS=$(node src/bind/ffmpeg/export-runtime.js) # exported built-in functions
 | 
			
		||||
  --pre-js src/bind/ffmpeg/bind.js        # extra bindings, contains most of the ffmpeg.wasm javascript code
 | 
			
		||||
  # ffmpeg source code
 | 
			
		||||
  wasm/fftools/cmdutils.c 
 | 
			
		||||
  wasm/fftools/ffmpeg.c 
 | 
			
		||||
  wasm/fftools/ffmpeg_filter.c 
 | 
			
		||||
  wasm/fftools/ffmpeg_hw.c 
 | 
			
		||||
  wasm/fftools/ffmpeg_mux.c 
 | 
			
		||||
  wasm/fftools/ffmpeg_opt.c 
 | 
			
		||||
  wasm/fftools/opt_common.c 
 | 
			
		||||
  src/fftools/cmdutils.c 
 | 
			
		||||
  src/fftools/ffmpeg.c 
 | 
			
		||||
  src/fftools/ffmpeg_filter.c 
 | 
			
		||||
  src/fftools/ffmpeg_hw.c 
 | 
			
		||||
  src/fftools/ffmpeg_mux.c 
 | 
			
		||||
  src/fftools/ffmpeg_opt.c 
 | 
			
		||||
  src/fftools/opt_common.c 
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
emcc "${CONF_FLAGS[@]}" $@
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										11372
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										11372
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										2
									
								
								packages/core-mt/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								packages/core-mt/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
dist/
 | 
			
		||||
types/
 | 
			
		||||
							
								
								
									
										50
									
								
								packages/core-mt/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								packages/core-mt/package.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@ffmpeg/core-mt",
 | 
			
		||||
  "version": "0.11.5",
 | 
			
		||||
  "description": "FFmpeg WebAssembly version",
 | 
			
		||||
  "main": "./dist/umd/ffmpeg-core.js",
 | 
			
		||||
  "types": "./types/ffmpeg-core.d.ts",
 | 
			
		||||
  "exports": {
 | 
			
		||||
    ".": {
 | 
			
		||||
      "types": "./types/ffmpeg-core.d.ts",
 | 
			
		||||
      "import": "./dist/esm/ffmpeg-core.js",
 | 
			
		||||
      "require": "./dist/umd/ffmpeg-core.js"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "lint": "eslint types"
 | 
			
		||||
  },
 | 
			
		||||
  "files": [
 | 
			
		||||
    "dist",
 | 
			
		||||
    "types/ffmpeg-core.d.ts"
 | 
			
		||||
  ],
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "git+https://github.com/ffmpegwasm/ffmpeg.wasm.git"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "ffmpeg",
 | 
			
		||||
    "WebAssembly",
 | 
			
		||||
    "video",
 | 
			
		||||
    "audio",
 | 
			
		||||
    "transcode"
 | 
			
		||||
  ],
 | 
			
		||||
  "author": "Jerome Wu <jeromewus@gmail.com>",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "bugs": {
 | 
			
		||||
    "url": "https://github.com/ffmpegwasm/ffmpeg.wasm/issues"
 | 
			
		||||
  },
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">=16.6.0"
 | 
			
		||||
  },
 | 
			
		||||
  "homepage": "https://github.com/ffmpegwasm/ffmpeg.wasm#readme",
 | 
			
		||||
  "publishConfig": {
 | 
			
		||||
    "access": "public"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^5.37.0",
 | 
			
		||||
    "@typescript-eslint/parser": "^5.37.0",
 | 
			
		||||
    "eslint": "^8.23.1",
 | 
			
		||||
    "typescript": "^4.8.3"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								packages/core/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								packages/core/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,2 @@
 | 
			
		||||
dist/
 | 
			
		||||
types/
 | 
			
		||||
							
								
								
									
										50
									
								
								packages/core/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								packages/core/package.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@ffmpeg/core",
 | 
			
		||||
  "version": "0.11.5",
 | 
			
		||||
  "description": "FFmpeg WebAssembly version",
 | 
			
		||||
  "main": "./dist/umd/ffmpeg-core.js",
 | 
			
		||||
  "types": "./types/ffmpeg-core.d.ts",
 | 
			
		||||
  "exports": {
 | 
			
		||||
    ".": {
 | 
			
		||||
      "types": "./types/ffmpeg-core.d.ts",
 | 
			
		||||
      "import": "./dist/esm/ffmpeg-core.js",
 | 
			
		||||
      "require": "./dist/umd/ffmpeg-core.js"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "lint": "eslint types"
 | 
			
		||||
  },
 | 
			
		||||
  "files": [
 | 
			
		||||
    "dist",
 | 
			
		||||
    "types/ffmpeg-core.d.ts"
 | 
			
		||||
  ],
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "git+https://github.com/ffmpegwasm/ffmpeg.wasm.git"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "ffmpeg",
 | 
			
		||||
    "WebAssembly",
 | 
			
		||||
    "video",
 | 
			
		||||
    "audio",
 | 
			
		||||
    "transcode"
 | 
			
		||||
  ],
 | 
			
		||||
  "author": "Jerome Wu <jeromewus@gmail.com>",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "bugs": {
 | 
			
		||||
    "url": "https://github.com/ffmpegwasm/ffmpeg.wasm/issues"
 | 
			
		||||
  },
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">=16.6.0"
 | 
			
		||||
  },
 | 
			
		||||
  "homepage": "https://github.com/ffmpegwasm/ffmpeg.wasm#readme",
 | 
			
		||||
  "publishConfig": {
 | 
			
		||||
    "access": "public"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^5.37.0",
 | 
			
		||||
    "@typescript-eslint/parser": "^5.37.0",
 | 
			
		||||
    "eslint": "^8.23.1",
 | 
			
		||||
    "typescript": "^4.8.3"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								packages/ffmpeg/.eslintignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packages/ffmpeg/.eslintignore
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
.eslintrc.cjs
 | 
			
		||||
							
								
								
									
										13
									
								
								packages/ffmpeg/.eslintrc.cjs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								packages/ffmpeg/.eslintrc.cjs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  extends: [
 | 
			
		||||
    "eslint:recommended",
 | 
			
		||||
    "plugin:@typescript-eslint/recommended",
 | 
			
		||||
    "plugin:@typescript-eslint/recommended-requiring-type-checking",
 | 
			
		||||
  ],
 | 
			
		||||
  parser: "@typescript-eslint/parser",
 | 
			
		||||
  parserOptions: {
 | 
			
		||||
    tsconfigRootDir: __dirname,
 | 
			
		||||
    project: ["./tsconfig.json", "./src/worker/tsconfig.json"],
 | 
			
		||||
  },
 | 
			
		||||
  plugins: ["@typescript-eslint"],
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										2
									
								
								packages/ffmpeg/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								packages/ffmpeg/.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,2 +1,2 @@
 | 
			
		||||
dist/
 | 
			
		||||
types/
 | 
			
		||||
docs/
 | 
			
		||||
 | 
			
		||||
@ -3,16 +3,23 @@
 | 
			
		||||
  "version": "0.11.5",
 | 
			
		||||
  "description": "FFmpeg WebAssembly version",
 | 
			
		||||
  "main": "./dist/umd/ffmpeg.js",
 | 
			
		||||
  "types": "./types/ffmpeg.d.ts",
 | 
			
		||||
  "types": "./dist/umd/ffmpeg.d.ts",
 | 
			
		||||
  "exports": {
 | 
			
		||||
    ".": {
 | 
			
		||||
      "types": "./types/ffmpeg.d.ts",
 | 
			
		||||
      "import": "./dist/esm/ffmpeg.js",
 | 
			
		||||
      "types": "./dist/umd/ffmpeg.d.ts",
 | 
			
		||||
      "import": "./dist/esm/index.js",
 | 
			
		||||
      "require": "./dist/umd/ffmpeg.js"
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "lint": "eslint types"
 | 
			
		||||
    "dev": "webpack --watch -c webpack.dev.config.js",
 | 
			
		||||
    "lint": "eslint src",
 | 
			
		||||
    "clean": "rimraf dist",
 | 
			
		||||
    "build:umd": "webpack",
 | 
			
		||||
    "build:d": "tsc -p tsconfig.d.json",
 | 
			
		||||
    "build:esm": "tsc -p tsconfig.esm.json",
 | 
			
		||||
    "build": "npm-run-all clean build:*",
 | 
			
		||||
    "docs": "typedoc --entryPointStrategy expand ./src"
 | 
			
		||||
  },
 | 
			
		||||
  "files": [
 | 
			
		||||
    "dist",
 | 
			
		||||
@ -45,6 +52,16 @@
 | 
			
		||||
    "@typescript-eslint/eslint-plugin": "^5.37.0",
 | 
			
		||||
    "@typescript-eslint/parser": "^5.37.0",
 | 
			
		||||
    "eslint": "^8.23.1",
 | 
			
		||||
    "typescript": "^4.8.3"
 | 
			
		||||
    "npm-run-all": "^4.1.5",
 | 
			
		||||
    "rimraf": "^3.0.2",
 | 
			
		||||
    "ts-loader": "^9.4.1",
 | 
			
		||||
    "typedoc": "^0.23.15",
 | 
			
		||||
    "typescript": "^4.8.3",
 | 
			
		||||
    "webpack-cli": "^4.10.0",
 | 
			
		||||
    "worker-loader": "^3.0.8"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@ffmpeg/types": "^0.11.5",
 | 
			
		||||
    "events": "^3.3.0"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										215
									
								
								packages/ffmpeg/src/classes.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								packages/ffmpeg/src/classes.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,215 @@
 | 
			
		||||
import EventEmitter from "events";
 | 
			
		||||
import { FFMessageType } from "./const";
 | 
			
		||||
import {
 | 
			
		||||
  CallbackData,
 | 
			
		||||
  Callbacks,
 | 
			
		||||
  DownloadProgressEvent,
 | 
			
		||||
  FFMessageEventCallback,
 | 
			
		||||
  FFMessageLoadConfig,
 | 
			
		||||
  IsDone,
 | 
			
		||||
  IsFirst,
 | 
			
		||||
  LogEvent,
 | 
			
		||||
  Message,
 | 
			
		||||
  Progress,
 | 
			
		||||
} from "./types";
 | 
			
		||||
import { getMessageID } from "./utils";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provides APIs to interact with ffmpeg web worker.
 | 
			
		||||
 *
 | 
			
		||||
 * @example
 | 
			
		||||
 * ```ts
 | 
			
		||||
 * const ffmpeg = new FFmpeg();
 | 
			
		||||
 * ```
 | 
			
		||||
 */
 | 
			
		||||
export class FFmpeg extends EventEmitter {
 | 
			
		||||
  /** @event */ static readonly DOWNLOAD = "download" as const;
 | 
			
		||||
  /** @event */ static readonly LOG = "log" as const;
 | 
			
		||||
  /** @event */ static readonly PROGRESS = "progress" as const;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Listen to download progress events from `ffmpeg.load()`.
 | 
			
		||||
   *
 | 
			
		||||
   * @category Event
 | 
			
		||||
   */
 | 
			
		||||
  on(
 | 
			
		||||
    event: typeof FFmpeg.DOWNLOAD,
 | 
			
		||||
    listener: (data: DownloadProgressEvent) => void
 | 
			
		||||
  ): this;
 | 
			
		||||
  /**
 | 
			
		||||
   * Listen to log events from `ffmpeg.exec()`.
 | 
			
		||||
   *
 | 
			
		||||
   * @remarks
 | 
			
		||||
   * log includes output to stdout and stderr.
 | 
			
		||||
   *
 | 
			
		||||
   * @category Event
 | 
			
		||||
   */
 | 
			
		||||
  on(event: typeof FFmpeg.LOG, listener: (log: LogEvent) => void): this;
 | 
			
		||||
  /**
 | 
			
		||||
   * Listen to progress events from `ffmpeg.exec()`.
 | 
			
		||||
   *
 | 
			
		||||
   * @remarks
 | 
			
		||||
   * The progress events are accurate only when the length of
 | 
			
		||||
   * input and output video/audio file are the same.
 | 
			
		||||
   *
 | 
			
		||||
   * @category Event
 | 
			
		||||
   */
 | 
			
		||||
  on(
 | 
			
		||||
    event: typeof FFmpeg.PROGRESS,
 | 
			
		||||
    listener: (progress: Progress) => void
 | 
			
		||||
  ): this;
 | 
			
		||||
  on(event: string, listener: any): this {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  #worker: Worker;
 | 
			
		||||
  #resolves: Callbacks = {};
 | 
			
		||||
  #rejects: Callbacks = {};
 | 
			
		||||
 | 
			
		||||
  constructor() {
 | 
			
		||||
    super();
 | 
			
		||||
    this.#worker = new Worker(new URL("./worker.ts", import.meta.url));
 | 
			
		||||
    this.#registerHandlers();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /** register worker message event handlers.
 | 
			
		||||
   */
 | 
			
		||||
  #registerHandlers = () => {
 | 
			
		||||
    this.#worker.onmessage = ({
 | 
			
		||||
      data: { id, type, data },
 | 
			
		||||
    }: FFMessageEventCallback) => {
 | 
			
		||||
      switch (type) {
 | 
			
		||||
        case FFMessageType.LOAD:
 | 
			
		||||
        case FFMessageType.EXEC:
 | 
			
		||||
        case FFMessageType.WRITE_FILE:
 | 
			
		||||
        case FFMessageType.READ_FILE:
 | 
			
		||||
          this.#resolves[id](data);
 | 
			
		||||
          break;
 | 
			
		||||
        case FFMessageType.DOWNLOAD:
 | 
			
		||||
          this.emit(FFmpeg.DOWNLOAD, data as DownloadProgressEvent);
 | 
			
		||||
          break;
 | 
			
		||||
        case FFMessageType.LOG:
 | 
			
		||||
          this.emit(FFmpeg.LOG, data as LogEvent);
 | 
			
		||||
          break;
 | 
			
		||||
        case FFMessageType.PROGRESS:
 | 
			
		||||
          this.emit(FFmpeg.PROGRESS, data as Progress);
 | 
			
		||||
          break;
 | 
			
		||||
        case FFMessageType.ERROR:
 | 
			
		||||
          this.#rejects[id](data);
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
      delete this.#resolves[id];
 | 
			
		||||
      delete this.#rejects[id];
 | 
			
		||||
    };
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Generic function to send messages to web worker.
 | 
			
		||||
   */
 | 
			
		||||
  #send = (
 | 
			
		||||
    { type, data }: Message,
 | 
			
		||||
    trans: Transferable[] = []
 | 
			
		||||
  ): Promise<CallbackData> =>
 | 
			
		||||
    new Promise((resolve, reject) => {
 | 
			
		||||
      const id = getMessageID();
 | 
			
		||||
      this.#worker.postMessage({ id, type, data }, trans);
 | 
			
		||||
      this.#resolves[id] = resolve;
 | 
			
		||||
      this.#rejects[id] = reject;
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Loads ffmpeg-core inside web worker. It is required to call this method first
 | 
			
		||||
   * as it initializes WebAssembly and other essential variables.
 | 
			
		||||
   *
 | 
			
		||||
   * @category FFmpeg
 | 
			
		||||
   * @returns `true` if ffmpeg core is loaded for the first time.
 | 
			
		||||
   */
 | 
			
		||||
  public load = (config: FFMessageLoadConfig): Promise<IsFirst> =>
 | 
			
		||||
    this.#send({
 | 
			
		||||
      type: FFMessageType.LOAD,
 | 
			
		||||
      data: config,
 | 
			
		||||
    }) as Promise<IsFirst>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Execute ffmpeg command.
 | 
			
		||||
   *
 | 
			
		||||
   * @remarks
 | 
			
		||||
   * To avoid common I/O issues, ["-nostdin", "-y"] are prepended to the args
 | 
			
		||||
   * by default.
 | 
			
		||||
   *
 | 
			
		||||
   * @example
 | 
			
		||||
   * ```ts
 | 
			
		||||
   * const ffmpeg = new FFmpeg();
 | 
			
		||||
   * await ffmpeg.load();
 | 
			
		||||
   * await ffmpeg.writeFile("video.avi", ...);
 | 
			
		||||
   * // ffmpeg -i video.avi video.mp4
 | 
			
		||||
   * await ffmpeg.exec(["-i", "video.avi", "video.mp4"]);
 | 
			
		||||
   * const data = ffmpeg.readFile("video.mp4");
 | 
			
		||||
   * ```
 | 
			
		||||
   *
 | 
			
		||||
   * @returns `0` if no error, `!= 0` if timeout (1) or error.
 | 
			
		||||
   * @category FFmpeg
 | 
			
		||||
   */
 | 
			
		||||
  public exec = (
 | 
			
		||||
    /** ffmpeg command line args */
 | 
			
		||||
    args: string[],
 | 
			
		||||
    /**
 | 
			
		||||
     * milliseconds to wait before stopping the command execution.
 | 
			
		||||
     *
 | 
			
		||||
     * @defaultValue -1
 | 
			
		||||
     */
 | 
			
		||||
    timeout = -1
 | 
			
		||||
  ): Promise<number> =>
 | 
			
		||||
    this.#send({
 | 
			
		||||
      type: FFMessageType.EXEC,
 | 
			
		||||
      data: { args, timeout },
 | 
			
		||||
    }) as Promise<number>;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Write data to ffmpeg.wasm in memory file system.
 | 
			
		||||
   *
 | 
			
		||||
   * @example
 | 
			
		||||
   * ```ts
 | 
			
		||||
   * const ffmpeg = new FFmpeg();
 | 
			
		||||
   * await ffmpeg.load();
 | 
			
		||||
   * await ffmpeg.writeFile("video.avi", await fetchFile("../video.avi"));
 | 
			
		||||
   * await ffmpeg.writeFile("text.txt", "hello world");
 | 
			
		||||
   * ```
 | 
			
		||||
   *
 | 
			
		||||
   * @category File System
 | 
			
		||||
   */
 | 
			
		||||
  public writeFile = (
 | 
			
		||||
    path: string,
 | 
			
		||||
    bin: Uint8Array | string
 | 
			
		||||
  ): Promise<IsDone> => {
 | 
			
		||||
    const trans: Transferable[] = [];
 | 
			
		||||
    if (bin instanceof Uint8Array) {
 | 
			
		||||
      trans.push(bin.buffer);
 | 
			
		||||
    }
 | 
			
		||||
    return this.#send(
 | 
			
		||||
      {
 | 
			
		||||
        type: FFMessageType.WRITE_FILE,
 | 
			
		||||
        data: { path, bin },
 | 
			
		||||
      },
 | 
			
		||||
      trans
 | 
			
		||||
    ) as Promise<IsDone>;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Read data from ffmpeg.wasm in memory file system.
 | 
			
		||||
   *
 | 
			
		||||
   * @example
 | 
			
		||||
   * ```ts
 | 
			
		||||
   * const ffmpeg = new FFmpeg();
 | 
			
		||||
   * await ffmpeg.load();
 | 
			
		||||
   * const data = await ffmpeg.readFile("video.mp4");
 | 
			
		||||
   * ```
 | 
			
		||||
   *
 | 
			
		||||
   * @category File System
 | 
			
		||||
   */
 | 
			
		||||
  public readFile = (path: string): Promise<Uint8Array> =>
 | 
			
		||||
    this.#send({
 | 
			
		||||
      type: FFMessageType.READ_FILE,
 | 
			
		||||
      data: { path },
 | 
			
		||||
    }) as Promise<Uint8Array>;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								packages/ffmpeg/src/const.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								packages/ffmpeg/src/const.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
export const HeaderContentLength = "Content-Length";
 | 
			
		||||
export const MIME_TYPE_JAVASCRIPT = "text/javascript";
 | 
			
		||||
export const MIME_TYPE_WASM = "application/wasm";
 | 
			
		||||
 | 
			
		||||
export const CORE_VERSION = "0.12.0";
 | 
			
		||||
export const CORE_URL = `https://unpkg.com/@ffmpeg/core@${CORE_VERSION}/dist/umd/ffmpeg-core.js`;
 | 
			
		||||
 | 
			
		||||
export enum FFMessageType {
 | 
			
		||||
  LOAD = "load",
 | 
			
		||||
  WRITE_FILE = "WRITE_FILE",
 | 
			
		||||
  EXEC = "EXEC",
 | 
			
		||||
  READ_FILE = "READ_FILE",
 | 
			
		||||
  ERROR = "ERROR",
 | 
			
		||||
 | 
			
		||||
  DOWNLOAD = "DOWNLOAD",
 | 
			
		||||
  PROGRESS = "PROGRESS",
 | 
			
		||||
  LOG = "LOG",
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								packages/ffmpeg/src/errors.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								packages/ffmpeg/src/errors.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
export const ERROR_RESPONSE_BODY_READER = new Error(
 | 
			
		||||
  "failed to get response body reader"
 | 
			
		||||
);
 | 
			
		||||
export const ERROR_ZERO_CONTENT_LENGTH = new Error(
 | 
			
		||||
  "failed to get Content-Length"
 | 
			
		||||
);
 | 
			
		||||
export const ERROR_UNKNOWN_MESSAGE_TYPE = new Error("unknown message type");
 | 
			
		||||
export const ERROR_NOT_LOADED = new Error(
 | 
			
		||||
  "ffmpeg is not loaded, call `await ffmpeg.load()` first"
 | 
			
		||||
);
 | 
			
		||||
export const ERROR_INCOMPLETED_DOWNLOAD = new Error(
 | 
			
		||||
  "failed to complete download"
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										1
									
								
								packages/ffmpeg/src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packages/ffmpeg/src/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
			
		||||
export * from "./classes";
 | 
			
		||||
							
								
								
									
										128
									
								
								packages/ffmpeg/src/types.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								packages/ffmpeg/src/types.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,128 @@
 | 
			
		||||
export type FFFSPath = string;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * ffmpeg-core loading configuration.
 | 
			
		||||
 */
 | 
			
		||||
export interface FFMessageLoadConfig {
 | 
			
		||||
  /**
 | 
			
		||||
   * `ffmpeg-core.js` URL.
 | 
			
		||||
   *
 | 
			
		||||
   * @defaultValue `https://unpkg.com/@ffmpeg/core@${CORE_VERSION}/dist/umd/ffmpeg-core.js`;
 | 
			
		||||
   */
 | 
			
		||||
  coreURL?: string;
 | 
			
		||||
  /**
 | 
			
		||||
   * `ffmpeg-core.wasm` URL.
 | 
			
		||||
   *
 | 
			
		||||
   * @defaultValue `https://unpkg.com/@ffmpeg/core@${CORE_VERSION}/dist/umd/ffmpeg-core.wasm`;
 | 
			
		||||
   */
 | 
			
		||||
  wasmURL?: string;
 | 
			
		||||
  /**
 | 
			
		||||
   * `ffmpeg-core.worker.js` URL, only being loaded when `thread` is `true`.
 | 
			
		||||
   *
 | 
			
		||||
   * @defaultValue `https://unpkg.com/@ffmpeg/core-mt@${CORE_VERSION}/dist/umd/ffmpeg-core.worker.js`;
 | 
			
		||||
   */
 | 
			
		||||
  workerURL?: string;
 | 
			
		||||
  /**
 | 
			
		||||
   * When `blob` is true, the content of `coreURL`, `wasmURL` and `workerURL`
 | 
			
		||||
   * will be fetched and convert to blob URL. This avoids problems like CORS
 | 
			
		||||
   * and provides download progress than can be listened like below:
 | 
			
		||||
   *
 | 
			
		||||
   * @example
 | 
			
		||||
   * ```ts
 | 
			
		||||
   * const ffmpeg = new FFmpeg();
 | 
			
		||||
   * ffmpeg.on(FFmpeg.DOWNLOAD, (ev) => {
 | 
			
		||||
   *   console.log(ev);
 | 
			
		||||
   * })
 | 
			
		||||
   * await ffmpeg.load();
 | 
			
		||||
   * ```
 | 
			
		||||
   *
 | 
			
		||||
   * @defaultValue `true`
 | 
			
		||||
   */
 | 
			
		||||
  blob?: boolean;
 | 
			
		||||
  /**
 | 
			
		||||
   * When `thread` is true, ffmpeg imports `ffmpeg-core.worker.js` and thus
 | 
			
		||||
   * makes multi-threaded core work.
 | 
			
		||||
   *
 | 
			
		||||
   * @defaultValue `false`
 | 
			
		||||
   */
 | 
			
		||||
  thread?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FFMessageWriteFileData {
 | 
			
		||||
  path: FFFSPath;
 | 
			
		||||
  bin: Uint8Array | string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FFMessageExecData {
 | 
			
		||||
  args: string[];
 | 
			
		||||
  timeout?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FFMessageReadFileData {
 | 
			
		||||
  path: FFFSPath;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type FFMessageData =
 | 
			
		||||
  | FFMessageLoadConfig
 | 
			
		||||
  | FFMessageWriteFileData
 | 
			
		||||
  | FFMessageExecData
 | 
			
		||||
  | FFMessageReadFileData;
 | 
			
		||||
 | 
			
		||||
export interface Message {
 | 
			
		||||
  type: string;
 | 
			
		||||
  data?: FFMessageData;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FFMessage extends Message {
 | 
			
		||||
  id: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FFMessageEvent extends MessageEvent {
 | 
			
		||||
  data: FFMessage;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface DownloadProgressEvent {
 | 
			
		||||
  url: string | URL;
 | 
			
		||||
  total: number;
 | 
			
		||||
  received: number;
 | 
			
		||||
  delta: number;
 | 
			
		||||
  done: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface LogEvent {
 | 
			
		||||
  type: string;
 | 
			
		||||
  message: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type ExitCode = number;
 | 
			
		||||
export type ErrorMessage = string;
 | 
			
		||||
export type FileData = Uint8Array;
 | 
			
		||||
export type Progress = number;
 | 
			
		||||
export type IsFirst = boolean;
 | 
			
		||||
export type IsDone = boolean;
 | 
			
		||||
 | 
			
		||||
export type CallbackData =
 | 
			
		||||
  | FileData
 | 
			
		||||
  | ExitCode
 | 
			
		||||
  | ErrorMessage
 | 
			
		||||
  | DownloadProgressEvent
 | 
			
		||||
  | LogEvent
 | 
			
		||||
  | Progress
 | 
			
		||||
  | IsFirst
 | 
			
		||||
  | IsDone
 | 
			
		||||
  | Error
 | 
			
		||||
  | undefined;
 | 
			
		||||
 | 
			
		||||
export interface Callbacks {
 | 
			
		||||
  [id: number | string]: (data: CallbackData) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FFMessageEventCallback {
 | 
			
		||||
  data: {
 | 
			
		||||
    id: number;
 | 
			
		||||
    type: string;
 | 
			
		||||
    data: CallbackData;
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type ProgressCallback = (event: DownloadProgressEvent) => void;
 | 
			
		||||
							
								
								
									
										62
									
								
								packages/ffmpeg/src/utils.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								packages/ffmpeg/src/utils.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,62 @@
 | 
			
		||||
import {
 | 
			
		||||
  ERROR_RESPONSE_BODY_READER,
 | 
			
		||||
  ERROR_ZERO_CONTENT_LENGTH,
 | 
			
		||||
  ERROR_INCOMPLETED_DOWNLOAD,
 | 
			
		||||
} from "./errors";
 | 
			
		||||
import { HeaderContentLength } from "./const";
 | 
			
		||||
import { ProgressCallback } from "./types";
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Generate an unique message ID.
 | 
			
		||||
 */
 | 
			
		||||
export const getMessageID = (() => {
 | 
			
		||||
  let messageID = 0;
 | 
			
		||||
  return () => messageID++;
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Download content of a URL with progress.
 | 
			
		||||
 */
 | 
			
		||||
export const downloadWithProgress = async (
 | 
			
		||||
  url: string | URL,
 | 
			
		||||
  cb: ProgressCallback
 | 
			
		||||
): Promise<Uint8Array> => {
 | 
			
		||||
  const resp = await fetch(url);
 | 
			
		||||
  const reader = resp.body?.getReader();
 | 
			
		||||
  if (!reader) throw ERROR_RESPONSE_BODY_READER;
 | 
			
		||||
 | 
			
		||||
  const total = parseInt(resp.headers.get(HeaderContentLength) || "0");
 | 
			
		||||
  if (total === 0) throw ERROR_ZERO_CONTENT_LENGTH;
 | 
			
		||||
 | 
			
		||||
  const data = new Uint8Array(total);
 | 
			
		||||
  let received = 0;
 | 
			
		||||
  for (;;) {
 | 
			
		||||
    const { done, value } = await reader.read();
 | 
			
		||||
    const delta = value ? value.length : 0;
 | 
			
		||||
 | 
			
		||||
    if (done) {
 | 
			
		||||
      if (total !== received) throw ERROR_INCOMPLETED_DOWNLOAD;
 | 
			
		||||
      cb({ url, total, received, delta, done });
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    data.set(value, received);
 | 
			
		||||
    received += delta;
 | 
			
		||||
    cb({ url, total, received, delta, done });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Convert an URL to an Blob URL to avoid issues like CORS.
 | 
			
		||||
 */
 | 
			
		||||
export const toBlobURL = async (
 | 
			
		||||
  url: string,
 | 
			
		||||
  /** mime type like `text/javascript` and `application/wasm` */
 | 
			
		||||
  mimeType: string,
 | 
			
		||||
  cb: ProgressCallback
 | 
			
		||||
): Promise<string> =>
 | 
			
		||||
  URL.createObjectURL(
 | 
			
		||||
    new Blob([(await downloadWithProgress(url, cb)).buffer], { type: mimeType })
 | 
			
		||||
  );
 | 
			
		||||
							
								
								
									
										132
									
								
								packages/ffmpeg/src/worker.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								packages/ffmpeg/src/worker.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,132 @@
 | 
			
		||||
/// <reference no-default-lib="true" />
 | 
			
		||||
/// <reference lib="esnext" />
 | 
			
		||||
/// <reference lib="webworker" />
 | 
			
		||||
 | 
			
		||||
import type { FFmpegCoreModule, FFmpegCoreModuleFactory } from "@ffmpeg/types";
 | 
			
		||||
import type {
 | 
			
		||||
  FFMessageEvent,
 | 
			
		||||
  FFMessageLoadConfig,
 | 
			
		||||
  FFMessageWriteFileData,
 | 
			
		||||
  FFMessageExecData,
 | 
			
		||||
  FFMessageReadFileData,
 | 
			
		||||
  CallbackData,
 | 
			
		||||
  IsFirst,
 | 
			
		||||
  IsDone,
 | 
			
		||||
  ExitCode,
 | 
			
		||||
} from "./types";
 | 
			
		||||
import { toBlobURL } from "./utils";
 | 
			
		||||
import {
 | 
			
		||||
  CORE_URL,
 | 
			
		||||
  FFMessageType,
 | 
			
		||||
  MIME_TYPE_JAVASCRIPT,
 | 
			
		||||
  MIME_TYPE_WASM,
 | 
			
		||||
} from "./const";
 | 
			
		||||
import { ERROR_UNKNOWN_MESSAGE_TYPE, ERROR_NOT_LOADED } from "./errors";
 | 
			
		||||
 | 
			
		||||
declare global {
 | 
			
		||||
  interface WorkerGlobalScope {
 | 
			
		||||
    createFFmpegCore: FFmpegCoreModuleFactory;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let ffmpeg: FFmpegCoreModule;
 | 
			
		||||
 | 
			
		||||
const load = async ({
 | 
			
		||||
  coreURL: _coreURL = CORE_URL,
 | 
			
		||||
  wasmURL: _wasmURL,
 | 
			
		||||
  workerURL: _workerURL,
 | 
			
		||||
  blob = true,
 | 
			
		||||
  thread = false,
 | 
			
		||||
}: FFMessageLoadConfig): Promise<IsFirst> => {
 | 
			
		||||
  const first = !ffmpeg;
 | 
			
		||||
  let coreURL = _coreURL;
 | 
			
		||||
  let wasmURL = _wasmURL ? _wasmURL : _coreURL.replace(/.js$/g, ".wasm");
 | 
			
		||||
  let workerURL = _workerURL
 | 
			
		||||
    ? _workerURL
 | 
			
		||||
    : _coreURL.replace(/.js$/g, ".worker.js");
 | 
			
		||||
 | 
			
		||||
  if (blob) {
 | 
			
		||||
    coreURL = await toBlobURL(coreURL, MIME_TYPE_JAVASCRIPT, (data) =>
 | 
			
		||||
      self.postMessage({ type: FFMessageType.DOWNLOAD, data })
 | 
			
		||||
    );
 | 
			
		||||
    wasmURL = await toBlobURL(wasmURL, MIME_TYPE_WASM, (data) =>
 | 
			
		||||
      self.postMessage({ type: FFMessageType.DOWNLOAD, data })
 | 
			
		||||
    );
 | 
			
		||||
    if (thread) {
 | 
			
		||||
      try {
 | 
			
		||||
        workerURL = await toBlobURL(workerURL, MIME_TYPE_JAVASCRIPT, (data) =>
 | 
			
		||||
          self.postMessage({ type: FFMessageType.DOWNLOAD, data })
 | 
			
		||||
        );
 | 
			
		||||
        // eslint-disable-next-line
 | 
			
		||||
      } catch (e) {}
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  importScripts(coreURL);
 | 
			
		||||
  ffmpeg = await (self as WorkerGlobalScope).createFFmpegCore({
 | 
			
		||||
    // Fixed `Overload resolution failed.` when using multi-threaded ffmpeg-core.
 | 
			
		||||
    mainScriptUrlOrBlob: coreURL,
 | 
			
		||||
    locateFile: (path: string, prefix: string): string => {
 | 
			
		||||
      if (path.endsWith(".wasm")) return wasmURL;
 | 
			
		||||
      if (path.endsWith(".worker.js")) return workerURL;
 | 
			
		||||
      return prefix + path;
 | 
			
		||||
    },
 | 
			
		||||
  });
 | 
			
		||||
  ffmpeg.setLogger((data) =>
 | 
			
		||||
    self.postMessage({ type: FFMessageType.LOG, data })
 | 
			
		||||
  );
 | 
			
		||||
  ffmpeg.setProgress((data: number) =>
 | 
			
		||||
    self.postMessage({ type: FFMessageType.PROGRESS, data })
 | 
			
		||||
  );
 | 
			
		||||
  return first;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const writeFile = ({ path, bin }: FFMessageWriteFileData): IsDone => {
 | 
			
		||||
  ffmpeg.FS.writeFile(path, bin);
 | 
			
		||||
  return true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const exec = ({ args, timeout = -1 }: FFMessageExecData): ExitCode => {
 | 
			
		||||
  ffmpeg.setTimeout(timeout);
 | 
			
		||||
  ffmpeg.exec(...args);
 | 
			
		||||
  const ret = ffmpeg.ret;
 | 
			
		||||
  ffmpeg.reset();
 | 
			
		||||
  return ret;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const readFile = ({ path }: FFMessageReadFileData): Uint8Array =>
 | 
			
		||||
  ffmpeg.FS.readFile(path);
 | 
			
		||||
 | 
			
		||||
self.onmessage = async ({
 | 
			
		||||
  data: { id, type, data: _data },
 | 
			
		||||
}: FFMessageEvent): Promise<void> => {
 | 
			
		||||
  const trans = [];
 | 
			
		||||
  let data: CallbackData;
 | 
			
		||||
  try {
 | 
			
		||||
    if (type !== FFMessageType.LOAD && !ffmpeg) throw ERROR_NOT_LOADED;
 | 
			
		||||
 | 
			
		||||
    switch (type) {
 | 
			
		||||
      case FFMessageType.LOAD:
 | 
			
		||||
        data = await load(_data as FFMessageLoadConfig);
 | 
			
		||||
        break;
 | 
			
		||||
      case FFMessageType.WRITE_FILE:
 | 
			
		||||
        data = writeFile(_data as FFMessageWriteFileData);
 | 
			
		||||
        break;
 | 
			
		||||
      case FFMessageType.EXEC:
 | 
			
		||||
        data = exec(_data as FFMessageExecData);
 | 
			
		||||
        break;
 | 
			
		||||
      case FFMessageType.READ_FILE:
 | 
			
		||||
        data = readFile(_data as FFMessageReadFileData);
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        throw ERROR_UNKNOWN_MESSAGE_TYPE;
 | 
			
		||||
    }
 | 
			
		||||
  } catch (e) {
 | 
			
		||||
    self.postMessage({ id, type: FFMessageType.ERROR, data: e as Error });
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  if (data instanceof Uint8Array) {
 | 
			
		||||
    trans.push(data.buffer);
 | 
			
		||||
  }
 | 
			
		||||
  self.postMessage({ id, type, data }, trans);
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										10
									
								
								packages/ffmpeg/tsconfig.d.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								packages/ffmpeg/tsconfig.d.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": "./tsconfig.json",
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "rootDir": "src",
 | 
			
		||||
    "declaration": true,
 | 
			
		||||
    "declarationMap": true,
 | 
			
		||||
    "emitDeclarationOnly": true,
 | 
			
		||||
    "outFile": "dist/umd/ffmpeg.d.ts"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										9
									
								
								packages/ffmpeg/tsconfig.esm.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								packages/ffmpeg/tsconfig.esm.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": "./tsconfig.json",
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "rootDir": "src",
 | 
			
		||||
    "declaration": true,
 | 
			
		||||
    "outDir": "./dist/esm",
 | 
			
		||||
    "target": "esnext"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										7
									
								
								packages/ffmpeg/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								packages/ffmpeg/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "extends": "../../tsconfig.json",
 | 
			
		||||
  "compilerOptions": {
 | 
			
		||||
    "module": "esnext",
 | 
			
		||||
    "rootDir": "src"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								packages/ffmpeg/webpack.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								packages/ffmpeg/webpack.config.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
const path = require("path");
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  mode: "production",
 | 
			
		||||
  devtool: "source-map",
 | 
			
		||||
  entry: "./src/index.ts",
 | 
			
		||||
  module: {
 | 
			
		||||
    rules: [
 | 
			
		||||
      {
 | 
			
		||||
        test: /\.ts$/,
 | 
			
		||||
        loader: "ts-loader",
 | 
			
		||||
        options: {
 | 
			
		||||
          transpileOnly: false,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
  resolve: {
 | 
			
		||||
    extensions: [".ts"],
 | 
			
		||||
  },
 | 
			
		||||
  output: {
 | 
			
		||||
    path: path.resolve(__dirname, "dist/umd"),
 | 
			
		||||
    filename: "ffmpeg.js",
 | 
			
		||||
    library: "FFmpegWASM",
 | 
			
		||||
    libraryTarget: "umd",
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										27
									
								
								packages/ffmpeg/webpack.dev.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								packages/ffmpeg/webpack.dev.config.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,27 @@
 | 
			
		||||
const path = require("path");
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  mode: "development",
 | 
			
		||||
  devtool: "source-map",
 | 
			
		||||
  entry: "./src/index.ts",
 | 
			
		||||
  module: {
 | 
			
		||||
    rules: [
 | 
			
		||||
      {
 | 
			
		||||
        test: /\.ts$/,
 | 
			
		||||
        loader: "ts-loader",
 | 
			
		||||
        options: {
 | 
			
		||||
          transpileOnly: false,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    ],
 | 
			
		||||
  },
 | 
			
		||||
  resolve: {
 | 
			
		||||
    extensions: [".ts"],
 | 
			
		||||
  },
 | 
			
		||||
  output: {
 | 
			
		||||
    path: path.resolve(__dirname, "dist/umd"),
 | 
			
		||||
    filename: "ffmpeg.js",
 | 
			
		||||
    library: "FFmpegWASM",
 | 
			
		||||
    libraryTarget: "umd",
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										38
									
								
								packages/types/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								packages/types/package.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@ffmpeg/types",
 | 
			
		||||
  "version": "0.11.5",
 | 
			
		||||
  "description": "ffmpeg.wasm types",
 | 
			
		||||
  "types": "types",
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "lint": "dtslint types"
 | 
			
		||||
  },
 | 
			
		||||
  "files": [
 | 
			
		||||
    "types"
 | 
			
		||||
  ],
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "git+https://github.com/ffmpegwasm/ffmpeg.wasm.git"
 | 
			
		||||
  },
 | 
			
		||||
  "keywords": [
 | 
			
		||||
    "ffmpeg",
 | 
			
		||||
    "WebAssembly",
 | 
			
		||||
    "video",
 | 
			
		||||
    "audio",
 | 
			
		||||
    "transcode"
 | 
			
		||||
  ],
 | 
			
		||||
  "author": "Jerome Wu <jeromewus@gmail.com>",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "bugs": {
 | 
			
		||||
    "url": "https://github.com/ffmpegwasm/ffmpeg.wasm/issues"
 | 
			
		||||
  },
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">=16.6.0"
 | 
			
		||||
  },
 | 
			
		||||
  "homepage": "https://github.com/ffmpegwasm/ffmpeg.wasm#readme",
 | 
			
		||||
  "publishConfig": {
 | 
			
		||||
    "access": "public"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@definitelytyped/dtslint": "^0.0.133"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								packages/types/types/index.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								packages/types/types/index.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,39 @@
 | 
			
		||||
export type Pointer = number;
 | 
			
		||||
export type StringPointer = Pointer;
 | 
			
		||||
export type StringArrayPointer = Pointer;
 | 
			
		||||
 | 
			
		||||
export interface FS {
 | 
			
		||||
  mkdir: (fileName: string) => void;
 | 
			
		||||
  readFile: (fileName: string) => Uint8Array;
 | 
			
		||||
  readdir: (pathName: string) => string[];
 | 
			
		||||
  unlink: (fileName: string) => void;
 | 
			
		||||
  writeFile: (fileName: string, binaryData: Uint8Array | string) => void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Log {
 | 
			
		||||
  type: string;
 | 
			
		||||
  message: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FFmpegCoreModule {
 | 
			
		||||
  DEFAULT_ARGS: string[];
 | 
			
		||||
  FS: FS;
 | 
			
		||||
  NULL: Pointer;
 | 
			
		||||
  SIZE_I32: number;
 | 
			
		||||
 | 
			
		||||
  ret: number;
 | 
			
		||||
  timeout: number;
 | 
			
		||||
  mainScriptUrlOrBlob: string;
 | 
			
		||||
 | 
			
		||||
  exec: (...args: string[]) => number;
 | 
			
		||||
  reset: () => void;
 | 
			
		||||
  setLogger: (logger: (log: Log) => void) => void;
 | 
			
		||||
  setTimeout: (timeout: number) => void;
 | 
			
		||||
  setProgress: (handler: (progress: number) => void) => void;
 | 
			
		||||
 | 
			
		||||
  locateFile: (path: string, prefix: string) => string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type FFmpegCoreModuleFactory = (
 | 
			
		||||
  moduleOverrides?: Partial<FFmpegCoreModule>
 | 
			
		||||
) => Promise<FFmpegCoreModule>;
 | 
			
		||||
							
								
								
									
										18
									
								
								packages/types/types/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								packages/types/types/tsconfig.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
			
		||||
{
 | 
			
		||||
    "compilerOptions": {
 | 
			
		||||
        "module": "commonjs",
 | 
			
		||||
        "lib": ["es6"],
 | 
			
		||||
        "noImplicitAny": true,
 | 
			
		||||
        "noImplicitThis": true,
 | 
			
		||||
        "strictFunctionTypes": true,
 | 
			
		||||
        "strictNullChecks": true,
 | 
			
		||||
        "types": [],
 | 
			
		||||
        "noEmit": true,
 | 
			
		||||
        "forceConsistentCasingInFileNames": true,
 | 
			
		||||
 | 
			
		||||
        // If the library is an external module (uses `export`), this allows your test file to import "mylib" instead of "./index".
 | 
			
		||||
        // If the library is global (cannot be imported via `import` or `require`), leave this out.
 | 
			
		||||
        "baseUrl": ".",
 | 
			
		||||
        "paths": { "@ffmpeg/types": ["."] }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1707,7 +1707,8 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (print_stats || is_last_report) {
 | 
			
		||||
        const char end = is_last_report ? '\n' : '\r';
 | 
			
		||||
        // Always print a new line of message.
 | 
			
		||||
        const char end = '\n'; //is_last_report ? '\n' : '\r';
 | 
			
		||||
        if (print_stats==1 && AV_LOG_INFO > av_log_get_level()) {
 | 
			
		||||
            fprintf(stderr, "%s    %c", buf.str, end);
 | 
			
		||||
        } else
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@
 | 
			
		||||
  "extends": "eslint:recommended",
 | 
			
		||||
  "globals": {
 | 
			
		||||
    "expect": true,
 | 
			
		||||
    "createFFmpeg": true,
 | 
			
		||||
    "createFFmpegCore": true,
 | 
			
		||||
    "VIDEO_1S_MP4": true,
 | 
			
		||||
    "FFMPEG_TYPE": true
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
@ -9,13 +9,13 @@
 | 
			
		||||
  <div id="mocha"></div>
 | 
			
		||||
  <script src="../node_modules/mocha/mocha.js"></script>
 | 
			
		||||
  <script src="../node_modules/chai/chai.js"></script>
 | 
			
		||||
  <script src="../packages/ffmpeg-mt/dist/umd/ffmpeg.js"></script>
 | 
			
		||||
  <script src="../packages/core-mt/dist/umd/ffmpeg-core.js"></script>
 | 
			
		||||
  <script src="./constants.js"></script>
 | 
			
		||||
  <script type="text/javascript">
 | 
			
		||||
    window.FFMPEG_TYPE = "mt";
 | 
			
		||||
  </script>
 | 
			
		||||
  <script>mocha.setup('bdd');</script>
 | 
			
		||||
  <script src="./ffmpeg.test.js"></script>
 | 
			
		||||
  <script src="./ffmpeg-core.test.js"></script>
 | 
			
		||||
  <script>
 | 
			
		||||
    window.expect = chai.expect;
 | 
			
		||||
    mocha.run();
 | 
			
		||||
@ -9,13 +9,13 @@
 | 
			
		||||
  <div id="mocha"></div>
 | 
			
		||||
  <script src="../node_modules/mocha/mocha.js"></script>
 | 
			
		||||
  <script src="../node_modules/chai/chai.js"></script>
 | 
			
		||||
  <script src="../packages/ffmpeg/dist/umd/ffmpeg.js"></script>
 | 
			
		||||
  <script src="../packages/core/dist/umd/ffmpeg-core.js"></script>
 | 
			
		||||
  <script src="./constants.js"></script>
 | 
			
		||||
  <script type="text/javascript">
 | 
			
		||||
    window.FFMPEG_TYPE = "st";
 | 
			
		||||
  </script>
 | 
			
		||||
  <script>mocha.setup('bdd');</script>
 | 
			
		||||
  <script src="./ffmpeg.test.js"></script>
 | 
			
		||||
  <script src="./ffmpeg-core.test.js"></script>
 | 
			
		||||
  <script>
 | 
			
		||||
    window.expect = chai.expect;
 | 
			
		||||
    mocha.run();
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
let ffmpeg;
 | 
			
		||||
 | 
			
		||||
const genName = (name) => `[ffmpeg][${FFMPEG_TYPE}] ${name}`;
 | 
			
		||||
const genName = (name) => `[ffmpeg-core][${FFMPEG_TYPE}] ${name}`;
 | 
			
		||||
 | 
			
		||||
const b64ToUint8Array = (b64) => {
 | 
			
		||||
  const bin = atob(b64);
 | 
			
		||||
@ -19,7 +19,7 @@ const reset = () => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
before(async () => {
 | 
			
		||||
  ffmpeg = await createFFmpeg();
 | 
			
		||||
  ffmpeg = await createFFmpegCore();
 | 
			
		||||
  ffmpeg.FS.writeFile("video.mp4", b64ToUint8Array(VIDEO_1S_MP4));
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ const chai = require("chai");
 | 
			
		||||
const constants = require("./constants");
 | 
			
		||||
 | 
			
		||||
global.expect = chai.expect;
 | 
			
		||||
global.createFFmpeg = require("../packages/ffmpeg-mt");
 | 
			
		||||
global.createFFmpegCore = require("../packages/core-mt");
 | 
			
		||||
global.atob = require("./util").atob;
 | 
			
		||||
global.FFMPEG_TYPE = "mt";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ const chai = require("chai");
 | 
			
		||||
const constants = require("./constants");
 | 
			
		||||
 | 
			
		||||
global.expect = chai.expect;
 | 
			
		||||
global.createFFmpeg = require("../packages/ffmpeg");
 | 
			
		||||
global.createFFmpegCore = require("../packages/core");
 | 
			
		||||
global.atob = require("./util").atob;
 | 
			
		||||
global.FFMPEG_TYPE = "st";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,7 @@
 | 
			
		||||
 | 
			
		||||
    /* Projects */
 | 
			
		||||
    // "incremental": true,                              /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
 | 
			
		||||
    // "composite": true,                                /* Enable constraints that allow a TypeScript project to be used with project references. */
 | 
			
		||||
    // "composite": true,                                [> Enable constraints that allow a TypeScript project to be used with project references. <]
 | 
			
		||||
    // "tsBuildInfoFile": "./.tsbuildinfo",              /* Specify the path to .tsbuildinfo incremental compilation file. */
 | 
			
		||||
    // "disableSourceOfProjectReferenceRedirect": true,  /* Disable preferring source files instead of declaration files when referencing composite projects. */
 | 
			
		||||
    // "disableSolutionSearching": true,                 /* Opt a project out of multi-project reference checking when editing. */
 | 
			
		||||
@ -46,7 +46,7 @@
 | 
			
		||||
    // "maxNodeModuleJsDepth": 1,                        /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
 | 
			
		||||
 | 
			
		||||
    /* Emit */
 | 
			
		||||
    "declaration": true,                              /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
 | 
			
		||||
    // "declaration": true,                              [> Generate .d.ts files from TypeScript and JavaScript files in your project. <]
 | 
			
		||||
    // "declarationMap": true,                           /* Create sourcemaps for d.ts files. */
 | 
			
		||||
    // "emitDeclarationOnly": true,                      /* Only output d.ts files and not JavaScript files. */
 | 
			
		||||
    // "sourceMap": true,                                /* Create source map files for emitted JavaScript files. */
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user