← 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