|
import os |
|
import re |
|
import subprocess |
|
import glob |
|
import shutil |
|
import time |
|
import cv2 |
|
import numpy as np |
|
|
|
|
|
def clamp(n, smallest, largest): |
|
return sorted([smallest, n, largest])[1] |
|
|
|
|
|
def create_movie_from_frames( dir, start, end, number_of_digits, fps, output_path, export_type): |
|
def get_export_str(export_type): |
|
if export_type == "mp4": |
|
return " -vcodec libx264 -pix_fmt yuv420p " |
|
elif export_type == "webm": |
|
|
|
return " -crf 40 -b:v 0 -threads 4 " |
|
elif export_type == "gif": |
|
return " " |
|
elif export_type == "rawvideo": |
|
return " -vcodec rawvideo -pix_fmt bgr24 " |
|
|
|
vframes = end - start + 1 |
|
path = os.path.join(dir , '%0' + str(number_of_digits) + 'd.png') |
|
|
|
|
|
subprocess.call("ffmpeg -framerate " + str(fps) + " -r " + str(fps) + |
|
" -start_number " + str(start) + |
|
" -i " + path + |
|
" -vframes " + str( vframes ) + |
|
get_export_str(export_type) + |
|
output_path, shell=True) |
|
|
|
|
|
def search_out_dirs(proj_dir, blend_rate): |
|
|
|
p = re.compile(r'.*[\\\/]out\-([0-9]+)[\\\/]') |
|
|
|
number_of_digits = -1 |
|
|
|
out_dirs=[] |
|
for d in glob.glob( os.path.join(proj_dir ,"out-*/"), recursive=False): |
|
m = p.fullmatch(d) |
|
if m: |
|
if number_of_digits == -1: |
|
number_of_digits = len(m.group(1)) |
|
out_dirs.append({ 'keyframe':int(m.group(1)), 'path':d }) |
|
|
|
out_dirs = sorted(out_dirs, key=lambda x: x['keyframe'], reverse=True) |
|
|
|
print(number_of_digits) |
|
|
|
prev_key = -1 |
|
for out_d in out_dirs: |
|
out_d['next_keyframe'] = prev_key |
|
prev_key = out_d['keyframe'] |
|
|
|
out_dirs = sorted(out_dirs, key=lambda x: x['keyframe']) |
|
|
|
|
|
|
|
prev_key = 0 |
|
for out_d in out_dirs: |
|
imgs = sorted(glob.glob( os.path.join( out_d['path'], '[0-9]'*number_of_digits + '.png') )) |
|
|
|
first_img = imgs[0] |
|
print(first_img) |
|
basename_without_ext = os.path.splitext(os.path.basename(first_img))[0] |
|
blend_timing = (prev_key - out_d['keyframe'])*blend_rate + out_d['keyframe'] |
|
blend_timing = round(blend_timing) |
|
start_frame = max( blend_timing, int(basename_without_ext) ) |
|
out_d['startframe'] = start_frame |
|
|
|
last_img = imgs[-1] |
|
print(last_img) |
|
basename_without_ext = os.path.splitext(os.path.basename(last_img))[0] |
|
end_frame = min( out_d['next_keyframe'], int(basename_without_ext) ) |
|
if end_frame == -1: |
|
end_frame = int(basename_without_ext) |
|
out_d['endframe'] = end_frame |
|
prev_key = out_d['keyframe'] |
|
|
|
return number_of_digits, out_dirs |
|
|
|
def get_ext(export_type): |
|
if export_type in ("mp4","webm","gif"): |
|
return "." + export_type |
|
else: |
|
return ".avi" |
|
|
|
def trying_to_add_audio(original_movie_path, no_snd_movie_path, output_path, tmp_dir ): |
|
if os.path.isfile(original_movie_path): |
|
sound_path = os.path.join(tmp_dir , 'sound.mp4') |
|
subprocess.call("ffmpeg -i " + original_movie_path + " -vn -acodec copy " + sound_path, shell=True) |
|
|
|
if os.path.isfile(sound_path): |
|
|
|
|
|
subprocess.call("ffmpeg -i " + no_snd_movie_path + " -i " + sound_path + " -c:v copy -c:a aac -map 0:v:0 -map 1:a:0 " + output_path, shell=True) |
|
return True |
|
|
|
return False |
|
|
|
def ebsynth_utility_stage7(dbg, project_args, blend_rate,export_type,is_invert_mask): |
|
dbg.print("stage7") |
|
dbg.print("") |
|
|
|
project_dir, original_movie_path, _, _, _, _, _ = project_args |
|
|
|
fps = 30 |
|
clip = cv2.VideoCapture(original_movie_path) |
|
if clip: |
|
fps = clip.get(cv2.CAP_PROP_FPS) |
|
clip.release() |
|
|
|
blend_rate = clamp(blend_rate, 0.0, 1.0) |
|
|
|
dbg.print("blend_rate: {}".format(blend_rate)) |
|
dbg.print("export_type: {}".format(export_type)) |
|
dbg.print("fps: {}".format(fps)) |
|
|
|
if is_invert_mask: |
|
project_dir = os.path.join( project_dir , "inv") |
|
|
|
tmp_dir = os.path.join( project_dir , "crossfade_tmp") |
|
|
|
|
|
if os.path.isdir(tmp_dir): |
|
shutil.rmtree(tmp_dir) |
|
os.mkdir(tmp_dir) |
|
|
|
number_of_digits, out_dirs = search_out_dirs( project_dir, blend_rate ) |
|
|
|
if number_of_digits == -1: |
|
dbg.print('no out dir') |
|
return |
|
|
|
|
|
|
|
start = out_dirs[0]['startframe'] |
|
end = out_dirs[-1]['endframe'] |
|
|
|
cur_clip = 0 |
|
next_clip = cur_clip+1 if len(out_dirs) > cur_clip+1 else -1 |
|
|
|
current_frame = 0 |
|
|
|
print(str(start) + " -> " + str(end+1)) |
|
|
|
black_img = np.zeros_like( cv2.imread( os.path.join(out_dirs[cur_clip]['path'], str(start).zfill(number_of_digits) + ".png") ) ) |
|
|
|
for i in range(start, end+1): |
|
|
|
print(str(i) + " / " + str(end)) |
|
|
|
if next_clip == -1: |
|
break |
|
|
|
if i in range( out_dirs[cur_clip]['startframe'], out_dirs[cur_clip]['endframe'] +1): |
|
pass |
|
elif i in range( out_dirs[next_clip]['startframe'], out_dirs[next_clip]['endframe'] +1): |
|
cur_clip = next_clip |
|
next_clip = cur_clip+1 if len(out_dirs) > cur_clip+1 else -1 |
|
if next_clip == -1: |
|
break |
|
else: |
|
|
|
|
|
|
|
cv2.imwrite( os.path.join(tmp_dir, filename) , black_img) |
|
current_frame = i |
|
continue |
|
|
|
filename = str(i).zfill(number_of_digits) + ".png" |
|
|
|
|
|
|
|
|
|
if i in range( out_dirs[next_clip]['startframe'], out_dirs[next_clip]['endframe'] +1): |
|
|
|
|
|
img_f = cv2.imread( os.path.join(out_dirs[cur_clip]['path'] , filename) ) |
|
img_b = cv2.imread( os.path.join(out_dirs[next_clip]['path'] , filename) ) |
|
|
|
back_rate = (i - out_dirs[next_clip]['startframe'])/ max( 1 , (out_dirs[cur_clip]['endframe'] - out_dirs[next_clip]['startframe']) ) |
|
|
|
img = cv2.addWeighted(img_f, 1.0 - back_rate, img_b, back_rate, 0) |
|
|
|
cv2.imwrite( os.path.join(tmp_dir , filename) , img) |
|
else: |
|
|
|
|
|
filename = str(i).zfill(number_of_digits) + ".png" |
|
shutil.copy( os.path.join(out_dirs[cur_clip]['path'] , filename) , os.path.join(tmp_dir , filename) ) |
|
|
|
current_frame = i |
|
|
|
|
|
start2 = current_frame+1 |
|
|
|
print(str(start2) + " -> " + str(end+1)) |
|
|
|
for i in range(start2, end+1): |
|
filename = str(i).zfill(number_of_digits) + ".png" |
|
shutil.copy( os.path.join(out_dirs[cur_clip]['path'] , filename) , os.path.join(tmp_dir , filename) ) |
|
|
|
|
|
movie_base_name = time.strftime("%Y%m%d-%H%M%S") |
|
if is_invert_mask: |
|
movie_base_name = "inv_" + movie_base_name |
|
|
|
nosnd_path = os.path.join(project_dir , movie_base_name + get_ext(export_type)) |
|
|
|
start = out_dirs[0]['startframe'] |
|
end = out_dirs[-1]['endframe'] |
|
|
|
create_movie_from_frames( tmp_dir, start, end, number_of_digits, fps, nosnd_path, export_type) |
|
|
|
dbg.print("exported : " + nosnd_path) |
|
|
|
if export_type == "mp4": |
|
|
|
with_snd_path = os.path.join(project_dir , movie_base_name + '_with_snd.mp4') |
|
|
|
if trying_to_add_audio(original_movie_path, nosnd_path, with_snd_path, tmp_dir): |
|
dbg.print("exported : " + with_snd_path) |
|
|
|
dbg.print("") |
|
dbg.print("completed.") |
|
|
|
|