diff --git a/scripts/deforum_helpers/run_deforum.py b/scripts/deforum_helpers/run_deforum.py index 86c70b827..47335b9e5 100644 --- a/scripts/deforum_helpers/run_deforum.py +++ b/scripts/deforum_helpers/run_deforum.py @@ -27,7 +27,7 @@ from .frame_interpolation import process_video_interpolation from .general_utils import get_deforum_version from .upscaling import make_upscale_v2 -from .video_audio_utilities import ffmpeg_stitch_video, make_gifski_gif, handle_imgs_deletion, handle_input_frames_deletion, handle_cn_frames_deletion, get_ffmpeg_params, get_ffmpeg_paths +from .video_audio_utilities import ffmpeg_stitch_video, make_gifski_gif, make_gifski_gif_from_interpolated, handle_imgs_deletion, handle_input_frames_deletion, handle_cn_frames_deletion, get_ffmpeg_params, get_ffmpeg_paths from pathlib import Path from .settings import save_settings_from_animation_run from .deforum_controlnet import num_of_models @@ -164,10 +164,8 @@ def run_deforum(*args): else: print(f"** FFMPEG DID NOT STITCH ANY VIDEO ** Error: {e}") pass - - if video_args.make_gif and not video_args.skip_video_creation and not video_args.store_frames_in_ram: - make_gifski_gif(imgs_raw_path = args.outdir, imgs_batch_id = root.timestring, fps = video_args.fps, models_folder = root.models_path, current_user_os = root.current_user_os) - + + # Upscale video once generation is done: if video_args.r_upscale_video and not video_args.skip_video_creation and not video_args.store_frames_in_ram: # out mp4 path is defined in make_upscale func @@ -193,6 +191,12 @@ def run_deforum(*args): print(f"Moving upscaled, interpolated vid from {ouput_vid_path} to {ouput_vid_path_final}") shutil.move(ouput_vid_path, ouput_vid_path_final) + if video_args.make_gif and not video_args.skip_video_creation and not video_args.store_frames_in_ram: + if video_args.frame_interpolation_engine != "None": + make_gifski_gif_from_interpolated(imgs_raw_path = args.outdir, imgs_batch_id = root.timestring, fps = video_args.fps, models_folder = root.models_path, current_user_os = root.current_user_os) + else: + make_gifski_gif(imgs_raw_path = args.outdir, imgs_batch_id = root.timestring, fps = video_args.fps, models_folder = root.models_path, current_user_os = root.current_user_os) + if video_args.delete_imgs and not video_args.skip_video_creation: handle_imgs_deletion(vid_path=mp4_path, imgs_folder_path=args.outdir, batch_id=root.timestring) diff --git a/scripts/deforum_helpers/video_audio_utilities.py b/scripts/deforum_helpers/video_audio_utilities.py index 8ed25f34f..a3dea02a2 100644 --- a/scripts/deforum_helpers/video_audio_utilities.py +++ b/scripts/deforum_helpers/video_audio_utilities.py @@ -411,7 +411,49 @@ def make_gifski_gif(imgs_raw_path, imgs_batch_id, fps, models_folder, current_us print("\r" + " " * len(msg_to_print), end="", flush=True) print(f"\r{msg_to_print}", flush=True) print(f"GIF stitching *failed* with error:\n{e}") + +def find_interpolated_folder(directory): + """Return the first child folder starting with 'interpolated_' or None if not found.""" + for entry in os.listdir(directory): + full_path = os.path.join(directory, entry) + if os.path.isdir(full_path) and entry.startswith('interpolated_'): + return full_path + return None + +def make_gifski_gif_from_interpolated(imgs_raw_path, imgs_batch_id, fps, models_folder, current_user_os): + msg_to_print = f"Stitching *gif* from frames using Gifski..." + # blink the msg in the cli until action is done + console.print(msg_to_print, style="blink yellow", end="") + start_time = time.time() + gifski_location = os.path.join(models_folder, 'gifski' + ('.exe' if current_user_os == 'Windows' else '')) + final_gif_path = os.path.join(imgs_raw_path, imgs_batch_id + '.gif') + + interpolated_folder = find_interpolated_folder(imgs_raw_path) + if current_user_os == "Linux": + input_img_pattern = '*.png' + input_img_files = [os.path.join(interpolated_folder, file) for file in sorted(glob.glob(os.path.join(interpolated_folder, input_img_pattern)))] + cmd = [gifski_location, '-o', final_gif_path] + input_img_files + ['--fps', str(fps), '--quality', str(95)] + elif current_user_os == "Windows": + input_img_pattern = '*.png' + input_img_pattern_for_gifski = os.path.join(interpolated_folder, input_img_pattern) + cmd = [gifski_location, '-o', final_gif_path, input_img_pattern_for_gifski, '--fps', str(fps), '--quality', str(95)] + else: # should never this else as we check before, but just in case + print("\r" + " " * len(msg_to_print), end="", flush=True) + print(f"\r{msg_to_print}", flush=True) + raise Exception(f"No support for OS type: {current_user_os}") + check_and_download_gifski(models_folder, current_user_os) + + try: + process = subprocess.run(cmd, capture_output=True, check=True, text=True, cwd=(models_folder if current_user_os == 'Mac' else None)) + print("\r" + " " * len(msg_to_print), end="", flush=True) + print(f"\r{msg_to_print}", flush=True) + print(f"GIF stitching \033[0;32mdone\033[0m in {time.time() - start_time:.2f} seconds!") + except Exception as e: + print("\r" + " " * len(msg_to_print), end="", flush=True) + print(f"\r{msg_to_print}", flush=True) + print(f"GIF stitching *failed* with error:\n{e}") + def handle_imgs_deletion(vid_path=None, imgs_folder_path=None, batch_id=None): try: total_imgs_to_delete = count_matching_frames(imgs_folder_path, batch_id)