vidgod/bin/vg-transcode
type-two 7911a59186 VIDGOD: local AI video production toolkit
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>
2026-08-24 14:17:50 +10:00

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 ]]