Skip to content

Instantly share code, notes, and snippets.

@cpcloud
Created January 19, 2021 15:20
Show Gist options
  • Save cpcloud/32bf024bb5aa91a7b63febd67b0ea9a6 to your computer and use it in GitHub Desktop.
Save cpcloud/32bf024bb5aa91a7b63febd67b0ea9a6 to your computer and use it in GitHub Desktop.
hardware accelerated ffmpeg hls mosaic
#!/usr/bin/env nix-shell
#!nix-shell --pure -i bash -p ffmpeg-full -p bc -p findutils -p ripgrep
set -euxo pipefail
function join_by {
local d=$1
shift
local f=$1
shift
printf %s "$f" "${@/#/$d}"
}
data_dir="$1"
filter="$(mktemp)"
files=($(find "$data_dir" -regextype sed -regex '.*/cam_[0-9]\+\.m3u8' | sort -n))
inputs=()
cams=()
for file in "${files[@]}"; do
inputs+=(-hwaccel cuvid -hwaccel_output_format cuda -c:v h264_cuvid -i "$file")
cam=$(rg -o --pcre2 '\d+(?=\.m3u8)' <<<"$file")
cams+=($cam)
printf "[$cam:v] scale_npp=1280:720, hwdownload, format=nv12, drawtext=text='$cam': x=0: y=0: fontcolor=white: fontsize=100: box=1: boxcolor=black@0.4: boxborderw=5 [a$cam];" >>"$filter"
done
printf "[a%d]" "${cams[@]}" >>"$filter"
num_inputs="${#files[@]}"
width=$(bc <<<"scale=0; sqrt($num_inputs) + 1")
height=$width
layout=()
for y in $(seq 0 $(((height - 1)))); do
ys=($(seq 0 $(((y - 1)))))
if [ "${#ys[@]}" -eq 0 ]; then
right="0"
else
right=$(join_by "+" "${ys[@]/#/h}")
fi
for x in $(seq 0 $(((width - 1)))); do
xs=($(seq 0 $(((x - 1)))))
if [ "${#xs[@]}" -eq 0 ]; then
left="0"
else
left=$(join_by "+" "${xs[@]/#/w}")
fi
layout+=("${left}_${right}")
done
done
layout_s=$(join_by "|" "${layout[@]}")
printf "xstack=inputs=$num_inputs:layout=$layout_s[out]" >>"$filter"
ffmpeg ${inputs[@]} -c:v h264_nvenc -filter_complex_script "$filter" -map '[out]' -f matroska - | ffplay -i -
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment