Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save froh/eb66eb2aea127689f14a4f2dae074142 to your computer and use it in GitHub Desktop.
Save froh/eb66eb2aea127689f14a4f2dae074142 to your computer and use it in GitHub Desktop.
#!/bin/bash
# Anh Nguyen <[email protected]>
# 2016-04-30
# Susanne Oberhauser-Hirschoff <[email protected]>
# MIT License
# This script takes in same-size images from a folder and make a crossfade video from the images using ffmpeg.
# Make sure you have ffmpeg installed before running.
# The output command looks something like the below, but for as many images as you have in the folder.
# See the answer by LordNeckbeard at:
# http://superuser.com/questions/833232/create-video-with-5-images-with-fadein-out-effect-in-ffmpeg/1071748#1071748
#
#
# ffmpeg \
# -loop 1 -t 1 -i 001.png \
# -loop 1 -t 1 -i 002.png \
# -loop 1 -t 1 -i 003.png \
# -loop 1 -t 1 -i 004.png \
# -loop 1 -t 1 -i 005.png \
# -filter_complex \
# "[1:v][0:v]blend=all_expr='A*(if(gte(T,0.5),1,T/0.5))+B*(1-(if(gte(T,0.5),1,T/0.5)))'[b1v]; \
# [2:v][1:v]blend=all_expr='A*(if(gte(T,0.5),1,T/0.5))+B*(1-(if(gte(T,0.5),1,T/0.5)))'[b2v]; \
# [3:v][2:v]blend=all_expr='A*(if(gte(T,0.5),1,T/0.5))+B*(1-(if(gte(T,0.5),1,T/0.5)))'[b3v]; \
# [4:v][3:v]blend=all_expr='A*(if(gte(T,0.5),1,T/0.5))+B*(1-(if(gte(T,0.5),1,T/0.5)))'[b4v]; \
# [0:v][b1v][1:v][b2v][2:v][b3v][3:v][b4v][4:v]concat=n=9:v=1:a=0,format=yuv420p[v]" -map "[v]" out.mp4
#set -o xtrace
#----------------------------------------------------------------
# SETTINGS
: ${input_dir:=.}
: ${input_glob:="*.png"}
files=(${input_dir}/${input_glob}) # Change the file type to the correct type of your images
n_files=$((${#files[@]})) # Replace this by a number of images
#: ${output_size:=2560:1440}
: ${output_size:=3840:2160}
: ${output_basename:=video}
: ${output_type:=gif}
: ${output_file:=${output_basename}-${output_size/:/x}.${output_type}} # Name of output video
: ${crossfade:=0.75} # Crossfade duration between two images
: ${first_extra_rep=2}
: ${last_extra_rep=8}
#----------------------------------------------------------------
# Making an ffmpeg script...
input=()
loop_filters=()
blend_filters=()
function L_i_stay_N () {
i=$1 N=$2
eval echo "[L${i}stay{1..$N}]"
}
first_extra_rep_L=($(L_i_stay_N 0 $first_extra_rep))
concat_filter=${first_extra_rep_L[*]}
last_file=$((n_files - 1))
last_extra_rep_L=($(L_i_stay_N $last_file $last_extra_rep))
i=0
for f in "${files[@]}"; do
input+=("\\\\
-f image2 -i '$f'")
#
loop_filters+=("\
[${i}:v] scale=${output_size},loop=loop=50:size=1,trim=duration=${crossfade},")
if [ $i -eq 0 ]
then
loop_filters+=("split=$((first_extra_rep + 2))" ${first_extra_rep_L[*]} "[L${i}stay][L${i}down];
")
elif [ $i -eq $last_file ]
then
loop_filters+=("split=$((2 + last_extra_rep)) [L${last_file}up][L${last_file}stay]" ${last_extra_rep_L[*]} ";
")
else
loop_filters+=("split=3 [L${i}up][L${i}stay][L${i}down];
")
fi
next=$((i+1))
if [ "${i}" -ne "$last_file" ]; then
blend_filters+=("\
[L${next}up][L${i}down] blend=all_expr='A*(if(gte(T,${crossfade}),1,T/${crossfade}))+B*(1-(if(gte(T,${crossfade}),1,T/${crossfade})))' [blend${i}_${next}];
")
concat_filter+=("
[L${i}stay]
[blend${i}_${next}]")
fi
i=$((i+1))
done
concat_filter+=("
[L${last_file}stay]
" ${last_extra_rep_L[*]})
concat_filter+=("
concat=unsafe=1:n=$((last_file * 2 + 1 + first_extra_rep + last_extra_rep)):v=1:a=0,format=yuv420p[v]")
script="ffmpeg ${input[*]} \\\\
-filter_complex \"
${loop_filters[*]}
${blend_filters[*]}
${concat_filter[*]}
\" \\\\
-map \"[v]\" $@ ${output_file}"
printf "${script}\n"
# Run it
#eval "${script}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment