Skip to content

Instantly share code, notes, and snippets.

@ArnoldsK
Last active January 21, 2024 10:42
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save ArnoldsK/291ffaa32715e6830136d1199fc73f22 to your computer and use it in GitHub Desktop.
Save ArnoldsK/291ffaa32715e6830136d1199fc73f22 to your computer and use it in GitHub Desktop.
Bash script for reducing a file size of a video using ffmpeg to reduce bitrate
#!/bin/bash
# Usage:
# ~$ sh reduce_video_file_size.sh [./input.mp4] [size mb] [./output.mp4]
# Parameters can be preset or set by providing none
# Input and output names must end with ".mp4"
# Can use Git Bash to run the script on Windows
display_help() {
local FILE=`basename "$0"`
echo ""
echo "Usage: $FILE input_file target_size_mb [output_file=output.mp4]"
exit 0
}
INPUT_FILE=$1
TARGET_SIZE_MB=$2
OUTPUT_FILE=$3
# Ask for input before validating
if [[ $INPUT_FILE == "" ]]; then
read -p "Enter the input file name: " INPUT_FILE
fi
if [[ $TARGET_SIZE_MB == "" ]]; then
read -p "Enter the target file size in MB: " TARGET_SIZE_MB
fi
if [[ $OUTPUT_FILE == "" ]]; then
read -p "Enter the output file name: (output.mp4) " OUTPUT_FILE
fi
# Require input file name
if [[ $INPUT_FILE == "" ]]; then
echo "Input file name missing"
display_help
fi
# Require target size
if [[ $TARGET_SIZE_MB == "" || !($TARGET_SIZE_MB > 0) ]]; then
echo "Target size has to be at least 1 MB"
display_help
fi
# Set the default output file name
if [[ $OUTPUT_FILE == "" ]]; then
OUTPUT_FILE="output.mp4"
fi
# Check if the input file exists
if [ ! -f $INPUT_FILE ]; then
echo "Input file $INPUT_FILE not found"
exit 0
fi
# Check if the file size is already below the target size
INPUT_FILE_SIZE_MB=$(($(wc -c < $INPUT_FILE) / 1000000))
if [ $INPUT_FILE_SIZE_MB -lt $TARGET_SIZE_MB ]; then
echo "The file size is already below the target size"
exit 0
fi
# Additional bitrate division to make sure the size is below the target
ADD_TO_DIVIDER=50
# Calculate the target bitrate
BITRATE="$(awk "BEGIN {print int($TARGET_SIZE_MB * 1024 * 1024 * 8 / $(ffprobe \
-v error \
-show_entries format=duration \
-of default=noprint_wrappers=1:nokey=1 \
"$INPUT_FILE" \
) / (1000 + $ADD_TO_DIVIDER))}")k"
# Custom 2pass log file prefix
PASSLOGFILE="$INPUT_FILE-pass"
# Do the resizing
echo "Working..."
ffmpeg -v error -y -i $INPUT_FILE -c:v libx264 -preset medium -b:v $BITRATE -pass 1 -passlogfile $PASSLOGFILE -c:a aac -b:a 128k -f mp4 /dev/null && \
ffmpeg -v error -i $INPUT_FILE -c:v libx264 -preset medium -b:v $BITRATE -pass 2 -passlogfile $PASSLOGFILE -c:a aac -b:a 128k $OUTPUT_FILE
echo "Done"
# Delete junk files 2pass creates - could not find a way to disable
if [ -f $PASSLOGFILE-0.log ]; then
rm $PASSLOGFILE-0.log
fi
if [ -f $PASSLOGFILE-0.log.mbtree ]; then
rm $PASSLOGFILE-0.log.mbtree
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment