feat: initial CLI converter (v1.2)

This commit is contained in:
m4xx1m committed 2026-11-12 17:18:06 +03:00
commit 02fd1dc817
5 files changed
+284

No files matched your search

+187
View File
@@ -0,0 +1,187 @@
package main
import (
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"time"
)
const DEFAULT_PRESET = "slow"
const DEFAULT_CRF = "20"
func scanArgFromConsole(text string, v *string) error {
fmt.Print(text)
if _, err := fmt.Scanln(v); err != nil && err.Error() == "EOF" {
return err
}
return nil
}
func pressEnterToExit(code int) {
fmt.Print("\npress enter to exit... ")
_, _ = fmt.Scanln()
os.Exit(code)
}
func main() {
var err error
var debug bool
var vfArgs []string
var audioFilters []string
var videoFilters []string
var inputVideo, ss, to, an, crf, preset, mergeAudioStreams, speedUp string
ffmpegExecutable := "ffmpeg"
ffmpegArgs := append(make([]string, 0, 30), "-hide_banner")
inputArgs := []string{
"-hwaccel", "nvdec",
"-threads", "1",
}
postArgs := []string{
"-c:v", "h264",
"-profile:v", "high",
"-pix_fmt", "yuv420p",
"-tune", "film",
"-movflags", "+faststart",
"-r", "60",
}
flag.StringVar(&inputVideo, "i", "", "input video path")
flag.BoolVar(&debug, "debug", false, "debug mode (default params)")
flag.Parse()
// check video exists
if _, err := os.Stat(inputVideo); err != nil {
fmt.Println(err)
pressEnterToExit(1)
}
stat, err := ffprobe(inputVideo)
if err != nil {
fmt.Println(err)
return
}
if !debug {
err = func() error {
if err = scanArgFromConsole("ss > ", &ss); err != nil {
return err
}
if err = scanArgFromConsole("to > ", &to); err != nil {
return err
}
if err = scanArgFromConsole("an > ", &an); err != nil {
return err
}
if err = scanArgFromConsole(fmt.Sprintf("crf [%v] > ", DEFAULT_CRF), &crf); err != nil {
return err
}
if err = scanArgFromConsole("speed up > ", &speedUp); err != nil {
return err
}
if err = scanArgFromConsole(fmt.Sprintf("preset [%v] > ", DEFAULT_PRESET), &preset); err != nil {
return err
}
if err = scanArgFromConsole("merge audio streams > ", &mergeAudioStreams); err != nil {
return err
}
return nil
}()
if err != nil {
os.Exit(0)
}
}
for _, v := range []*string{&ss, &to, &an, &crf, &preset, &mergeAudioStreams, &speedUp} {
*v = strings.ToLower(strings.TrimSpace(*v))
}
if len(ss) != 0 {
inputArgs = append(inputArgs, "-ss", ss)
}
if len(to) != 0 {
inputArgs = append(inputArgs, "-to", to)
}
if len(an) != 0 {
postArgs = append(postArgs, "-an")
} else {
audioFilters = append(audioFilters, "amix=inputs=2:normalize=0")
}
if len(crf) == 0 {
crf = DEFAULT_CRF
}
if len(preset) == 0 {
preset = DEFAULT_PRESET
}
postArgs = append(postArgs, "-preset", preset)
postArgs = append(postArgs, "-crf", crf)
// speed up video and audio(?)
if len(speedUp) != 0 {
videoFilters = append(videoFilters, fmt.Sprintf("setpts=1/%s*PTS", speedUp))
if len(an) == 0 {
audioFilters = append(audioFilters, fmt.Sprintf("atempo=%s", speedUp))
}
}
if len(videoFilters) != 0 {
vfArgs = append(vfArgs, "[0:v:0]"+strings.Join(videoFilters, ",")+"[v]")
postArgs = append(postArgs, "-map", "[v]")
} else {
postArgs = append(postArgs, "-map", "0:v:0")
}
if len(audioFilters) != 0 {
vfArgs = append(vfArgs, "[0:a]"+strings.Join(audioFilters, ",")+"[a]")
postArgs = append(postArgs, "-map", "[a]")
} else {
postArgs = append(postArgs, "-map", "0:a")
}
// merge filter complex args
if len(vfArgs) != 0 {
postArgs = append(postArgs, "-filter_complex", strings.Join(vfArgs, ";"))
}
// out file name
outDir, _ := filepath.Split(inputVideo)
outFile := filepath.Join(outDir, strconv.FormatInt(time.Now().Unix(), 10)+".mp4")
// merge args to one slice
ffmpegArgs = append(ffmpegArgs, inputArgs...)
ffmpegArgs = append(ffmpegArgs, "-i", inputVideo)
ffmpegArgs = append(ffmpegArgs, postArgs...)
ffmpegArgs = append(ffmpegArgs, outFile)
fmt.Printf("
running %v: %v
", ffmpegExecutable, strings.Join(ffmpegArgs, " "))
proc := exec.Command(ffmpegExecutable, ffmpegArgs...)
proc.Stderr = os.Stderr
err = proc.Start()
if err != nil {
fmt.Println(err)
pressEnterToExit(1)
}
err = proc.Wait()
if err != nil {
fmt.Println(err)
pressEnterToExit(1)
}
if proc.ProcessState.ExitCode() != 0 {
fmt.Println(err)
pressEnterToExit(1)
}
}