init
This commit is contained in:
commit
353f528154
5 changed files with 137 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
out/
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2022 nullprop
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
5
README.md
Normal file
5
README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# ffmpeg-life
|
||||||
|
|
||||||
|
Conway's Game of Life in ffmpeg.
|
||||||
|
|
||||||
|
See it in action [here](https://nullprop.sh/ffmpeg-life/).
|
BIN
gosper.png
Normal file
BIN
gosper.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 674 B |
110
life.sh
Executable file
110
life.sh
Executable file
|
@ -0,0 +1,110 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
#
|
||||||
|
# script for Conway's Game of Life using ffmpeg filters
|
||||||
|
#
|
||||||
|
# usage: life.sh <input_image> <num_frames> <fps> <scale>
|
||||||
|
#
|
||||||
|
# example: life.sh gosper.png 200 12 10
|
||||||
|
# would produce a 200 frame video of life from gosper.png
|
||||||
|
# at 12 fps and 10x resolution of the original image.
|
||||||
|
#
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
#
|
||||||
|
# nullprop - 2022
|
||||||
|
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ "$#" -ne 4 ]; then
|
||||||
|
echo "invalid number of parameters"
|
||||||
|
echo "usage: life.sh <input_image> <num_frames> <fps> <scale>"
|
||||||
|
exit
|
||||||
|
fi
|
||||||
|
|
||||||
|
INPUT=$1
|
||||||
|
FRAMES=$2
|
||||||
|
FPS=$3
|
||||||
|
SCALE=$4
|
||||||
|
|
||||||
|
rm -rf ./out
|
||||||
|
mkdir out
|
||||||
|
cp $INPUT out/frame-00000.png
|
||||||
|
|
||||||
|
# check if pixel (X, Y) is alive
|
||||||
|
is_alive () {
|
||||||
|
echo "\
|
||||||
|
eq( r(X,Y), 0)*\
|
||||||
|
eq( g(X,Y), 0)*\
|
||||||
|
eq( b(X,Y), 0)\
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
# check if pixel (X, Y) with offset ($1, $2) is alive.
|
||||||
|
# if position is outside image bounds, it is considered dead.
|
||||||
|
is_alive_off () {
|
||||||
|
echo "\
|
||||||
|
eq( r(X$1,Y$2), 0)*\
|
||||||
|
eq( g(X$1,Y$2), 0)*\
|
||||||
|
eq( b(X$1,Y$2), 0)*\
|
||||||
|
lt(X$1, W)*\
|
||||||
|
gte(X$1, 0)*\
|
||||||
|
lt(Y$2, H)*\
|
||||||
|
gte(Y$2, 0)\
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
# check if pixel (X, Y) has $1 neighbours
|
||||||
|
has_neighbours () {
|
||||||
|
echo "\
|
||||||
|
eq(\
|
||||||
|
$1,\
|
||||||
|
$(is_alive_off -1 -1) +\
|
||||||
|
$(is_alive_off -1 +0) +\
|
||||||
|
$(is_alive_off -1 +1) +\
|
||||||
|
$(is_alive_off +0 -1) +\
|
||||||
|
$(is_alive_off +0 +1) +\
|
||||||
|
$(is_alive_off +1 -1) +\
|
||||||
|
$(is_alive_off +1 +0) +\
|
||||||
|
$(is_alive_off +1 +1)\
|
||||||
|
)\
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
# should the pixel (X, Y) be alive?
|
||||||
|
should_live () {
|
||||||
|
echo "\
|
||||||
|
$(is_alive)*$(has_neighbours 2) +\
|
||||||
|
$(is_alive)*$(has_neighbours 3) +\
|
||||||
|
ifnot($(is_alive), $(has_neighbours 3))
|
||||||
|
"
|
||||||
|
}
|
||||||
|
|
||||||
|
# load image from $1,
|
||||||
|
# step the game forward,
|
||||||
|
# and save image to $2
|
||||||
|
step () {
|
||||||
|
ffmpeg \
|
||||||
|
-i $1 \
|
||||||
|
-vf \
|
||||||
|
geq="\
|
||||||
|
r='if( $(should_live), 0, 255 )':\
|
||||||
|
b='if( $(should_live), 0, 255 )':\
|
||||||
|
g='if( $(should_live), 0, 255 )':\
|
||||||
|
a=255:
|
||||||
|
interpolation=nearest" \
|
||||||
|
$2
|
||||||
|
}
|
||||||
|
|
||||||
|
# generate frames
|
||||||
|
for ((i=0; i<FRAMES; i++))
|
||||||
|
do
|
||||||
|
j=$((i+1))
|
||||||
|
printf -v i_str "%05d" $i
|
||||||
|
printf -v j_str "%05d" $j
|
||||||
|
step out/frame-$i_str.png out/frame-$j_str.png
|
||||||
|
done
|
||||||
|
|
||||||
|
# combine to video
|
||||||
|
ffmpeg -framerate $FPS -pattern_type glob -i 'out/frame-*.png' -c:v libx264 -pix_fmt yuv420p -vf scale="'$SCALE*iw:$SCALE*ih:flags=neighbor'" out/life.mp4
|
Loading…
Add table
Add a link
Reference in a new issue