import os import subprocess import roop.globals import roop.utilities as util from typing import List, Any def run_ffmpeg(args: List[str]) -> bool: commands = [ "ffmpeg", "-hide_banner", "-hwaccel", "auto", "-y", "-loglevel", roop.globals.log_level, ] commands.extend(args) print("Running ffmpeg") try: subprocess.check_output(commands, stderr=subprocess.STDOUT) return True except Exception as e: print("Running ffmpeg failed! Commandline:") print(" ".join(commands)) return False def cut_video( original_video: str, cut_video: str, start_frame: int, end_frame: int, reencode: bool, ): fps = util.detect_fps(original_video) start_time = start_frame / fps num_frames = end_frame - start_frame if reencode: run_ffmpeg( [ "-ss", format(start_time, ".2f"), "-i", original_video, "-c:v", roop.globals.video_encoder, "-c:a", "aac", "-frames:v", str(num_frames), cut_video, ] ) else: run_ffmpeg( [ "-ss", format(start_time, ".2f"), "-i", original_video, "-frames:v", str(num_frames), "-c:v", "copy", "-c:a", "copy", cut_video, ] ) def join_videos(videos: List[str], dest_filename: str, simple: bool): if simple: txtfilename = util.resolve_relative_path("../temp") txtfilename = os.path.join(txtfilename, "joinvids.txt") with open(txtfilename, "w", encoding="utf-8") as f: for v in videos: v = v.replace("\\", "/") f.write(f"file {v}\n") commands = [ "-f", "concat", "-safe", "0", "-i", f"{txtfilename}", "-vcodec", "copy", f"{dest_filename}", ] run_ffmpeg(commands) else: inputs = [] filter = "" for i, v in enumerate(videos): inputs.append("-i") inputs.append(v) filter += f"[{i}:v:0][{i}:a:0]" run_ffmpeg( [ " ".join(inputs), "-filter_complex", f'"{filter}concat=n={len(videos)}:v=1:a=1[outv][outa]"', "-map", '"[outv]"', "-map", '"[outa]"', dest_filename, ] ) # filter += f'[{i}:v:0][{i}:a:0]' # run_ffmpeg([" ".join(inputs), '-filter_complex', f'"{filter}concat=n={len(videos)}:v=1:a=1[outv][outa]"', '-map', '"[outv]"', '-map', '"[outa]"', dest_filename]) def extract_frames( target_path: str, trim_frame_start, trim_frame_end, fps: float ) -> bool: util.create_temp(target_path) temp_directory_path = util.get_temp_directory_path(target_path) commands = [ "-i", target_path, "-q:v", "1", "-pix_fmt", "rgb24", ] if trim_frame_start is not None and trim_frame_end is not None: commands.extend( [ "-vf", "trim=start_frame=" + str(trim_frame_start) + ":end_frame=" + str(trim_frame_end) + ",fps=" + str(fps), ] ) commands.extend( [ "-vsync", "0", os.path.join( temp_directory_path, "%06d." + roop.globals.CFG.output_image_format ), ] ) return run_ffmpeg(commands) def create_video( target_path: str, dest_filename: str, fps: float = 24.0, temp_directory_path: str = None, ) -> None: if temp_directory_path is None: temp_directory_path = util.get_temp_directory_path(target_path) run_ffmpeg( [ "-r", str(fps), "-i", os.path.join( temp_directory_path, f"%06d.{roop.globals.CFG.output_image_format}" ), "-c:v", roop.globals.video_encoder, "-crf", str(roop.globals.video_quality), "-pix_fmt", "yuv420p", "-vf", "colorspace=bt709:iall=bt601-6-625:fast=1", "-y", dest_filename, ] ) return dest_filename def create_gif_from_video(video_path: str, gif_path): from roop.capturer import get_video_frame, release_video fps = util.detect_fps(video_path) frame = get_video_frame(video_path) release_video() scalex = frame.shape[0] scaley = frame.shape[1] if scalex >= scaley: scaley = -1 else: scalex = -1 run_ffmpeg( [ "-i", video_path, "-vf", f"fps={fps},scale={int(scalex)}:{int(scaley)}:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse", "-loop", "0", gif_path, ] ) def create_video_from_gif(gif_path: str, output_path): fps = util.detect_fps(gif_path) filter = """scale='trunc(in_w/2)*2':'trunc(in_h/2)*2',format=yuv420p,fps=10""" run_ffmpeg( [ "-i", gif_path, "-vf", f'"{filter}"', "-movflags", "+faststart", "-shortest", output_path, ] ) def repair_video(original_video: str, final_video: str): run_ffmpeg( [ "-i", original_video, "-movflags", "faststart", "-acodec", "copy", "-vcodec", "copy", final_video, ] ) def restore_audio( intermediate_video: str, original_video: str, trim_frame_start, trim_frame_end, final_video: str, ) -> None: fps = util.detect_fps(original_video) commands = ["-i", intermediate_video] if trim_frame_start is None and trim_frame_end is None: commands.extend(["-c:a", "copy"]) else: # if trim_frame_start is not None: # start_time = trim_frame_start / fps # commands.extend([ '-ss', format(start_time, ".2f")]) # else: # commands.extend([ '-ss', '0' ]) # if trim_frame_end is not None: # end_time = trim_frame_end / fps # commands.extend([ '-to', format(end_time, ".2f")]) # commands.extend([ '-c:a', 'aac' ]) if trim_frame_start is not None: start_time = trim_frame_start / fps commands.extend(["-ss", format(start_time, ".2f")]) else: commands.extend(["-ss", "0"]) if trim_frame_end is not None: end_time = trim_frame_end / fps commands.extend(["-to", format(end_time, ".2f")]) commands.extend(["-i", original_video, "-c", "copy"]) commands.extend(["-map", "0:v:0", "-map", "1:a:0?", "-shortest", final_video]) run_ffmpeg(commands)