From 25c62302706f9757ae449d9df9dcb2c0a4528741 Mon Sep 17 00:00:00 2001 From: Tong Sun Date: Sun, 10 Oct 2021 16:33:28 -0400 Subject: [PATCH 1/2] - [+] add option -S,Seg -- split video into multiple segments --- config.go | 17 ++++++++++++++++- ffcvt_cli.yaml | 8 +++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/config.go b/config.go index a99454c..d83e3b0 100644 --- a/config.go +++ b/config.go @@ -31,6 +31,7 @@ type Options struct { VN bool // no video, output audio only VSS bool // video: same size Cut mFlags // Cut segment(s) out to keep. Specify in the form of start-[end],\n\tstrictly in the format of hh:mm:ss, and may repeat + Seg string // Split video into multiple segments (strictly in format: hh:mm:ss) Lang string // language selection for audio stream extraction SEL mFlags // subtitle encoding language (language picked for reencoded video) OptExtra string // more options that will pass to ffmpeg program @@ -108,6 +109,12 @@ func init() { "video: same size") flag.Var(&Opts.Cut, "C", "Cut segment(s) out to keep. Specify in the form of start-[end],\n\tstrictly in the format of hh:mm:ss, and may repeat") + flag.Var(&Opts.Cut, "Cut", + "Cut segment(s) out to keep. Specify in the form of start-[end],\n\tstrictly in the format of hh:mm:ss, and may repeat") + flag.StringVar(&Opts.Seg, "S", "", + "Split video into multiple segments (strictly in format: hh:mm:ss)") + flag.StringVar(&Opts.Seg, "Seg", "", + "Split video into multiple segments (strictly in format: hh:mm:ss)") flag.StringVar(&Opts.Lang, "lang", "eng", "language selection for audio stream extraction") flag.Var(&Opts.SEL, "sel", @@ -227,6 +234,14 @@ func init() { if _, exists = os.LookupEnv("FFCVT_VSS"); Opts.VSS || exists { Opts.VSS = true } + if len(Opts.Seg) == 0 || + len(os.Getenv("FFCVT_S")) != 0 { + Opts.Seg = os.Getenv("FFCVT_S") + } + if len(Opts.Seg) == 0 || + len(os.Getenv("FFCVT_SEG")) != 0 { + Opts.Seg = os.Getenv("FFCVT_SEG") + } if len(Opts.Lang) == 0 || len(os.Getenv("FFCVT_LANG")) != 0 { Opts.Lang = os.Getenv("FFCVT_LANG") @@ -269,7 +284,7 @@ func init() { } -const usageSummary = " -t\ttarget type: webm/x265-opus/x264-mp3/wx/youtube (FFCVT_T)\n -ves\tvideo encoding method set (FFCVT_VES)\n -aes\taudio encoding method set (FFCVT_AES)\n -ses\tsubtitle encoding method set (FFCVT_SES)\n -vep\tvideo encoding method prepend (FFCVT_VEP)\n -aep\taudio encoding method prepend (FFCVT_AEP)\n -sep\tsubtitle encoding method prepend (FFCVT_SEP)\n -vea\tvideo encoding method append (FFCVT_VEA)\n -aea\taudio encoding method append (FFCVT_AEA)\n -abr\taudio bitrate (64k for opus, 256k for mp3) (FFCVT_ABR)\n -crf\tthe CRF value: 0-51. Higher CRF gives lower quality\n\t (28 for x265, ~ 23 for x264) (FFCVT_CRF)\n\n -d\tdirectory that hold input files (FFCVT_D)\n -f\tinput file name (either -d or -f must be specified) (FFCVT_F)\n -sym\tsymlinks will be processed as well (FFCVT_SYM)\n -exts\textension list for all the files to be queued (FFCVT_EXTS)\n -suf\tsuffix to the output file names (FFCVT_SUF)\n -ext\textension for the output file (FFCVT_EXT)\n -w\twork directory that hold output files (FFCVT_W)\n\n -ac\tcopy audio codec (FFCVT_AC)\n -vc\tcopy video codec (FFCVT_VC)\n -an\tno audio, output video only (FFCVT_AN)\n -vn\tno video, output audio only (FFCVT_VN)\n -vss\tvideo: same size (FFCVT_VSS)\n -C\tCut segment(s) out to keep. Specify in the form of start-[end],\n\tstrictly in the format of hh:mm:ss, and may repeat (FFCVT_C)\n -lang\tlanguage selection for audio stream extraction (FFCVT_LANG)\n -sel\tsubtitle encoding language (language picked for reencoded video) (FFCVT_SEL)\n -o\tmore options that will pass to ffmpeg program (FFCVT_O)\n -ato-opus\taudio encode to opus, using -abr (FFCVT_ATO_OPUS)\n -vto-x265\tvideo video encode to x265, using -crf (FFCVT_VTO_X265)\n\n -p\tpar2create, create par2 files (in work directory) (FFCVT_P)\n -nc\tno clobber, do not queue those already been converted (FFCVT_NC)\n -n\tno exec, dry run (FFCVT_N)\n\n -force\toverwrite any existing none-empty file (FFCVT_FORCE)\n -debug\tdebugging level (FFCVT_DEBUG)\n -ffmpeg\tffmpeg program executable name (FFCVT_FFMPEG)\n -ffprobe\tffprobe program execution (FFCVT_FFPROBE)\n -version\tprint version then exit (FFCVT_VERSION)\n\nDetails:\n\n" +const usageSummary = " -t\ttarget type: webm/x265-opus/x264-mp3/wx/youtube (FFCVT_T)\n -ves\tvideo encoding method set (FFCVT_VES)\n -aes\taudio encoding method set (FFCVT_AES)\n -ses\tsubtitle encoding method set (FFCVT_SES)\n -vep\tvideo encoding method prepend (FFCVT_VEP)\n -aep\taudio encoding method prepend (FFCVT_AEP)\n -sep\tsubtitle encoding method prepend (FFCVT_SEP)\n -vea\tvideo encoding method append (FFCVT_VEA)\n -aea\taudio encoding method append (FFCVT_AEA)\n -abr\taudio bitrate (64k for opus, 256k for mp3) (FFCVT_ABR)\n -crf\tthe CRF value: 0-51. Higher CRF gives lower quality\n\t (28 for x265, ~ 23 for x264) (FFCVT_CRF)\n\n -d\tdirectory that hold input files (FFCVT_D)\n -f\tinput file name (either -d or -f must be specified) (FFCVT_F)\n -sym\tsymlinks will be processed as well (FFCVT_SYM)\n -exts\textension list for all the files to be queued (FFCVT_EXTS)\n -suf\tsuffix to the output file names (FFCVT_SUF)\n -ext\textension for the output file (FFCVT_EXT)\n -w\twork directory that hold output files (FFCVT_W)\n\n -ac\tcopy audio codec (FFCVT_AC)\n -vc\tcopy video codec (FFCVT_VC)\n -an\tno audio, output video only (FFCVT_AN)\n -vn\tno video, output audio only (FFCVT_VN)\n -vss\tvideo: same size (FFCVT_VSS)\n -C,Cut\tCut segment(s) out to keep. Specify in the form of start-[end],\n\tstrictly in the format of hh:mm:ss, and may repeat (FFCVT_C,CUT)\n -S,Seg\tSplit video into multiple segments (strictly in format: hh:mm:ss) (FFCVT_S,SEG)\n -lang\tlanguage selection for audio stream extraction (FFCVT_LANG)\n -sel\tsubtitle encoding language (language picked for reencoded video) (FFCVT_SEL)\n -o\tmore options that will pass to ffmpeg program (FFCVT_O)\n -ato-opus\taudio encode to opus, using -abr (FFCVT_ATO_OPUS)\n -vto-x265\tvideo video encode to x265, using -crf (FFCVT_VTO_X265)\n\n -p\tpar2create, create par2 files (in work directory) (FFCVT_P)\n -nc\tno clobber, do not queue those already been converted (FFCVT_NC)\n -n\tno exec, dry run (FFCVT_N)\n\n -force\toverwrite any existing none-empty file (FFCVT_FORCE)\n -debug\tdebugging level (FFCVT_DEBUG)\n -ffmpeg\tffmpeg program executable name (FFCVT_FFMPEG)\n -ffprobe\tffprobe program execution (FFCVT_FFPROBE)\n -version\tprint version then exit (FFCVT_VERSION)\n\nDetails:\n\n" // Usage function shows help on commandline usage func Usage() { diff --git a/ffcvt_cli.yaml b/ffcvt_cli.yaml index 0b01a2f..207d2f0 100644 --- a/ffcvt_cli.yaml +++ b/ffcvt_cli.yaml @@ -182,10 +182,16 @@ Options: - Name: Cut Type: mFlags - Flag: C + Flag: C,Cut Value: '""' Usage: "Cut segment(s) out to keep. Specify in the form of start-[end],\\n\\tstrictly in the format of hh:mm:ss, and may repeat" + - Name: Seg + Type: string + Flag: S,Seg + Value: '""' + Usage: "Split video into multiple segments (strictly in format: hh:mm:ss)" + - Name: Lang Type: string Flag: lang From f8b25e1b15760ca4fb907a8afcc7e2457943cc10 Mon Sep 17 00:00:00 2001 From: Tong Sun Date: Sun, 10 Oct 2021 18:17:57 -0400 Subject: [PATCH 2/2] - [#] implemented option -S,Seg -- split video into multiple segments --- ffcvt.go | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/ffcvt.go b/ffcvt.go index e798428..3ae6498 100644 --- a/ffcvt.go +++ b/ffcvt.go @@ -64,6 +64,15 @@ func main() { os.Exit(0) } + if len(Opts.Seg) > 0 { + // sanity check + _, err := time.Parse("15:04:05", Opts.Seg) + if err != nil { + fmt.Fprintf(os.Stderr, "Seg format error: '%s'\n", Opts.Seg) + os.Exit(1) + } + } + if len(Opts.Cut) > 0 { var b, vc strings.Builder var ci int @@ -264,7 +273,10 @@ func transcodeVideos(startTime time.Time) { func transcodeFile(inputName string) { startTime := time.Now() - outputName := getOutputName(inputName) + outputName, outputGrpName := getOutputName(inputName), "" + if len(Opts.Seg) > 0 { + outputName, outputGrpName = getOutputNameSeg(inputName) + } debug(outputName, 4) os.MkdirAll(filepath.Dir(outputName), os.ModePerm) var oldAEP, oldVEP, oldSEP string @@ -319,6 +331,14 @@ func transcodeFile(inputName string) { if Opts.Force { args = append(args, "-y") } + if len(Opts.Seg) > 0 { + args = append(args, "-f") + args = append(args, "segment") + args = append(args, "-segment_time") + args = append(args, Opts.Seg) + args = append(args, "-reset_timestamps") + args = append(args, "1") + } if len(cutOps) != 0 { args = append(args, "-filter_complex") args = append(args, cutOps) @@ -328,7 +348,11 @@ func transcodeFile(inputName string) { args = append(args, "[ao]") } args = append(args, flag.Args()...) - args = append(args, outputName) + if len(Opts.Seg) > 0 { + args = append(args, outputGrpName) + } else { + args = append(args, outputName) + } debug(Opts.FFMpeg+" "+strings.Join(args, " "), 1) if Opts.NoExec { @@ -529,6 +553,16 @@ func getOutputName(input string) string { return r } +// getOutputNameSeg will do getOutputName() but tailored toward video segmenting. +// The first return will be the first video segment file name, 00_.mkv, while +// the second return will be the segment group file name, %02d_.mkv +func getOutputNameSeg(input string) (string, string) { + r := getOutputName(input) + fileFirst := strings.Replace(r, encodedExt, "00"+encodedExt, 1) + fileGroup := strings.Replace(r, encodedExt, "%02d"+encodedExt, 1) + return fileFirst, fileGroup +} + //========================================================================== // Support functions