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