import glob from pathlib import Path import uuid import sys from typing import List sys.path.append((Path(__file__).parent / "extern").as_posix()) import argparse from rich_argparse import RichHelpFormatter from rich.console import Console from rich.progress import Progress import numpy as np import subprocess def write_prores_444_video(output_file, frames: List[np.ndarray], fps): # Convert float images to the range of 0-65535 (12-bit color depth) frames = [(frame * 65535).clip(0, 65535).astype(np.uint16) for frame in frames] height, width, _ = frames[0].shape # Prepare the FFmpeg command command = [ "ffmpeg", "-y", # Overwrite output file if it already exists "-f", "rawvideo", "-vcodec", "rawvideo", "-s", f"{width}x{height}", "-pix_fmt", "rgb48le", "-r", str(fps), "-i", "-", "-c:v", "prores_ks", "-profile:v", "4", "-pix_fmt", "yuva444p10le", "-r", str(fps), "-y", # Overwrite output file if it already exists output_file, ] process = subprocess.Popen(command, stdin=subprocess.PIPE) for frame in frames: process.stdin.write(frame.tobytes()) process.stdin.close() process.wait() if __name__ == "__main__": default_output = f"./output_{uuid.uuid4()}.mov" parser = argparse.ArgumentParser( description="FILM frame interpolation", formatter_class=RichHelpFormatter ) parser.add_argument("inputs", nargs="*", help="Input image files") parser.add_argument("--output", help="Output JSON file", default=default_output) parser.add_argument("-v", "--verbose", action="store_true", help="Verbose mode") parser.add_argument( "--glob", help="Enable glob pattern matching", metavar="PATTERN" ) parser.add_argument( "--interpolate", type=int, default=4, help="Time for interpolated frames" ) parser.add_argument("--fps", type=int, default=30, help="Out FPS") align = 64 block_width = 2 block_height = 2 args = parser.parse_args() # - checks if not args.glob and not args.inputs: parser.error("Either --glob flag or inputs must be provided.") if args.glob: glob_pattern = args.glob try: pattern_path = str(Path(glob_pattern).expanduser().resolve()) if not any(glob.glob(pattern_path)): raise ValueError(f"No files found for glob pattern: {glob_pattern}") except Exception as e: console = Console() console.print( f"[bold red]Error: Invalid glob pattern '{glob_pattern}': {e}[/bold red]" ) exit(1) else: glob_pattern = None input_files: List[Path] = [] if glob_pattern: input_files = [ Path(p) for p in list(glob.glob(str(Path(glob_pattern).expanduser().resolve()))) ] else: input_files = [Path(p) for p in args.inputs] console = Console() console.print("Input Files:", style="bold", end=" ") console.print(f"{len(input_files):03d} files", style="cyan") # for input_file in args.inputs: # console.print(f"- {input_file}", style="cyan") console.print("\nOutput File:", style="bold", end=" ") console.print(f"{Path(args.output).resolve().absolute()}", style="cyan") with Progress(console=console, auto_refresh=True) as progress: from frame_interpolation.eval import util from frame_interpolation.eval import util, interpolator # files = Path(pth).rglob("*.png") model = interpolator.Interpolator( "G:/MODELS/FILM/pretrained_models/film_net/Style", None ) # [2,2] task = progress.add_task("[cyan]Interpolating frames...", total=1) frames = list( util.interpolate_recursively_from_files( [x.as_posix() for x in input_files], args.interpolate, model ) ) # mediapy.write_video(args.output, frames, fps=args.fps) write_prores_444_video(args.output, frames, fps=args.fps) progress.update(task, advance=1) progress.refresh()