Skip to content

Instantly share code, notes, and snippets.

@itsanishjain
Created February 4, 2026 17:46
Show Gist options
  • Select an option

  • Save itsanishjain/4da9cd14dbad4c0bb1146109e8a9be8a to your computer and use it in GitHub Desktop.

Select an option

Save itsanishjain/4da9cd14dbad4c0bb1146109e8a9be8a to your computer and use it in GitHub Desktop.
Instagram Reels Video Cropper
#!/bin/bash
# ==============================================================================
# Instagram Reels Video Cropper
# ==============================================================================
# Converts any video to 9:16 aspect ratio (1080x1920) for Instagram Reels
#
# Usage: ./crop-for-reels.sh <input_video> [output_video]
#
# Requirements: ffmpeg (brew install ffmpeg)
# ==============================================================================
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Instagram Reels dimensions (9:16 aspect ratio)
TARGET_WIDTH=1080
TARGET_HEIGHT=1920
# Check if ffmpeg is installed
if ! command -v ffmpeg &> /dev/null; then
echo -e "${RED}Error: ffmpeg is not installed.${NC}"
echo "Install it with: brew install ffmpeg"
exit 1
fi
# Check if input file is provided
if [ -z "$1" ]; then
echo -e "${RED}Error: No input video provided.${NC}"
echo ""
echo "Usage: $0 <input_video> [output_video]"
echo ""
echo "Examples:"
echo " $0 my_video.mp4"
echo " $0 my_video.mp4 my_reel.mp4"
exit 1
fi
INPUT_FILE="$1"
# Check if input file exists
if [ ! -f "$INPUT_FILE" ]; then
echo -e "${RED}Error: Input file '$INPUT_FILE' not found.${NC}"
exit 1
fi
# Generate output filename if not provided
if [ -z "$2" ]; then
FILENAME=$(basename -- "$INPUT_FILE")
EXTENSION="${FILENAME##*.}"
BASENAME="${FILENAME%.*}"
OUTPUT_FILE="${BASENAME}_reel.${EXTENSION}"
else
OUTPUT_FILE="$2"
fi
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BLUE} 📱 Instagram Reels Video Cropper${NC}"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
# Get input video dimensions
echo -e "${YELLOW}Analyzing input video...${NC}"
INPUT_WIDTH=$(ffprobe -v error -select_streams v:0 -show_entries stream=width -of csv=s=x:p=0 "$INPUT_FILE")
INPUT_HEIGHT=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=s=x:p=0 "$INPUT_FILE")
DURATION=$(ffprobe -v error -show_entries format=duration -of csv=s=x:p=0 "$INPUT_FILE" 2>/dev/null | cut -d. -f1)
echo -e " Input: ${GREEN}${INPUT_WIDTH}x${INPUT_HEIGHT}${NC}"
echo -e " Output: ${GREEN}${TARGET_WIDTH}x${TARGET_HEIGHT}${NC} (9:16)"
echo -e " Duration: ${GREEN}${DURATION:-unknown}s${NC}"
echo ""
# Determine the video orientation and build the appropriate filter
INPUT_ASPECT=$(echo "scale=6; $INPUT_WIDTH / $INPUT_HEIGHT" | bc)
TARGET_ASPECT=$(echo "scale=6; $TARGET_WIDTH / $TARGET_HEIGHT" | bc) # 0.5625
# Check if input is landscape (wider than 9:16)
IS_LANDSCAPE=$(echo "$INPUT_ASPECT > $TARGET_ASPECT" | bc)
if [ "$IS_LANDSCAPE" -eq 1 ]; then
echo -e "${YELLOW}Detected: Landscape video → Converting to portrait${NC}"
echo -e "${YELLOW}Mode: Blurred background with centered video${NC}"
echo ""
# For landscape videos: Create blurred background + overlay original centered
# This preserves the entire video content with a nice blurred background
FILTER_COMPLEX="
[0:v]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,boxblur=20:5[bg];
[0:v]scale=1080:-2:force_original_aspect_ratio=decrease[fg];
[bg][fg]overlay=(W-w)/2:(H-h)/2,setsar=1
"
else
echo -e "${YELLOW}Detected: Portrait/Square video → Cropping to 9:16${NC}"
echo ""
# For portrait or square videos: Scale and crop to exactly 9:16
FILTER_COMPLEX="
[0:v]scale=1080:1920:force_original_aspect_ratio=increase,crop=1080:1920,setsar=1
"
fi
echo -e "${YELLOW}Processing video...${NC}"
# Run ffmpeg with progress indicator
ffmpeg -i "$INPUT_FILE" \
-filter_complex "$FILTER_COMPLEX" \
-c:v libx264 \
-preset medium \
-crf 23 \
-c:a aac \
-b:a 128k \
-movflags +faststart \
-y \
"$OUTPUT_FILE" \
2>&1 | while read line; do
if [[ "$line" == *"frame="* ]]; then
echo -ne "\r $line"
fi
done
echo ""
echo ""
# Verify output file was created and has content
if [ ! -f "$OUTPUT_FILE" ] || [ ! -s "$OUTPUT_FILE" ]; then
echo -e "${RED}Error: Failed to create output file.${NC}"
exit 1
fi
echo -e "${GREEN}✓ Successfully created Instagram Reel!${NC}"
echo ""
# Get output file size
OUTPUT_SIZE=$(du -h "$OUTPUT_FILE" | cut -f1)
echo -e " Output file: ${BLUE}$OUTPUT_FILE${NC}"
echo -e " File size: ${GREEN}$OUTPUT_SIZE${NC}"
echo ""
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e " 📤 Ready to upload to Instagram Reels!"
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment