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 (6797B) --- 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 loop|looop) 164 [ "$1" == "looop" ] && repeats=10 165 i=0 166 input="" 167 while test $i -lt $repeats; do 168 input="$input -i $2" 169 i=$((i + 1)) 170 done 171 $ffmpeg_common $input \ 172 -filter_complex "concat=n=${repeats}:v=1:a=1 [v] [a]" -map "[v]" -map "[a]" \ 173 "$3" </dev/null;; 174 mow) 175 mix_audio "${mediadir}/lawn-mower.mp3" "$2" "$3";; 176 namflashback) 177 mix_audio "${mediadir}/namflashback.opus" "$2" "$3";; 178 news) 179 mix_audio "${mediadir}/news.opus" "$2" "$3";; 180 pullmyfinger) 181 mix_audio "${mediadir}/fart.opus" "$2" "$3";; 182 reverse) 183 $ffmpeg_common -i "$2" \ 184 -vf reverse -af areverse \ 185 "$3" </dev/null;; 186 richardstrauss) 187 mix_audio "${mediadir}/richardstrauss.opus" "$2" "$3";; 188 sadviolin) 189 mix_audio "${mediadir}/sad-violin.opus" "$2" "$3";; 190 science) 191 replace_audio "${mediadir}/accelerating-science.mp3" "$2" "$3";; 192 scrollify) 193 mix_audio "${mediadir}/elder_scrolls.mp3" "$2" "$3";; 194 sendtohell|amsterdamify) 195 mix_audio_video "${mediadir}/hell.mkv" "$2" "$3" 1920 1080;; 196 sexify) 197 mix_audio "${mediadir}/careless_whisper.mp3" "$2" "$3";; 198 slavify) 199 replace_audio "${mediadir}/remove-kebab.opus" "$2" "$3";; 200 slowdown) 201 $ffmpeg_common -i "$2" \ 202 -filter_complex "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]" -map "[v]" -map "[a]" \ 203 "$3" </dev/null;; 204 speedup) 205 $ffmpeg_common -i "$2" \ 206 -filter_complex "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]" -map "[v]" -map "[a]" \ 207 "$3" </dev/null;; 208 techno) 209 replace_audio "${mediadir}/techno.mp3" "$2" "$3";; 210 technodrugs) 211 $ffmpeg_common -i "${mediadir}/techno.mp3" -i "$2" \ 212 -filter:v "tmix=frames=9:weights='0.2 0.4 0.6 0.8 1 0.8 0.6 0.4 0.2'" \ 213 -map 1:v:0 -map 0:a:0 -shortest \ 214 "$3" </dev/null;; 215 thin) 216 $ffmpeg_common -i "$2" \ 217 -vf "scale=iw/4:ih,setsar=1" \ 218 "$3" </dev/null;; 219 torture) 220 side_by_side "${mediadir}/clockworkorange.mkv" "$2" "$3";; 221 trumpapprove) 222 mix_audio "${mediadir}/trump-approves.opus" "$2" "$3";; 223 usa) 224 mix_audio_video "${mediadir}/american-asmr.mkv" "$2" "$3" 800 450;; 225 USA) 226 mix_audio_video "${mediadir}/american-ambiente.mp4" "$2" "$3" 800 450;; 227 USAUSA) 228 mix_audio "${mediadir}/USAUSA.opus" "$2" "$3";; 229 wide|widen) 230 $ffmpeg_common -i "$2" \ 231 -vf "scale=iw*4:ih,crop=iw/4:ih:iw/4:ih,setsar=1" \ 232 "$3" </dev/null;; 233 ww1) 234 mix_audio "${mediadir}/ww1.mp3" "$2" "$3";; 235 yellow) 236 mix_audio "${mediadir}/yellow.opus" "$2" "$3";; 237 *) usage;; 238 esac 239 } 240 241 while getopts 'hn:' opt; do 242 case $opt in 243 h) usage;; 244 n) n="$OPTARG";; 245 *) break;; 246 esac 247 done 248 shift $((OPTIND - 1)) 249 if [ "$#" -lt 3 ] || [ ! -r "$2" ]; then 250 usage 251 fi 252 253 if process_filter "$1" "$2" "$3"; then 254 printf '%s\n' "$3" 255 else 256 exit $? 257 fi 258