home ~ projects ~ socials

Make Animated AVIFs (Instead of GIFs) With FFmpeg

Scratch Notes

These are scratch notes while I'm figuring out how to get things working. Feel free to play along at home. Just keep in mind that things are still very much in flux.

#!/bin/bash

time ffmpeg -i "initial.mp4" \
-t 0.1 -vf cropdetect -f null - 2>&1 | \
awk '/crop/ { print $NF }' | \
tail -1 | xargs -I{CROP} \
ffmpeg -i "initial.mp4" -vf "{CROP}" \
-y output.avif
Output:
Process took to long and was halted
ffmpeg version 7.1.1 Copyright (c) 2000-2025 the FFmpeg developers
  built with Apple clang version 16.0.0 (clang-1600.0.26.6)
  configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/7.1.1_2 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags='-Wl,-ld_classic' --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libharfbuzz --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox --enable-neon
  libavutil      59. 39.100 / 59. 39.100
  libavcodec     61. 19.101 / 61. 19.101
  libavformat    61.  7.100 / 61.  7.100
  libavdevice    61.  3.100 / 61.  3.100
  libavfilter    10.  4.100 / 10.  4.100
  libswscale      8.  3.100 /  8.  3.100
  libswresample   5.  3.100 /  5.  3.100
  libpostproc    58.  3.100 / 58.  3.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'initial.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf61.1.100
  Duration: 00:00:06.17, start: 0.000000, bitrate: 881 kb/s
  Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 1072x912 [SAR 1:1 DAR 67:57], 877 kb/s, 23.98 fps, 23.98 tbr, 24k tbn (default)
      Metadata:
        handler_name    : VideoHandler
        vendor_id       : [0][0][0][0]
        encoder         : Lavc61.3.100 libx264
        timecode        : 01:00:00:00
  Stream #0:1[0x2](eng): Data: none (tmcd / 0x64636D74), 0 kb/s
      Metadata:
        handler_name    : VideoHandler
        timecode        : 01:00:00:00
Stream mapping:
  Stream #0:0 -> #0:0 (h264 (native) -> av1 (libaom-av1))
Press [q] to stop, [?] for help
[libaom-av1 @ 0x13de05b00] 3.12.1
[libaom-av1 @ 0x13de05b00] Neither bitrate nor constrained quality specified, using default CRF of 32
Output #0, avif, to 'output.avif':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf61.7.100
  Stream #0:0(und): Video: av1 (av01 / 0x31307661), yuv420p(tv, bt709, progressive), 1072x912 [SAR 1:1 DAR 67:57], q=2-31, 23.98 fps, 24k tbn (default)
      Metadata:
        handler_name    : VideoHandler
        vendor_id       : [0][0][0][0]
        timecode        : 01:00:00:00
        encoder         : Lavc61.19.101 libaom-av1
      Side data:
        cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    0 fps=0.0 q=0.0 size=       0KiB time=N/A bitrate=N/A speed=N/A    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00306x    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00295x    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00285x    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00275x    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00266x    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00258x    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.0025x    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00243x    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00236x    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.0023x    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00223x    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00217x    
frame=    1 fps=0.1 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00212x    
frame=    1 fps=0.0 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00207x    
frame=    1 fps=0.0 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00202x    
frame=    1 fps=0.0 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00197x    
frame=    1 fps=0.0 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00192x    
frame=    1 fps=0.0 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00188x    
frame=    1 fps=0.0 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00184x    
frame=    1 fps=0.0 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.0018x    
frame=    1 fps=0.0 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00176x    
frame=    1 fps=0.0 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00172x    
frame=    1 fps=0.0 q=0.0 size=       0KiB time=00:00:00.04 bitrate=   0.0kbits/s speed=0.00169x

Notes

  • This is what I'm experimenting with to replace animated GIFs.
  • Calling an animated AVIF in a standard HTML <img> tag works on my mac in Firefox, Safari, and Chrome. Need to do more testing though to get a better idea of support.
  • I'm my older iPhone the animation gets pretty slow with bigger files. (the first test I did was ~1200 pixels wide at 30fpx. The speed it played back varied. The first bit was pretty much real time, then it slowed to probably 5fps or so) (TODO: Get iPhone model number)
  • On my older iPad the animation only played one time then stopped on the first frame in Safari (TODO: get the version number)
  • TODO: note about Can I Use support and Baseline 2024 inclusion and how that doesn't really talk about animated stuff, but maybe it's all baked in?
  • TODO: Figure out if there are built in ways to click to start stop the animation. (There's nothing obvious in the right click menu for Zen)
  • Make a process with a web component that allows you to stop/start the animation.
-- end of line --