Last active
March 11, 2020 16:23
-
-
Save Chaparro/7f8b0b9bfaf38dae469e635f51a69a9e to your computer and use it in GitHub Desktop.
This file contains 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
#all rights, credits and congratulations go to Bazoo from the project slippi discord | |
import re | |
import time | |
import ffmpeg | |
import subprocess | |
in_name = '1x.mp4' | |
out_name = 'out.mp4' | |
def get_black_frames(): | |
# cmd = f'ffmpeg -i {in_name} -vf blackdetect=d=0:pic_th=.98 -f null -' | |
# cmd = f'ffmpeg -i {in_name} -vf blackdetect=d=0.016667:pix_th=.0001 -f null -' | |
# cmd = f'ffmpeg -i {in_name} -vf blackdetect=d=0.000001:pix_th=.0001 -f null -' | |
cmd = f'ffmpeg -hwaccel nvdec -i {in_name} -vf blackdetect=d=0.000001:pix_th=.0001 -f null -' | |
regex = r'\[blackdetect @ .+] black_start:(.+) black_end:(.+) ' | |
return get_info(cmd, regex, 'err') | |
# def get_duration(): | |
# cmd = f'ffmpeg -i {in_name} -f null -' | |
# regex = r'Duration: (\d{2}):(\d{2}):(\d{2})\.(\d{2}), start' | |
# return get_info(cmd, regex)[0] | |
def get_duration(): | |
cmd = f'ffprobe -i {in_name} -show_entries format=duration' | |
regex = r'duration=(.*)' | |
return get_info(cmd, regex)[0] | |
def get_info(cmd, regex, type='out'): | |
pr = None | |
txt = None | |
if (type == 'out'): | |
pr = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE) | |
txt = pr.communicate()[0] | |
elif (type == 'err'): | |
pr = subprocess.Popen(cmd.split(), stderr=subprocess.PIPE) | |
txt = pr.communicate()[1] | |
else: | |
return | |
return re.findall(regex, txt.decode('utf-8').replace('\r', '')) | |
def trim_black_frames_ffmpeg(): | |
black_frames = get_black_frames() | |
if (len(black_frames) == 0): | |
return | |
in_file = ffmpeg.input(in_name) | |
for frames in black_frames: | |
in_file = ffmpeg.trim(in_file, start_pts=frames[0], end_pts=frames[1]) | |
in_file = ffmpeg.output(in_file, out_name) | |
subprocess.run(['ffmpeg', *ffmpeg.get_args(in_file, overwrite_output=True)]) | |
# in_file = ffmpeg.run(in_file, overwrite_output=True) | |
def trim_black_frames(): | |
black_frames = get_black_frames() | |
if (len(black_frames) == 0): | |
return | |
cmd1 = f'ffmpeg -hwaccel nvdec -i {in_name} -y -vf select=\'not(' | |
cmd2 = ')\',setpts=N/FRAME_RATE/TB -af aselect=\'not(' | |
cmd3 = ')\',asetpts=N/SR/TB -c:v libx264 -crf 15 -preset veryslow ' | |
# cmd3 = ')\',asetpts=N/SR/TB -c:v h264_nvenc -tier high -preset slow -profile:v high -rc cbr_hq -cbr 1 -2pass 1 ' | |
trims = '' | |
count = 0 | |
for frames in black_frames: | |
if count > 0: | |
trims += '+' | |
trims += f'between(t,{frames[0]},{frames[1]})' | |
count += 1 | |
cmd = cmd1 + trims + cmd2 + trims + cmd3 + out_name | |
print(cmd) | |
subprocess.run(cmd.split()) | |
def cut(ifile, ofile, start='00:00.000000', end=None): | |
# -ss before -i is apparently faster, but less precise. | |
# try using -t instead of -to? requieres black_duration regex group capture | |
if (end is None): | |
# return f'ffmpeg -ss {start} -i {ifile} -y -c copy {ofile}' | |
return f'ffmpeg -ss {start} -i {ifile} -y -c copy -avoid_negative_ts 1 {ofile}' | |
else: | |
# return f'ffmpeg -ss {start} -to {end} -i {ifile} -y -c copy {ofile}' | |
return f'ffmpeg -ss {start} -i {ifile} -to {end} -y -c copy -avoid_negative_ts 1 {ofile}' | |
def duration_to_seconds(duration): | |
pass | |
def trim_parts(): | |
black_frames = get_black_frames() | |
duration = get_duration() | |
length = len(black_frames) | |
ends_with_black_frame = False | |
if (length > 0): | |
ends_with_black_frame = 0.017 > float(duration) - float(black_frames[length - 1][1]) | |
print(f'\n\n\n\n{(float(duration) - float(black_frames[length - 1][1]))}\n\n\n') | |
# print(black_frames, duration) | |
cmd = '' | |
if (length == 0): | |
return | |
elif (length == 1): | |
frames = black_frames[0] | |
if (frames[0] == '0'): | |
cmd = cut(in_name, out_name, frames[1]) | |
subprocess.run(cmd.split()) | |
elif (ends_with_black_frame): # TODO: adjust precision | |
# print('ends with black frame') | |
cmd = cut(in_name, out_name, frames[1], duration) | |
subprocess.run(cmd.split()) | |
else: | |
cmd = cut(in_name, f'parts/part_0_{out_name}', end=frames[0]) | |
subprocess.run(cmd.split()) | |
cmd = cut(in_name, f'parts/part_1_{out_name}', frames[1], duration) | |
subprocess.run(cmd.split()) | |
write_parts(f'file \'part_0_{out_name}\'\nfile \'part_1_{out_name}\'') | |
subprocess.run(f'ffmpeg -f concat -i parts/parts.txt -y -c copy {out_name}'.split()) | |
# TODO: Cut black frames for each black_frames | |
else: | |
print(black_frames) | |
i = 0 | |
text = '' | |
for frames in black_frames: | |
cmd = '' | |
name = f'part_{i}_{out_name}' | |
pname = f'parts/{name}' | |
if (frames[0] == '0' and length > 1): | |
print('\n\n\n\n\n\n first frame is bf\n\n\n\n') | |
cmd = cut(in_name, pname, hack(frames[1]), black_frames[i + 1][0]) | |
print(frames[1], black_frames[i + 1][0]) | |
elif (i == length - 1 and ends_with_black_frame): | |
print('\n\n\n\n\nends with bf\n\n\n\n') | |
cmd = cut(in_name, pname, hack(black_frames[i - 1][1])) | |
else: | |
print( | |
f'\n\n\n\n\n inbetween {black_frames[i - 1]}, {frames}\n\n\n\n') | |
cmd = cut(in_name, pname, hack(black_frames[i - 1][1]), frames[0]) | |
subprocess.run(cmd.split()) | |
text += f'file \'{name}\'\n' | |
i += 1 | |
write_parts(text) | |
cmd = f'ffmpeg -f concat -i parts/parts.txt -y -c copy {out_name}' | |
( | |
ffmpeg | |
.input(out_name) | |
.concat() | |
) | |
subprocess.run(cmd.split()) | |
def write_parts(text): | |
with open('parts/parts.txt', 'w') as file: | |
file.write(text) | |
def hack(seconds): | |
return seconds | |
fseconds = float(seconds) | |
# return str(round(fseconds + 0.01697999999999933, 6)) | |
return str(round(fseconds + 0.016667, 6)) | |
# return str(fseconds - 0.017) | |
# trim_parts() | |
trim_black_frames() | |
# trim_black_frames_ffmpeg() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment