package ffmpeg import ( "context" "os/exec" "strings" ) type ffmpegBuilder struct { binary string // ffmpeg binary path options map[string]string // global options inputs []*inputBuilder // input options outputs []*outputBuilder // output options } func newFFmpegBuilder() *ffmpegBuilder { return &ffmpegBuilder{ binary: "ffmpeg", options: make(map[string]string), } } func (b *ffmpegBuilder) AddInput(src *inputBuilder) { b.inputs = append(b.inputs, src) } func (b *ffmpegBuilder) AddOutput(dst *outputBuilder) { b.outputs = append(b.outputs, dst) } func (b *ffmpegBuilder) SetBinary(bin string) { b.binary = bin } func (b *ffmpegBuilder) SetFlag(flag string) { b.options[flag] = "" } func (b *ffmpegBuilder) SetOption(name, value string) { b.options[name] = value } func (b *ffmpegBuilder) Args() (args []string) { for name, val := range b.options { args = append(args, "-"+name) if val != "" { args = append(args, val) } } for _, input := range b.inputs { args = append(args, input.Args()...) } for _, output := range b.outputs { args = append(args, output.Args()...) } return } func (b *ffmpegBuilder) Command(ctx context.Context) *exec.Cmd { bin := "ffmpeg" if b.binary != "" { bin = b.binary } return exec.CommandContext(ctx, bin, b.Args()...) } // inputBuilder is the builder for ffmpeg input options type inputBuilder struct { path string options map[string][]string } func newInputBuilder(path string) *inputBuilder { return &inputBuilder{ path: path, options: make(map[string][]string), } } func (b *inputBuilder) AddOption(name, value string) { b.options[name] = append(b.options[name], value) } func (b *inputBuilder) Args() (args []string) { for name, values := range b.options { for _, val := range values { args = append(args, "-"+name, val) } } return append(args, "-i", b.path) } // outputBuilder is the builder for ffmpeg output options type outputBuilder struct { path string options map[string][]string } func newOutputBuilder(path string) *outputBuilder { return &outputBuilder{ path: path, options: make(map[string][]string), } } func (b *outputBuilder) AddOption(name, value string) { b.options[name] = append(b.options[name], value) } func (b *outputBuilder) Args() (args []string) { for name, values := range b.options { for _, val := range values { args = append(args, "-"+name, val) } } return append(args, b.path) } // AddMetadata is the shortcut for adding "metadata" option func (b *outputBuilder) AddMetadata(stream, key, value string) { optVal := strings.TrimSpace(key) + "=" + strings.TrimSpace(value) if stream != "" { b.AddOption("metadata:"+stream, optVal) } else { b.AddOption("metadata", optVal) } }