120 lines
3.9 KiB
Bash
Executable File
120 lines
3.9 KiB
Bash
Executable File
#!/bin/bash
|
|
set -e
|
|
|
|
# Base directories
|
|
VIDEO_SOURCE_DIR="static/videos"
|
|
HLS_OUTPUT_DIR="static/videos/hls"
|
|
POSTER_OUTPUT_DIR="static/videos/posters"
|
|
|
|
# Create output directories if they don't exist
|
|
mkdir -p "$HLS_OUTPUT_DIR"
|
|
mkdir -p "$POSTER_OUTPUT_DIR"
|
|
|
|
# HLS Settings
|
|
SEGMENT_TIME=4 # Segment duration in seconds
|
|
KEYFRAME_INTERVAL=48 # Keyframe interval (2 seconds at 24fps)
|
|
|
|
# Resolutions for adaptive streaming
|
|
RESOLUTIONS=(
|
|
"256:144" # 144p
|
|
"426:240" # 240p
|
|
"640:360" # 360p
|
|
"854:480" # 480p
|
|
"1280:720" # 720p
|
|
)
|
|
|
|
# Bitrates for each resolution (in kbps)
|
|
BITRATES=(
|
|
"200k" # 144p
|
|
"400k" # 240p
|
|
"800k" # 360p
|
|
"1500k" # 480p
|
|
"2500k" # 720p
|
|
)
|
|
|
|
# Function to generate HLS streams for a video
|
|
transcode_to_hls() {
|
|
local input_file="$1"
|
|
local video_id=$(basename "$input_file" .mp4)
|
|
local output_dir="$HLS_OUTPUT_DIR/$video_id"
|
|
|
|
echo "Transcoding $input_file to HLS format..."
|
|
|
|
# Create output directory
|
|
mkdir -p "$output_dir"
|
|
|
|
# Generate variant playlists for each resolution
|
|
for i in "${!RESOLUTIONS[@]}"; do
|
|
local resolution=${RESOLUTIONS[$i]}
|
|
local bitrate=${BITRATES[$i]}
|
|
local width=$(echo $resolution | cut -d':' -f1)
|
|
local height=$(echo $resolution | cut -d':' -f2)
|
|
|
|
echo " Creating $height stream ($bitrate)..."
|
|
|
|
# Using better encoding settings for quality and efficiency
|
|
ffmpeg -y -i "$input_file" \
|
|
-vf "scale=$resolution:force_original_aspect_ratio=decrease,pad=$resolution:-1:-1:color=black" \
|
|
-c:v libx264 -preset slower -crf 22 -maxrate $bitrate -bufsize $(echo $bitrate | sed 's/k/000/') \
|
|
-g $KEYFRAME_INTERVAL -keyint_min $KEYFRAME_INTERVAL \
|
|
-sc_threshold 0 -hls_time $SEGMENT_TIME \
|
|
-hls_playlist_type vod \
|
|
-hls_segment_filename "$output_dir/${video_id}_${height}p_%03d.ts" \
|
|
-master_pl_name "master.m3u8" \
|
|
-var_stream_map "v:0,name:${height}p" \
|
|
-c:a aac -b:a 128k \
|
|
"$output_dir/${video_id}_${height}p.m3u8"
|
|
done
|
|
|
|
# Create master playlist
|
|
echo "#EXTM3U" > "$output_dir/master.m3u8"
|
|
echo "#EXT-X-VERSION:3" >> "$output_dir/master.m3u8"
|
|
|
|
for i in "${!RESOLUTIONS[@]}"; do
|
|
local resolution=${RESOLUTIONS[$i]}
|
|
local bitrate=${BITRATES[$i]}
|
|
local width=$(echo $resolution | cut -d':' -f1)
|
|
local height=$(echo $resolution | cut -d':' -f2)
|
|
|
|
echo "#EXT-X-STREAM-INF:BANDWIDTH=$(echo $bitrate | sed 's/k/000/'),RESOLUTION=$resolution" >> "$output_dir/master.m3u8"
|
|
echo "${video_id}_${height}p.m3u8" >> "$output_dir/master.m3u8"
|
|
done
|
|
|
|
# Create a symlink for index.m3u8
|
|
ln -sf "master.m3u8" "$output_dir/index.m3u8"
|
|
|
|
echo " Transcoding complete for $video_id"
|
|
}
|
|
|
|
# Function to generate WebP thumbnails
|
|
generate_thumbnails() {
|
|
local input_file="$1"
|
|
local video_id=$(basename "$input_file" .mp4)
|
|
|
|
echo "Generating thumbnails for $input_file..."
|
|
|
|
# Generate thumbnail at 25% of the video duration
|
|
ffmpeg -y -i "$input_file" -ss $(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$input_file" | awk '{print $1/4}') \
|
|
-vframes 1 -vf "scale=640:-1" "$POSTER_OUTPUT_DIR/${video_id}.jpg"
|
|
|
|
# Convert to WebP with better quality
|
|
ffmpeg -y -i "$POSTER_OUTPUT_DIR/${video_id}.jpg" -vf "scale=640:-1" -quality 90 "$POSTER_OUTPUT_DIR/${video_id}.webp"
|
|
|
|
# Copy thumbnails to HLS directory for reference
|
|
cp "$POSTER_OUTPUT_DIR/${video_id}.webp" "$HLS_OUTPUT_DIR/$video_id/poster.webp"
|
|
cp "$POSTER_OUTPUT_DIR/${video_id}.jpg" "$HLS_OUTPUT_DIR/$video_id/poster.jpg"
|
|
|
|
echo " Thumbnail generation complete for $video_id"
|
|
}
|
|
|
|
# Process each video
|
|
for video_file in $VIDEO_SOURCE_DIR/*.mp4; do
|
|
if [ -f "$video_file" ]; then
|
|
transcode_to_hls "$video_file"
|
|
generate_thumbnails "$video_file"
|
|
fi
|
|
done
|
|
|
|
echo "All videos have been transcoded to HLS format and thumbnails generated."
|
|
echo "HLS streams are available in $HLS_OUTPUT_DIR"
|
|
echo "Thumbnails are available in $POSTER_OUTPUT_DIR" |