Batch transcoder for Garmin Varia dashcam footage. Converts H.264 source clips to HEVC MP4, optimized for Apple Photos / QuickTime compatibility.
ffmpeg and ffprobe in PATH (any recent version with libx265/libx264; videotoolbox on macOS)# Transcode everything in SampleFootage → Output (hardware encoder on macOS)
./garmin_varia_transcode.sh -s SampleFootage -d Output
# Preview what would happen without writing any files
./garmin_varia_transcode.sh -s SampleFootage -d Output --dry-run
# Single file, verbose output
./garmin_varia_transcode.sh -s SampleFootage/Day/clip.mp4 -d Output --verbose
# Transcode + delete originals after validation
./garmin_varia_transcode.sh -s SampleFootage -d Output --delete-source
# Long unattended run preset (delete-source + keep-going; also stages input when --staging-dir is set)
./garmin_varia_transcode.sh -s SampleFootage -d Output --unattended
# NFS destination with local staging for temp outputs
./garmin_varia_transcode.sh -s SampleFootage -d ~/Autofs/xdev/is-baobab/nvme0n1/@backup/Garmin --staging-dir /tmp/varia_staging
# Flaky NAS/autofs source: copy each source clip to local staging before encode
./garmin_varia_transcode.sh -s ~/Autofs/xdev/autonas/ext01/@Camera/import -d ~/Autofs/xdev/autonas/ext00/@Garmin --unattended --staging-dir /Volumes/VARIA_RAM --staging-ramdisk-mb 512 --stage-input
# Timing debug: process first 20 files then stop and print final statistics
./garmin_varia_transcode.sh -s SampleFootage -d Output --debug-timing 20
# Media cleanup helper (Apple artifacts, zero-byte MP4, duplicate suffix normalization)
./cleanup_garmin_varia_media_folder.sh --dry-run ~/Autofs/xdev/autonas/ext01/@Camera/import
| Mode | Encoder | Speed (30s clip) | Power* | Use when |
|---|---|---|---|---|
hardware |
hevc_videotoolbox | ~4-5s | ~35W | Default — battery, large libraries, dashcam footage |
auto |
videotoolbox → x265 → x264 | varies | varies | Cross-platform or unknown machine |
quality |
libx265 (CRF 20) | ~50s | ~80W | Archival, cinema, complex sources |
compat |
libx264 (CRF 19) | ~30s | ~70W | Older TVs, players without HEVC support |
* Measured on Apple Silicon MacBook Pro.
Options:
-s, --source, --input DIR Source directory or single file (default: current directory)
-d, --destination, --output DIR Destination directory (default: current directory)
--staging-dir DIR Temporary staging directory for intermediate output files
Falls back to destination temp files if staging is unavailable
or does not have enough free space for current file
--stage-input Copy each source video to staging before encoding; useful
for flaky NAS/autofs source reads
--staging-ramdisk-mb N RAM disk size in MB when auto-creating missing /Volumes staging
directory on macOS (default: 8192)
--debug-timing N Process at most N video files, then stop and print timing stats
--mode MODE hardware|auto|quality|compat (default: hardware)
--crf N CRF for quality/compat modes (lower = better; default: 20/19)
--no-overwrite Skip files that already exist at destination
--dry-run Print actions without writing files
--no-recursive Process only the top-level source directory
--extensions LIST Comma-separated extensions (default: mp4,mov,avi,m4v)
--verbose Full per-operation logs + ffmpeg/ffprobe output
--delete-source Delete source after strict post-encode validation
--keep-going Continue after source-file failures (default: stop)
--unattended Preset for long runs: --delete-source + --keep-going
--no-apple-repack-fallback Disable macOS avconvert fallback for unreadable MP4/MOV sources
--apple-repack-fallback Enable macOS avconvert fallback (default)
-h, --help Show full help with encoding mode details
.mp4hvc1 (required for Apple Photos / QuickTime)touch -r)2026-05-04 12:08:00 : Transcoding SampleFootage/Day/2026-04-04_18-10-36.mp4 ... done in 5s
2026-05-04 12:08:04 : Transcoding SampleFootage/Day/2026-04-04_18-10-05.mp4 ... done in 4s
[2026-05-04 12:08:35] [INFO] Summary: videos_processed=10 videos_skipped=0 errors=0
[2026-05-04 12:08:35] [INFO] Timing: total_elapsed=44s, video_encode_avg=4s
--delete-source only deletes source after codec + duration validation passes--dry-run never writes filesCtrl+C behavior during long runs:
first press requests stop after current file; second press force-stops current encodeq (or Q) during interactive runs to request a graceful stop before
the next file begins. --unattended disables q/Q terminal polling so
buffered terminal input cannot stop long runs accidentally; use Ctrl+C.avconvert --preset PresetPassthrough
as fallback before being marked as unreadableBackward-compatible aliases:
- --move-source maps to --delete-source
- --continue-on-error maps to --keep-going
cleanup_garmin_varia_media_folder.sh is a companion utility for import and transcoded media folders.
What it does:
- Removes AppleDouble artifacts (._*) up to 4096 bytes
- Removes zero-size .mp4 files
- Normalizes duplicate timestamp files:
if YYYY-MM-DD_HH-MM-SS.mp4 is missing and exactly one
YYYY-MM-DD_HH-MM-SS_<n>.mp4 exists, it renames it to base name
- Reports blocked duplicate groups when base exists or multiple suffixed duplicates exist
Usage:
# Preview only
./cleanup_garmin_varia_media_folder.sh --dry-run ~/Autofs/xdev/autonas/ext01/@Camera/import
# Apply changes
./cleanup_garmin_varia_media_folder.sh ~/Autofs/xdev/autonas/ext01/@Camera/import
# Example on transcoded output folder
./cleanup_garmin_varia_media_folder.sh --dry-run ~/Autofs/xdev/is-baobab/nvme0n1/@backup/Garmin
Exit codes:
- 0: cleanup completed with no blocked duplicate groups
- 1: cleanup completed but blocked duplicate groups require manual review
- 2: invalid invocation or runtime error
SampleFootage/ Original clips (gitignored)
Output/ Transcoded output (gitignored)
garmin_varia_transcode.sh Main script
cleanup_garmin_varia_media_folder.sh Media cleanup utility (import + transcoded folders)
CHANGELOG.md Version history
DEVLOG.md Development decisions and rationale