Skip to content

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"
done
bash
# 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:

  1. 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"
  2. Videos differ in properties → Must re-encode. Choose encoder:

    Option A: Hardware accelerated (FASTEST, Mac only)

    bash
    ffmpeg -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)

    bash
    ffmpeg -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

PresetPortrait (9:16)Landscape (16:9)
720p720x12801280x720
1080p1080x19201920x1080
4k2160x38403840x2160

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:

ItemStatus
Processedtime / total_time (percentage)
SpeedNx realtime
Elapsedmm:ss
Output SizeX 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

  1. h264_videotoolbox on Apple Silicon: 3-5x faster than libx264, uses dedicated media engine
  2. Stream copy (-c copy): Near-instant when all inputs match — always check first
  3. Thunderbolt bridge: ~40MB/s transfer, ideal for remote rendering
  4. CRF 23 is a good default for libx264; for videotoolbox use -b:v 8M (bitrate mode)
  5. RAM check: Ensure remote has enough RAM (ffmpeg typically uses <1GB for concat)

Known Remote Hosts

HostConnectionSpecs
davids-mac-mini.localThunderbolt bridge (169.254.x.x)Apple M4 Pro, 24GB RAM

Read-only documentation bundle of the Med Tracker agent stack. AU compliance baked in (AHPRA + Privacy Act 1988 + Spam Act 2003).