From 421f6bbce7e5ae7b155b746e9e19b9f694ebf962 Mon Sep 17 00:00:00 2001 From: n9Mtq4 Date: Sun, 16 Aug 2020 00:20:58 -0400 Subject: [PATCH] Add initial svt-vp9 code --- Av1an/arg_parse.py | 2 +- Av1an/bar.py | 2 +- Av1an/encoders/__init__.py | 3 +++ Av1an/encoders/svtvp9.py | 33 +++++++++++++++++++++++++++++++++ Av1an/setup.py | 16 ++++++++++++---- Av1an/target_vmaf.py | 5 +++++ 6 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 Av1an/encoders/svtvp9.py diff --git a/Av1an/arg_parse.py b/Av1an/arg_parse.py index 3f14001..6b8dbe6 100755 --- a/Av1an/arg_parse.py +++ b/Av1an/arg_parse.py @@ -107,7 +107,7 @@ def arg_parsing(): encode_group.add_argument('--passes', '-p', type=int, default=None, help='Specify encoding passes', choices=[1, 2]) encode_group.add_argument('--video_params', '-v', type=str, default=None, help='encoding settings') encode_group.add_argument('--encoder', '-enc', type=str, default='aom', help='Choosing encoder', - choices=['aom', 'svt_av1', 'rav1e', 'vpx','x265', 'x264', 'vvc']) + choices=['aom', 'svt_av1', 'svt_vp9', 'rav1e', 'vpx', 'x265', 'x264', 'vvc']) encode_group.add_argument('--workers', '-w', type=int, default=0, help='Number of workers') encode_group.add_argument('-cfg', '--config', type=Path, help='Parameters file. Save/Read: ' 'Video, Audio, Encoder, FFmpeg parameteres') diff --git a/Av1an/bar.py b/Av1an/bar.py index ed381e6..e5f5b68 100755 --- a/Av1an/bar.py +++ b/Av1an/bar.py @@ -159,7 +159,7 @@ def tqdm_bar(ffmpeg_gen_cmd, pass_cmd: CommandPair, encoder, counter, frame_prob if encoder in ('aom', 'vpx', 'rav1e', 'x265', 'x264', 'vvc'): process_encoding_pipe(pipe, encoder, counter) - if encoder == 'svt_av1': + if encoder in ('svt_av1', 'svt_vp9'): # SVT-AV1 developer: SVT-AV1 is special in the way it outputs to console process_pipe(pipe) counter.update(frame_probe_source // passes) diff --git a/Av1an/encoders/__init__.py b/Av1an/encoders/__init__.py index b5dd71a..dd85fc3 100644 --- a/Av1an/encoders/__init__.py +++ b/Av1an/encoders/__init__.py @@ -1,15 +1,18 @@ from .aom import Aom from .rav1e import Rav1e from .svtav1 import SvtAv1 +from .svtvp9 import SvtVp9 from .vpx import Vpx from .vvc import Vvc from .x264 import X264 from .x265 import X265 + ENCODERS = { 'aom': Aom(), 'rav1e': Rav1e(), 'svt_av1': SvtAv1(), + 'svt_vp9': SvtVp9(), 'vpx': Vpx(), 'vvc': Vvc(), 'x264': X264(), diff --git a/Av1an/encoders/svtvp9.py b/Av1an/encoders/svtvp9.py new file mode 100644 index 0000000..e4bb540 --- /dev/null +++ b/Av1an/encoders/svtvp9.py @@ -0,0 +1,33 @@ +from Av1an.arg_parse import Args +from Av1an.chunk import Chunk +from Av1an.commandtypes import MPCommands, CommandPair, Command +from Av1an.encoders.encoder import Encoder + + +class SvtVp9(Encoder): + + def __init__(self): + super(SvtVp9, self).__init__( + encoder_bin='SvtVp9EncApp', + default_args=None, + output_extension='ivf' + ) + + @staticmethod + def compose_ffmpeg_raw_pipe(a: Args) -> Command: + """ + Compose a rawvideo ffmpeg pipe for svt-vp9 + SVT-VP9 requires rawvideo, so we can't use arg.ffmpeg_pipe + + :param a: the Args + :return: a command + """ + return ['ffmpeg', '-y', '-hide_banner', '-loglevel', 'error', '-i', '-', *a.ffmpeg, *a.pix_format, '-bufsize', '50000K', '-f', 'rawvideo', '-'] + + def compose_1_pass(self, a: Args, c: Chunk) -> MPCommands: + return [ + CommandPair(SvtVp9.compose_ffmpeg_raw_pipe(a), ['SvtVp9EncApp', '-i', 'stdin', '-n', f'{c.frames}', *a.video_params, '-b', c.output]) + ] + + def compose_2_pass(self, a: Args, c: Chunk) -> MPCommands: + raise ValueError("SVT-VP9 doesn't support 2 pass") diff --git a/Av1an/setup.py b/Av1an/setup.py index 8a882b4..3bce918 100755 --- a/Av1an/setup.py +++ b/Av1an/setup.py @@ -26,7 +26,7 @@ def set_vmaf(args): print('Target vmaf require more than 3 probes/steps') terminate() - default_ranges = {'svt_av1': (20, 40), 'rav1e': (70, 150), 'aom': (25, 50), 'vpx': (25, 50),'x265': (20, 40), 'x264': (20, 35), 'vvc': (20, 50)} + default_ranges = {'svt_av1': (20, 40), 'svt_vp9': (20, 40), 'rav1e': (70, 150), 'aom': (25, 50), 'vpx': (25, 50),'x265': (20, 40), 'x264': (20, 35), 'vvc': (20, 50)} if args.min_q is None: args.min_q, _ = default_ranges[args.encoder] @@ -58,9 +58,9 @@ def check_exes(args: Args): terminate() -def startup_check(args): +def startup_check(args: Args): - encoders_default_passes = {'svt_av1': 1, 'rav1e': 1, 'aom': 2, 'vpx': 2,'x265': 1, 'x264': 1, 'vvc':1 } + encoders_default_passes = {'svt_av1': 1, 'svt_vp9': 1, 'rav1e': 1, 'aom': 2, 'vpx': 2,'x265': 1, 'x264': 1, 'vvc':1 } if sys.version_info < (3, 6): @@ -102,11 +102,19 @@ def startup_check(args): ) terminate() + if args.video_params is None and args.encoder == 'svt_vp9': + print('SVT-VP9 requires: -w, -h, and -fps/-fps-num/-fps-denom') + terminate() + # TODO: rav1e 2 pass is broken if args.encoder == 'rav1e' and args.passes == 2: print("Implicitly changing 2 pass rav1e to 1 pass\n2 pass Rav1e doesn't work") args.passes = 1 + if args.encoder == 'svt_vp9' and args.passes == 2: + print("Implicitly changing 2 pass svt-vp9 to 1 pass\n2 pass svt-vp9 isn't supported") + args.passes = 1 + if args.video_params is None: args.video_params = ENCODERS[args.encoder].default_args else: @@ -131,7 +139,7 @@ def determine_resources(encoder, workers): if encoder in ('aom', 'rav1e', 'vpx'): workers = round(min(cpu / 2, ram / 1.5)) - elif encoder in ('svt_av1', 'x265', 'x264'): + elif encoder in ('svt_av1', 'svt_vp9', 'x265', 'x264'): workers = round(min(cpu, ram)) // 8 elif encoder in ('vvc'): diff --git a/Av1an/target_vmaf.py b/Av1an/target_vmaf.py index 2a81f2b..58729c8 100644 --- a/Av1an/target_vmaf.py +++ b/Av1an/target_vmaf.py @@ -70,6 +70,11 @@ def probe_cmd(chunk: Chunk, q, ffmpeg_pipe, encoder, vmaf_rate) -> CommandPair: params = ['SvtAv1EncApp', '-i', 'stdin', '--preset', '8', '--rc', '0', '--qp', f'{q}'] cmd = CommandPair(pipe, [*params, '-b', probe_name, '-']) + elif encoder == 'svt_vp9': + params = ['SvtVp9EncApp', '-i', 'stdin', '-enc-mode', '8', '-q', f'{q}'] + # TODO: pipe needs to output rawvideo + cmd = CommandPair(pipe, [*params, '-b', probe_name, '-']) + elif encoder == 'x264': params = ['x264', '--log-level', 'error', '--demuxer', 'y4m', '-', '--no-progress', '--preset', 'slow', '--crf', f'{q}'] cmd = CommandPair(pipe, [*params, '-o', probe_name, '-'])