- removed Theora support

- removed --context
- added Opus support (now default)
- added VP9 support (now default)
- added WebM support
This commit is contained in:
Martinez 2018-05-07 01:21:48 +02:00
parent fa9b3fe790
commit da0d60eecf
3 changed files with 32 additions and 59 deletions

31
aux.py
View file

@ -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):
try:
return float(a)

View file

@ -23,11 +23,12 @@ command = over.types.ndict()
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.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_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_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_vfilter = Command("-filter:v", "ARGS")
command.force_yuv420p = Command("-pix_fmt", "yuv420p")
@ -38,24 +39,24 @@ command.sub_copy_video = Command("-codec:v", "copy")
if __name__ == "__main__":
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-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("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-preset", "Video encoding preset, if supported by the selected encoder.", 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("context", "Use .over-video file in CWD, if available, to remember encoding parameters per-directory.", bool, [True], abbr="C")
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. Ignored by <W>--<g>audio<.> <m>opus<.>.", float, [4], abbr="q", 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 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>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("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("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("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("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("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_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("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("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>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()
@ -65,10 +66,7 @@ if __name__ == "__main__":
files = over.types.ndict()
audio_words = []
video_words = []
files.container = "mkv"
if main.cfg.context:
aux.update_cfg_context(main, ["context", "armed", "probe", "dump-commands", "ffmpeg-map"])
files.container = main.cfg.container
if main.cfg.audio in ("copy", "drop"):
audio_words.append("<c>%s<.>" %(main.cfg.audio))
@ -99,6 +97,8 @@ if __name__ == "__main__":
files.container = "wav"
elif main.cfg.audio == "vorbis":
files.container = "ogg"
elif main.cfg.audio == "opus":
files.container = "opus"
main.print("settings", main.print.tl.start, end=":\n")
main.print("audio: %s" %(", ".join(audio_words)))
@ -108,10 +108,10 @@ if __name__ == "__main__":
if 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))
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))
if not main.targets:
@ -300,6 +300,11 @@ if __name__ == "__main__":
command.sub_vorbis.NORMALIZE = info.normalize_command
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:
info.vfilter_command = command.sub_vfilter
@ -323,12 +328,12 @@ if __name__ == "__main__":
encode_cmd.VIDEO = command.sub_copy_video
elif main.cfg.video == "drop":
encode_cmd.VIDEO = "-vn"
elif main.cfg.video == "theora":
command.sub_theora.reset()
command.sub_theora.QUALITY = main.cfg.video_quality
command.sub_theora.VFILTER = info.vfilter_command
elif main.cfg.video == "vp9":
command.sub_vp9.reset()
command.sub_vp9.QUALITY = main.cfg.video_quality
command.sub_vp9.VFILTER = info.vfilter_command
encode_cmd.VIDEO = command.sub_theora
encode_cmd.VIDEO = command.sub_vp9
elif main.cfg.video == "x264":
command.sub_x264.reset()
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.PRESET = main.cfg.video_preset
command.sub_x265.VFILTER = info.vfilter_command
command.sub_x265.PIXFMT = None
encode_cmd.VIDEO = command.sub_x265

View file

@ -2,7 +2,7 @@
# encoding: utf-8
major = 1 # VERSION_MAJOR_IDENTIFIER
minor = 102 # VERSION_MINOR_IDENTIFIER
# VERSION_LAST_MM 1.102
patch = 3 # VERSION_PATCH_IDENTIFIER
minor = 110 # VERSION_MINOR_IDENTIFIER
# VERSION_LAST_MM 1.110
patch = 0 # VERSION_PATCH_IDENTIFIER
str = ".".join(str(v) for v in (major, minor, patch))