summaryrefslogtreecommitdiff
path: root/internal/media/ffmpeg/wasm.go
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2024-11-06 13:38:13 +0000
committerLibravatar GitHub <noreply@github.com>2024-11-06 14:38:13 +0100
commitb84637801ae9e9cf330d91ce7e2e7734a7c6130c (patch)
treee7518f95e0a44506c24c298dd88c654c0a4bdae5 /internal/media/ffmpeg/wasm.go
parent[bugfix] sets the max value placeholders to MaxInt32 instead of MaxInt (#3517) (diff)
downloadgotosocial-b84637801ae9e9cf330d91ce7e2e7734a7c6130c.tar.xz
[chore] update go ffmpreg to v0.6.0 (#3515)
* pull in go-ffmpreg v0.6.0 * add code comment * grrr linter * set empty module name when calling ffmpeg / ffprobe
Diffstat (limited to 'internal/media/ffmpeg/wasm.go')
-rw-r--r--internal/media/ffmpeg/wasm.go133
1 files changed, 70 insertions, 63 deletions
diff --git a/internal/media/ffmpeg/wasm.go b/internal/media/ffmpeg/wasm.go
index b23809d93..a5612ba14 100644
--- a/internal/media/ffmpeg/wasm.go
+++ b/internal/media/ffmpeg/wasm.go
@@ -22,72 +22,27 @@ package ffmpeg
import (
"context"
"os"
+ "sync/atomic"
+ "unsafe"
- ffmpeglib "codeberg.org/gruf/go-ffmpreg/embed/ffmpeg"
- ffprobelib "codeberg.org/gruf/go-ffmpreg/embed/ffprobe"
+ "codeberg.org/gruf/go-ffmpreg/embed"
"codeberg.org/gruf/go-ffmpreg/wasm"
"github.com/tetratelabs/wazero"
)
-var (
- // shared WASM runtime instance.
- runtime wazero.Runtime
-
- // ffmpeg / ffprobe compiled WASM.
- ffmpeg wazero.CompiledModule
- ffprobe wazero.CompiledModule
-)
-
-// compileFfmpeg ensures the ffmpeg WebAssembly has been
-// pre-compiled into memory. If already compiled is a no-op.
-func compileFfmpeg(ctx context.Context) error {
- if ffmpeg != nil {
- return nil
- }
-
- // Ensure runtime already initialized.
- if err := initRuntime(ctx); err != nil {
- return err
- }
-
- // Compile the ffmpeg WebAssembly module into memory.
- cmod, err := runtime.CompileModule(ctx, ffmpeglib.B)
- if err != nil {
- return err
- }
-
- // Set module.
- ffmpeg = cmod
- return nil
-}
-
-// compileFfprobe ensures the ffprobe WebAssembly has been
-// pre-compiled into memory. If already compiled is a no-op.
-func compileFfprobe(ctx context.Context) error {
- if ffprobe != nil {
- return nil
- }
-
- // Ensure runtime already initialized.
- if err := initRuntime(ctx); err != nil {
- return err
- }
-
- // Compile the ffprobe WebAssembly module into memory.
- cmod, err := runtime.CompileModule(ctx, ffprobelib.B)
- if err != nil {
- return err
- }
-
- // Set module.
- ffprobe = cmod
- return nil
-}
-
-// initRuntime initializes the global wazero.Runtime,
-// if already initialized this function is a no-op.
-func initRuntime(ctx context.Context) (err error) {
- if runtime != nil {
+// ffmpreg is a concurrency-safe pointer
+// to our necessary WebAssembly runtime
+// and compiled ffmpreg module instance.
+var ffmpreg atomic.Pointer[struct {
+ run wazero.Runtime
+ mod wazero.CompiledModule
+}]
+
+// initWASM safely prepares new WebAssembly runtime
+// and compiles ffmpreg module instance, if the global
+// pointer has not been already. else, is a no-op.
+func initWASM(ctx context.Context) error {
+ if ffmpreg.Load() != nil {
return nil
}
@@ -105,7 +60,59 @@ func initRuntime(ctx context.Context) (err error) {
cfg = cfg.WithCompilationCache(cache)
}
+ var (
+ run wazero.Runtime
+ mod wazero.CompiledModule
+ err error
+ set bool
+ )
+
+ defer func() {
+ if err == nil && set {
+ // Drop binary.
+ embed.B = nil
+ return
+ }
+
+ // Close module.
+ if !isNil(mod) {
+ mod.Close(ctx)
+ }
+
+ // Close runtime.
+ if !isNil(run) {
+ run.Close(ctx)
+ }
+ }()
+
// Initialize new runtime from config.
- runtime, err = wasm.NewRuntime(ctx, cfg)
- return
+ run, err = wasm.NewRuntime(ctx, cfg)
+ if err != nil {
+ return err
+ }
+
+ // Compile ffmpreg WebAssembly into memory.
+ mod, err = run.CompileModule(ctx, embed.B)
+ if err != nil {
+ return err
+ }
+
+ // Try set global WASM runtime and module,
+ // or if beaten to it defer will handle close.
+ set = ffmpreg.CompareAndSwap(nil, &struct {
+ run wazero.Runtime
+ mod wazero.CompiledModule
+ }{
+ run: run,
+ mod: mod,
+ })
+
+ return nil
+}
+
+// isNil will safely check if 'v' is nil without
+// dealing with weird Go interface nil bullshit.
+func isNil(i interface{}) bool {
+ type eface struct{ Type, Data unsafe.Pointer }
+ return (*eface)(unsafe.Pointer(&i)).Data == nil
}