Skip to content

Instantly share code, notes, and snippets.

@majal
Forked from sgqy/minterpolate.sh
Last active May 1, 2024 12:00
Show Gist options
  • Save majal/1e63a511b41faeae188083777f8e4b46 to your computer and use it in GitHub Desktop.
Save majal/1e63a511b41faeae188083777f8e4b46 to your computer and use it in GitHub Desktop.
Multi-threaded minterpolate in ffmpeg
#!/bin/bash
# Multicore minterpolate in ffmpeg
# Just slice & process & concat
# NB: The concat points between slices may be weird
# Default arguments
ff=/usr/bin/ffmpeg
fps=60
dur=00:00:10
enc=libx264
[ "${OSTYPE}" == "darwin"* ] && task=$(( $(sysctl -n hw.logicalcpu) - 2 )) || task=$(( $(nproc --all) - 2 ))
# Reference: https://ffmpeg.org/ffmpeg-filters.html#minterpolate
m_args=":mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1"
ff_args=( -hide_banner -loglevel level+warning -nostats -y )
ff_args_enc=( -crf 20 -preset slow )
################################################################################
# Usage notes
err_args () {
printf "\nUsage: %s -i INPUT_FILE [ARGUMENTS] OUTPUT_FILENAME\n" "$(basename "${0}")"
printf "\n"
printf "Arguments:\t\t\t\t\t[default values]\n"
echo
printf "\t-b str\tffmpeg binary path\t\t[%s]\n" "${ff}"
printf "\t-d hms\tSlices duration [hour:min:sec]\t[%s]\n" "${dur}"
printf "\t-e str\tEncoder name\t\t\t[%s]\n" "${enc}"
printf "\t-f str\tffmpeg encoding arguments\t[%s]\n" "'${ff_args_enc[*]}'"
printf "\t-p int\tProcess/thread count. 0 is max\t[%s]\n" "${task}"
printf "\t-r int\tTarget FPS\t\t\t[%s]\n" "${fps}"
printf "\t-m str\tminterpolate arguments\t\t[%s]\n" "'${m_args}'"
printf "\t-s hms\tStart point of source video\t[00:00:00]\n"
printf "\t-t hms\tEnd point of source video\t[until end of the video]\n"
echo
exit 1
}
# Clean slices and temporary files
clean () {
rm -f _cut.mp4
rm -f _s_?????.mp4
rm -f _m__s_?????.mp4
rm -f _list.txt
}
while getopts 'i:r:s:t:e:p:d:b:m:f' OPTION; do
case $OPTION in
i)
in=$OPTARG # input file
;;
r)
fps=$OPTARG # target fps, fraction is also OK
;;
s)
ss=$OPTARG # begin time of input
;;
t)
to=$OPTARG # end time of input
;;
e)
enc=$OPTARG # encoder
;;
p)
task=$((OPTARG)) # process count, xargs use max when it is 0
;;
d)
dur=$OPTARG # parallel block length
;;
b)
ff=$OPTARG # ffmpeg binary
;;
m)
m_args=$OPTARG # minterpolate arguments
;;
f)
ff_args_enc=$OPTARG # ffmpeg encoding arguments
;;
*)
err_args
;;
esac
done
shift $((OPTIND - 1))
# Set output file
out="${1}"
# Select input file
temp="${in}"
# Check arguments and files
if [ -z "${in}" ]; then
echo
echo "$(basename ${0}): missing input file"
err_args
fi
if [ -z "${out}" ]; then
echo
echo "$(basename ${0}): missing output filename"
err_args
fi
# Set start and end duration for minterpolation
duration=()
if [ -n "${ss}" ]; then
duration+=(-ss)
duration+=("${ss}")
temp=_cut.mp4
fi
if [ -n "${to}" ]; then
duration+=(-to)
duration+=("${to}")
temp=_cut.mp4
fi
################################################################################
clean
echo
echo "Processing ${in} ..."
echo
# Use origin file or cut a part from origin file
if [ "${temp}" == _cut.mp4 ]; then
"${ff}" "${ff_args[@]}" "${duration[@]}" -i "${in}" -c copy "${temp}"
fi
# Make slices for parallel use
"${ff}" "${ff_args[@]}" -i "${temp}" -c copy -f segment -segment_time "${dur}" '_s_%05d.mp4'
xargs_cmd="/usr/bin/nice -n 19 ${ff} ${ff_args[@]} -i _fname -vf minterpolate=fps=${fps}${m_args} -c:a copy -c:v ${enc} ${ff_args_enc[@]} _m__fname"
# Minterpolate the slices. Get coffee, go out and exercise, or sleep. This will a while.
find . -name '_s_?????.mp4' | sed 's@^.*/@@g' | xargs -I "_fname" -t -P ${task} -- ${xargs_cmd} && echo "Processed slice: $(ls _m__s_?????.mp4 | wc -l) of $(ls _s_?????.mp4 | wc -l) ..."
# Make a list of minterpolated slices
printf "file '%s'\n" ./_m__s_?????.mp4 > _list.txt
# Concatenate the result
"${ff}" "${ff_args[@]}" -f concat -safe 0 -i _list.txt -c copy "${out}"
echo
echo "Processing of ${in} complete. Created ${out}."
echo
echo "################################################################################"
echo
clean
@Usulyre
Copy link

Usulyre commented Feb 20, 2023

How would one use this script in ffmpeg in windows os?

@majal
Copy link
Author

majal commented Feb 20, 2023

How would one use this script in ffmpeg in windows os?

Will this help? https://learn.microsoft.com/en-us/windows/wsl/install

@Usulyre
Copy link

Usulyre commented Feb 20, 2023

Maybe I could turn it into a .bat file? Adjusting some parameters in the script?

Also, does this script run minterpolate faster, is that the point? Can one use it in realtime (with like ffplay) and it will run faster than usual?

@majal
Copy link
Author

majal commented Mar 10, 2023

Maybe I could turn it into a .bat file? Adjusting some parameters in the script?

Sure. Please link here if you've done this. Will surely be helpful to Windows users.

Also, does this script run minterpolate faster, is that the point?

Yes it runs in parallel, thus faster if you have more processor threads. And that is if you're OK with the little quirks on the joining points of the splits.

Can one use it in realtime (with like ffplay) and it will run faster than usual?

Nope. Not at the moment. Minterpolate is CPU intensive. So it processes the video (much) slower than playing it realtime.

@Usulyre
Copy link

Usulyre commented Mar 10, 2023

Maybe I could turn it into a .bat file? Adjusting some parameters in the script?

Sure. Please link here if you've done this. Will surely be helpful to Windows users.

Also, does this script run minterpolate faster, is that the point?

Yes it runs in parallel, thus faster if you have more processor threads. And that is if you're OK with the little quirks on the joining points of the splits.

Can one use it in realtime (with like ffplay) and it will run faster than usual?

Nope. Not at the moment. Minterpolate is CPU intensive. So it processes the video (much) slower than playing it realtime.

Maybe I could turn it into a .bat file? Adjusting some parameters in the script?

Sure. Please link here if you've done this. Will surely be helpful to Windows users.

Also, does this script run minterpolate faster, is that the point?

Yes it runs in parallel, thus faster if you have more processor threads. And that is if you're OK with the little quirks on the joining points of the splits.

Can one use it in realtime (with like ffplay) and it will run faster than usual?

Nope. Not at the moment. Minterpolate is CPU intensive. So it processes the video (much) slower than playing it realtime.

Isn't minterpolate only slow because it's single thread-cpu?

It by itself doesn't utilize full cpu and/or gpu yet?

I tried it with ffplay on windows for realtime playback.

How can I use the script with ffplay? I want to see if it runs faster

@majal
Copy link
Author

majal commented Mar 10, 2023

How can I use your script with ffplay?

The script will not work with ffplay. Because ffplay will read the video from start to finish, while the script cuts the video into pieces and runs minterpolate on each slice in parallel.

@anttiryt
Copy link

anttiryt commented Jun 2, 2023

Have you been satisfied with script?
How good is the segmentation cut and concatenate, does it need manual work to make it smooth?
I would ditch the dur parameter and use videolength / nproc, or is there complications?

@majal
Copy link
Author

majal commented Jun 4, 2023

Hi @anttiryt! Satisfied? Honestly I'm now not using the script because I don't like those missed single frames during concatenate. I still have no idea on how to fix those frames on the concatenate points.

You know what? I think the videolength / nproc is a much better idea.

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