|
|
|
|
@ -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,31 +200,16 @@ 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() { |
|
|
|
|
settings := config.Load() |
|
|
|
|
|
|
|
|
|
@ -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) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|