Five CLIs around DaVinci Resolve music-video editing, all inference local on Apple Silicon (MPS/MLX): - vg-roto: SAM 2.1 + MatAnyone click-to-cutout -> ProRes 4444 alpha - vg-index / vg-find: PySceneDetect + mlx-whisper searchable clip library - vg-beats: librosa beat grid -> Resolve marker EDL - vg-transcode: legacy codecs -> ProRes LT, deinterlaced, resumable setup/setup_venvs.sh rebuilds venvs, tool clones, checkpoints and applies patches/matanyone-cv2-reader.patch (torchvision >= 0.23 removed read_video). Verified end-to-end on ultra 2026-08-24; setup/smoke_test.sh covers the lanes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
68 lines
2.7 KiB
Bash
Executable File
68 lines
2.7 KiB
Bash
Executable File
#!/bin/zsh
|
|
# vg-transcode — batch-normalize old footage to ProRes LT for editing.
|
|
# Usage: vg-transcode SRC_DIR [DEST_DIR] [--h264]
|
|
# Recurses SRC_DIR, converts every video to ProRes LT .mov (or H.264 with --h264),
|
|
# mirrors the directory structure, skips files already done, deinterlaces
|
|
# interlaced sources (bwdif to progressive at double rate).
|
|
# Heartbeat: ~/.jobs/vidgod-transcode.status
|
|
export PATH=/opt/homebrew/bin:/usr/bin:/bin:/usr/sbin:/sbin
|
|
set -u
|
|
|
|
SRC="${1:?usage: vg-transcode SRC_DIR [DEST_DIR] [--h264]}"
|
|
DEST="${2:-}"
|
|
CODEC=prores
|
|
[[ "${2:-}" == "--h264" ]] && { DEST=""; CODEC=h264; }
|
|
[[ "${3:-}" == "--h264" ]] && CODEC=h264
|
|
SRC="${SRC:A}"
|
|
[[ -d "$SRC" ]] || { echo "not a dir: $SRC" >&2; exit 1; }
|
|
[[ -z "$DEST" ]] && DEST="${SRC}-prores"
|
|
mkdir -p "$DEST"
|
|
|
|
hb(){ mkdir -p ~/.jobs; echo "$(date '+%F %T') | $1 | $2" > ~/.jobs/vidgod-transcode.status; }
|
|
|
|
typeset -a files
|
|
files=()
|
|
while IFS= read -r -d '' f; do files+=("$f"); done < <(
|
|
find "$SRC" \( -iname '*.avi' -o -iname '*.wmv' -o -iname '*.mpg' -o -iname '*.mpeg' \
|
|
-o -iname '*.asf' -o -iname '*.flv' -o -iname '*.rm' -o -iname '*.rmvb' -o -iname '*.vob' \
|
|
-o -iname '*.m2v' -o -iname '*.divx' -o -iname '*.mov' -o -iname '*.mp4' -o -iname '*.mkv' \
|
|
-o -iname '*.webm' -o -iname '*.m4v' -o -iname '*.3gp' -o -iname '*.mts' -o -iname '*.m2ts' \) \
|
|
-not -path "$DEST/*" -print0 | sort -z)
|
|
|
|
total=${#files[@]}
|
|
[[ $total -eq 0 ]] && { echo "no video files under $SRC"; exit 0; }
|
|
echo "transcoding $total files: $SRC -> $DEST ($CODEC)"
|
|
|
|
n=0; ok=0; skip=0; fail=0
|
|
for f in "${files[@]}"; do
|
|
n=$((n+1))
|
|
rel="${f#$SRC/}"
|
|
out="$DEST/${rel%.*}.mov"
|
|
[[ "$CODEC" == "h264" ]] && out="$DEST/${rel%.*}.mp4"
|
|
mkdir -p "${out:h}"
|
|
hb "$n/$total" "${rel:t}"
|
|
if [[ -s "$out" && "$out" -nt "$f" ]]; then skip=$((skip+1)); continue; fi
|
|
|
|
# detect interlacing
|
|
fo=$(ffprobe -v error -select_streams v:0 -show_entries stream=field_order -of csv=p=0 "$f" 2>/dev/null)
|
|
vf="format=yuv422p10le"
|
|
case "$fo" in
|
|
tt|bb|tb|bt) vf="bwdif=mode=1:parity=auto,format=yuv422p10le" ;;
|
|
esac
|
|
|
|
if [[ "$CODEC" == "prores" ]]; then
|
|
ffmpeg -hide_banner -loglevel error -y -i "$f" -vf "$vf" \
|
|
-c:v prores_ks -profile:v 1 -vendor apl0 \
|
|
-c:a pcm_s16le -map 0:v:0 -map '0:a:0?' "$out" </dev/null
|
|
else
|
|
ffmpeg -hide_banner -loglevel error -y -i "$f" -vf "${vf%,format=yuv422p10le},format=yuv420p" \
|
|
-c:v libx264 -preset fast -crf 18 -c:a aac -b:a 192k \
|
|
-map 0:v:0 -map '0:a:0?' "$out" </dev/null
|
|
fi
|
|
if [[ $? -eq 0 && -s "$out" ]]; then ok=$((ok+1)); else fail=$((fail+1)); rm -f "$out"; echo "FAILED: $rel" >&2; fi
|
|
done
|
|
|
|
hb "DONE $n/$total" "ok=$ok skip=$skip fail=$fail"
|
|
echo "done: $ok converted, $skip skipped (already done), $fail failed"
|
|
[[ $fail -eq 0 ]]
|