ffmpeg-effect - annna - Annna the nice friendly bot. HTML git clone git://bitreich.org/annna/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/annna/ DIR Log DIR Files DIR Refs DIR Tags DIR README --- ffmpeg-effect (6929B) --- 1 #!/bin/sh 2 # modify a video input file with an effect. 3 # requirements: ffmpeg, ffprobe. 4 5 ffmpeg_common="${FFMPEG_EFFECT_COMMON:-ffmpeg -n -loglevel error}" 6 ffprobe_common="${FFMPEG_EFFECT_FFPROBE:-ffprobe -v error -of default=noprint_wrappers=1:nokey=1}" 7 mediadir="${FFMPEG_EFFECT_MEDIA_DIR:-/home/annna/bin/modules/filter-media}" 8 repeats=5 9 10 usage() { 11 printf 'usage: %s [-n REPEATS] FILTER infile outfile\n' "${0##*/}" 1>&2 12 exit 1 13 } 14 15 is_image() { 16 mimetype="$(file -ib "$1")" 17 case "${mimetype}" in 18 image/*) 19 return 0;; 20 esac 21 return 1 22 } 23 24 has_audio() { 25 ffprobe "$1" 2>&1 | grep -qE 'Stream .* Audio: ' 26 } 27 28 replace_audio() { 29 $ffmpeg_common -i "$1" -i "$2" \ 30 -c:v copy -map 1:v:0 -map 0:a:0 -shortest \ 31 "$3" </dev/null 32 } 33 34 side_by_side() { 35 $ffmpeg_common -i "$1" -i "$2" \ 36 -filter_complex " 37 amix=inputs=2:duration=shortest; \ 38 [1:v][0:v] scale2ref=oh*mdar:h=in_h:[v1][v0]; 39 [v0][v1] hstack=shortest=1, 40 scale='2*trunc(iw/2)':'2*trunc(ih/2)'" \ 41 -shortest \ 42 "$3" </dev/null 43 } 44 45 mix_audio() { 46 if has_audio "$2"; then 47 $ffmpeg_common -i "$1" -i "$2" \ 48 -filter_complex "amerge=inputs=2" \ 49 "$3" </dev/null 50 else 51 replace_audio "$1" "$2" "$3" 52 fi 53 } 54 55 mix_audio_video() { 56 if has_audio "$2"; then 57 $ffmpeg_common -i "$2" \ 58 -i "$1" \ 59 -filter_complex " 60 [0:v] scale=w=${4:-1920}:h=${5:-1080}, pad=w=${4:-1920}:h=${5:-1080} [video0]; 61 [video0][1:v] blend=all_mode=average:shortest=1; 62 amix=inputs=2:duration=shortest:weights=3 2" \ 63 "$3" </dev/null 64 else 65 $ffmpeg_common -i "$2" \ 66 -i "$1" \ 67 -filter_complex " 68 [0:v] scale=w=${4:-1920}:h=${5:-1080}, pad=w=${4:-1920}:h=${5:-1080} [video0]; 69 [video0][1:v] blend=all_mode=average:shortest=1" \ 70 "$3" </dev/null 71 fi 72 } 73 74 replace_face() { 75 face_replacement="$1" 76 input="$2" 77 output="$3" 78 79 if is_image "$input" 80 then 81 ext="${input##*.}" 82 tmp=/tmp/replace_face_$$.$ext 83 else 84 tmp="/tmp/replace_face_$$.mkv" 85 fi 86 87 $HOME/.local/bin/deface "$input" --replacewith img \ 88 --replaceimg "$face_replacement" -o "$tmp" >/dev/null 2>&1 89 if has_audio "$input"; 90 then 91 replace_audio "$input" "$tmp" "$output" 92 rm -f "$tmp" 93 else 94 mv "$tmp" "$output" 95 fi 96 } 97 98 process_filter() { 99 # Filters which do not require image2mkv 100 case "$1" in 101 smith) 102 replace_face "${mediadir}/smith.png" "$2" "$3" 103 return 0;; 104 wat) 105 replace_face "${mediadir}/wat.png" "$2" "$3" 106 return 0;; 107 zucc) 108 replace_face "${mediadir}/zucc.png" "$2" "$3" 109 return 0;; 110 esac 111 112 # extend duration if less than a second or image 113 if is_image "$2" 114 then 115 tmp=/tmp/ffmpeg-effect.$$.mkv 116 trap 'rm -f "$tmp"' EXIT INT TERM HUP 117 $ffmpeg_common -loop 1 -i "$2" -t 20 -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2" "$tmp" 118 set -- "$1" "$tmp" "$3" 119 fi 120 121 case "$1" in 122 amplify) 123 $ffmpeg_common -i "$2" -filter:a "volume=10" "$3";; 124 banjo) 125 replace_audio "${mediadir}/banjo.mp3" "$2" "$3";; 126 bounce) 127 repeats=0 128 $ffmpeg_common -i "$2" \ 129 -filter_complex "[0:v]reverse[vrev];[0:v][vrev]concat,loop=${repeats}:250,setpts='PTS-STARTPTS/TB' [v]" \ 130 -filter_complex "[0:a]areverse[arev];[0:a][arev]concat=v=0:a=1,aloop=${repeats}:250,asetpts='PTS-STARTPTS/TB' [a]" \ 131 -map "[v]" -map "[a]" \ 132 "$3" </dev/null;; 133 breakingnews) 134 mix_audio "${mediadir}/breakingnews.opus" "$2" "$3";; 135 celtify) 136 mix_audio "${mediadir}/broceliande.ogg" "$2" "$3";; 137 concatenate) 138 mix_audio "${mediadir}/concatenate.mp3" "$2" "$3";; 139 crimetv) 140 mix_audio "${mediadir}/crimetv.opus" "$2" "$3";; 141 curb) 142 mix_audio "${mediadir}/curb.opus" "$2" "$3";; 143 daybowbow) 144 replace_audio "${mediadir}/day-bow-bow.ogg" "$2" "$3";; 145 deathmetal) 146 mix_audio "${mediadir}/artificial-brain.opus" "$2" "$3";; 147 developers) 148 mix_audio "${mediadir}/developers.opus" "$2" "$3";; 149 dontdoit) 150 mix_audio "${mediadir}/dontdoit.mp3" "$2" "$3";; 151 dontsaytoyourmother) 152 mix_audio "${mediadir}/dont-say-to-your-mother.opus" "$2" "$3";; 153 doomify) 154 mix_audio "${mediadir}/doom.mp3" "$2" "$3";; 155 dutchapprove) 156 mix_audio_video "${mediadir}/krul.mkv" "$2" "$3" 524 480;; 157 french) 158 mix_audio_video "${mediadir}/french-friday.mp4" "$2" "$3" 800 450;; 159 FRENCH) 160 mix_audio_video "${mediadir}/french-thursday.mp4" "$2" "$3" 800 450;; 161 imam) 162 mix_audio "${mediadir}/imam.mp3" "$2" "$3";; 163 lop|loop|looop|loooop) 164 # Mr. Fibonacci 165 [ "$1" == "lop" ] && repeats=3 166 [ "$1" == "loop" ] && repeats=5 167 [ "$1" == "looop" ] && repeats=8 168 [ "$1" == "loooop" ] && repeats=13 169 i=0 170 input="" 171 while test $i -lt $repeats; do 172 input="$input -i $2" 173 i=$((i + 1)) 174 done 175 $ffmpeg_common $input \ 176 -filter_complex "concat=n=${repeats}:v=1:a=1 [v] [a]" -map "[v]" -map "[a]" \ 177 "$3" </dev/null;; 178 mow) 179 mix_audio "${mediadir}/lawn-mower.mp3" "$2" "$3";; 180 namflashback) 181 mix_audio "${mediadir}/namflashback.opus" "$2" "$3";; 182 news) 183 mix_audio "${mediadir}/news.opus" "$2" "$3";; 184 pullmyfinger) 185 mix_audio "${mediadir}/fart.opus" "$2" "$3";; 186 reverse) 187 $ffmpeg_common -i "$2" \ 188 -vf reverse -af areverse \ 189 "$3" </dev/null;; 190 richardstrauss) 191 mix_audio "${mediadir}/richardstrauss.opus" "$2" "$3";; 192 sadviolin) 193 mix_audio "${mediadir}/sad-violin.opus" "$2" "$3";; 194 science) 195 replace_audio "${mediadir}/accelerating-science.mp3" "$2" "$3";; 196 scrollify) 197 mix_audio "${mediadir}/elder_scrolls.mp3" "$2" "$3";; 198 sendtohell|amsterdamify) 199 mix_audio_video "${mediadir}/hell.mkv" "$2" "$3" 1920 1080;; 200 sexify) 201 mix_audio "${mediadir}/careless_whisper.mp3" "$2" "$3";; 202 slavify) 203 replace_audio "${mediadir}/remove-kebab.opus" "$2" "$3";; 204 slowdown) 205 $ffmpeg_common -i "$2" \ 206 -filter_complex "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]" -map "[v]" -map "[a]" \ 207 "$3" </dev/null;; 208 speedup) 209 $ffmpeg_common -i "$2" \ 210 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" \ 211 "$3" </dev/null;; 212 techno) 213 replace_audio "${mediadir}/techno.mp3" "$2" "$3";; 214 technodrugs) 215 $ffmpeg_common -i "${mediadir}/techno.mp3" -i "$2" \ 216 -filter:v "tmix=frames=9:weights='0.2 0.4 0.6 0.8 1 0.8 0.6 0.4 0.2'" \ 217 -map 1:v:0 -map 0:a:0 -shortest \ 218 "$3" </dev/null;; 219 thin) 220 $ffmpeg_common -i "$2" \ 221 -vf "scale=iw/4:ih,setsar=1" \ 222 "$3" </dev/null;; 223 torture) 224 side_by_side "${mediadir}/clockworkorange.mkv" "$2" "$3";; 225 trumpapprove) 226 mix_audio "${mediadir}/trump-approves.opus" "$2" "$3";; 227 usa) 228 mix_audio_video "${mediadir}/american-asmr.mkv" "$2" "$3" 800 450;; 229 USA) 230 mix_audio_video "${mediadir}/american-ambiente.mp4" "$2" "$3" 800 450;; 231 USAUSA) 232 mix_audio "${mediadir}/USAUSA.opus" "$2" "$3";; 233 wide|widen) 234 $ffmpeg_common -i "$2" \ 235 -vf "scale=iw*4:ih,crop=iw/4:ih:iw/4:ih,setsar=1" \ 236 "$3" </dev/null;; 237 ww1) 238 mix_audio "${mediadir}/ww1.mp3" "$2" "$3";; 239 yellow) 240 mix_audio "${mediadir}/yellow.opus" "$2" "$3";; 241 *) usage;; 242 esac 243 } 244 245 while getopts 'hn:' opt; do 246 case $opt in 247 h) usage;; 248 n) n="$OPTARG";; 249 *) break;; 250 esac 251 done 252 shift $((OPTIND - 1)) 253 if [ "$#" -lt 3 ] || [ ! -r "$2" ]; then 254 usage 255 fi 256 257 if process_filter "$1" "$2" "$3"; then 258 printf '%s\n' "$3" 259 else 260 exit $? 261 fi 262