- removed Theora support
- removed --context - added Opus support (now default) - added VP9 support (now default) - added WebM support
This commit is contained in:
parent
fa9b3fe790
commit
da0d60eecf
3 changed files with 32 additions and 59 deletions
31
aux.py
31
aux.py
|
@ -31,37 +31,6 @@ def to_Path(raw_path):
|
||||||
|
|
||||||
# --------------------------------------------------
|
# --------------------------------------------------
|
||||||
|
|
||||||
context_file_header = """# Context file for %s-%s
|
|
||||||
# This file stores configuration valid for this directory.
|
|
||||||
# It is updated automatically with options you use.
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
def update_cfg_context(main, ignore=[]):
|
|
||||||
"""
|
|
||||||
All main.options that are sourced from either the cfg file or defaults get overridden by those in .over-video.
|
|
||||||
Those that are from command line get saved into .over-video.
|
|
||||||
|
|
||||||
File format:
|
|
||||||
name=value
|
|
||||||
"""
|
|
||||||
|
|
||||||
options_to_consider = [option for option in main.options.values() if option.name not in ignore and option.in_cfg_file]
|
|
||||||
options_to_write = {option.name: option for option in options_to_consider if option.source == over.app.Option_sources.command_line}
|
|
||||||
options_to_read = {option.name: option for option in options_to_consider if option.source != over.app.Option_sources.command_line}
|
|
||||||
|
|
||||||
context_file_read = over.app.ConfigFile(options_to_read, ".over-video", ignore_unknown=True)
|
|
||||||
restored = context_file_read.read_config()
|
|
||||||
if restored:
|
|
||||||
main.print("restored from <m>.over-video<.>: %s" %(", ".join("<g>%s<.>" %(o.name) for o in restored)), main.print.tl.note)
|
|
||||||
|
|
||||||
context_file_write = over.app.ConfigFile(options_to_write, ".over-video")
|
|
||||||
added = context_file_write.update_config(context_file_header, (main.name, main.version))
|
|
||||||
if added:
|
|
||||||
main.print("added to <m>.over-video<.>: %s" %(", ".join("<g>%s<.>" %(o.name) for o in added)))
|
|
||||||
|
|
||||||
# --------------------------------------------------
|
|
||||||
|
|
||||||
def float_or_string(a):
|
def float_or_string(a):
|
||||||
try:
|
try:
|
||||||
return float(a)
|
return float(a)
|
||||||
|
|
|
@ -23,11 +23,12 @@ command = over.types.ndict()
|
||||||
command.identify = Command("ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", "INFILE")
|
command.identify = Command("ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", "INFILE")
|
||||||
command.normalize_prepass = Command("ffmpeg", "-i", "INFILE", "-max_muxing_queue_size", "512", "-filter:a", "loudnorm=I=-16:TP=-1.5:LRA=11:print_format=json", "-f", "null", "/dev/null")
|
command.normalize_prepass = Command("ffmpeg", "-i", "INFILE", "-max_muxing_queue_size", "512", "-filter:a", "loudnorm=I=-16:TP=-1.5:LRA=11:print_format=json", "-f", "null", "/dev/null")
|
||||||
command.encode_generic = Command("ffmpeg", "FPS", "CUT_FROM", "-i", "INFILE", "-max_muxing_queue_size", "512", "CUT_TO", "MAP", "VIDEO", "AUDIO", "-sn", "OUTFILE")
|
command.encode_generic = Command("ffmpeg", "FPS", "CUT_FROM", "-i", "INFILE", "-max_muxing_queue_size", "512", "CUT_TO", "MAP", "VIDEO", "AUDIO", "-sn", "OUTFILE")
|
||||||
|
command.sub_opus = Command("-codec:a", "libopus", "NORMALIZE")
|
||||||
command.sub_vorbis = Command("-codec:a", "libvorbis", "-qscale:a", "QUALITY", "NORMALIZE")
|
command.sub_vorbis = Command("-codec:a", "libvorbis", "-qscale:a", "QUALITY", "NORMALIZE")
|
||||||
command.sub_pcm = Command("-codec:a", "pcm_s16le", "NORMALIZE")
|
command.sub_pcm = Command("-codec:a", "pcm_s16le", "NORMALIZE")
|
||||||
command.sub_theora = Command("-codec:v", "libtheora", "-qscale:v", "QUALITY", "VFILTER")
|
|
||||||
command.sub_x264 = Command("PIXFMT", "-codec:v", "libx264", "-preset", "PRESET", "-crf", "QUALITY", "-profile:v", "high", "-level", "4.2", "VFILTER")
|
command.sub_x264 = Command("PIXFMT", "-codec:v", "libx264", "-preset", "PRESET", "-crf", "QUALITY", "-profile:v", "high", "-level", "4.2", "VFILTER")
|
||||||
command.sub_x265 = Command("PIXFMT", "-codec:v", "libx265", "-preset", "PRESET", "-crf", "QUALITY", "VFILTER")
|
command.sub_x265 = Command("-codec:v", "libx265", "-preset", "PRESET", "-crf", "QUALITY", "VFILTER")
|
||||||
|
command.sub_vp9 = Command("-codec:v", "libvpx-vp9", "-crf", "QUALITY", "-b:v", "0", "VFILTER")
|
||||||
command.sub_normalize = Command("-filter:a", "LOUDNORM_INCANTATION", "-ar", "48k")
|
command.sub_normalize = Command("-filter:a", "LOUDNORM_INCANTATION", "-ar", "48k")
|
||||||
command.sub_vfilter = Command("-filter:v", "ARGS")
|
command.sub_vfilter = Command("-filter:v", "ARGS")
|
||||||
command.force_yuv420p = Command("-pix_fmt", "yuv420p")
|
command.force_yuv420p = Command("-pix_fmt", "yuv420p")
|
||||||
|
@ -38,24 +39,24 @@ command.sub_copy_video = Command("-codec:v", "copy")
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main = over.app.Main("over-video", version.str, "AO-JSL", features={"config_file": True})
|
main = over.app.Main("over-video", version.str, "AO-JSL", features={"config_file": True})
|
||||||
main.add_option("audio", "Audio codec to use, either <M>vorbis<.>, <M>pcm<.>, <M>copy<.> or <M>drop<.>.", str, ["vorbis"], abbr="a", count=1)
|
main.add_option("audio", "Audio codec to use, either <M>opus<.>, <M>vorbis<.>, <M>pcm<.>, <M>copy<.> or <M>drop<.>.", str, ["opus"], abbr="a", count=1)
|
||||||
main.add_option("audio-quality", "Audio encoding quality with <M>-1<.> being the worst and <M>10<.> being the best.", float, [4], abbr="q", count=1)
|
main.add_option("audio-quality", "Audio encoding quality with <M>-1<.> being the worst and <M>10<.> being the best. Ignored by <W>--<g>audio<.> <m>opus<.>.", float, [4], abbr="q", count=1)
|
||||||
main.add_option("video", "Video codec to use, either <M>x265<.>, <M>x264<.>, <M>theora<.>, <M>copy<.> or <M>drop<.>.", str, ["x264"], abbr="v", count=1)
|
main.add_option("video", "Video codec to use, either <M>vp9<.>, <M>x265<.>, <M>x264<.>, <M>copy<.> or <M>drop<.>.", str, ["vp9"], abbr="v", count=1)
|
||||||
main.add_option("video-preset", "Video encoding preset, if supported by the selected encoder.", str, ["slow"], abbr="P", count=1)
|
main.add_option("video-preset", "Video encoding preset to use by <W>--<g>video<.> <m>x264<.> and <m>x265<.>.", str, ["slow"], abbr="P", count=1)
|
||||||
main.add_option("video-quality", "Video encoding quality (CRF). Use <M>0<.>-<M>10<.> for Theora (<M>0<.> being the lowest, <M>5<.>-<M>7<.> is generally watchable) and <M>0<.>-<M>51<.> for x264/5 (<M>0<.> being lossless, <M>18<.>-<M>28<.> is reasonable).", float, [22], abbr="Q", count=1)
|
main.add_option("video-quality", "Video encoding quality (CRF). Use <M>0<.>-<M>51<.> for <W>--<g>video<.> <m>x264<.> and <m>x265<.> (<M>0<.> being lossless, <M>18<.>-<M>28<.> is reasonable) and <M>0<.>-<M>63<.> for <W>--<g>video<.> <m>vp9<.> (<M>0<.> being highest, <M>15<.>-<M>35<.> typical, and <M>31<.> recommended for HD video).", float, [31], abbr="Q", count=1)
|
||||||
main.add_option("context", "Use .over-video file in CWD, if available, to remember encoding parameters per-directory.", bool, [True], abbr="C")
|
main.add_option("container", "The initial container type. Either <M>mkv<.> or <M>webm<.> (or anything else supported by ffmpeg).", str, ["mkv"], count=1)
|
||||||
main.add_option("normalize", "Normalize the audio track without clipping. May use dynamic range compression.", bool, [True], abbr="n")
|
main.add_option("normalize", "Normalize the audio track without clipping. May use dynamic range compression.", bool, [True], abbr="n")
|
||||||
main.add_option("ffmpeg-vfilter", 'Raw ffmpeg -filter:v options, e.g. "<M>scale=1280:trunc(ow/a/2)*2,transpose=dir=1<.>"', str, abbr="F", count=1)
|
main.add_option("ffmpeg-vfilter", 'Raw ffmpeg -filter:v options, e.g. "<M>scale=1280:trunc(ow/a/2)*2,transpose=dir=1<.>"', str, abbr="F", count=1)
|
||||||
main.add_option("ffmpeg-map", "Raw ffmpeg <c>-map<.> options, e.g. <W>--<g>map<.> <M>0:1<.> <W>--<g>map<.> <M>0:2<.>. This is a drop-in fix until we get proper stream selection.", str, abbr="M", overwrite=False, count=1)
|
main.add_option("ffmpeg-map", "Raw ffmpeg <c>-map<.> options, e.g. <W>--<g>map<.> <M>0:1<.> <W>--<g>map<.> <M>0:2<.>. This is a drop-in fix until we get proper stream selection.", str, abbr="M", overwrite=False, count=1)
|
||||||
main.add_option("cut", "Start and end timestamps of the portion to cut out. Uses native ffmpeg <c>-ss<.> and <c>-to<.> format, so it's either seconds from start or <M>[<HH>:]<MM>:<SS>[.<<m>...]<.>. Example: <W>--<g>cut<.> <M>25 35<.> uses 10 seconds of video starting at 25s, <W>--<g>cut<.> <M>1:10:45 1:23:54.5<.> uses video from 4245s to 5034.5s.", over.callback.strings, abbr="X", count=2)
|
main.add_option("cut", "Start timestamp and the duration of the portion to use. Uses native ffmpeg <c>-ss<.> and <c>-to<.> format, so it's either seconds from start or <M>[<HH>:]<MM>:<SS>[.<<m>...]<.>. Example: <W>--<g>cut<.> <M>25 10<.> uses 10 seconds of video starting at 25s, <W>--<g>cut<.> <M>1:10:45 13:9.5<.> uses video from 4245s to 5034.5s.", over.callback.strings, abbr="X", count=2)
|
||||||
main.add_option("fps", "Override input framerate.", float, abbr="f", count=1)
|
main.add_option("fps", "Override input framerate.", float, abbr="f", count=1)
|
||||||
main.add_option("move-source", "Move source file to this directory after conversion. Use an empty string to disable.", str, ["processed"], count=1)
|
main.add_option("move-source", "Move source file to this directory after conversion. Pass an empty string to disable.", str, ["processed"], count=1)
|
||||||
main.add_option("dump-commands", "Print ffmpeg commands that would be executed. If <W>--<g>normalize<.> is in effect, the normalization pre-pass will still be performed so that the proper volume correction can be computed.", bool, [False], abbr="D", in_cfg_file=False)
|
main.add_option("dump-commands", "Print ffmpeg commands that would be executed. If <W>--<g>normalize<.> is in effect, the normalization pre-pass will still be performed so that the proper volume correction can be computed.", bool, [False], abbr="D", in_cfg_file=False)
|
||||||
main.add_option("probe", "Print the raw JSON output of ffprobe and exit.", bool, [False], abbr="p", in_cfg_file=False)
|
main.add_option("probe", "Print the raw dict (JSON-esque) output of ffprobe and exit.", bool, [False], abbr="p", in_cfg_file=False)
|
||||||
main.add_option("armed", "Perform the suggested action.", bool, [False], abbr="A", in_cfg_file=False)
|
main.add_option("armed", "Perform the suggested action.", bool, [False], abbr="A", in_cfg_file=False)
|
||||||
|
|
||||||
main.add_doc("Description", ["A video converter meant to coerce all video formats into HEVC+Vorbis within Matroska containers. Other uses include extracting audio from video files, resizing, cutting..."])
|
main.add_doc("Description", ["A video converter meant to coerce all video formats into one format with properly normalized audio. It can also be used to extract audio from video files, resizing, or very basic cutting."])
|
||||||
main.add_doc("Good encoder settings", ["<W>x264<.>: <W>--<g>video<.> <M>x264<.> <W>--<g>video-preset<.> <M>slow<.> <W>--<g>video-quality<.> <M>22<.>", "<W>x265<.>: <W>--<g>video<.> <M>x265<.> <W>--<g>video-preset<.> <M>medium<.> <W>--<g>video-quality<.> <M>20<.>"])
|
main.add_doc("Good encoder settings", ["<W>vp9<.>: <W>--<g>video<.> <M>vp9<.> <W>--<g>video-quality<.> <M>31<.> <W>--<g>audio<.> <M>opus<.> (this is the default and should provide best overall results)", "<W>x264<.>: <W>--<g>video<.> <M>x264<.> <W>--<g>video-preset<.> <M>slow<.> <W>--<g>video-quality<.> <M>22<.>", "<W>x265<.>: <W>--<g>video<.> <M>x265<.> <W>--<g>video-preset<.> <M>medium<.> <W>--<g>video-quality<.> <M>20<.>"])
|
||||||
|
|
||||||
main.setup()
|
main.setup()
|
||||||
|
|
||||||
|
@ -65,10 +66,7 @@ if __name__ == "__main__":
|
||||||
files = over.types.ndict()
|
files = over.types.ndict()
|
||||||
audio_words = []
|
audio_words = []
|
||||||
video_words = []
|
video_words = []
|
||||||
files.container = "mkv"
|
files.container = main.cfg.container
|
||||||
|
|
||||||
if main.cfg.context:
|
|
||||||
aux.update_cfg_context(main, ["context", "armed", "probe", "dump-commands", "ffmpeg-map"])
|
|
||||||
|
|
||||||
if main.cfg.audio in ("copy", "drop"):
|
if main.cfg.audio in ("copy", "drop"):
|
||||||
audio_words.append("<c>%s<.>" %(main.cfg.audio))
|
audio_words.append("<c>%s<.>" %(main.cfg.audio))
|
||||||
|
@ -99,6 +97,8 @@ if __name__ == "__main__":
|
||||||
files.container = "wav"
|
files.container = "wav"
|
||||||
elif main.cfg.audio == "vorbis":
|
elif main.cfg.audio == "vorbis":
|
||||||
files.container = "ogg"
|
files.container = "ogg"
|
||||||
|
elif main.cfg.audio == "opus":
|
||||||
|
files.container = "opus"
|
||||||
|
|
||||||
main.print("settings", main.print.tl.start, end=":\n")
|
main.print("settings", main.print.tl.start, end=":\n")
|
||||||
main.print("audio: %s" %(", ".join(audio_words)))
|
main.print("audio: %s" %(", ".join(audio_words)))
|
||||||
|
@ -108,10 +108,10 @@ if __name__ == "__main__":
|
||||||
if main.cfg.move_source:
|
if main.cfg.move_source:
|
||||||
main.print("move source files to <W>%s<.>/" %(main.cfg.move_source))
|
main.print("move source files to <W>%s<.>/" %(main.cfg.move_source))
|
||||||
|
|
||||||
if main.cfg.audio not in ("drop", "copy", "pcm", "vorbis"):
|
if main.cfg.audio not in ("drop", "copy", "pcm", "vorbis", "opus"):
|
||||||
raise ValueError("unknown audio codec: %s" %(main.cfg.audio))
|
raise ValueError("unknown audio codec: %s" %(main.cfg.audio))
|
||||||
|
|
||||||
if main.cfg.video not in ("drop", "copy", "theora", "x264", "x265"):
|
if main.cfg.video not in ("drop", "copy", "x264", "x265", "vp9"):
|
||||||
raise ValueError("unknown video codec: %s" %(main.cfg.video))
|
raise ValueError("unknown video codec: %s" %(main.cfg.video))
|
||||||
|
|
||||||
if not main.targets:
|
if not main.targets:
|
||||||
|
@ -300,6 +300,11 @@ if __name__ == "__main__":
|
||||||
command.sub_vorbis.NORMALIZE = info.normalize_command
|
command.sub_vorbis.NORMALIZE = info.normalize_command
|
||||||
|
|
||||||
encode_cmd.AUDIO = command.sub_vorbis
|
encode_cmd.AUDIO = command.sub_vorbis
|
||||||
|
elif main.cfg.audio == "opus":
|
||||||
|
command.sub_opus.reset()
|
||||||
|
command.sub_opus.NORMALIZE = info.normalize_command
|
||||||
|
|
||||||
|
encode_cmd.AUDIO = command.sub_opus
|
||||||
|
|
||||||
if main.cfg.ffmpeg_vfilter:
|
if main.cfg.ffmpeg_vfilter:
|
||||||
info.vfilter_command = command.sub_vfilter
|
info.vfilter_command = command.sub_vfilter
|
||||||
|
@ -323,12 +328,12 @@ if __name__ == "__main__":
|
||||||
encode_cmd.VIDEO = command.sub_copy_video
|
encode_cmd.VIDEO = command.sub_copy_video
|
||||||
elif main.cfg.video == "drop":
|
elif main.cfg.video == "drop":
|
||||||
encode_cmd.VIDEO = "-vn"
|
encode_cmd.VIDEO = "-vn"
|
||||||
elif main.cfg.video == "theora":
|
elif main.cfg.video == "vp9":
|
||||||
command.sub_theora.reset()
|
command.sub_vp9.reset()
|
||||||
command.sub_theora.QUALITY = main.cfg.video_quality
|
command.sub_vp9.QUALITY = main.cfg.video_quality
|
||||||
command.sub_theora.VFILTER = info.vfilter_command
|
command.sub_vp9.VFILTER = info.vfilter_command
|
||||||
|
|
||||||
encode_cmd.VIDEO = command.sub_theora
|
encode_cmd.VIDEO = command.sub_vp9
|
||||||
elif main.cfg.video == "x264":
|
elif main.cfg.video == "x264":
|
||||||
command.sub_x264.reset()
|
command.sub_x264.reset()
|
||||||
command.sub_x264.QUALITY = main.cfg.video_quality
|
command.sub_x264.QUALITY = main.cfg.video_quality
|
||||||
|
@ -347,7 +352,6 @@ if __name__ == "__main__":
|
||||||
command.sub_x265.QUALITY = main.cfg.video_quality
|
command.sub_x265.QUALITY = main.cfg.video_quality
|
||||||
command.sub_x265.PRESET = main.cfg.video_preset
|
command.sub_x265.PRESET = main.cfg.video_preset
|
||||||
command.sub_x265.VFILTER = info.vfilter_command
|
command.sub_x265.VFILTER = info.vfilter_command
|
||||||
command.sub_x265.PIXFMT = None
|
|
||||||
|
|
||||||
encode_cmd.VIDEO = command.sub_x265
|
encode_cmd.VIDEO = command.sub_x265
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
major = 1 # VERSION_MAJOR_IDENTIFIER
|
major = 1 # VERSION_MAJOR_IDENTIFIER
|
||||||
minor = 102 # VERSION_MINOR_IDENTIFIER
|
minor = 110 # VERSION_MINOR_IDENTIFIER
|
||||||
# VERSION_LAST_MM 1.102
|
# VERSION_LAST_MM 1.110
|
||||||
patch = 3 # VERSION_PATCH_IDENTIFIER
|
patch = 0 # VERSION_PATCH_IDENTIFIER
|
||||||
str = ".".join(str(v) for v in (major, minor, patch))
|
str = ".".join(str(v) for v in (major, minor, patch))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue