Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
#!/bin/bash
# Anh Nguyen <anh.ng8@gmail.com>
# 2016-04-30
# 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
#----------------------------------------------------------------
# SETTINGS
input_dir="/path/to/your/folder" # Replace this by a path to your folder /path/to/your/folder
n_files=10 # Replace this by a number of images
files=`ls ${input_dir}/*.jpg | head -${n_files}` # Change the file type to the correct type of your images
output_file="video.mp4" # Name of output video
crossfade=0.9 # Crossfade duration between two images
#----------------------------------------------------------------
# Making an ffmpeg script...
input=""
filters=""
output="[0:v]"
i=0
for f in ${files}; do
input+=" -loop 1 -t 1 -i $f"
next=$((i+1))
if [ "${i}" -ne "$((n_files-1))" ]; then
filters+=" [${next}:v][${i}:v]blend=all_expr='A*(if(gte(T,${crossfade}),1,T/${crossfade}))+B*(1-(if(gte(T,${crossfade}),1,T/${crossfade})))'[b${next}v];"
fi
if [ "${i}" -gt "0" ]; then
output+="[b${i}v][${i}:v]"
fi
i=$((i+1))
done
output+="concat=n=$((i * 2 - 1)):v=1:a=0,format=yuv420p[v]\" -map \"[v]\" ${output_file}"
script="ffmpeg ${input} -filter_complex \"${filters} ${output}"
echo ${script}
# Run it
eval "${script}"
@DavidOliver
Copy link

DavidOliver commented Jul 9, 2016

Hi @anguyen8. Thanks for this script.

Between each crossfade there is a pause of a second or two where the image is shown. How can I remove this please? I'm trying to fade multiple eight-second exposures of polar lights into each other to improve the sense of slowish movement.

Edit: I'm now accomplishing what I need to do with G'MIC.

@jeffehobbs
Copy link

Great script! Really helps with those complicated ffmpeg filter config statements.

@anguyen8
Copy link
Author

anguyen8 commented Sep 21, 2016

@DavidOliver: probably you got your solution by now. But I'd say it's the crossfade of 0.9 that you can tweak.

@kosar
Copy link

kosar commented Oct 1, 2016

@DavidOliver: I would appreciate if you could post how you did this in G'MIC. As far as I can tell it is not easy to do. I tried posting a question to their Google Group.
@anguyen8: I did something similar to this using Powershell -- I will try this now, using a *nix system.
EDIT: here is my super early super hacky version of this in Powershell. https://github.com/kosar/miv

@hasnhasan
Copy link

I'm getting an error. Could you help ?

Invalid file index 5 in filtergraph description [1:v][0:v]blend=all_expr='A*(if(gte(T,0.9),1,T/0.9))+B*(1-(if(gte(T,0.9),1,T/0.9)))'[b1v]; [2:v][1:v]blend=all_expr='A*(if(gte(T,0.9),1,T/0.9))+B*(1-(if(gte(T,0.9),1,T/0.9)))'[b2v]; [3:v][2:v]blend=all_expr='A*(if(gte(T,0.9),1,T/0.9))+B*(1-(if(gte(T,0.9),1,T/0.9)))'[b3v]; [4:v][3:v]blend=all_expr='A*(if(gte(T,0.9),1,T/0.9))+B*(1-(if(gte(T,0.9),1,T/0.9)))'[b4v]; [5:v][4:v]blend=all_expr='A*(if(gte(T,0.9),1,T/0.9))+B*(1-(if(gte(T,0.9),1,T/0.9)))'[b5v]; [0:v][b1v][1:v][b2v][2:v][b3v][3:v][b4v][4:v]concat=n=9:v=1:a=0,format=yuv420p[v].

@iBobik
Copy link

iBobik commented Mar 1, 2017

On line 46 I changed time to -t 15, so one image will be there shown for 15 seconds, but it prints very long output like this:

[Parsed_blend_5 @ 0x7fcdff606900] [framesync @ 0x7fcdff606ec8] Buffer queue overflow, dropping.
[Parsed_concat_8 @ 0x7fcdff609660] Buffer queue overflow, dropping.
[Parsed_blend_5 @ 0x7fcdff606900] [framesync @ 0x7fcdff606ec8] Buffer queue overflow, dropping.
[Parsed_concat_8 @ 0x7fcdff609660] Buffer queue overflow, dropping.
[Parsed_blend_5 @ 0x7fcdff606900] [framesync @ 0x7fcdff606ec8] Buffer queue overflow, dropping.
[Parsed_concat_8 @ 0x7fcdff609660] Buffer queue overflow, dropping.

Do you know how to fix it?

@MotionDesignStudio
Copy link

How can I control the display length of time for each image? Changing this input+=" -loop 1 -t 1 -i $f" to input+=" -loop 1 -t 15 -i $f" only makes the second image display 30 seconds and the third 45 seconds. So it adds 15 seconds to each image.

@KalpeshJadvani
Copy link

can you tell me how i can add mp3 file in this command ... plz i have done this script but i could not add mp3 file in this complex command ....

@ZuzooVn
Copy link

ZuzooVn commented Jul 15, 2017

@anguyen8: can you add more animation for ffmpeg slideshow?

@spiralofhope
Copy link

The URL can be shortened:

http://superuser.com/questions/833232/create-video-with-5-images-with-fadein-out-effect-in-ffmpeg/1071748#1071748
=>
http://superuser.com/questions/833232#1071748

@gcrowder1
Copy link

Thank you friends, your script successfully solved my problem. If the image size is different, an error will occur. But the problem is not big, I have processed the image to the same size. Thanks again

@shakram02
Copy link

Thank you so much, worked like a charm 🙏.
I converted it to python if anyone is interested, here

@Butateng
Copy link

Hey guys, I just wanna asked if this is feasible with ffmpeg. https://trello-attachments.s3.amazonaws.com/545a93cff0b222f456c5ad82/5d8cfc0d75e80e63dae2fe6a/5a523ed328f24b0454c5c56cd0ee68e6/23442279.mp4

I've been googling around finding on how to have smooth easing and effects on the video link above. I am really new to ffmpeg, please please yung help will be really meant a lot. Cheers!

@MrMegamind
Copy link

Guys thank you so much, can I attach bg voice or I have to attach later in an other command?

@rossomaltese
Copy link

Thanks @anguyen8 for the script, it worked like a charm!
I post a little patch I did to manage some ffmpeg parameters, remove some useless brackets and refactor the main loop a little bit; I mainly did it to better understand the ffmpeg use, so all the kudos go to you! ;-)
With this patch, the script uses all the .jpg files in the current directory.
NOTE: all the images must have the same size.

--- make_crossfade_ffmpeg_video_from_images.sh.orig	2022-10-18 11:11:33.851470982 +0200
+++ make_crossfade_ffmpeg_video_from_images.sh	2022-10-18 11:40:52.239914716 +0200
@@ -4,7 +4,7 @@
 # 2016-04-30
 # MIT License
 
-# This script takes in images from a folder and make a crossfade video from the images using ffmpeg.
+# This script takes in all .jpg from current 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.
@@ -27,40 +27,42 @@
 
 #----------------------------------------------------------------
 # SETTINGS
-input_dir="/path/to/your/folder"  # Replace this by a path to your folder /path/to/your/folder
-n_files=10                        # Replace this by a number of images
-files=`ls ${input_dir}/*.jpg | head -${n_files}`  # Change the file type to the correct type of your images
-output_file="video.mp4"           # Name of output video
-crossfade=0.9                     # Crossfade duration between two images
+if (($# != 3)); then
+  echo "usage: $0 time[s] crossfade[s] output"
+  exit 1
+fi
+files=(*.jpg)                     # Change the file type to the correct type of your images
+output_file="$3"                  # Name of output video
+crossfade=$2                      # Crossfade duration between two images
+time=$1
+
+if [[ -e $output_file ]]; then
+  echo "$0: file $output_file already exists." >&2
+  exit 2
+fi
 #----------------------------------------------------------------
 
 # Making an ffmpeg script...
-input=""
-filters=""
-output="[0:v]"
-
-i=0
-
-for f in ${files}; do
-  input+=" -loop 1 -t 1 -i $f"
-
-  next=$((i+1))
-  if [ "${i}" -ne "$((n_files-1))" ]; then
-    filters+=" [${next}:v][${i}:v]blend=all_expr='A*(if(gte(T,${crossfade}),1,T/${crossfade}))+B*(1-(if(gte(T,${crossfade}),1,T/${crossfade})))'[b${next}v];"
-  fi
-
-  if [ "${i}" -gt "0" ]; then
-    output+="[b${i}v][${i}:v]"
-  fi
-
-  i=$((i+1))
+input="-hide_banner"
+for ((i = 0; i < ${#files[*]}; ++i)); do
+  input+=" -loop 1 -t $time -i "\'"${files[i]}"\'
 done
 
-output+="concat=n=$((i * 2 - 1)):v=1:a=0,format=yuv420p[v]\" -map \"[v]\" ${output_file}"
+filters=`mktemp`
+expr="if(gte(T,$crossfade),1,T/$crossfade)"
+output="[0:v]"
+{
+  for ((i = 1; i < ${#files[*]}; ++i)); do
+    echo "[$i:v][$((i-1)):v]blend=all_expr='A*($expr)+B*(1-($expr))'[b${i}v];"
+    output+="[b${i}v][$i:v]"
+  done
+  echo "$output"
+  echo "concat=n=$((${#files[*]} * 2 - 1)):v=1:a=0,format=yuv420p[v]"
+} >> $filters
 
-script="ffmpeg ${input} -filter_complex \"${filters} ${output}"
+script="ffmpeg $input -filter_complex_script $filters -map '[v]' "\'"$output_file"\'
 
-echo ${script}
+echo "$script"
 
 # Run it
-eval "${script}"
\ No newline at end of file
+eval "$script"

@anguyen8
Copy link
Author

Thanks @rossomaltese for sharing with us your updated/improved version!! :)

@martin3000
Copy link

martin3000 commented Jan 27, 2023

I have 30 jpgs and the script eats up all of the 8 GB system memory and then the machine crashes.
So I do

script="systemd-run --user --scope -p MemoryMax=2G -p MemorySwapMax=2G ffmpeg  ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment