!/bin/bash
#
#(what's going on)
# ffmpeg uses a graph to create an output file, a graph consist of filters
# each filter can have input and output streams,
# streams are denoted by their names between square brackets []
# [0:v], 0 is the first input file, v means video, a means audio
# filters can be chained by comma's, filter parameters are separated by colons
# -i is an input stream, there can be several input streams but in this case there is only one
# trim is used split the input stream in 4 video scenes
# split is used to duplicate the scenes (so each duplicate can have its own adaptions), i want 7 streams
# xfade is used to join the scenes again in a different order (so i get 7 streams with the scenes in a different order)
# each of this 7 streams can have there own filter again, eg a black border, rotate, negate, etc
# the first 4 streams are used to create a 2x2 mosaic on a canvas
# the other 3 streams are used for some bouncing ball effect over this mosaic
# the audio is handled separately
# filters starting with 'a' are for audio
# you can adapt the volume of each stream
# the audio streams are mixed into one stream
# -map is used the join the final video stream with the final audio stream
# -t defines the duration of the movie
# next the output video and audio encoding is set
# and finally the outputfile name is set
#
#problems
# make sure there is no space after \
# use -loglevel debug to find typos
# the duration changes when length of transition changes
# for 'easy' calculation of the transition offset in this example
# all scenes have same length and all durations of transitions are the same
# when the offset is wrong the transition keeps showing the same frame
# you have to calculate the final duration (-t and canvas:d)
# sometimes the code does not seem to stop at the end
# maybe this is caused by duration=longest? or shortest=0? or repeatlast=0? or
# the length of the background canvas (subtract durations of the transitions?)
#
inputFileName=origFile.mp4
outputFilename=outFile.ffMpegFun.mp4
rm -f $outputFilename
/usr/bin/ffmpeg -hide_banner -loglevel info -fflags +genpts \
-i $inputFileName \
-filter_complex " \
[0:v] trim=0:20, setpts=PTS-STARTPTS, drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:fontsize=36:fontcolor=yellow@0.8:y=h-line_h-10:x=w-(t-4.5)*w/5.5:enable='between(t,2,12)':text='scene 1', pad=ih*16/9:ih:(ow-iw)/2:(oh-ih)/2, scale=480:270, setdar=16/9, setsar=1/1 [vsc1]; \
[0:v] trim=20:40, setpts=PTS-STARTPTS, drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:fontsize=36:fontcolor=yellow@0.8:y=h-line_h-10:x=w-(t-4.5)*w/5.5:enable='between(t,2,12)':text='scene 2', pad=ih*16/9:ih:(ow-iw)/2:(oh-ih)/2, scale=480:270, setdar=16/9, setsar=1/1 [vsc2]; \
[0:v] trim=40:60, setpts=PTS-STARTPTS, drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:fontsize=36:fontcolor=yellow@0.8:y=h-line_h-10:x=w-(t-4.5)*w/5.5:enable='between(t,2,12)':text='scene 3', pad=ih*16/9:ih:(ow-iw)/2:(oh-ih)/2, scale=480:270, setdar=16/9, setsar=1/1 [vsc3]; \
[0:v] trim=60:80, setpts=PTS-STARTPTS, drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:fontsize=36:fontcolor=yellow@0.8:y=h-line_h-10:x=w-(t-4.5)*w/5.5:enable='between(t,2,12)':text='scene 4', pad=ih*16/9:ih:(ow-iw)/2:(oh-ih)/2, scale=480:270, setdar=16/9, setsar=1/1 [vsc4]; \
[0:a] atrim=0:20, asetpts=PTS-STARTPTS, aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=mono [asc1]; \
[0:a] atrim=20:40, asetpts=PTS-STARTPTS, aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=mono [asc2]; \
[0:a] atrim=40:60, asetpts=PTS-STARTPTS, aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=mono [asc3]; \
[0:a] atrim=60:80, asetpts=PTS-STARTPTS, aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=mono [asc4]; \
[vsc1] split=7 [v0101][v0202][v0302][v0404][v0501][v0602][v0701]; \
[vsc2] split=7 [v0102][v0201][v0301][v0403][v0502][v0601][v0702]; \
[vsc3] split=7 [v0103][v0203][v0304][v0402][v0503][v0603][v0703]; \
[vsc4] split=7 [v0104][v0204][v0303][v0401][v0504][v0604][v0704]; \
[asc1] asplit=7 [a0101][a0202][a0302][a0404][a0501][a0602][a0701]; \
[asc2] asplit=7 [a0102][a0201][a0301][a0403][a0502][a0601][a0702]; \
[asc3] asplit=7 [a0103][a0203][a0304][a0402][a0503][a0603][a0703]; \
[asc4] asplit=7 [a0104][a0204][a0303][a0401][a0504][a0604][a0704]; \
[v0101][v0102] xfade=transition=circlecrop:duration=2.0:offset=19.0 [vt0101]; \
[vt0101][v0103] xfade=transition=wipetl:duration=2.0:offset=37.0 [vt0102]; \
[vt0102][v0104] xfade=transition=wipetr:duration=2.0:offset=54.0 [vs01]; \
[v0201][v0202] xfade=transition=circlecrop:duration=2.0:offset=19.0 [vt0201]; \
[vt0201][v0203] xfade=transition=wipetl:duration=2.0:offset=37.0 [vt0202]; \
[vt0202][v0204] xfade=transition=wipetr:duration=2.0:offset=54.0 [vs02]; \
[v0301][v0302] xfade=transition=circlecrop:duration=2.0:offset=19.0 [vt0301]; \
[vt0301][v0303] xfade=transition=wipetl:duration=2.0:offset=37.0 [vt0302]; \
[vt0302][v0304] xfade=transition=wipetr:duration=2.0:offset=54.0 [vs03]; \
[v0401][v0402] xfade=transition=circlecrop:duration=2.0:offset=19.0 [vt0401]; \
[vt0401][v0403] xfade=transition=wipetl:duration=2.0:offset=37.0 [vt0402]; \
[vt0402][v0404] xfade=transition=wipetr:duration=2.0:offset=54.0 [vs04]; \
[v0501][v0502] xfade=transition=circlecrop:duration=2.0:offset=19.0 [vt0501]; \
[vt0501][v0503] xfade=transition=wipetl:duration=2.0:offset=37.0 [vt0502]; \
[vt0502][v0504] xfade=transition=wipetr:duration=2.0:offset=54.0 [vs05]; \
[v0601][v0602] xfade=transition=circlecrop:duration=2.0:offset=19.0 [vt0601]; \
[vt0601][v0603] xfade=transition=wipetl:duration=2.0:offset=37.0 [vt0602]; \
[vt0602][v0604] xfade=transition=wipetr:duration=2.0:offset=54.0 [vs06]; \
[v0701][v0702] xfade=transition=circlecrop:duration=2.0:offset=19.0 [vt0701]; \
[vt0701][v0703] xfade=transition=wipetl:duration=2.0:offset=37.0 [vt0702]; \
[vt0702][v0704] xfade=transition=wipetr:duration=2.0:offset=54.0 [vs07]; \
[a0101][a0102] acrossfade=d=2.0 [at0101]; \
[at0101][a0103] acrossfade=d=2.0 [at0102]; \
[at0102][a0104] acrossfade=d=2.0 [as01]; \
[a0201][a0202] acrossfade=d=2.0 [at0201]; \
[at0201][a0203] acrossfade=d=2.0 [at0202]; \
[at0202][a0204] acrossfade=d=2.0 [as02]; \
[a0301][a0302] acrossfade=d=2.0 [at0301]; \
[at0301][a0303] acrossfade=d=2.0 [at0302]; \
[at0302][a0304] acrossfade=d=2.0 [as03]; \
[a0401][a0402] acrossfade=d=2.0 [at0401]; \
[at0401][a0403] acrossfade=d=2.0 [at0402]; \
[at0402][a0404] acrossfade=d=2.0 [as04]; \
[a0501][a0502] acrossfade=d=2.0 [at0501]; \
[at0501][a0503] acrossfade=d=2.0 [at0502]; \
[at0502][a0504] acrossfade=d=2.0 [as05]; \
[a0601][a0602] acrossfade=d=2.0 [at0601]; \
[at0601][a0603] acrossfade=d=2.0 [at0602]; \
[at0602][a0604] acrossfade=d=2.0 [as06]; \
[a0701][a0702] acrossfade=d=2.0 [at0701]; \
[at0701][a0703] acrossfade=d=2.0 [at0702]; \
[at0702][a0704] acrossfade=d=2.0 [as07]; \
[vs01] pad=iw+5:color=black [vsf01]; \
[vs02] null [vsf02]; \
[vs03] pad=iw+5:color=black [vsf03]; \
[vs04] null [vsf04]; \
[vs05] null [vsf05]; \
[vs06] null [vsf06]; \
[vs07] null [vsf07]; \
[as01] aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=mono, volume=-10dB [asf01]; \
[as02] aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=mono, volume=-90dB [asf02]; \
[as03] aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=mono, volume=-90dB [asf03]; \
[as04] aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=mono, volume=-10dB [asf04]; \
[as05] aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=mono, volume=-90dB [asf05]; \
[as06] aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=mono, volume=-90dB [asf06]; \
[as07] aformat=sample_fmts=fltp:sample_rates=44100:channel_layouts=mono, volume=-10dB [asf07]; \
[vsf05] fifo, setpts=PTS-STARTPTS+10/TB, trim=end=50, scale=iw/2:-1,negate[vsf05]; \
[vsf06] fifo, setpts=PTS-STARTPTS+20/TB, trim=end=70, scale=iw/2:-1,drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:fontsize=20:fontcolor=yellow@0.9:box=1:boxcolor=black@0.6:x=(w-tw)/2:y=h-(2*lh):text='Frame\: %{frame_num}':start_number=1[vsf06]; \
[vsf07] fifo, setpts=PTS-STARTPTS+15/TB, trim=end=88, rotate=PI/3+2*PI*t/4,format=yuva444p,geq=lum='p(X,Y)':a='st(1,pow(min(W/2,H/2),2))+st(3,pow(X-(W/2),2)+pow(Y-(H/2),2));if(lte(ld(3),ld(1)),255,0)',drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSans.ttf:fontsize=20:fontcolor=yellow@0.9:box=1:boxcolor=black@0.6:x=(w-tw)/2:y=h-(2*lh):timecode='01\:00\:00\:00':r=25[vsf07]; \
[asf05] afifo, adelay=delays=10s:all=1, atrim=end=50, asetpts=PTS-STARTPTS [asf05]; \
[asf06] afifo, adelay=delays=20s:all=1, atrim=end=70, asetpts=PTS-STARTPTS [asf06]; \
[asf07] afifo, adelay=delays=15s:all=1, atrim=end=87, asetpts=PTS-STARTPTS, afade=type=out:duration=7:start_time=80 [asf07]; \
color=c=black:size=970x550:r=25:d=90 [bgCanvas]; \
[bgCanvas][vsf01] overlay=x=3:y=3:shortest=0:repeatlast=1 [ovl01]; \
[ovl01][vsf02] overlay=x=486:y=3:shortest=0:repeatlast=1 [ovl02]; \
[ovl02][vsf03] overlay=x=3:y=276:shortest=0:repeatlast=1 [ovl03]; \
[ovl03][vsf04] overlay=x=486:y=276:shortest=0:repeatlast=1 [ovl04]; \
[ovl04][vsf05] overlay=x=0:y=0:'(W/2-w/2)+sin(t*2)*(W/2-w/2):(H/2-h/2)+cos(t)*(H/2-h/2)':shortest=0:repeatlast=0 [ovl05]; \
[ovl05][vsf06] overlay=x=0:y=0:'if(eq(mod(floor(st(8,t*320)/(W-w)),2),0),mod(ld(8),W-w),W-w-mod(ld(8),W-w)):if(eq(mod(floor(st(9,t*140)/(H-h)),2),0),mod(ld(9),H-h),H-h-mod(ld(9),H-h)):eval=frame:shortest=0:repeatlast=0' [ovl06]; \
[ovl06][vsf07] overlay=x=((W-w)/2)+((W-w)/2)*sin(2*t+PI/8):y=((H-h)/2)+((H-h)/2)*sin(3*t):shortest=0:repeatlast=0 [ovl07]; \
[asf01][asf02][asf03][asf04][asf05][asf06][asf07] amix=inputs=7:duration=longest [a]" \
-map "[ovl07]" \
-map "[a]" -t 90 \
-vcodec libx264 -preset slow -crf 22 -r 25 \
-acodec libmp3lame -ab 64k -ar 44100 \
$outputFilename
/usr/bin/ffplay \
$outputFilename