package main import ( "fmt" "path/filepath" "runtime" "log" "os" "math/rand" "strings" "lcthw.dev/vidcrunch/config" "github.com/modfy/fluent-ffmpeg" ) func ModFile(fname string, scale string) string { cleaned := filepath.Clean(fname) dir, file := filepath.Split(cleaned) ext := filepath.Ext(file) base, found := strings.CutSuffix(file, ext) if !found { panic("no extension found?!") } dim := strings.Replace(scale, ":", ".", 1) renamed := fmt.Sprint(base, ".", dim, ext) return filepath.Join(dir, renamed) } func Run(pass int, pid int, input string, output string) { encode := fluentffmpeg.NewCommand("") mp4_opts := []string{ "-vf", fmt.Sprintf("scale=%s:flags=lanczos", config.Settings.Scale), "-aspect", config.Settings.Scale, "-pix_fmt", "yuv420p", "-tune", config.Settings.Tune, "-movflags", "faststart", "-pass", fmt.Sprint(pass), "-passlogfile", fmt.Sprintf("ffmpeg2pass-%x.log", pid), "-preset", config.Settings.Speed, } if pass != 3 { mp4_opts = append(mp4_opts, "-an") } else { encode.AudioCodec("aac") mp4_opts = append(mp4_opts, "-b:a", fmt.Sprint(config.Settings.AudioBitrate * 1024)) } if config.Settings.Test > 0 { encode.InputOptions( "-ss", fmt.Sprintf("00:%d", config.Settings.TestStart)) mp4_opts = append(mp4_opts, "-t", fmt.Sprint(config.Settings.Test)) } encode.VideoCodec("libx264"). VideoBitRate(config.Settings.VideoBitrate * 1024). FrameRate(config.Settings.FPS). ConstantRateFactor(config.Settings.CRF) encode.OutputOptions(mp4_opts...) cmd := encode.InputPath(input). OutputFormat("mp4"). OutputPath(output). Build() fmt.Println(">", cmd.String()) err := cmd.Run() if err != nil { log.Fatalf("%v", err) } } func DevNull() string { if runtime.GOOS == "windows" { return "NUL" } else { return "/dev/null" } } func RenderFile(pid int, path string, target string) { target = ModFile(target, config.Settings.Scale) Run(1, pid, path, DevNull()) Run(2, pid, path, DevNull()) Run(3, pid, path, target) } func RenderToDir() { matches, err := filepath.Glob(config.Settings.Input) if err != nil { log.Fatalf("%v", err) } for _, path := range matches { base := filepath.Base(path) target := filepath.Join(config.Settings.OutDir, base) _, err := os.Stat(target) if err != nil { fmt.Println("--- PATH", path, "->", target) RenderFile(rand.Int(), path, target) } else { fmt.Println("^^^ SKIP", path, "->", target) } } } func main() { config.Load() if config.Settings.Output != "" { RenderFile(rand.Int(), config.Settings.Input, config.Settings.Output) } else if config.Settings.OutDir != "" { RenderToDir() } else { log.Fatal("config file needs either Output or OutDir") } }