Skip to content

Instantly share code, notes, and snippets.

@nin-jat
Created September 27, 2021 02:30
Show Gist options
  • Save nin-jat/7946d50ca41b73d4102b438f7b45c2a9 to your computer and use it in GitHub Desktop.
Save nin-jat/7946d50ca41b73d4102b438f7b45c2a9 to your computer and use it in GitHub Desktop.
#!/bin/bash
# This script content aware/steam carves frames from the provided video.
# It works by exploding each frame into a bmp. Passing each bmp through
# imgagemagick's convert-im6 program set to screw with each frame.
# The lastly, combine the frames back into a video with the audio from
# to source video file.
# As you can see, most of this script is inspired by what's found at
# https://gitgud.io/-/snippets/498, In-fact the ffprobe and last ffmpeg
# command was copied over. My version just adds some extra bits to
# improve my "meme" production.
# How many processes should we run until we wait for them to complete.
maxProcesses=18
## === Prepare to do processing ===
# Configure glob to return nothing if nothing is found.
shopt -s nullglob
# Get the filename from the 1st argument.
filename="${1%.*}"
# Prepare our directories for the frames.
mkdir ./frames
mkdir ./frames/"$filename"
mkdir ./frames/"$filename"/liquid
# Grab the FPS from the source video (1st arg.) as we need it to reconstruct
# the video at the end.
fps=$(ffprobe -v 0 -of csv=p=0 -select_streams v:0 -show_entries stream=r_frame_rate "$1")
# Strip the frames from the source video.
ffmpeg -i "$1" "frames/$filename/%06d.bmp"
# Cound the frames in the folder.
totalFrames=$(ls ./frames/"$filename"/*.bmp | wc -l)
# Get the size of the image.
size=$(identify -format "%[fx:w]x%[fx:h]" ./frames/"$filename"/000001.bmp)
## === Doing the processing ===
i=1
t=0
for f in "./frames/$filename/"*.bmp; do
# Calculate how much scaling we do based on how far through the frames we are.
let "scale=512 - ($i * 340 / $totalFrames)"
# Make a filename to dump the new frame into.
frame_name=./frames/"$filename"/liquid/$(printf %06d $i).bmp
# The magick (ha get it) happens here. We run it in the background too.
convert-im6 "$f" -liquid-rescale "$scale"x"$scale" -resize $size\! "$frame_name" &
# Increment our frame "I"ncrement and "C"oncurrent processes counter.
((i++))
((c++))
# When our concurrent processes exceeds our limit, wait until the finish and
# reset our counter.
if (( $c > $maxProcesses )); then
echo "Processing batch $i/$totalFrames"
wait
c=0
fi
done
# Hold up, wait a minute.
# Wait for any background processes to finish before we re combine the frames.
wait
# Convert the images into a video again and merge the audio from the source back in.
ffmpeg -framerate "$fps" -thread_queue_size 1024 -i ./frames/"$filename"/liquid/%06d.bmp -thread_queue_size 1024 -i "$1" -c:v libx264 -preset slow -crf 23 -pix_fmt yuv420p -map "0:v:0" -map "1:a:0?" -y "./liquid_$filename.mp4"
# Delete all the left over junk.
rm -rf ./frames/"$filename"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment