@@ -0,0 +1,135 @@
#! /bin/bash
# Function to display usage information
usage () {
echo " Usage: $0 /path/to/input.mp4 [ /path/to/output_directory ]"
exit 1
}
# Check if at least one argument (input file) is provided
if [ $# -lt 1 ]; then
usage
fi
# Assign input file and output directory from arguments
INPUT_FILE=" $1 "
# Check if input file exists
if [ ! -f " $INPUT_FILE " ]; then
echo " Error: Input file '$INPUT_FILE ' does not exist."
exit 1
fi
# Check for required commands
for cmd in ffmpeg ffprobe; do
if ! command -v $cmd & > /dev/null; then
echo " Error: $cmd is not installed or not in PATH."
exit 1
fi
done
# Get the base filename without extension
FILENAME=$( basename " $INPUT_FILE " )
BASENAME=" ${FILENAME% .* } "
# Determine input directory
INPUT_DIR=$( dirname " $INPUT_FILE " )
# Assign output directory: second argument or default to current directory
if [ $# -ge 2 ]; then
OUTPUT_BASE_DIR=" $2 "
# Create the output base directory if it doesn't exist
mkdir -p " $OUTPUT_BASE_DIR "
else
OUTPUT_BASE_DIR=" $PWD "
fi
# Create specific output directory within the base output directory using the base filename
OUTPUT_DIR=" $OUTPUT_BASE_DIR /$BASENAME "
# Remove existing output directory if it exists
if [ -d " $OUTPUT_DIR " ]; then
echo " Output directory '$OUTPUT_DIR ' already exists. Removing it to avoid unused .ts files."
rm -rf " $OUTPUT_DIR "
fi
mkdir -p " $OUTPUT_DIR "
# Get the frame rate of the input video
FRAME_RATE=$( ffprobe -v 0 -of default=noprint_wrappers=1:nokey=1 \
-select_streams v:0 -show_entries stream=avg_frame_rate " $INPUT_FILE " )
# Convert frame rate to a number
IFS=' /' read -r num denom <<< " $FRAME_RATE"
if [ -z " $denom " ] || [ " $denom " -eq 0 ]; then
denom=1
fi
FRAME_RATE=$( echo " scale=2; $num /$denom " | bc)
FRAME_RATE=${FRAME_RATE% .* }
# Calculate GOP size (number of frames per 4 seconds)
GOP_SIZE=$(( FRAME_RATE * 4 ))
# Define resolutions, bitrates, and output names
RESOLUTIONS=(" 1280x720" " 1920x1080" " 3840x2160" )
BITRATES=(" 1200k" " 2500k" " 8000k" )
OUTPUTS=(" 720p" " 1080p" " 2160p" )
PLAYLISTS=()
# Loop over the variants
for i in " ${! RESOLUTIONS[@]} " ; do
RES=" ${RESOLUTIONS[$i]} "
BITRATE=" ${BITRATES[$i]} "
OUTPUT_NAME=" ${OUTPUTS[$i]} "
PLAYLIST=" ${OUTPUT_NAME} .m3u8"
PLAYLISTS+=(" $PLAYLIST " )
# Set profile and level based on resolution
if [ " $OUTPUT_NAME " == " 2160p" ]; then
PROFILE=" high"
LEVEL=" 5.1"
elif [ " $OUTPUT_NAME " == " 1080p" ]; then
PROFILE=" high"
LEVEL=" 4.2"
else
PROFILE=" main"
LEVEL=" 3.1"
fi
echo " Processing $OUTPUT_NAME ..."
if ! ffmpeg -y -i " $INPUT_FILE " \
-c:v libx264 -preset veryfast -profile:v " $PROFILE " -level:v " $LEVEL " -b:v " $BITRATE " -s " $RES " \
-c:a aac -b:a 128k -ac 2 \
-g $GOP_SIZE -keyint_min $GOP_SIZE -sc_threshold 0 \
-force_key_frames " expr:gte(t,n_forced*4)" \
-hls_time 4 -hls_list_size 0 -hls_flags independent_segments \
-hls_segment_filename " $OUTPUT_DIR /${OUTPUT_NAME} _%03d.ts" \
" $OUTPUT_DIR /$PLAYLIST " ; then
echo " Error: Failed to process $OUTPUT_NAME ."
exit 1
fi
done
# Generate master playlist
MASTER_PLAYLIST=" $OUTPUT_DIR /playlist.m3u8"
echo " Generating master playlist..."
{
echo " #EXTM3U"
echo " #EXT-X-VERSION:3"
for i in " ${! RESOLUTIONS[@]} " ; do
RESOLUTION=" ${RESOLUTIONS[$i]} "
OUTPUT_NAME=" ${OUTPUTS[$i]} "
PLAYLIST=" ${OUTPUTS[$i]} .m3u8"
BITRATE=" ${BITRATES[$i]} "
BANDWIDTH=$(( ${BITRATE% k} * 1000 + 128000 )) # Video bitrate + audio bitrate in bits per second
echo " "
echo " #EXT-X-STREAM-INF:BANDWIDTH=$BANDWIDTH ,RESOLUTION=$RESOLUTION "
echo " $PLAYLIST "
done
} > " $MASTER_PLAYLIST "
echo " Processing completed successfully."
echo " Output directory: $OUTPUT_DIR "