Appearance
Concatenate/stitch multiple video files into a single output file using ffmpeg.
Workflow
Step 1: Analyze Input Videos
Probe all input files to determine their properties:
bash
# Get codec, resolution, fps, pixel format for each file
for f in "${FILES[@]}"; do
ffprobe -v error -select_streams v:0 \
-show_entries stream=width,height,codec_name,r_frame_rate,pix_fmt \
-of csv=p=0 "$f"
donebash
# Get total duration
for f in "${FILES[@]}"; do
ffprobe -v error -show_entries format=duration -of csv=p=0 "$f"
done | awk '{s+=$1} END {printf "Total: %.0f seconds (%.1f minutes)\n", s, s/60}'Step 2: Choose Encoding Strategy
Decision tree:
All videos have identical codec, resolution, fps, pixel format → Use stream copy (instant, no quality loss):
bash# Create concat list for f in "${FILES[@]}"; do echo "file '$f'"; done > concat_list.txt ffmpeg -f concat -safe 0 -i concat_list.txt \ -c copy -movflags +faststart \ -y "$OUTPUT"Videos differ in properties → Must re-encode. Choose encoder:
Option A: Hardware accelerated (FASTEST, Mac only)
bashffmpeg -f concat -safe 0 -i concat_list.txt \ -vf "scale=${WIDTH}:${HEIGHT}:force_original_aspect_ratio=decrease,pad=${WIDTH}:${HEIGHT}:(ow-iw)/2:(oh-ih)/2:black" \ -c:v h264_videotoolbox -b:v 8M -profile:v high \ -c:a aac -b:a 128k -ar 44100 -ac 2 \ -r ${FPS} \ -movflags +faststart \ -y "$OUTPUT"Option B: Software encoding (best compatibility/quality)
bashffmpeg -f concat -safe 0 -i concat_list.txt \ -vf "scale=${WIDTH}:${HEIGHT}:force_original_aspect_ratio=decrease,pad=${WIDTH}:${HEIGHT}:(ow-iw)/2:(oh-ih)/2:black" \ -c:v libx264 -preset medium -crf 23 \ -c:a aac -b:a 128k -ar 44100 -ac 2 \ -r ${FPS} \ -movflags +faststart \ -y "$OUTPUT"
Step 3: Resolution Presets
| Preset | Portrait (9:16) | Landscape (16:9) |
|---|---|---|
| 720p | 720x1280 | 1280x720 |
| 1080p | 1080x1920 | 1920x1080 |
| 4k | 2160x3840 | 3840x2160 |
Auto-detect orientation from the majority of input files (if height > width → portrait).
Step 4: Remote Rendering (Optional)
When rendering on a remote Mac (e.g. Mac Mini via Thunderbolt):
bash
# 1. Check remote specs
ssh $REMOTE "sysctl -n hw.memsize | awk '{print \$1/1024/1024/1024 \" GB RAM\"}'; \
sysctl -n machdep.cpu.brand_string; which ffmpeg"
# 2. Create temp directory on remote
ssh $REMOTE "mkdir -p ~/video_render_tmp"
# 3. Copy files via rsync (Thunderbolt is fast)
# Generate file list, then rsync
for f in "${FILES[@]}"; do echo "$f"; done > /tmp/render_filelist.txt
rsync -av --files-from=/tmp/render_filelist.txt / $REMOTE:~/video_render_tmp/
# 4. Create concat list on remote (adjust paths)
# ...generate concat_list.txt with remote paths...
# 5. Run ffmpeg on remote in background
ssh $REMOTE "nohup ffmpeg [OPTIONS] > ~/video_render_tmp/ffmpeg.log 2>&1 & echo \$!"
# 6. Monitor progress
ssh $REMOTE "tail -1 ~/video_render_tmp/ffmpeg.log"
# 7. Copy result back
rsync -av --progress $REMOTE:~/video_render_tmp/OUTPUT.mp4 ./
# 8. Cleanup remote
ssh $REMOTE "rm -rf ~/video_render_tmp"Step 5: Progress Monitoring
For background renders, check progress with:
bash
# Local
tail -1 ffmpeg.log
# Remote
ssh $REMOTE "ps aux | grep ffmpeg | grep -v grep | wc -l; tail -c 300 ~/video_render_tmp/ffmpeg.log"Report progress as a table:
| Item | Status |
|---|---|
| Processed | time / total_time (percentage) |
| Speed | Nx realtime |
| Elapsed | mm:ss |
| Output Size | X GB |
| ETA | ~N minutes |
Step 6: Cleanup
After completion:
- Remove
concat_list.txt - Remove remote temp files if remote rendering was used
- Verify output file exists and has reasonable size
Performance Tips
- h264_videotoolbox on Apple Silicon: 3-5x faster than libx264, uses dedicated media engine
- Stream copy (
-c copy): Near-instant when all inputs match — always check first - Thunderbolt bridge: ~40MB/s transfer, ideal for remote rendering
- CRF 23 is a good default for libx264; for videotoolbox use
-b:v 8M(bitrate mode) - RAM check: Ensure remote has enough RAM (ffmpeg typically uses <1GB for concat)
Known Remote Hosts
| Host | Connection | Specs |
|---|---|---|
| davids-mac-mini.local | Thunderbolt bridge (169.254.x.x) | Apple M4 Pro, 24GB RAM |