diff options
| -rw-r--r-- | go.mod | 2 | ||||
| -rw-r--r-- | go.sum | 4 | ||||
| -rw-r--r-- | internal/media/ffmpeg.go | 8 | ||||
| -rw-r--r-- | internal/media/ffmpeg/ffmpeg.go | 18 | ||||
| -rw-r--r-- | internal/media/ffmpeg/ffprobe.go | 18 | ||||
| -rw-r--r-- | internal/media/ffmpeg/wasm.go | 133 | ||||
| -rw-r--r-- | vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpeg/ffmpeg.wasm | bin | 15504215 -> 0 bytes | |||
| -rw-r--r-- | vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpeg/lib.go | 25 | ||||
| -rw-r--r-- | vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpreg.wasm.gz | bin | 0 -> 8253333 bytes | |||
| -rw-r--r-- | vendor/codeberg.org/gruf/go-ffmpreg/embed/ffprobe/ffprobe.wasm | bin | 15415068 -> 0 bytes | |||
| -rw-r--r-- | vendor/codeberg.org/gruf/go-ffmpreg/embed/ffprobe/lib.go | 25 | ||||
| -rw-r--r-- | vendor/codeberg.org/gruf/go-ffmpreg/embed/lib.go | 39 | ||||
| -rw-r--r-- | vendor/codeberg.org/gruf/go-ffmpreg/wasm/run.go | 7 | ||||
| -rw-r--r-- | vendor/modules.txt | 5 | 
14 files changed, 160 insertions, 124 deletions
@@ -12,7 +12,7 @@ require (  	codeberg.org/gruf/go-debug v1.3.0  	codeberg.org/gruf/go-errors/v2 v2.3.2  	codeberg.org/gruf/go-fastcopy v1.1.3 -	codeberg.org/gruf/go-ffmpreg v0.4.2 +	codeberg.org/gruf/go-ffmpreg v0.6.0  	codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf  	codeberg.org/gruf/go-kv v1.6.5  	codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f @@ -46,8 +46,8 @@ codeberg.org/gruf/go-fastcopy v1.1.3 h1:Jo9VTQjI6KYimlw25PPc7YLA3Xm+XMQhaHwKnM7x  codeberg.org/gruf/go-fastcopy v1.1.3/go.mod h1:GDDYR0Cnb3U/AIfGM3983V/L+GN+vuwVMvrmVABo21s=  codeberg.org/gruf/go-fastpath/v2 v2.0.0 h1:iAS9GZahFhyWEH0KLhFEJR+txx1ZhMXxYzu2q5Qo9c0=  codeberg.org/gruf/go-fastpath/v2 v2.0.0/go.mod h1:3pPqu5nZjpbRrOqvLyAK7puS1OfEtQvjd6342Cwz56Q= -codeberg.org/gruf/go-ffmpreg v0.4.2 h1:HKkPapm/PWkxsnUdjyQOGpwl5Qoa2EBrUQ09s4R4/FA= -codeberg.org/gruf/go-ffmpreg v0.4.2/go.mod h1:Ar5nbt3tB2Wr0uoaqV3wDBNwAx+H+AB/mV7Kw7NlZTI= +codeberg.org/gruf/go-ffmpreg v0.6.0 h1:/cfUJ9bFKEoXT9LDYZy3eZ0HF60YWcO+0nGciepJKMw= +codeberg.org/gruf/go-ffmpreg v0.6.0/go.mod h1:Ar5nbt3tB2Wr0uoaqV3wDBNwAx+H+AB/mV7Kw7NlZTI=  codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf h1:84s/ii8N6lYlskZjHH+DG6jyia8w2mXMZlRwFn8Gs3A=  codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf/go.mod h1:zZAICsp5rY7+hxnws2V0ePrWxE0Z2Z/KXcN3p/RQCfk=  codeberg.org/gruf/go-kv v1.6.5 h1:ttPf0NA8F79pDqBttSudPTVCZmGncumeNIxmeM9ztz0= diff --git a/internal/media/ffmpeg.go b/internal/media/ffmpeg.go index 1d7b01905..c225d4378 100644 --- a/internal/media/ffmpeg.go +++ b/internal/media/ffmpeg.go @@ -181,6 +181,10 @@ func ffmpeg(ctx context.Context, inpath string, outpath string, args ...string)  			}  			fscfg = fscfg.WithFSMount(shared, path.Dir(inpath)) +			// Set anonymous module name. +			modcfg = modcfg.WithName("") + +			// Update with prepared fs config.  			return modcfg.WithFSConfig(fscfg)  		},  	}) @@ -247,6 +251,10 @@ func ffprobe(ctx context.Context, filepath string) (*result, error) {  			}  			fscfg = fscfg.WithFSMount(in, path.Dir(filepath)) +			// Set anonymous module name. +			modcfg = modcfg.WithName("") + +			// Update with prepared fs config.  			return modcfg.WithFSConfig(fscfg)  		},  	}) diff --git a/internal/media/ffmpeg/ffmpeg.go b/internal/media/ffmpeg/ffmpeg.go index 0571c029a..b978201c1 100644 --- a/internal/media/ffmpeg/ffmpeg.go +++ b/internal/media/ffmpeg/ffmpeg.go @@ -21,6 +21,7 @@ package ffmpeg  import (  	"context" +	"errors"  	"codeberg.org/gruf/go-ffmpreg/wasm"  ) @@ -35,12 +36,25 @@ var ffmpegRunner runner  // prepares the runner to only allow max given concurrent running instances.  func InitFfmpeg(ctx context.Context, max int) error {  	ffmpegRunner.Init(max) -	return compileFfmpeg(ctx) +	return initWASM(ctx)  }  // Ffmpeg runs the given arguments with an instance of ffmpeg.  func Ffmpeg(ctx context.Context, args Args) (uint32, error) {  	return ffmpegRunner.Run(ctx, func() (uint32, error) { -		return wasm.Run(ctx, runtime, ffmpeg, args) + +		// Load WASM rt and module. +		ffmpreg := ffmpreg.Load() +		if ffmpreg == nil { +			return 0, errors.New("wasm not initialized") +		} + +		// Call into ffmpeg. +		args.Name = "ffmpeg" +		return wasm.Run(ctx, +			ffmpreg.run, +			ffmpreg.mod, +			args, +		)  	})  } diff --git a/internal/media/ffmpeg/ffprobe.go b/internal/media/ffmpeg/ffprobe.go index ccd5072dd..410935d9c 100644 --- a/internal/media/ffmpeg/ffprobe.go +++ b/internal/media/ffmpeg/ffprobe.go @@ -21,6 +21,7 @@ package ffmpeg  import (  	"context" +	"errors"  	"codeberg.org/gruf/go-ffmpreg/wasm"  ) @@ -35,12 +36,25 @@ var ffprobeRunner runner  // prepares the runner to only allow max given concurrent running instances.  func InitFfprobe(ctx context.Context, max int) error {  	ffprobeRunner.Init(max) -	return compileFfprobe(ctx) +	return initWASM(ctx)  }  // Ffprobe runs the given arguments with an instance of ffprobe.  func Ffprobe(ctx context.Context, args Args) (uint32, error) {  	return ffprobeRunner.Run(ctx, func() (uint32, error) { -		return wasm.Run(ctx, runtime, ffprobe, args) + +		// Load WASM rt and module. +		ffmpreg := ffmpreg.Load() +		if ffmpreg == nil { +			return 0, errors.New("wasm not initialized") +		} + +		// Call into ffprobe. +		args.Name = "ffprobe" +		return wasm.Run(ctx, +			ffmpreg.run, +			ffmpreg.mod, +			args, +		)  	})  } 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  } diff --git a/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpeg/ffmpeg.wasm b/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpeg/ffmpeg.wasm Binary files differdeleted file mode 100644 index 9d1faa3ed..000000000 --- a/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpeg/ffmpeg.wasm +++ /dev/null diff --git a/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpeg/lib.go b/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpeg/lib.go deleted file mode 100644 index abe32d7c1..000000000 --- a/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpeg/lib.go +++ /dev/null @@ -1,25 +0,0 @@ -package ffmpeg - -import ( -	_ "embed" -	"os" -) - -func init() { -	// Check for WASM source file path. -	path := os.Getenv("FFMPEG_WASM") -	if path == "" { -		return -	} - -	var err error - -	// Read file into memory. -	B, err = os.ReadFile(path) -	if err != nil { -		panic(err) -	} -} - -//go:embed ffmpeg.wasm -var B []byte diff --git a/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpreg.wasm.gz b/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpreg.wasm.gz Binary files differnew file mode 100644 index 000000000..1545d58bc --- /dev/null +++ b/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffmpreg.wasm.gz diff --git a/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffprobe/ffprobe.wasm b/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffprobe/ffprobe.wasm Binary files differdeleted file mode 100644 index 0094c53f4..000000000 --- a/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffprobe/ffprobe.wasm +++ /dev/null diff --git a/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffprobe/lib.go b/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffprobe/lib.go deleted file mode 100644 index c3c3a3df1..000000000 --- a/vendor/codeberg.org/gruf/go-ffmpreg/embed/ffprobe/lib.go +++ /dev/null @@ -1,25 +0,0 @@ -package ffprobe - -import ( -	_ "embed" -	"os" -) - -func init() { -	// Check for WASM source file path. -	path := os.Getenv("FFPROBE_WASM") -	if path == "" { -		return -	} - -	var err error - -	// Read file into memory. -	B, err = os.ReadFile(path) -	if err != nil { -		panic(err) -	} -} - -//go:embed ffprobe.wasm -var B []byte diff --git a/vendor/codeberg.org/gruf/go-ffmpreg/embed/lib.go b/vendor/codeberg.org/gruf/go-ffmpreg/embed/lib.go new file mode 100644 index 000000000..7829b5524 --- /dev/null +++ b/vendor/codeberg.org/gruf/go-ffmpreg/embed/lib.go @@ -0,0 +1,39 @@ +package embed + +import ( +	"bytes" +	"compress/gzip" +	_ "embed" +	"io" +	"os" +) + +func init() { +	var err error + +	if path := os.Getenv("FFMPREG_WASM"); path != "" { +		// Read file into memory. +		B, err = os.ReadFile(path) +		if err != nil { +			panic(err) +		} +	} + +	// Wrap bytes in reader. +	b := bytes.NewReader(B) + +	// Create unzipper from reader. +	gz, err := gzip.NewReader(b) +	if err != nil { +		panic(err) +	} + +	// Extract gzipped binary. +	B, err = io.ReadAll(gz) +	if err != nil { +		panic(err) +	} +} + +//go:embed ffmpreg.wasm.gz +var B []byte diff --git a/vendor/codeberg.org/gruf/go-ffmpreg/wasm/run.go b/vendor/codeberg.org/gruf/go-ffmpreg/wasm/run.go index 62ce2bc25..7b07d851d 100644 --- a/vendor/codeberg.org/gruf/go-ffmpreg/wasm/run.go +++ b/vendor/codeberg.org/gruf/go-ffmpreg/wasm/run.go @@ -14,6 +14,11 @@ import (  // wazero.Runtime on module instantiation.  type Args struct { +	// Program name, depending on the +	// module being run this may or may +	// not be necessary. +	Name string +  	// Optional further module configuration function.  	// (e.g. to mount filesystem dir, set env vars, etc).  	Config func(wazero.ModuleConfig) wazero.ModuleConfig @@ -39,7 +44,7 @@ func Run(  	// Prefix arguments with module name.  	cargs := make([]string, len(args.Args)+1) -	cargs[0] = module.Name() +	cargs[0] = args.Name  	copy(cargs[1:], args.Args)  	// Prepare new module configuration. diff --git a/vendor/modules.txt b/vendor/modules.txt index 10c1e595c..e11598f09 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -24,10 +24,9 @@ codeberg.org/gruf/go-fastcopy  # codeberg.org/gruf/go-fastpath/v2 v2.0.0  ## explicit; go 1.14  codeberg.org/gruf/go-fastpath/v2 -# codeberg.org/gruf/go-ffmpreg v0.4.2 +# codeberg.org/gruf/go-ffmpreg v0.6.0  ## explicit; go 1.22.0 -codeberg.org/gruf/go-ffmpreg/embed/ffmpeg -codeberg.org/gruf/go-ffmpreg/embed/ffprobe +codeberg.org/gruf/go-ffmpreg/embed  codeberg.org/gruf/go-ffmpreg/wasm  # codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf  ## explicit; go 1.21  | 
