Created
January 9, 2020 15:19
-
-
Save 505e06b2/b18eb00de7ab940aa15dcab3943a6a1f to your computer and use it in GitHub Desktop.
FFMPEG Webm Encoder - With Progress
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import subprocess, sys, multiprocessing, json, os, shlex, re | |
from datetime import timedelta | |
error_messages = { | |
"param_len": """Not enough parameters | |
Format: %s [input_file] (optional)[parameters] [movie_title] | |
""" | |
} | |
output_display = "-hide_banner -loglevel error" | |
default_params = " ".join([ | |
"-c:v libvpx -vf %sscale=w=1280:h=720:force_original_aspect_ratio=decrease -b:v %s -crf 10", | |
'-c:a libopus -ac 2',#-af "pan=stereo|FL=0.5*FC+0.707*FL+0.707*BL+0.5*LFE|FR=0.5*FC+0.707*FR+0.707*BR+0.5*LFE"', | |
"-map_metadata -1 -metadata title=\"%s\" -threads %d -y -progress -" | |
]) | |
def parseParams(params): | |
parsed = shlex.split(params) | |
vf_param = "" | |
bitrate = "1M" | |
try: | |
param_contents = parsed.index("-vf")+1 | |
vf_param = parsed[param_contents] + "," | |
except ValueError: | |
pass | |
try: | |
param_contents = parsed.index("-b:v")+1 | |
bitrate = parsed[param_contents] | |
except ValueError: | |
pass | |
return vf_param, bitrate | |
def videoFilesize(filename): | |
if not os.path.isfile(filename): | |
return 0 | |
return os.path.getsize(filename)/1024 #to kb | |
def videoLength(filename): | |
if not os.path.isfile(filename): | |
return 0.0 | |
result = subprocess.run( | |
shlex.split('ffprobe %s -show_entries format=duration -print_format json "%s"' % ( | |
output_display, | |
filename | |
)), | |
stdout = subprocess.PIPE | |
) | |
return int(json.loads(result.stdout.decode("utf-8"))["format"]["duration"].replace(".", "")) | |
def encode(file_in, movie_title, params = ""): | |
vf_filters, v_bitrate = parseParams(params) | |
p = subprocess.Popen( | |
shlex.split('ffmpeg %s -i "%s" %s %s "%s.webm"' % ( | |
output_display, | |
file_in, | |
params, #get overwritten by defaults | |
default_params % (vf_filters, v_bitrate, movie_title, multiprocessing.cpu_count()), | |
movie_title.lower().replace(" ", "_") | |
)), | |
stdout = subprocess.PIPE | |
) | |
ffmpeg_output = {} | |
video_length = videoLength(file_in) | |
video_filesize = videoFilesize(file_in) | |
if video_length <= 0 or video_filesize <= 0: | |
print("Input file not found!") | |
return | |
print("Encoding...\nPress [q] to exit") | |
for line in iter(p.stdout.readline, b""): | |
l = line.decode("utf-8").rstrip().split("=") | |
if l[0] != "progress": | |
if l[0] == "out_time_ms" or l[0] == "total_size": #if not structured like this, the next if will fail | |
ffmpeg_output[l[0]] = int(l[1]) | |
elif l[0] == "speed" and l[1] != "N/A": | |
ffmpeg_output[l[0]] = float(l[1][:-1]) | |
elif ffmpeg_output["out_time_ms"] > 0: | |
percent = ffmpeg_output["out_time_ms"] / float(video_length) | |
filesize = (ffmpeg_output["total_size"] / percent) / 1024 #to kb | |
print("\rEst. Remaining Time: %s | Est. Filesize: %s | %6.2f%% " % ( #format example: " 2.44%" | |
':'.join(str(timedelta(microseconds=( #only want the (days), hours, mins | |
int((video_length - ffmpeg_output["out_time_ms"]) / ffmpeg_output["speed"]) | |
))).split(":")[:2]), | |
("%7dK" if filesize < video_filesize else "!!%7dK!!") % (filesize), #alert if larger than original video | |
percent * 100 | |
), end = "") | |
p.wait() #ensure stdout isn't stolen | |
print() #just have a newline | |
if __name__ == "__main__": | |
if len(sys.argv) < 3: | |
sys.stderr.write( error_messages["param_len"] % (sys.argv[0]) ) | |
sys.exit(1) | |
sys.argv.pop(0) | |
i = sys.argv.pop(0) | |
o = sys.argv.pop(-1) | |
encode(i, o, " ".join(sys.argv)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment