Added a -serve and -port option to do a quick webserver for testing.

master
Zed A. Shaw 1 month ago
parent ff20dd1137
commit 9d87143a95
  1. 9
      Makefile
  2. 31
      config.json
  3. 6
      config/settings.go
  4. 209
      main.go

@ -1,8 +1,5 @@
GO_IS_STUPID_EXE=
ifeq '$(OS)' 'Windows_NT'
GO_IS_STUPID_EXE=.exe
endif
build:
go build .
install: build
sudo cp vidcrunch /usr/local/bin/

@ -6,9 +6,8 @@
"VideoBitrate": 900,
"AudioBitrate": 192,
"VideoCodec": "libvpx-vp9",
"Preset": "veryfast",
"CleanFilename": false,
"CRF": 30,
"CRF": 20,
"FPS": 30,
"Tune": "animation",
"Input": "LGo*.mp4",
@ -17,27 +16,13 @@
"Extras": [
"-deadline", "realtime",
"-row-mt", "1",
"-cpu-used", "8"
"-cpu-used", "8",
"-g", "150",
"-keyint_min", "150",
"-tile-columns", "4",
"-tile-rows", "2",
"-frame-parallel", "1",
"-tune-content", "1"
]
},
{
"Format": "webm",
"VideoCodec": "libvpx-vp9",
"Scale": "1280:720",
"Resize": false,
"VideoBitrate": 600,
"AudioBitrate": 192,
"CleanFilename": false,
"CRF": 30,
"FPS": 30,
"Tune": "animation",
"Input": "LGo*.mp4",
"OutDir": "dash_test",
"Passes": 1,
"Extras": [
"-deadline", "realtime",
"-row-mt", "1",
"-cpu-used", "8"
]
}
]

@ -31,7 +31,8 @@ type VideoOpts struct {
type Settings struct {
Debug int
Force bool
Server string
Serve string
Port string
ConfigPath string
Encodings []VideoOpts
}
@ -40,7 +41,8 @@ func ParseFlags(c *Settings) {
flag.IntVar(&c.Debug, "debug", 0, "1=print the ffmpeg command, 2=and its stderr output")
flag.BoolVar(&c.Force, "force", false, "Force the render even if the file exists.")
flag.StringVar(&c.ConfigPath, "config", "config.json", "config.json to load")
flag.StringVar(&c.Server, "server", ":8099", "start a simple HTTP server for testing")
flag.StringVar(&c.Serve, "serve", "", "serve a directory webserver")
flag.StringVar(&c.Port, "port", ":8099", "start a simple HTTP server for testing")
flag.Parse()
}

@ -1,128 +1,139 @@
package main
import (
"fmt"
"path/filepath"
"runtime"
"log"
"os"
"math/rand"
"strings"
"lcthw.dev/go/vidcrunch/config"
"github.com/modfy/fluent-ffmpeg"
"fmt"
"path/filepath"
"runtime"
"log"
"os"
"math/rand"
"net/http"
"strings"
"lcthw.dev/go/vidcrunch/config"
"github.com/modfy/fluent-ffmpeg"
)
func ModFile(fname string, encoding config.VideoOpts) string {
cleaned := filepath.Clean(fname)
dir, file := filepath.Split(cleaned)
ext := filepath.Ext(file)
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?!") }
base, found := strings.CutSuffix(file, ext)
if !found { panic("no extension found?!") }
dim := strings.Replace(encoding.Scale, ":", ".", 1)
renamed := fmt.Sprint(base, ".", dim, ".", encoding.Format)
return filepath.Join(dir, renamed)
dim := strings.Replace(encoding.Scale, ":", ".", 1)
renamed := fmt.Sprint(base, ".", dim, ".", encoding.Format)
return filepath.Join(dir, renamed)
}
func Run(encoding config.VideoOpts, pass int, pid int, input string, output string) {
encode := fluentffmpeg.NewCommand("")
extras := []string{
"-pix_fmt", "yuv420p",
"-pass", fmt.Sprint(pass),
"-passlogfile", fmt.Sprintf("ffmpegpass-%x.log", pid),
}
if encoding.Preset != "" {
extras = append(extras, "-preset", encoding.Preset)
}
if encoding.Resize {
extras = append(extras,
"-vf", fmt.Sprintf("scale=%s:flags=lanczos", encoding.Scale),
"-aspect", encoding.Scale)
}
if pass != encoding.Passes {
extras = append(extras, "-an")
} else {
encode.AudioCodec(encoding.AudioCodec)
extras = append(extras,
"-b:a", fmt.Sprint(encoding.AudioBitrate * 1024))
}
if encoding.Test > 0 {
encode.InputOptions(
"-ss", fmt.Sprintf("00:%d", encoding.TestStart))
extras = append(extras, "-t", fmt.Sprint(encoding.Test))
}
encode.VideoCodec(encoding.VideoCodec).
VideoBitRate(encoding.VideoBitrate * 1024).
FrameRate(encoding.FPS).
ConstantRateFactor(encoding.CRF)
extras = append(extras, encoding.Extras...)
encode.OutputOptions(extras...)
cmd := encode.InputPath(input).
OutputFormat(encoding.Format).
OutputPath(output).
encode := fluentffmpeg.NewCommand("")
extras := []string{
"-pix_fmt", "yuv420p",
"-pass", fmt.Sprint(pass),
"-passlogfile", fmt.Sprintf("ffmpegpass-%x.log", pid),
}
if encoding.Preset != "" {
extras = append(extras, "-preset", encoding.Preset)
}
if encoding.Resize {
extras = append(extras,
"-vf", fmt.Sprintf("scale=%s:flags=lanczos", encoding.Scale),
"-aspect", encoding.Scale)
}
if pass != encoding.Passes {
extras = append(extras, "-an")
} else {
encode.AudioCodec(encoding.AudioCodec)
extras = append(extras,
"-b:a", fmt.Sprint(encoding.AudioBitrate * 1024))
}
if encoding.Test > 0 {
encode.InputOptions("-ss", fmt.Sprintf("00:%d", encoding.TestStart))
extras = append(extras, "-t", fmt.Sprint(encoding.Test))
}
encode.VideoCodec(encoding.VideoCodec).
VideoBitRate(encoding.VideoBitrate * 1024).
FrameRate(encoding.FPS).
ConstantRateFactor(encoding.CRF)
extras = append(extras, encoding.Extras...)
encode.OutputOptions(extras...)
cmd := encode.InputPath(input).
OutputFormat(encoding.Format).
OutputPath(output).
OutputLogs(os.Stdout).
Overwrite(true).
Build()
Build()
fmt.Println(">", cmd.String())
fmt.Println(">", cmd.String())
err := cmd.Run()
if err != nil { log.Fatalf("%v", err) }
err := cmd.Run()
if err != nil { log.Fatalf("%v", err) }
}
func DevNull() string {
if runtime.GOOS == "windows" {
return "NUL"
} else {
return "/dev/null"
}
if runtime.GOOS == "windows" {
return "NUL"
} else {
return "/dev/null"
}
}
func RenderFile(encoding config.VideoOpts, pid int, path string, target string) {
for i := 1; i < encoding.Passes; i++ {
Run(encoding, i, pid, path, DevNull())
}
for i := 1; i < encoding.Passes; i++ {
Run(encoding, i, pid, path, DevNull())
}
Run(encoding, encoding.Passes, pid, path, target)
Run(encoding, encoding.Passes, pid, path, target)
}
func RenderToDir(encoding config.VideoOpts, force bool) {
matches, err := filepath.Glob(encoding.Input)
if err != nil { log.Fatalf("%v", err) }
for _, path := range matches {
base := filepath.Base(path)
target := filepath.Join(encoding.OutDir, base)
target = ModFile(target, encoding)
_, err := os.Stat(target)
if err != nil || force {
fmt.Println("--- PATH", path, "->", target)
RenderFile(encoding, rand.Int(), path, target)
} else {
fmt.Println("^^^ SKIP", path, "->", target)
}
}
matches, err := filepath.Glob(encoding.Input)
if err != nil { log.Fatalf("%v", err) }
for _, path := range matches {
base := filepath.Base(path)
target := filepath.Join(encoding.OutDir, base)
target = ModFile(target, encoding)
_, err := os.Stat(target)
if err != nil || force {
fmt.Println("--- PATH", path, "->", target)
RenderFile(encoding, rand.Int(), path, target)
} else {
fmt.Println("^^^ SKIP", path, "->", target)
}
}
}
func main() {
settings := config.Load()
for _, encoding := range settings.Encodings {
if encoding.OutDir != "" {
RenderToDir(encoding, settings.Force)
} else {
log.Fatal("config file needs either Output or OutDir")
}
}
settings := config.Load()
if settings.Serve != "" {
dir_handler := http.FileServer(http.Dir(settings.Serve))
http.HandleFunc("/", func (w http.ResponseWriter, r *http.Request) {
fmt.Println(r.Method, r.URL)
dir_handler.ServeHTTP(w, r)
})
log.Fatal(http.ListenAndServe(settings.Port, nil))
} else {
for _, encoding := range settings.Encodings {
if encoding.OutDir != "" {
RenderToDir(encoding, settings.Force)
} else {
log.Fatal("config file needs either Output or OutDir")
}
}
}
}

Loading…
Cancel
Save