A simple little command line tool in Go to crunch my videos. This includes many settings I've found that compress "code videos" really well. YMMV.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
vidcrunch/main.go

120 lines
2.8 KiB

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")
}
}