Closed PaTiToMaSteR closed 3 years ago
After seeing so many replies with the same subject, I am going to publish here how to deal with this and how you can compile ffmpeg yourself (some might be afraid or lazy).
Because of the nature of ffmpeg, it is better to have multi-threading to have a better performance. This requires SharedArrayBuffer though, which is the reason many complain it doesn't work / it is not production ready.
@jeromewu already added support to single-thread in the main branch of ffmpeg.wasm-core
. The trick is that it is not being published to npm, but it is ready for use basically (trust me). Saying that, to use it you have to do two things:
ffmpeg.wasm-core
Actions
tab)ffmpeg.wasm
In your application, you will realise quite quickly that just using the new compiled ffmpeg will not work (some error message around main
or proxy_main
).
When you build without multi-threading, proxy_main
is not published anymore, if i understood correctly. It is because this is used as a proxy entry point by ECMScripten when dealing with multi-threading + workers to not block the main thread (more details here). With the single-threaded version you want to use main
as an entry point.
The easiest way to deal with this is (again) forking this repository, applying this patch and build a dist: https://github.com/ffmpegwasm/ffmpeg.wasm/pull/235. This one is quite straight forward to do locally (npm ci && npm build
basically).
Now, in theory your application should work with the following options:
const ffmpeg = createFFmpeg({
corePath: './<path-to-ffmpeg-core-dist>/ffmpeg-core.js',
mainName: 'main'
});
While someone doesn't push these changes in a nicer packaged way, there are still work arounds.
It seems Chrome manifest v2 extensions have support to SharedArrayBuffer, but Firefox doesn't (as of Jan 2021). So, if you are planning to use the instructions above for browser extensions, bear in mind you will need two versions of the same thing.
I usually vendor the libs used on my Chrome Extensions, so if anyone is looking for compiled versions of the ffmpegwasm-core
single-threaded, you are welcome to copy the files at src/vendor/ffmpeg-st*
: https://github.com/brunoluiz/gifsane-extension. The ffmpegwasm
in there as well is patched to fix the proxy aforementioned issues.
I've written a post with the tricks and caveats around implementing FFmpeg in an extension. Mainly a bit of pain on Firefox, due to the missing SharedArrayBuffer, but I had my way: https://brunoluiz.net/blog/2022/jan/gif-sane-playback-control-ffmpegwasm/
Hi @brunoluiz
Thanks for putting together the post.
I have followed it step-by-step (and also tried your vendor files), but i keep coming up against this error when running the single threaded version (Chrome emulator, v98);
Uncaught (in promise) RuntimeError: abort(CompileError: WebAssembly.instantiate(): expected magic word 00 61 73 6d, found 0a 76 61 72 @+0). Build with -s ASSERTIONS=1 for more info.
and similar, yet differently worded error on Safari v15.3 ;
Unhandled Promise Rejection: RuntimeError: abort(CompileError: WebAssembly.Module doesn't parse at byte 0: module doesn't start with '\0asm'). Build with -s ASSERTIONS=1 for more info.
My implementation;
import { createFFmpeg } from '@/vendor/ffmpeg.min'
load = () => {
return new Promise(async resolve => {
this.ffmpeg = createFFmpeg({
log: true,
corePath: './ffmpeg/ffmpeg-core.st.js',
mainName: 'main',
})
await this.ffmpeg.load()
resolve()
})
}
Have you encountered this?
Any help appreciated, Thanks Cam
Ok, managed to resolve it.
It was to do with the 'st' / 'mt' - id's within the file name.
I didn't following your symbolic link approach, therefore the ffmpeg-core.js could never locate ffmpeg-core.wasm.
Hello @brunoluiz Thanks for the guidence, I have followed all steps, but stacked with the last one:
The easiest way to deal with this is (again) forking this repository, applying this patch and build a dist: #235. This one is quite straight forward to do locally (
npm ci && npm build
basically).
Sorry for maybe noob question. After changing createFFmpeg.js acording to #235 I should build a package, from this point could you explane more detaily? How to build the package? Can I build it via workflows/main.yml? If so could you share your yml script?
Sorry for maybe noob question. After changing createFFmpeg.js acording to https://github.com/ffmpegwasm/ffmpeg.wasm/pull/235 I should build a package, from this point could you explane more detaily? How to build the package? Can I build it via workflows/main.yml? If so could you share your yml script?
To build the package, you need to:
ffmpeg.wasm
locallynpm ci
(installs dependencies)npm build
This will generate a new JS package. The caveat is that, if you want to install in other projects through npm, you might need to publish in npm
. You can publish perhaps under a personal scope, such as @USER/ffmpegwasm
or something, but PLEASE leave a README note saying that this is a fork etc. As I used it in a Chrome extension, I didn't need to go through this (copied to a local lib
folder).
What's the conclusion for this? Are we still patching and building ourselves, or is there a simple way to disable the dependency on SharedArrayBuffer?
I added mainName: 'main'
to the options to my createFfmpeg()
call, but it still throws a ReferenceError
about SharedArrayBuffer
not being defined.
Looks like the problem is that this fix is in 0.11.1
, but the highest version on npm is 0.11.0
.
Update: Yes, if you fetch the 0.11.1
version, which is not yet available on npm, you can use the mainName
option.
Any news about a potential easier way instead of having to build ourselves ?
@FrenchGithubUser The unreleased v0.12.0-alpha works in non-SharedArrayBuffer mode. Code: https://github.com/ffmpegwasm/ffmpeg.wasm/tree/v0.12.0-alpha.1
You can install it from npm: npm install @ffmpeg/ffmpeg@0.12.0-alpha.1
However, note that the API is pretty different, and there aren't good docs yet.
I'm having an issue trying to run the latest beta version. Could someone help me figuring out what is wrong with what I did ?
Versions used :
"@ffmpeg/core": "^0.12.0-alpha.2"
"@ffmpeg/ffmpeg": "^0.12.0-alpha.1"
Here is my code :
import { FFmpeg } from '@ffmpeg/ffmpeg'
let load = () => {
return new Promise(async (resolve) => {
const ffmpeg = new FFmpeg({
log: true,
corePath: './ffmpeg/ffmpeg-core.js',
mainName: 'main',
})
ffmpeg.load()
resolve()
})
}
load()
And I'm getting these errors :
failed to send download progress event: RangeError: Invalid typed array length: -1
at new Uint8Array (<anonymous>)
at downloadWithProgress (utils.js?0649:25:1)
at async toBlobURL (utils.js?0649:61:1)
at async load (worker.js?ab3b:16:1)
at async self.onmessage (worker.js?ab3b:80:1)
1 Uncaught (in promise) TypeError: Failed to execute 'arrayBuffer' on 'Response': body stream is locked
at downloadWithProgress (utils.js?0649:45:1)
at async toBlobURL (utils.js?0649:61:1)
at async load (webpack-internal:///./node_modules/@ffmpeg/ffmpeg/dist/esm/worker.js:20:19)
at async self.onmessage (webpack-internal:///./node_modules/@ffmpeg/ffmpeg/dist/esm/worker.js:84:24)
@FrenchGithubUser, you might want to file a different bug report to make sure the team sees it and clearly indicate the alpha version you are using
@jimbojw we are excited to give the new alpha a spin today 😁
It seems that you no longer need to build any of the libraries or to rely on the alpha version as there is a hosted single threaded version on unkpg.
const ffmpeg = createFFmpeg({
corePath: "https://unpkg.com/@ffmpeg/core-st/dist/ffmpeg-core.js",
mainName: "main"
})
I'm still looking for ways to have the corePath take a local path, but it seems to raise issues that are for another thread.
So for now I'll just rely on the above solution. I hope this can help someone out there.
It seems that you no longer need to build any of the libraries or to rely on the alpha version as there is a hosted single threaded version on unkpg.
const ffmpeg = createFFmpeg({ corePath: "https://unpkg.com/@ffmpeg/core-st/dist/ffmpeg-core.js", mainName: "main" })
I'm still looking for ways to have the corePath take a local path, but it seems to raise issues that are for another thread.
So for now I'll just rely on the above solution. I hope this can help someone out there.
I can confirm this is THE Solution saved me from devleoper hell ty dude
It seems that you no longer need to build any of the libraries or to rely on the alpha version as there is a hosted single threaded version on unkpg.
const ffmpeg = createFFmpeg({ corePath: "https://unpkg.com/@ffmpeg/core-st/dist/ffmpeg-core.js", mainName: "main" })
I'm still looking for ways to have the corePath take a local path, but it seems to raise issues that are for another thread.
So for now I'll just rely on the above solution. I hope this can help someone out there.
Correct me if I'm wrong, but I believe it's now just https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.4/ without the "-st." Could be something else though.
Correct me if I'm wrong, but I believe it's now just https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.4/ without the "-st." Could be something else though.
Wouldn't that be the multithreading version? Aka st
means "single thread".
Correct me if I'm wrong, but I believe it's now just https://cdn.jsdelivr.net/npm/@ffmpeg/core@0.12.4/ without the "-st." Could be something else though.
Wouldn't that be the multithreading version? Aka
st
means "single thread".
But this is the multithreading version: https://cdn.jsdelivr.net/npm/@ffmpeg/core-mt@0.12.4/
Is your feature request related to a problem? Please describe. It's a known problem that SharedArrayBuffer was removed due to Spectre and Meldown hacks.
Describe the solution you'd like A safe version without SharedArrayBuffer
Describe alternatives you've considered I don't have the knowledge in Emcripten nor how you transpile the code to know if it's possible.
Additional context To be able to run this amazing project everywhere we need a version without SharedArrayBuffer!