mirror of
https://github.com/master-of-zen/Av1an.git
synced 2024-11-25 02:29:40 +00:00
Added x265 support
This commit is contained in:
parent
dbce1ab3aa
commit
f7a9eb4fde
5 changed files with 75 additions and 25 deletions
5
av1an.py
5
av1an.py
|
@ -131,7 +131,7 @@ class Av1an:
|
|||
|
||||
v = call_vmaf(i[1], i[2], model=self.vmaf_path, return_file=True)
|
||||
# Trying 25 percentile
|
||||
mean = read_vmaf_xml(v , 25)
|
||||
mean = read_vmaf_xml(v, 25)
|
||||
|
||||
vmaf_cq.append((mean, i[3]))
|
||||
|
||||
|
@ -268,7 +268,8 @@ class Av1an:
|
|||
|
||||
def video_encoding(self):
|
||||
"""Encoding video on local machine."""
|
||||
self.output_file = outputs_filenames(self.input, self.output_file)
|
||||
|
||||
self.output_file = outputs_filenames(self.input, self.output_file, self.encoder )
|
||||
|
||||
if self.resume and (self.temp / 'done.json').exists():
|
||||
set_log(self.logging, self.temp)
|
||||
|
|
|
@ -29,7 +29,7 @@ def arg_parsing():
|
|||
parser.add_argument('--passes', '-p', type=int, default=2, help='Specify encoding passes', choices=[1, 2])
|
||||
parser.add_argument('--video_params', '-v', type=str, default=None, help='encoding settings')
|
||||
parser.add_argument('--encoder', '-enc', type=str, default='aom', help='Choosing encoder',
|
||||
choices=['aom', 'svt_av1', 'rav1e', 'vpx'])
|
||||
choices=['aom', 'svt_av1', 'rav1e', 'vpx','x265'])
|
||||
parser.add_argument('--workers', '-w', type=int, default=0, help='Number of workers')
|
||||
parser.add_argument('-cfg', '--config', type=Path, help='Parameters file. Save/Read: '
|
||||
'Video, Audio, Encoder, FFmpeg parameteres')
|
||||
|
|
18
utils/bar.py
18
utils/bar.py
|
@ -48,7 +48,8 @@ def tqdm_bar(i, encoder, counter, frame_probe_source, passes):
|
|||
pipe = subprocess.Popen(e, stdin=ffmpeg_pipe.stdout, stdout=PIPE,
|
||||
stderr=STDOUT,
|
||||
universal_newlines=True)
|
||||
|
||||
pass_1_check = True
|
||||
skip_1_pass = False
|
||||
while True:
|
||||
line = pipe.stdout.readline().strip()
|
||||
if line:
|
||||
|
@ -58,9 +59,9 @@ def tqdm_bar(i, encoder, counter, frame_probe_source, passes):
|
|||
|
||||
if len(line) == 0:
|
||||
continue
|
||||
|
||||
if encoder in ('aom', 'vpx', 'rav1e'):
|
||||
if encoder in ('aom', 'vpx', 'rav1e','x265'):
|
||||
match = None
|
||||
|
||||
if encoder in ('aom', 'vpx'):
|
||||
if 'fatal' in line.lower():
|
||||
print('\n\nERROR IN ENCODING PROCESS\n\n', line)
|
||||
|
@ -73,12 +74,23 @@ def tqdm_bar(i, encoder, counter, frame_probe_source, passes):
|
|||
terminate()
|
||||
match = re.search(r"encoded.*? ([^ ]+?) ", line)
|
||||
|
||||
elif encoder in ('x265'):
|
||||
if not skip_1_pass and pass_1_check:
|
||||
if 'output file' in line:
|
||||
if 'nul' in line.lower():
|
||||
skip_1_pass = True
|
||||
else:
|
||||
pass_1_check = False
|
||||
if not skip_1_pass:
|
||||
match = re.search(r"^(\d+)", line)
|
||||
|
||||
if match:
|
||||
new = int(match.group(1))
|
||||
if new > frame:
|
||||
counter.update(new - frame)
|
||||
frame = new
|
||||
|
||||
|
||||
if encoder == 'svt_av1':
|
||||
counter.update(frame_probe_source // passes)
|
||||
|
||||
|
|
|
@ -43,13 +43,10 @@ def get_default_params_for_encoder(enc):
|
|||
DEFAULT_ENC_PARAMS = {
|
||||
'vpx': '--codec=vp9 --threads=4 --cpu-used=0 --end-usage=q --cq-level=30',
|
||||
'aom': '--threads=4 --cpu-used=6 --end-usage=q --cq-level=30',
|
||||
'rav1e': ' --tiles 8 --speed 6 --quantizer 100'
|
||||
# SVT-AV1 requires params for -w -h -fps
|
||||
'rav1e': ' --tiles 8 --speed 6 --quantizer 100',
|
||||
'svt_av1': ' --preset 4 --rc 0 --qp 25 ',
|
||||
'x265': ' -p slow --crf 23 --vbv-maxrate 10000 --vbv-bufsize 8000 ',
|
||||
}
|
||||
# TODO(n9Mtq4): we can get the width, height, and fps of the video and generate default params for svt
|
||||
if enc == 'svt_av1':
|
||||
print('-w -h -fps is required parameters (--video_params) for svt_av1 encoder')
|
||||
terminate()
|
||||
|
||||
return DEFAULT_ENC_PARAMS[enc]
|
||||
|
||||
|
@ -66,9 +63,6 @@ def svt_av1_encode(inputs, passes, pipe, params):
|
|||
"""
|
||||
encoder = 'SvtAv1EncApp'
|
||||
commands = []
|
||||
if not params:
|
||||
print('-w -h -fps is required parameters for svt_av1 encoder')
|
||||
terminate()
|
||||
|
||||
if passes == 1:
|
||||
commands = [
|
||||
|
@ -124,7 +118,8 @@ def aom_vpx_encode(inputs, enc, passes, pipe, params):
|
|||
|
||||
def rav1e_encode(inputs, passes, pipe, params):
|
||||
"""
|
||||
Generates commands for AOM, VPX encoders
|
||||
Generates commands for Rav1e encoder
|
||||
Currently 2 pass rav1e piping doesn't work
|
||||
|
||||
:param inputs: Files that need to be enocoded
|
||||
:param passes: Encoding passes
|
||||
|
@ -153,7 +148,9 @@ def rav1e_encode(inputs, passes, pipe, params):
|
|||
f' rav1e - --first-pass {file[0].with_suffix(".stat")} {params} '
|
||||
f'--output {file[1].with_suffix(".ivf")}',
|
||||
f'-i {file[0]} {pipe} '
|
||||
f' rav1e - --second-pass {file[0].with_suffix(".stat")} {params} '
|
||||
f' rav1e - --second-pass {file[0].with_suffix(".stat")} {pa65 [info]: Residual QT: max TU size, max depth : 32 / 1 inter / 1 intra
|
||||
265
|
||||
rams} '
|
||||
f'--output {file[1].with_suffix(".ivf")}',
|
||||
(file[0], file[1].with_suffix('.ivf')))
|
||||
for file in inputs]
|
||||
|
@ -161,6 +158,38 @@ def rav1e_encode(inputs, passes, pipe, params):
|
|||
return commands
|
||||
|
||||
|
||||
def x265_encode(inputs, passes, pipe, params):
|
||||
"""
|
||||
Generates commands for AOM, VPX encoders
|
||||
|
||||
:param inputs: Files that need to be enocoded
|
||||
:param passes: Encoding passes
|
||||
:param pipe: FFmpeg piping settings
|
||||
:param params: Encoding parameters
|
||||
:return: Composed commands for execution
|
||||
"""
|
||||
commands = []
|
||||
single_p = 'x265 --y4m'
|
||||
two_p_1 = 'x265 --pass 1 --y4m'
|
||||
two_p_2 = 'x265 --pass 2 --y4m'
|
||||
|
||||
if passes == 1:
|
||||
commands = [
|
||||
(f' -i {file[0]} {pipe} {single_p} {params} - -o {file[1].with_suffix(".ivf")}',
|
||||
(file[0], file[1].with_suffix('.ivf')))
|
||||
for file in inputs
|
||||
]
|
||||
|
||||
if passes == 2:
|
||||
commands = [
|
||||
(f' -i {file[0]} {pipe} {two_p_1} {params} --stats {file[0].with_suffix(".log")} - -o {os.devnull}',
|
||||
f' -i {file[0]} {pipe} {two_p_2} {params} --stats {file[0].with_suffix(".log")} - -o {file[1].with_suffix(".ivf")}',
|
||||
(file[0], file[1].with_suffix('.ivf')))
|
||||
for file in inputs
|
||||
]
|
||||
|
||||
return commands
|
||||
|
||||
def compose_encoding_queue(files, temp, encoder, params, pipe, passes):
|
||||
"""
|
||||
Composing encoding queue with split videos.
|
||||
|
@ -174,7 +203,7 @@ def compose_encoding_queue(files, temp, encoder, params, pipe, passes):
|
|||
|
||||
assert params is not None # params needs to be set with at least get_default_params_for_encoder before this func
|
||||
|
||||
encoders = {'svt_av1': 'SvtAv1EncApp', 'rav1e': 'rav1e', 'aom': 'aomenc', 'vpx': 'vpxenc'}
|
||||
encoders = {'svt_av1': 'SvtAv1EncApp', 'rav1e': 'rav1e', 'aom': 'aomenc', 'vpx': 'vpxenc', 'x265': 'x265'}
|
||||
enc_exe = encoders.get(encoder)
|
||||
inputs = [(temp / "split" / file.name,
|
||||
temp / "encode" / file.name,
|
||||
|
@ -189,6 +218,9 @@ def compose_encoding_queue(files, temp, encoder, params, pipe, passes):
|
|||
elif encoder == 'svt_av1':
|
||||
queue = svt_av1_encode(inputs, passes, pipe, params)
|
||||
|
||||
elif encoder == 'x265':
|
||||
queue = x265_encode(inputs, passes, pipe, params)
|
||||
|
||||
# Catch Error
|
||||
if len(queue) == 0:
|
||||
er = 'Error in making command queue'
|
||||
|
|
|
@ -23,7 +23,7 @@ def determine_resources(encoder, workers):
|
|||
if encoder in ('aom', 'rav1e', 'vpx'):
|
||||
workers = round(min(cpu / 2, ram / 1.5))
|
||||
|
||||
elif encoder == 'svt_av1':
|
||||
elif encoder in ('svt_av1', 'x265'):
|
||||
workers = round(min(cpu, ram)) // 5
|
||||
|
||||
# fix if workers round up to 0
|
||||
|
@ -34,7 +34,7 @@ def determine_resources(encoder, workers):
|
|||
|
||||
|
||||
def check_executables(encoder):
|
||||
encoders = {'svt_av1': 'SvtAv1EncApp', 'rav1e': 'rav1e', 'aom': 'aomenc', 'vpx': 'vpxenc'}
|
||||
encoders = {'svt_av1': 'SvtAv1EncApp', 'rav1e': 'rav1e', 'aom': 'aomenc', 'vpx': 'vpxenc','x265': 'x265'}
|
||||
if not find_executable('ffmpeg'):
|
||||
print('No ffmpeg')
|
||||
terminate()
|
||||
|
@ -47,7 +47,7 @@ def check_executables(encoder):
|
|||
print(f'Encoder {enc} not found')
|
||||
terminate()
|
||||
else:
|
||||
print(f'Not valid encoder {encoder}\nValid encoders: "aom rav1e", "svt_av1", "vpx" ')
|
||||
print(f'Not valid encoder {encoder}\nValid encoders: "aom rav1e", "svt_av1", "vpx", "x265" ')
|
||||
terminate()
|
||||
|
||||
|
||||
|
@ -62,8 +62,13 @@ def setup(temp: Path, resume):
|
|||
(temp / 'encode').mkdir(exist_ok=True)
|
||||
|
||||
|
||||
def outputs_filenames(inp: Path, out:Path):
|
||||
if out:
|
||||
return out.with_suffix('.mkv')
|
||||
def outputs_filenames(inp: Path, out:Path, encoder):
|
||||
if encoder == 'x265':
|
||||
suffix = '.mp4'
|
||||
else:
|
||||
return Path(f'{inp.stem}_av1.mkv')
|
||||
suffix = '.mkv'
|
||||
|
||||
if out:
|
||||
return out.with_suffix(suffix)
|
||||
else:
|
||||
return Path(f'{inp.stem}_av1{suffix}')
|
||||
|
|
Loading…
Reference in a new issue