← back to Goodquestion Ai

video-html/assemble.sh

96 lines

#!/bin/bash
# assemble.sh — ffmpeg video assembly
#
# Usage:
#   ./assemble.sh <frames-dir> <narration.mp3> <output.mp4> [--fps 30]
#
# Takes a directory of frame-NNNN.png files and an audio file,
# combines them into a final h264+AAC video.

set -euo pipefail

usage() {
  echo "Usage: $0 <frames-dir> <narration.mp3> <output.mp4> [--fps 30]"
  echo ""
  echo "  frames-dir    Directory containing frame-NNNN.png files"
  echo "  narration.mp3 Audio narration file"
  echo "  output.mp4    Output video file"
  echo "  --fps N       Frame rate (default: 30)"
  exit 1
}

if [ $# -lt 3 ]; then
  usage
fi

FRAMES_DIR="$1"
AUDIO="$2"
OUTPUT="$3"
FPS=30

# Parse optional flags
shift 3
while [ $# -gt 0 ]; do
  case "$1" in
    --fps) FPS="$2"; shift 2 ;;
    *) echo "Unknown option: $1"; usage ;;
  esac
done

# Validate inputs
if [ ! -d "$FRAMES_DIR" ]; then
  echo "Error: Frames directory not found: $FRAMES_DIR"
  exit 1
fi

if [ ! -f "$AUDIO" ]; then
  echo "Error: Audio file not found: $AUDIO"
  exit 1
fi

# Count frames
FRAME_COUNT=$(ls -1 "$FRAMES_DIR"/frame-*.png 2>/dev/null | wc -l)
if [ "$FRAME_COUNT" -eq 0 ]; then
  echo "Error: No frame-*.png files found in $FRAMES_DIR"
  exit 1
fi

# Create output directory if needed
OUTPUT_DIR=$(dirname "$OUTPUT")
mkdir -p "$OUTPUT_DIR"

echo "Assembly config:"
echo "  Frames:     $FRAMES_DIR ($FRAME_COUNT frames)"
echo "  Audio:      $AUDIO"
echo "  Output:     $OUTPUT"
echo "  FPS:        $FPS"
echo ""

# Build video from frames + audio
# -shortest: end when the shorter stream ends
# -c:v libx264: h264 video codec
# -c:a aac: AAC audio codec
# -pix_fmt yuv420p: compatibility pixel format
ffmpeg -y \
  -framerate "$FPS" \
  -i "$FRAMES_DIR/frame-%04d.png" \
  -i "$AUDIO" \
  -c:v libx264 \
  -preset medium \
  -crf 18 \
  -c:a aac \
  -b:a 192k \
  -pix_fmt yuv420p \
  -shortest \
  -movflags +faststart \
  "$OUTPUT"

echo ""
echo "Done! Output: $OUTPUT"
echo "Size: $(du -h "$OUTPUT" | cut -f1)"

# Probe output
echo ""
echo "Video info:"
ffprobe -v quiet -show_format -show_streams "$OUTPUT" 2>/dev/null | grep -E 'width|height|duration|bit_rate|codec_name' | head -10