toolkit / zsh /png2mp4.zsh
k4d3's picture
png2mp4 fun
6f44ddc
raw
history blame
6.58 kB
# png2mp4_x265()
# Converts a series of PNG images to an MP4 video using x265 encoding
#
# Usage: png2mp4_x265 [--max <number>] [--step <number>] [--repeat <number>]
#
# Options:
# --max <number> : Maximum number of images to process
# --step <number> : Multiplier for step count in overlay text (default: 1)
# --repeat <number> : Number of times to repeat each image (default: 1)
#
# This function:
# 1. Deactivates conda environment
# 2. Finds all PNG files in the current directory
# 3. Uses the current directory name as the output filename prefix
# 4. Uses ffmpeg to create an MP4 with x265 encoding, including:
# - Frame rate of 60 fps
# - Image scaling to 1024x1024
# - Step count overlay text (divided by 1,000,000 and truncated to remove 6 zeros and decimal places)
# - High-quality encoding settings
# 5. Adds padding and fade-out effect to the final video
# 6. Reactivates conda environment
#
# Requirements:
# - ffmpeg with libx265 support
# - Inconsolata-Light.ttf font in /usr/share/fonts/TTF/
png2mp4_x265() {
conda deactivate
local step_multiplier=1
local repeat=1
local frame_rate=60
local resolution="1024x1024"
while [[ "$#" -gt 0 ]]; do
case $1 in
--step) step_multiplier="$2"; shift ;;
--repeat) repeat="$2"; shift ;;
*) echo "Unknown parameter passed: $1"; return 1 ;;
esac
shift
done
output_filename="$(basename "$(pwd)")_x265.mp4"
echo "Output filename: $output_filename"
local nframes=$(find . -type f -name '*.png' | wc -l)
local duration=$(($nframes * $repeat / ${frame_rate}.))
local fade_start=$((duration + 3))
echo "Found $nframes for a duration of $duration seconds"
echo "Running ffmpeg with x265 encoding..."
local font=/usr/share/fonts/TTF/Inconsolata-Light.ttf
local drawtext="drawtext=fontfile=${font}:text='Steps\: %{eif\\:trunc(n*$step_multiplier)\\:u\\:3}':x=10:y=h-th-10:fontsize=24:fontcolor=white"
local fadeout="tpad=stop_mode=clone:stop_duration=8,fade=t=out:st=${fade_start}:d=5"
local encoder=(
-pix_fmt yuv420p
-c:v libx265
-preset slower
-tune animation
-crf 22
-x265-params "keyint=${repeat}:min-keyint=$((repeat-1)):scenecut=0:ref=5:bframes=8:b-adapt=2:rc-lookahead=$((2*repeat)):lookahead-slices=4:aq-mode=3:aq-strength=0.8:deblock=-1,-1:sao=0"
)
ffmpeg -framerate "$frame_rate/$repeat" -pattern_type glob -i "*.png" \
-vf "scale=${resolution},${drawtext},fps=${frame_rate},${fadeout}" \
"${encoder[@]}" -y sample_x265.mp4
if [ $? -ne 0 ]; then
echo "Error: ffmpeg command failed."
return 1
fi
conda activate
echo "Process completed successfully."
}
# png2mp4()
# Converts a series of PNG images to an MP4 video using x264 encoding
#
# Usage: png2mp4 [--max <number>] [--step <number>] [--repeat <number>]
#
# Options:
# --max <number> : Maximum number of images to process
# --step <number> : Multiplier for step count in overlay text (default: 1)
# --repeat <number> : Number of times to repeat each image (default: 1)
#
# This function:
# 1. Deactivates conda environment
# 2. Creates a temporary directory for processing
# 3. Finds all PNG files in the current directory
# 4. Uses the current directory name as the output filename prefix
# 5. Copies and optionally repeats images to the temp directory
# 6. Uses ffmpeg to create an MP4 with x264 encoding, including:
# - Frame rate of 60 fps
# - Image scaling to 1024x1024
# - Step count overlay text (divided by 1,000,000 and truncated to remove 6 zeros and decimal places)
# - CRF value of 28 for compression
# 7. Adds padding and fade-out effect to the final video
# 8. Cleans up temporary files
# 9. Reactivates conda environment
#
# Requirements:
# - ffmpeg with libx264 support
# - bc (basic calculator)
# - Inconsolata-Light.ttf font in /usr/share/fonts/TTF/
png2mp4() {
conda deactivate
local max_images=""
local step_multiplier=1
local repeat=1
local temp_dir="/home/kade/.local/tmp"
while [[ "$#" -gt 0 ]]; do
case $1 in
--max) max_images="$2"; shift ;;
--step) step_multiplier="$2"; shift ;;
--repeat) repeat="$2"; shift ;;
*) echo "Unknown parameter passed: $1"; return 1 ;;
esac
shift
done
echo "Creating temporary directory..."
mkdir -p "$temp_dir"
echo "Checking for PNG files..."
png_files=($(/usr/bin/env ls *.png 2>/dev/null))
if [ ${#png_files[@]} -eq 0 ]; then
echo "Error: No PNG files found in the current directory."
return 1
fi
echo "Setting output filename..."
output_filename="$(basename "$(pwd)").mp4"
echo "Output filename: $output_filename"
echo "Creating repeated images..."
for img in "${png_files[@]}"; do
for i in $(seq 1 $repeat); do
cp "$img" "$temp_dir/${img%.*}_${i}.png"
done
done
echo "Running ffmpeg..."
if [[ -n "$max_images" ]]; then
ffmpeg -framerate 60 -pattern_type glob -i "$temp_dir/*.png" -vf "scale=1024x1024,select='not(mod(n\,$max_images))',drawtext=fontfile=/usr/share/fonts/TTF/Inconsolata-Light.ttf:text='Steps\: %{expr\:trunc(n*$step_multiplier/$repeat/1000000)}':x=10:y=h-th-10:fontsize=24:fontcolor=white" -crf 28 \
-c:v libx264 -pix_fmt yuv420p -y "$temp_dir/temp.mp4"
else
ffmpeg -framerate 60 -pattern_type glob -i "$temp_dir/*.png" -vf "scale=1024x1024,drawtext=fontfile=/usr/share/fonts/TTF/Inconsolata-Light.ttf:text='Steps\: %{expr\:trunc(n*$step_multiplier/$repeat/1000000)}':x=10:y=h-th-10:fontsize=24:fontcolor=white" -crf 28 \
-c:v libx264 -pix_fmt yuv420p -y "$temp_dir/temp.mp4"
fi
if [ $? -ne 0 ]; then
echo "Error: ffmpeg command failed."
rm -rf "$temp_dir"
return 1
fi
echo "Processing final video..."
duration=$(ffmpeg -i "$temp_dir/temp.mp4" 2>&1 | grep 'Duration' | awk '{print $2}' | tr -d , | awk -F: '{print ($1 * 3600) + ($2 * 60) + $3}')
fade_start=$(echo "$duration + 3" | bc)
ffmpeg -i "$temp_dir/temp.mp4" -vf "tpad=stop_mode=clone:stop_duration=8,fade=t=out:st=$fade_start:d=5" -c:v libx264 -pix_fmt yuv420p -y "$output_filename"
if [ $? -ne 0 ]; then
echo "Error: Final ffmpeg processing failed."
rm -rf "$temp_dir"
return 1
fi
echo "Cleaning up temporary files..."
rm -rf "$temp_dir"
conda activate
echo "Process completed successfully."
}