#!/bin/zsh # vg-interp — RIFE frame interpolation (rife-ncnn-vulkan, Metal via MoltenVK). # Usage: vg-interp CLIP [--factor 2|4] [--slowmo] [--out FILE] [--model rife-v4.6] # default: smooth motion (fps × factor, audio kept) # --slowmo: same fps, clip runs factor× longer (audio dropped) # Output: ProRes LT .mov next to the input (CLIP_interp.mov / CLIP_slowmo.mov) export PATH=/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin set -u VG="$(cd "$(dirname "$0")/.." && pwd)" RIFE="$VG/tools/rife/rife-ncnn-vulkan" [[ -x "$RIFE" ]] || { echo "rife not installed — run setup/fetch_phase2.sh" >&2; exit 1; } IN="${1:?usage: vg-interp CLIP [--factor N] [--slowmo] [--out FILE] [--model NAME]}" shift FACTOR=2; SLOWMO=0; OUT=""; MODEL="rife-v4.6" while [[ $# -gt 0 ]]; do case "$1" in --factor) FACTOR="$2"; shift 2 ;; --slowmo) SLOWMO=1; shift ;; --out) OUT="$2"; shift 2 ;; --model) MODEL="$2"; shift 2 ;; *) echo "unknown arg: $1" >&2; exit 1 ;; esac done IN="${IN:A}" [[ -f "$IN" ]] || { echo "no such file: $IN" >&2; exit 1; } fps=$(ffprobe -v error -select_streams v:0 -show_entries stream=avg_frame_rate -of csv=p=0 "$IN") fps_num="${fps%%/*}"; fps_den="${fps##*/}" in_fps=$(( fps_num * 1.0 / fps_den )) W=$(mktemp -d "${TMPDIR:-/tmp}/vginterp.XXXXXX") trap "rm -rf $W" EXIT mkdir -p "$W/in" "$W/out" echo "extracting frames ..." ffmpeg -hide_banner -loglevel error -y -i "$IN" "$W/in/%08d.png" $n_out frames (${MODEL})" "$RIFE" -i "$W/in" -o "$W/out" -m "$VG/tools/rife/$MODEL" -n "$n_out" -f "%08d.png" || exit 1 n_got=$(ls "$W/out" | wc -l | tr -d " ") echo "rife produced $n_got frames" if [[ $SLOWMO -eq 1 ]]; then out_fps=$in_fps DEF="${IN%.*}_slowmo.mov" else out_fps=$(( in_fps * FACTOR )) DEF="${IN%.*}_interp.mov" fi OUT="${OUT:-$DEF}" out_fps=$(printf "%g" "$out_fps") echo "encoding ProRes at ${out_fps}fps ..." if [[ $SLOWMO -eq 1 ]]; then ffmpeg -hide_banner -loglevel error -y -framerate "$out_fps" -i "$W/out/%08d.png" \ -c:v prores_ks -profile:v 1 -pix_fmt yuv422p10le "$OUT"