Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
[ "$v" = "$version" ] || bad="$bad $p=$v"
done
# Every *_VERSION constant pins a published package version.
for f in packages/ffmpeg/src/const.ts apps/website/src/components/Playground/const.ts scripts/download-assets.js; do
for f in packages/ffmpeg/src/const.ts apps/website/src/components/Playground/const.ts apps/vanilla-app/download-assets.js; do
grep -q "_VERSION = \"$version\"" "$f" || bad="$bad $f"
if grep -E '_VERSION = "[0-9]' "$f" | grep -vq "\"$version\""; then
bad="$bad $f"
Expand Down
7 changes: 6 additions & 1 deletion apps/angular-app/angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,12 @@
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
"src/assets",
{
"glob": "*.js",
"input": "node_modules/@project516/ffmpeg-wasm/dist/esm",
"output": "ffmpeg"
}
],
"styles": [
"src/styles.css"
Expand Down
9 changes: 4 additions & 5 deletions apps/angular-app/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { RouterOutlet } from '@angular/router';
import { FFmpeg } from '@project516/ffmpeg-wasm';
import { fetchFile, toBlobURL } from '@project516/ffmpeg-wasm-util';

const baseURL = 'https://cdn.jsdelivr.net/npm/@project516/ffmpeg-wasm-core-mt@0.13.1/dist/esm';
const baseURL = 'https://cdn.jsdelivr.net/npm/@project516/ffmpeg-wasm-core@0.13.1/dist/esm';

@Component({
selector: 'app-root',
Expand All @@ -23,15 +23,14 @@ export class AppComponent {
this.message = message;
});
await this.ffmpeg.load({
// Angular does not bundle workers from node_modules; angular.json copies
// the library's to /ffmpeg.
classWorkerURL: new URL('ffmpeg/worker.js', document.baseURI).href,
coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, 'text/javascript'),
wasmURL: await toBlobURL(
`${baseURL}/ffmpeg-core.wasm`,
'application/wasm',
),
workerURL: await toBlobURL(
`${baseURL}/ffmpeg-core.worker.js`,
'text/javascript',
),
});
this.loaded = true;
}
Expand Down
4 changes: 2 additions & 2 deletions apps/vanilla-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@
You need to download assets from npm before running the examples:

```bash
$ npm run download
$ pnpm download
```

## Run

To run this example, execute:

```bash
$ npm start
$ pnpm start
```

Visit http://localhost:8080 to check available examples.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Downloads the @project516 packages from npm into public/assets.
const tar = require("tar");
const fs = require("fs");

Expand Down
4 changes: 2 additions & 2 deletions apps/vanilla-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"description": "browser example",
"private": true,
"scripts": {
"download": "node ../../scripts/download-assets.js",
"prestart": "npm run download",
"download": "node download-assets.js",
"prestart": "pnpm download",
"start": "node server.js"
},
"author": "Jerome Wu <jeromewus@gmail.com>",
Expand Down
70 changes: 59 additions & 11 deletions apps/website/docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,32 @@ releases; if you are pinned to one of those, use
[fluent-ffmpeg](https://www.npmjs.com/package/fluent-ffmpeg) instead, or
upgrade.

### Why ffmpeg.wasm is so slow comparing to ffmpeg?

As of now, WebAssembly is still a lot slower than native, it is possible to further speed up using
WebAssembly intrinsic, which is basically writing assembly code. It is something we are investigating
and hope to introduce in the future.

If you are OK with more unstable version of ffmpeg.wasm, using ffmpeg.wasm multithread (mt) version
can have around 2x speed comparing to single thread (but consume a lot more memory and cpu)
### Why is ffmpeg.wasm so slow compared to native ffmpeg?

The core is built with `--disable-asm`, so FFmpeg and its libraries run
plain C code instead of the hand-written assembly and SIMD that native builds
use. Encoding is several times slower than native. Decoding
and remuxing are closer. See [Performance](/docs/performance) and
[FATE and benchmarks](/docs/fate-and-benchmarks) for measurements.

Ways to speed things up:

- Use `@project516/ffmpeg-wasm-core-mt` on a cross-origin isolated page.
Threads run FFmpeg's pipeline and the encoders in parallel, at the cost of
more memory and CPU.
- Pick a faster preset: `-preset ultrafast` for x264, `-deadline realtime`
for VP9.
- Remux with `-c copy` when you do not need to re-encode.
- Mount large inputs with `WORKERFS` instead of copying them in with
`writeFile()`.
- Build a smaller core with a [preset](/docs/presets) if you only need a few
codecs, which also shortens load time.

### Is RTSP supported by ffmpeg.wasm?

We are trying to support, but so far WebAssembly itself lack of features like sockets which makes
it hard to implement RTSP protocol. Possible workarounds are still under investigation.
No. Browsers do not give WebAssembly raw TCP or UDP sockets, so network
protocols such as RTSP and RTMP cannot work. Fetch the input in JavaScript and
write it to the file system, or use WebRTC or MediaRecorder for live streams.

### What is the license of ffmpeg.wasm?

Expand All @@ -37,7 +50,42 @@ The whole project, including both packages, is licensed under AGPL-3.0-or-later.

### What is the maximum size of input file?

2 GB, which is a hard limit in WebAssembly. Might become 4 GB in the future.
It depends on how the file gets in. FFmpeg's own memory is capped at 2 GB in
both cores: the single-thread core starts at 48 MB and grows on demand, the
multi-thread core starts at 1 GB. A file copied in with `writeFile()` also
needs room in the browser's memory, so large files fail well before 2 GB on
low-memory devices.

For big inputs, mount the `File` with `WORKERFS` instead, which reads it
lazily without copying:

```js
await ffmpeg.mount('WORKERFS', { files: [file] }, '/input');
await ffmpeg.exec(['-i', `/input/${file.name}`, 'output.mp4']);
await ffmpeg.unmount('/input');
```

`WORKERFS` mounts are read-only, so write outputs outside the mount point.

### Why are all log messages of type `stderr`?

FFmpeg writes its log, including the banner, progress and warnings, to
stderr, the same as native `ffmpeg`. Listen with `ffmpeg.on('log', ...)` to
read it. Only a few outputs, such as `ffprobe` results printed without
`-o`, go to stdout.

### Why do raw frames differ slightly from native FFmpeg?

Native FFmpeg uses assembly paths in swscale whose rounding differs a little
from the C code this build uses, so pixel values can be off by one. For
output closer to native, add `-sws_flags accurate_rnd+bitexact`.

### How do I decode a WebM video with transparency?

FFmpeg's built-in VP8 and VP9 decoders drop the alpha channel. Ask for the
libvpx decoder before the input:
`['-c:v', 'libvpx-vp9', '-i', 'input.webm', ...]`. The `full` preset, which
the published packages use, includes it.

### How can I build my own ffmpeg.wasm?

Expand Down
17 changes: 13 additions & 4 deletions apps/website/src/components/Playground/Workspace/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,20 @@ import "ace-builds/src-noconflict/mode-text";
import "ace-builds/src-noconflict/theme-dracula";
import "ace-builds/src-noconflict/theme-github";

const genFFmpegText = (args: string) => {
let data: any = [];
// [] while the JSON is incomplete or not a list of strings.
export const parseArgs = (args: string): string[] => {
try {
data = JSON.parse(args);
} catch (e) {}
const data: unknown = JSON.parse(args);
return Array.isArray(data) && data.every((a) => typeof a === "string")
? data
: [];
} catch {
return [];
}
};

const genFFmpegText = (args: string) => {
const data = parseArgs(args);
return `// equivalent ffmpeg.wasm API call
ffmpeg.exec(${JSON.stringify(data)});

Expand Down
4 changes: 2 additions & 2 deletions apps/website/src/components/Playground/Workspace/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { downloadFile } from "@site/src/util";
import { Node } from "./types";
import FileSystemManager from "./FileSystemManager";
import { SAMPLE_FILES } from "../const";
import Editor from "./Editor";
import Editor, { parseArgs } from "./Editor";

const defaultArgs = JSON.stringify(["-i", "video.webm", "video.mp4"], null, 2);

Expand Down Expand Up @@ -155,7 +155,7 @@ export default function Workspace({ ffmpeg: _ffmpeg }: WorkspaceProps) {
ffmpeg.on("log", logListener);
ffmpeg.on("progress", progListener);
const start = performance.now();
const code = await ffmpeg.exec(JSON.parse(args));
const code = await ffmpeg.exec(parseArgs(args));
setTime(performance.now() - start);
ffmpeg.off("log", logListener);
ffmpeg.off("progress", progListener);
Expand Down
Loading