Can now use variants to produce things.

master
Zed A. Shaw 4 weeks ago
parent 5d58dae41f
commit cc1432889a
  1. 3
      Makefile
  2. 70
      config.json
  3. 14
      config/settings.go
  4. 111
      main.go

@ -3,3 +3,6 @@ build:
install: build
sudo cp vidcrunch /usr/local/bin/
clean:
rm -f dash_test/*.webm dash_test/*.mpd

@ -1,64 +1,34 @@
[
{
"Format": "webm",
"Variants": [
{
"Scale": "1920:1080",
"Resize": false,
"VideoBitrate": 900,
"AudioCodec": "none",
"VideoCodec": "libvpx-vp9",
"CleanFilename": false,
"CRF": 30,
"FPS": 30,
"Input": "test_video.mp4",
"OutDir": "dash_test",
"Passes": 1,
"Dash": true,
"Extras": [
"-deadline", "realtime",
"-row-mt", "1",
"-cpu-used", "8",
"-g", "150",
"-keyint_min", "150",
"-tile-columns", "4",
"-tile-rows", "2",
"-frame-parallel", "1",
"-tune-content", "1"
]
"VideoCodec": "libvpx-vp9"
},
{
"Format": "webm",
"Scale": "1280:720",
"Resize": false,
"Resize": true,
"VideoBitrate": 600,
"AudioCodec": "none",
"VideoCodec": "libvpx-vp9",
"CleanFilename": false,
"CRF": 30,
"FPS": 30,
"Input": "test_video.mp4",
"OutDir": "dash_test",
"Passes": 1,
"Dash": true,
"Extras": [
"-deadline", "realtime",
"-row-mt", "1",
"-cpu-used", "8",
"-g", "150",
"-keyint_min", "150",
"-tile-columns", "4",
"-tile-rows", "2",
"-frame-parallel", "1",
"-tune-content", "1"
]
"VideoCodec": "libvpx-vp9"
},
{
"Format": "webm",
"Scale": "640:360",
"Resize": false,
"Resize": true,
"VideoBitrate": 300,
"AudioCodec": "none",
"VideoCodec": "libvpx-vp9",
"CleanFilename": false,
"VideoCodec": "libvpx-vp9"
},
{
"AudioCodec": "libopus",
"AudioBitrate": 192,
"VideoCodec": "none"
}
],
"CRF": 30,
"FPS": 30,
"Input": "test_video.mp4",
@ -76,17 +46,5 @@
"-frame-parallel", "1",
"-tune-content", "1"
]
},
{
"Format": "webm",
"AudioBitrate": 192,
"AudioCodec": "libopus",
"VideoCodec": "none",
"CleanFilename": false,
"CRF": 30,
"FPS": 30,
"Input": "test_video.mp4",
"OutDir": "dash_test",
"Passes": 1
}
]

@ -7,23 +7,27 @@ import (
"encoding/json"
)
type VideoOpts struct {
Format string
type CodecOpts struct {
Scale string
Resize bool
VideoBitrate int
VideoCodec string
AudioBitrate int
AudioCodec string
// used internally, shouldn't set int json
Target string
}
type EncodeOpts struct {
Format string
Variants []CodecOpts
Preset string
CleanFilename bool
Dash bool
CRF int
FPS int
Tune string
Input string
OutDir string
FakeResult string
Test int
TestStart int
Passes int
@ -36,7 +40,7 @@ type Settings struct {
Serve string
Port string
ConfigPath string
Encodings []VideoOpts
Encodings []EncodeOpts
}
func ParseFlags(c *Settings) {

@ -17,33 +17,36 @@ import (
"iter"
)
func AudioOnly(encoding config.VideoOpts) bool {
return encoding.Scale == "" && encoding.VideoCodec == "none"
func AudioOnly(codec config.CodecOpts) bool {
return codec.Scale == "" && codec.VideoCodec == "none"
}
func VideoOnly(encoding config.VideoOpts) bool {
return encoding.AudioCodec == "none"
func VideoOnly(codec config.CodecOpts) bool {
return codec.AudioCodec == "none"
}
func ModFile(fname string, encoding config.VideoOpts) string {
cleaned := filepath.Clean(fname)
func SetCodecTarget(codec *config.CodecOpts, path string, encoding config.EncodeOpts) {
base := filepath.Base(path)
target := filepath.Join(encoding.OutDir, base)
cleaned := filepath.Clean(target)
dir, file := filepath.Split(cleaned)
ext := filepath.Ext(file)
base, found := strings.CutSuffix(file, ext)
if !found { panic("no extension found?!") }
if AudioOnly(encoding) {
if AudioOnly(*codec) {
renamed := fmt.Sprint(base, ".audio.", encoding.Format)
return filepath.Join(dir, renamed)
codec.Target = filepath.Join(dir, renamed)
} else {
dim := strings.Replace(encoding.Scale, ":", ".", 1)
dim := strings.Replace(codec.Scale, ":", ".", 1)
renamed := fmt.Sprint(base, ".", dim, ".", encoding.Format)
return filepath.Join(dir, renamed)
codec.Target = filepath.Join(dir, renamed)
}
}
func Run(encoding config.VideoOpts, pass int, pid int, input string, output string) {
func Run(encoding config.EncodeOpts, codec config.CodecOpts, pass int, pid int, input string, output string) {
encode := fluentffmpeg.NewCommand("")
extras := []string{
@ -60,18 +63,18 @@ func Run(encoding config.VideoOpts, pass int, pid int, input string, output stri
extras = append(extras, "-preset", encoding.Preset)
}
if encoding.Resize {
if codec.Resize {
extras = append(extras,
"-vf", fmt.Sprintf("scale=%s:flags=lanczos", encoding.Scale),
"-aspect", encoding.Scale)
"-vf", fmt.Sprintf("scale=%s:flags=lanczos", codec.Scale),
"-aspect", codec.Scale)
}
if pass != encoding.Passes || VideoOnly(encoding) {
if pass != encoding.Passes || VideoOnly(codec) {
extras = append(extras, "-an")
} else {
encode.AudioCodec(encoding.AudioCodec)
encode.AudioCodec(codec.AudioCodec)
extras = append(extras,
"-b:a", fmt.Sprint(encoding.AudioBitrate * 1024))
"-b:a", fmt.Sprint(codec.AudioBitrate * 1024))
}
@ -80,11 +83,11 @@ func Run(encoding config.VideoOpts, pass int, pid int, input string, output stri
extras = append(extras, "-t", fmt.Sprint(encoding.Test))
}
if encoding.VideoCodec == "none" {
if codec.VideoCodec == "none" {
extras = append(extras, "-vn")
} else {
encode.VideoCodec(encoding.VideoCodec).
VideoBitRate(encoding.VideoBitrate * 1024).
encode.VideoCodec(codec.VideoCodec).
VideoBitRate(codec.VideoBitrate * 1024).
FrameRate(encoding.FPS).
ConstantRateFactor(encoding.CRF)
}
@ -118,12 +121,28 @@ func DevNull() string {
}
}
func RenderFile(encoding config.VideoOpts, pid int, path string, target string) {
func RenderFile(encoding config.EncodeOpts, pid int, path string, force bool) {
for i := 0; i < len(encoding.Variants); i++ {
codec := &encoding.Variants[i]
SetCodecTarget(codec, path, encoding)
_, err := os.Stat(codec.Target)
if err == nil && !force {
fmt.Println("^^^ SKIP", path, "->", codec.Target)
return
}
fmt.Println("--- PATH", path, "->", codec.Target)
for i := 1; i < encoding.Passes; i++ {
Run(encoding, i, pid, path, DevNull())
Run(encoding, *codec, i, pid, path, DevNull())
}
Run(encoding, encoding.Passes, pid, path, target)
Run(encoding, *codec, encoding.Passes, pid, path, codec.Target)
}
SaveMPD(encoding)
}
func StrSeq(up_to int) iter.Seq[string] {
@ -134,18 +153,18 @@ func StrSeq(up_to int) iter.Seq[string] {
}
}
func SaveMPD(settings config.Settings) {
func SaveMPD(encoding config.EncodeOpts) {
args := make([]string, 0, 10)
var the_audio string
// force it to overwrite
args = append(args, "-y")
for _, encoding := range settings.Encodings {
if VideoOnly(encoding) {
args = append(args, "-f", "webm_dash_manifest", "-i", encoding.FakeResult)
} else if AudioOnly(encoding) {
the_audio = encoding.FakeResult
for _, codec := range encoding.Variants {
if VideoOnly(codec) {
args = append(args, "-f", "webm_dash_manifest", "-i", codec.Target)
} else if AudioOnly(codec) {
the_audio = codec.Target
}
}
@ -154,7 +173,7 @@ func SaveMPD(settings config.Settings) {
// create map for each
args = append(args, "-c", "copy")
for i := 0; i < len(settings.Encodings); i++ {
for i := 0; i < len(encoding.Variants); i++ {
args = append(args, "-map", strconv.Itoa(i))
}
@ -162,15 +181,15 @@ func SaveMPD(settings config.Settings) {
// id=0 is videos, id=1 is audio
args = append(args, "-f", "webm_dash_manifest", "-adaptation_sets")
da_ints := slices.Collect(StrSeq(len(settings.Encodings) - 1))
da_ints := slices.Collect(StrSeq(len(encoding.Variants) - 1))
video_set := strings.Join(da_ints, ",")
adapt_set := fmt.Sprintf("id=0,streams=%s id=1,streams=%d",
video_set, len(settings.Encodings) - 1)
video_set, len(encoding.Variants) - 1)
args = append(args, adapt_set)
args = append(args, filepath.Join(settings.Encodings[0].OutDir, "manifest.mpd"))
args = append(args, filepath.Join(encoding.OutDir, "manifest.mpd"))
fmt.Println("\n\n\n\nARGS", args)
@ -181,29 +200,14 @@ func SaveMPD(settings config.Settings) {
log.Fatal(err)
}
func RenderToDir(encoding config.VideoOpts, force bool) string {
func RenderToDir(encoding config.EncodeOpts, force bool) {
matches, err := filepath.Glob(encoding.Input)
if err != nil { log.Fatalf("%v", err) }
target := ""
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)
RenderFile(encoding, rand.Int(), path, force)
}
}
if target == "" { log.Fatal("fuck!") }
return target
}
func main() {
@ -224,13 +228,10 @@ func main() {
encoding := &settings.Encodings[i];
if encoding.OutDir != "" {
encoding.FakeResult = RenderToDir(*encoding, settings.Force)
fmt.Println("ENCODING result", encoding.FakeResult, "len=", len(settings.Encodings))
RenderToDir(*encoding, settings.Force)
} else {
log.Fatal("config file needs either Output or OutDir")
}
}
SaveMPD(settings)
}
}

Loading…
Cancel
Save