[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
This commit is contained in:
kim 2024-11-06 13:38:13 +00:00 committed by GitHub
parent 6f4cb2f14e
commit b84637801a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 159 additions and 123 deletions

2
go.mod
View file

@ -12,7 +12,7 @@ require (
codeberg.org/gruf/go-debug v1.3.0 codeberg.org/gruf/go-debug v1.3.0
codeberg.org/gruf/go-errors/v2 v2.3.2 codeberg.org/gruf/go-errors/v2 v2.3.2
codeberg.org/gruf/go-fastcopy v1.1.3 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-iotools v0.0.0-20240710125620-934ae9c654cf
codeberg.org/gruf/go-kv v1.6.5 codeberg.org/gruf/go-kv v1.6.5
codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f codeberg.org/gruf/go-list v0.0.0-20240425093752-494db03d641f

4
go.sum generated
View file

@ -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-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 h1:iAS9GZahFhyWEH0KLhFEJR+txx1ZhMXxYzu2q5Qo9c0=
codeberg.org/gruf/go-fastpath/v2 v2.0.0/go.mod h1:3pPqu5nZjpbRrOqvLyAK7puS1OfEtQvjd6342Cwz56Q= 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.6.0 h1:/cfUJ9bFKEoXT9LDYZy3eZ0HF60YWcO+0nGciepJKMw=
codeberg.org/gruf/go-ffmpreg v0.4.2/go.mod h1:Ar5nbt3tB2Wr0uoaqV3wDBNwAx+H+AB/mV7Kw7NlZTI= 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 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-iotools v0.0.0-20240710125620-934ae9c654cf/go.mod h1:zZAICsp5rY7+hxnws2V0ePrWxE0Z2Z/KXcN3p/RQCfk=
codeberg.org/gruf/go-kv v1.6.5 h1:ttPf0NA8F79pDqBttSudPTVCZmGncumeNIxmeM9ztz0= codeberg.org/gruf/go-kv v1.6.5 h1:ttPf0NA8F79pDqBttSudPTVCZmGncumeNIxmeM9ztz0=

View file

@ -181,6 +181,10 @@ func ffmpeg(ctx context.Context, inpath string, outpath string, args ...string)
} }
fscfg = fscfg.WithFSMount(shared, path.Dir(inpath)) fscfg = fscfg.WithFSMount(shared, path.Dir(inpath))
// Set anonymous module name.
modcfg = modcfg.WithName("")
// Update with prepared fs config.
return modcfg.WithFSConfig(fscfg) return modcfg.WithFSConfig(fscfg)
}, },
}) })
@ -247,6 +251,10 @@ func ffprobe(ctx context.Context, filepath string) (*result, error) {
} }
fscfg = fscfg.WithFSMount(in, path.Dir(filepath)) fscfg = fscfg.WithFSMount(in, path.Dir(filepath))
// Set anonymous module name.
modcfg = modcfg.WithName("")
// Update with prepared fs config.
return modcfg.WithFSConfig(fscfg) return modcfg.WithFSConfig(fscfg)
}, },
}) })

View file

@ -21,6 +21,7 @@ package ffmpeg
import ( import (
"context" "context"
"errors"
"codeberg.org/gruf/go-ffmpreg/wasm" "codeberg.org/gruf/go-ffmpreg/wasm"
) )
@ -35,12 +36,25 @@ var ffmpegRunner runner
// prepares the runner to only allow max given concurrent running instances. // prepares the runner to only allow max given concurrent running instances.
func InitFfmpeg(ctx context.Context, max int) error { func InitFfmpeg(ctx context.Context, max int) error {
ffmpegRunner.Init(max) ffmpegRunner.Init(max)
return compileFfmpeg(ctx) return initWASM(ctx)
} }
// Ffmpeg runs the given arguments with an instance of ffmpeg. // Ffmpeg runs the given arguments with an instance of ffmpeg.
func Ffmpeg(ctx context.Context, args Args) (uint32, error) { func Ffmpeg(ctx context.Context, args Args) (uint32, error) {
return ffmpegRunner.Run(ctx, func() (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,
)
}) })
} }

View file

@ -21,6 +21,7 @@ package ffmpeg
import ( import (
"context" "context"
"errors"
"codeberg.org/gruf/go-ffmpreg/wasm" "codeberg.org/gruf/go-ffmpreg/wasm"
) )
@ -35,12 +36,25 @@ var ffprobeRunner runner
// prepares the runner to only allow max given concurrent running instances. // prepares the runner to only allow max given concurrent running instances.
func InitFfprobe(ctx context.Context, max int) error { func InitFfprobe(ctx context.Context, max int) error {
ffprobeRunner.Init(max) ffprobeRunner.Init(max)
return compileFfprobe(ctx) return initWASM(ctx)
} }
// Ffprobe runs the given arguments with an instance of ffprobe. // Ffprobe runs the given arguments with an instance of ffprobe.
func Ffprobe(ctx context.Context, args Args) (uint32, error) { func Ffprobe(ctx context.Context, args Args) (uint32, error) {
return ffprobeRunner.Run(ctx, func() (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,
)
}) })
} }

View file

@ -22,72 +22,27 @@ package ffmpeg
import ( import (
"context" "context"
"os" "os"
"sync/atomic"
"unsafe"
ffmpeglib "codeberg.org/gruf/go-ffmpreg/embed/ffmpeg" "codeberg.org/gruf/go-ffmpreg/embed"
ffprobelib "codeberg.org/gruf/go-ffmpreg/embed/ffprobe"
"codeberg.org/gruf/go-ffmpreg/wasm" "codeberg.org/gruf/go-ffmpreg/wasm"
"github.com/tetratelabs/wazero" "github.com/tetratelabs/wazero"
) )
var ( // ffmpreg is a concurrency-safe pointer
// shared WASM runtime instance. // to our necessary WebAssembly runtime
runtime wazero.Runtime // and compiled ffmpreg module instance.
var ffmpreg atomic.Pointer[struct {
run wazero.Runtime
mod wazero.CompiledModule
}]
// ffmpeg / ffprobe compiled WASM. // initWASM safely prepares new WebAssembly runtime
ffmpeg wazero.CompiledModule // and compiles ffmpreg module instance, if the global
ffprobe wazero.CompiledModule // pointer has not been already. else, is a no-op.
) func initWASM(ctx context.Context) error {
if ffmpreg.Load() != nil {
// 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 {
return nil return nil
} }
@ -105,7 +60,59 @@ func initRuntime(ctx context.Context) (err error) {
cfg = cfg.WithCompilationCache(cache) 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. // Initialize new runtime from config.
runtime, err = wasm.NewRuntime(ctx, cfg) run, err = wasm.NewRuntime(ctx, cfg)
return 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
} }

Binary file not shown.

View file

@ -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

Binary file not shown.

Binary file not shown.

View file

@ -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

39
vendor/codeberg.org/gruf/go-ffmpreg/embed/lib.go generated vendored Normal file
View file

@ -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

View file

@ -14,6 +14,11 @@ import (
// wazero.Runtime on module instantiation. // wazero.Runtime on module instantiation.
type Args struct { 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. // Optional further module configuration function.
// (e.g. to mount filesystem dir, set env vars, etc). // (e.g. to mount filesystem dir, set env vars, etc).
Config func(wazero.ModuleConfig) wazero.ModuleConfig Config func(wazero.ModuleConfig) wazero.ModuleConfig
@ -39,7 +44,7 @@ func Run(
// Prefix arguments with module name. // Prefix arguments with module name.
cargs := make([]string, len(args.Args)+1) cargs := make([]string, len(args.Args)+1)
cargs[0] = module.Name() cargs[0] = args.Name
copy(cargs[1:], args.Args) copy(cargs[1:], args.Args)
// Prepare new module configuration. // Prepare new module configuration.

5
vendor/modules.txt vendored
View file

@ -24,10 +24,9 @@ codeberg.org/gruf/go-fastcopy
# codeberg.org/gruf/go-fastpath/v2 v2.0.0 # codeberg.org/gruf/go-fastpath/v2 v2.0.0
## explicit; go 1.14 ## explicit; go 1.14
codeberg.org/gruf/go-fastpath/v2 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 ## explicit; go 1.22.0
codeberg.org/gruf/go-ffmpreg/embed/ffmpeg codeberg.org/gruf/go-ffmpreg/embed
codeberg.org/gruf/go-ffmpreg/embed/ffprobe
codeberg.org/gruf/go-ffmpreg/wasm codeberg.org/gruf/go-ffmpreg/wasm
# codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf # codeberg.org/gruf/go-iotools v0.0.0-20240710125620-934ae9c654cf
## explicit; go 1.21 ## explicit; go 1.21