FFmpeg is the assembler of audio and video.
As a result, Ciro Santilli who likes "lower level stuff", has had many many hours if image manipulation fun with this software, see e.g.:
As older Ciro grows, the more he notices that FFmpeg can do basically any lower level audio video task. It is just an amazing piece of software, the immediate go-to for any low level operation.
FFmpeg was created by Fabrice Bellard, which Ciro deeply respects.
Resize a video: superuser.com/questions/624563/how-to-resize-a-video-to-make-it-smaller-with-ffmpeg:
ffmpeg -i input.avi -filter:v scale=720:-1 -c:a copy output.mkv
Unlike every other convention under the sun, the height in scale is the first number.
Filter graphs are a thing of great beauty. What an amazingly obscure domain-specific language, but which can produce striking results with very little!!!
ffplay -autoexit -nodisp -f lavfi -i '
sine=frequency=500[a];
sine=frequency=1000[b];
[a][b]amerge, atrim=end=2
'
which creates a graph:
                              +--------+
[sine=frequency=500]--->[a]-->|        |
                              | amerge |-->[atrim]-->[output]
[sine=frequency=1000]-->[b]-->|        |
                              +--------+
and plays 500 Hz on the left channel and 1000 Hz on the right channel for 2 seconds.
So we see the following syntax patterns:
  • sine, amerge and atrim are filters
  • sine=frequency=500: the first = says "araguments follow"
    • frequency=500 sets the frequency argument of the sine filter
    • for multiple arguments the syntax is to separate arguments with colons e.g. sine=frequency=500:duration=2
  • ;: separates statements
  • [a], [b]: sets the name of an edge
  • ,: creates unnamed edge between filters that have one input and one output
A list of all filters can be obtained ith:
ffmpeg -filters
and parameters for a single filter can be obtained with:
ffmpeg --help filter=sine
Related question: stackoverflow.com/questions/69251087/in-ffmpeg-command-line-how-to-show-all-filter-settings-and-their-parameters-bef
TODO dump graph to ASCII art? trac.ffmpeg.org/wiki/FilteringGuide#Visualizingfilters mentions a -dumpgraph option, but haven't managed to use it yet.
Bibliography:
Awesome tool to view quick stuff quickly without generating files. Unfortunately it doesn't support all options that the ffmpeg CLI supports, e.g. ffplay multiple input files. One day, one day.
For synthesized streams like sine we can do it e.g.
ffplay -autoexit -nodisp -f lavfi -i '
sine=frequency=500[a];
sine=frequency=1000[b];
[a][b]amerge, atrim=end=2
'
but it does not seem to accept multiple -i for some reason. So is there a way to open a file from some filter? E.g.:
ffplay -i tmp.wav -i tmp.mkv -filter_complex "[0:a]atrim=end=2[a];[1:v]trim=end=2[v]" -map '[a]' -map '[v]'
fails with:
Argument 'tmp.mkv' provided as input filename, but 'tmp.wav' was already specified.
2 second 1000 Hz:
ffmpeg -f lavfi -i "sine=f=1000:d=2" out.wav
Video with a solid color:
  • 2 second white video:
    ffplay -autoexit -f lavfi -i 'color=white:640x480:d=3,format=rgb24,trim=end=2'
    Also add some audio:
    ffmpeg -lavfi "color=white:640x480:d=3,format=rgb24,trim=end=2[v];sine=f=1000:d=2[a]" -map '[a]' -map '[v]' out.mkv
    TODO how to ffplay the video + audio directly? -map does not seem to work unfortunately.
  • 2 second white followed by 2 second black video:
    ffplay -autoexit -f lavfi -i 'color=white:640x480:d=3,format=rgb24,trim=end=2[a];color=black:640x480:d=3,format=rgb24,trim=end=2[b];[a][b]concat=n=2:v=1:a=0'
  • bibliography:
Display count in seconds on the video:
Crop 20 pixels from the bottom of the image:
convert image.png -gravity East -chop 20x0 result.png
convert -size 512x512 xc:blue blue.png
convert -size 256x256 gradient: out.png
convert -size 256x256 gradient:white-black out.png
convert -size 256x256 gradient:red-blue out.png
convert -size 256x256 radial-gradient: out.png
convert -size 256x256 radial-gradient:white-black out.png
Digits 0 to 9, white on black background:
for i in `seq 0 9`; do convert -size 512x512 xc:black -pointsize 500 -gravity center -fill white -draw "text 0,0 \"$i\"" $i.png; done