Av1an/main.py

145 lines
4.5 KiB
Python
Raw Normal View History

2020-01-08 00:39:49 +00:00
#!/usr/bin/python3
"""
mkvmerge required (python-pymkv)
2020-01-08 01:36:20 +00:00
ffmpeg required
TODO:
2020-01-08 22:43:20 +00:00
DONE make encoding queue with limiting by workers
DONE make concatenating videos after encoding
2020-01-09 14:54:01 +00:00
DONE make passing your arguments for encoding,
2020-01-08 01:52:57 +00:00
make separate audio and encode it separately,
2020-01-08 00:39:49 +00:00
"""
2020-01-08 00:20:18 +00:00
import os
import subprocess
2020-01-09 14:54:01 +00:00
import argparse
2020-01-09 15:50:26 +00:00
import time
2020-01-09 16:25:27 +00:00
import shutil
2020-01-09 18:01:40 +00:00
import pathlib
2020-01-08 20:44:44 +00:00
from multiprocessing import Pool
2020-01-08 18:56:47 +00:00
try:
import scenedetect
except:
print('ERROR: No PyScenedetect installed, try: sudo pip install scenedetect')
2020-01-08 00:20:18 +00:00
2020-01-09 15:49:28 +00:00
def arg_parsing():
"""
Command line parser
"""
parser = argparse.ArgumentParser()
parser.add_argument('--encoding_params', type=str,
default=' -an -c:v libaom-av1 -strict -2 -row-mt 1 -tiles 2x2 -cpu-used 8 -crf 60 ',
help='FFmpeg settings')
parser.add_argument('--input_file', '-i', type=str, default='bruh.mp4', help='input video file')
parser.add_argument('--num_worker', '-t', type=int, default=8, help='number of encode running at a time')
return parser.parse_args()
2020-01-08 00:20:18 +00:00
def get_cpu_count():
return os.cpu_count()
def get_ram():
return round((os.sysconf('SC_PAGE_SIZE') * os.sysconf('SC_PHYS_PAGES')) / (1024. ** 3), 3)
2020-01-08 22:43:20 +00:00
def extract_audio(input_vid):
2020-01-09 15:50:26 +00:00
"""
Extracting audio from video file
"""
cmd = f'ffmpeg -i {os.getcwd()}/{input_vid} -vn -acodec libopus {os.getcwd()}/temp/audio.opus'
subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).wait()
2020-01-08 22:43:20 +00:00
2020-01-08 00:39:49 +00:00
def split_video(input_vid):
2020-01-08 21:16:53 +00:00
cmd2 = f'scenedetect -i {input_vid} --output temp/split detect-content split-video -c'
2020-01-08 00:39:49 +00:00
subprocess.call(cmd2, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
2020-01-09 15:52:11 +00:00
print(f'Video {input_vid} splitted')
2020-01-08 00:20:18 +00:00
2020-01-08 18:56:47 +00:00
def get_video_queue(source_path):
videos = []
for root, dirs, files in os.walk(source_path):
for file in files:
f = os.path.getsize(os.path.join(root, file))
videos.append([file, f])
videos = sorted(videos, key=lambda x: -x[1])
return videos
2020-01-08 20:44:44 +00:00
def encode(commands):
2020-01-09 15:33:47 +00:00
"""
Passing encoding params to ffmpeg for encoding
TODO:
Replace ffmpeg with aomenc because ffmpeg libaom doen't work with parameters properly
"""
2020-01-08 20:44:44 +00:00
cmd = f'ffmpeg {commands}'
2020-01-09 15:52:11 +00:00
print('Started encode process...')
2020-01-08 22:43:20 +00:00
subprocess.Popen(cmd, shell=True).wait()
2020-01-09 15:52:11 +00:00
print('Finished encode process')
2020-01-08 22:43:20 +00:00
def concat():
"""
Using FFMPEG to concatenate all encoded videos to 1 file.
Reading all files in A-Z order and saving it to concat.txt
"""
with open(f'{os.getcwd()}/temp/concat.txt', 'w') as f:
2020-01-08 20:44:44 +00:00
2020-01-08 23:15:17 +00:00
for root, firs, files in os.walk(f'{os.getcwd()}/temp/encode'):
2020-01-08 22:43:20 +00:00
for file in sorted(files):
f.write(f"file '{os.path.join(root, file)}'\n")
2020-01-08 20:44:44 +00:00
cmd = f'ffmpeg -f concat -safe 0 -i {os.getcwd()}/temp/concat.txt -i {os.getcwd()}/temp/audio.opus -c copy output.webm'
2020-01-08 22:43:20 +00:00
subprocess.Popen(cmd, shell=True).wait()
2020-01-09 15:52:11 +00:00
print('File finished')
2020-01-08 21:27:21 +00:00
2020-01-09 14:54:01 +00:00
def main(input_video, encoding_params, num_worker):
2020-01-08 21:27:21 +00:00
2020-01-09 17:44:36 +00:00
# Make temporal directories, and remove them if already presented
if os.path.isdir(f'{os.getcwd()}/temp/'):
shutil.rmtree(f'{os.getcwd()}/temp')
os.makedirs(f'{os.getcwd()}/temp/split')
os.makedirs(f'{os.getcwd()}/temp/encode')
2020-01-08 21:27:21 +00:00
# Extracting audio
extract_audio(input_video)
2020-01-08 21:27:21 +00:00
# Spliting video and sorting big-first
2020-01-08 20:44:44 +00:00
split_video(input_video)
vid_queue = get_video_queue('temp')
files = [i[0] for i in vid_queue[:-1]]
2020-01-08 21:27:21 +00:00
# Making list of commands for encoding
2020-01-08 23:15:17 +00:00
commands = [f'-i {os.getcwd()}/temp/split/{file} {encoding_params} {os.getcwd()}/temp/encode/{file}' for file in files]
2020-01-08 21:27:21 +00:00
# Creating threading pool to encode fixed amount of files at the same time
2020-01-09 14:54:01 +00:00
pool = Pool(num_worker)
2020-01-08 20:44:44 +00:00
pool.map(encode, commands)
2020-01-08 22:43:20 +00:00
# Merging all encoded videos to 1
concat()
2020-01-08 20:44:44 +00:00
2020-01-08 23:36:39 +00:00
2020-01-08 20:44:44 +00:00
if __name__ == '__main__':
2020-01-09 15:33:47 +00:00
# Command line parser
2020-01-09 14:54:01 +00:00
parser = argparse.ArgumentParser()
parser.add_argument('--encoding_params', type=str, default=' -an -c:v libaom-av1 -strict -2 -row-mt 1 -tiles 2x2 -cpu-used 8 -crf 60 ', help='FFmpeg settings')
parser.add_argument('--input_file', '-i', type=str, default='bruh.mp4', help='input video file')
2020-01-09 14:58:05 +00:00
parser.add_argument('--num_worker', '-t', type=int, default=8, help='number of encode running at a time')
2020-01-09 15:49:28 +00:00
args = arg_parsing()
2020-01-09 15:33:47 +00:00
# Main thread
2020-01-09 15:49:28 +00:00
start = time.time()
main(args.input_file, args.encoding_params, args.num_worker)
print(f'Encoding completed in {round(time.time()-start)}ces')
2020-01-09 16:25:27 +00:00
# Delete temp folders
shutil.rmtree(f'{os.getcwd()}/temp')