182 lines
4.2 KiB
Go
182 lines
4.2 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/xml"
|
|
"flag"
|
|
"fmt"
|
|
"git.gammaspectra.live/WeebDataHoarder/go-dcp/dcp"
|
|
"git.gammaspectra.live/WeebDataHoarder/go-dcp/utils"
|
|
"os"
|
|
"os/exec"
|
|
"strings"
|
|
"sync"
|
|
)
|
|
|
|
func main() {
|
|
mpvCmd := flag.String("mpv", "mpv", "mpv command path")
|
|
xyz2yuvCmd := flag.String("xyz2yuv", "xyz2yuv", "xyz2yuv command path")
|
|
|
|
dcpPath := flag.String("dcp", "", "Path to DCP folder or ASSETMAP")
|
|
pklUUID := flag.String("pkl-id", "", "PKL ID to use. Empty for first PKL found")
|
|
customCPL := flag.String("custom-cpl", "", "Custom CPL path to use.")
|
|
reelIDs := flag.String("drop-reel-ids", "", "IDs of reels to drop. Use to skip ads or logos")
|
|
|
|
audioMapping := flag.String("audio-channel-mapping", "auto", "Audio channel mapping, usually 5.1/2.0/1.0 etc. Leave empty to disable")
|
|
doASS := flag.Bool("ass", true, "Encode subtitles if present to ASS")
|
|
|
|
width := flag.Int("width", 1998, "Video stream width for subtitles. Default is 2K Flat")
|
|
height := flag.Int("height", 1080, "Video stream height for subtitles. Default is 2K Flat")
|
|
|
|
flag.Parse()
|
|
|
|
dcPackage, err := dcp.Open(*dcpPath)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
var cpl dcp.CompositionPlaylist
|
|
|
|
var dropReelUUIDs []string
|
|
|
|
for _, id := range strings.Split(*reelIDs, ",") {
|
|
dropReelUUIDs = append(dropReelUUIDs, utils.CleanUUID(id))
|
|
}
|
|
|
|
if *customCPL == "" {
|
|
cpl, err = utils.SelectCPL(dcPackage, *pklUUID)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
} else {
|
|
cplContents, err := os.ReadFile(*customCPL)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
err = xml.Unmarshal(cplContents, &cpl)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if !(cpl.IsSMPTE() && dcPackage.IsSMPTE()) && !(cpl.IsIOP() && dcPackage.IsIOP()) {
|
|
panic(fmt.Errorf("unexpected namespace %s", cpl.XMLName.Space))
|
|
}
|
|
}
|
|
|
|
err = utils.Concat(dcPackage, cpl, utils.ConcatSettings{
|
|
DropReelUUIDs: dropReelUUIDs,
|
|
Subtitles: *doASS,
|
|
Width: *width,
|
|
Height: *height,
|
|
}, func(desc, videoFile, audioFile, subtitleFile string) {
|
|
af := ""
|
|
|
|
switch strings.ToLower(strings.ReplaceAll(strings.ReplaceAll(*audioMapping, ".", ""), "-", "")) {
|
|
case "71":
|
|
af = "pan=7.1|c0=c0|c1=c1|c2=c2|c3=c3|c4=c4|c5=c5|c6=c6|c7=c7"
|
|
case "51":
|
|
af = "pan=5.1|c0=c0|c1=c1|c2=c2|c3=c3|c4=c4|c5=c5"
|
|
case "50":
|
|
af = "pan=5.0|c0=c0|c1=c1|c2=c2|c3=c4|c4=c5"
|
|
case "20":
|
|
af = "pan=2.0|c0=c0|c1=c1"
|
|
case "10", "10center":
|
|
af = "pan=1c|c0=c2"
|
|
case "10side", "10fl":
|
|
af = "pan=1c|c0=c0"
|
|
case "10fr":
|
|
af = "pan=1c|c0=c1"
|
|
|
|
}
|
|
|
|
xyz2yuv := []string{
|
|
"-lowres", "0",
|
|
"-limited",
|
|
"-depth", "10",
|
|
"-in", videoFile,
|
|
//TODO: allow configuring
|
|
"-colorspace", "rec2020_pure24",
|
|
"-out", "-",
|
|
}
|
|
|
|
mpv := []string{
|
|
fmt.Sprintf("--force-media-title=%s", desc),
|
|
// allow concat demuxer input files
|
|
"--demuxer-lavf-o=safe=0",
|
|
//"--msg-level=vo=v",
|
|
|
|
"--demuxer-max-bytes=4096MiB",
|
|
"--demuxer-max-back-bytes=512M",
|
|
"--cache-secs=30",
|
|
"--demuxer-seekable-cache=yes",
|
|
"--hr-seek=yes",
|
|
"--demuxer-cache-wait=yes",
|
|
"--cache=yes",
|
|
"--force-seekable=yes",
|
|
|
|
"-",
|
|
fmt.Sprintf("--vf=format=colormatrix=%s:colorlevels=limited:primaries=%s:gamma=%s", "bt.2020-ncl", "bt.2020", "bt.1886"),
|
|
|
|
fmt.Sprintf("--external-file=%s", audioFile),
|
|
}
|
|
|
|
if subtitleFile != "" {
|
|
mpv = append(mpv, fmt.Sprintf("--external-file=%s", subtitleFile))
|
|
}
|
|
|
|
mpv = append(mpv, "--vid=1", "--aid=1", "--sid=1")
|
|
|
|
if af != "" {
|
|
mpv = append(mpv,
|
|
fmt.Sprintf("--af=\"lavfi=%s\"", af),
|
|
)
|
|
}
|
|
|
|
xyz2yuvProcess := exec.Command(*xyz2yuvCmd, xyz2yuv...)
|
|
|
|
xyz2yuvProcess.Stdin = os.Stdin
|
|
xyz2yuvProcess.Stderr = os.Stderr
|
|
|
|
mpvProcess := exec.Command(*mpvCmd, mpv...)
|
|
|
|
mpvProcess.Stdin, err = xyz2yuvProcess.StdoutPipe()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
mpvProcess.Stdout = os.Stdout
|
|
mpvProcess.Stderr = os.Stderr
|
|
|
|
err = xyz2yuvProcess.Start()
|
|
if err != nil {
|
|
defer xyz2yuvProcess.Process.Release()
|
|
panic(err)
|
|
}
|
|
|
|
err = mpvProcess.Start()
|
|
if err != nil {
|
|
defer mpvProcess.Process.Release()
|
|
panic(err)
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
wg.Add(2)
|
|
go func() {
|
|
defer wg.Done()
|
|
|
|
_ = xyz2yuvProcess.Wait()
|
|
}()
|
|
go func() {
|
|
defer wg.Done()
|
|
defer xyz2yuvProcess.Process.Kill()
|
|
|
|
_ = mpvProcess.Wait()
|
|
}()
|
|
|
|
wg.Wait()
|
|
})
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
}
|