# FFmpeg build record Minimal LGPL-2.1-or-later FFmpeg shipped inside Audio Converter. Built 2026-10-13 on the Windows 11 x64 build PC with MSYS2 MINGW64. How to rebuild: `tools/ffmpeg/README.md`. Script: `tools/ffmpeg/build-ffmpeg.sh`. Tests: `tools/ffmpeg/test-ffmpeg.sh`. Artifacts: `tools/bin/ffmpeg/` (gitignored). ## Sources - FFmpeg tag `n9.0.2`, commit `946fcce07b6dcd0331c8cc609192aeff5e1924f8`, https://github.com/FFmpeg/FFmpeg/tree/n9.0.2 (unmodified). - MSYS2 packages (static `.a` linked): `mingw-w64-x86_64-lame 3.100-3`, `mingw-w64-x86_64-libogg 1.3.6-1`, `mingw-w64-x86_64-libvorbis 1.3.7-3`, `mingw-w64-x86_64-opus 1.6.1-1`, `mingw-w64-x86_64-zlib 1.3.2-2`, `mingw-w64-x86_64-gcc 16.2.0-5`, `mingw-w64-x86_64-crt` and `-winpthreads 14.0.0.r426.g4564ee4b5-1`, `nasm 3.02-1`. ## Configure line ``` ./configure --arch=x86_64 --target-os=mingw32 --pkg-config-flags=--static --extra-cflags=-static --extra-ldflags=-static --disable-shared --enable-static --disable-autodetect --disable-everything --disable-programs --enable-ffmpeg --enable-ffprobe --disable-doc --disable-debug --disable-network --disable-devices --disable-hwaccels --enable-indev=lavfi --enable-small --enable-zlib --enable-libmp3lame --enable-libopus --enable-libvorbis --enable-protocol=file,pipe --enable-decoder=mp3float,mp3,aac,aac_fixed,aac_latm,alac,flac,vorbis,opus,wmav1,wmav2,wmapro,wmalossless,amrnb,amrwb,ac3,ac3_fixed,eac3,gsm,adpcm_ima_wav,adpcm_ms,pcm_s8,pcm_u8,pcm_s16le,pcm_s16be,pcm_u16le,pcm_u16be,pcm_s24le,pcm_s24be,pcm_u24le,pcm_u24be,pcm_s32le,pcm_s32be,pcm_u32le,pcm_u32be,pcm_s64le,pcm_s64be,pcm_f16le,pcm_f24le,pcm_f32le,pcm_f32be,pcm_f64le,pcm_f64be,pcm_s16le_planar,pcm_s24le_planar,pcm_s32le_planar,pcm_s8_planar,pcm_alaw,pcm_mulaw,mjpeg,png,bmp,wrapped_avframe --enable-encoder=libmp3lame,libopus,libvorbis,aac,flac,alac,wmav2,pcm_s16le,pcm_s24le,pcm_s32le,pcm_f32le,pcm_s16be,pcm_s24be,pcm_s32be,pcm_u8,mjpeg --enable-demuxer=mov,matroska,ogg,wav,w64,aiff,flac,mp3,aac,asf,avi,amr,amrnb,amrwb,caf,ac3,eac3,mpegts,image2,image2pipe,image_jpeg_pipe,image_png_pipe,image_bmp_pipe,mjpeg,pcm_s16le,pcm_s16be,pcm_s24le,pcm_f32le,gsm --enable-muxer=mp3,ipod,mp4,mov,wav,w64,flac,ogg,opus,aiff,asf,adts,null,image2,mjpeg,pcm_s16le --enable-parser=mpegaudio,aac,aac_latm,flac,vorbis,opus,ac3,amr,gsm,mjpeg,png,bmp --enable-bsf=aac_adtstoasc,opus_metadata,null --enable-filter=abuffer,abuffersink,buffer,buffersink,aresample,aformat,atrim,asetpts,volume,loudnorm,anull,apad,sine,anullsrc,format,null,trim,setpts,scale,testsrc,testsrc2 ``` ## Verification ### Licence - configure: `License: LGPL version 2.1 or later`; `config.h` has `CONFIG_GPL 0`, `CONFIG_NONFREE 0`, `CONFIG_VERSION3 0`. - `ffmpeg -buildconf`: no `--enable-gpl`, `--enable-nonfree` or `--enable-version3` (0 matches). `ffmpeg -L` prints the GNU Lesser GPL text. - External libraries: libmp3lame (LGPL), libopus, libvorbis/libogg (BSD), zlib. ### Size | File | Unstripped (`*_g.exe`) | Shipped (stripped) | |---|---|---| | ffmpeg.exe | 6,927,715 B (6.6 MiB) | 5,721,600 B (5.5 MiB) | | ffprobe.exe | 6,748,289 B (6.4 MiB) | 5,565,952 B (5.3 MiB) | (The BtbN full LGPL build is ~134 MB per exe.) `--enable-small` is on; the default `--enable-optimizations` is kept. FFmpeg's `make` already strips `ffmpeg.exe`; the script runs `strip` again. ### Imports (`objdump -p | grep 'DLL Name'`) Both exes: `bcrypt.dll`, `KERNEL32.dll`, `msvcrt.dll`, `SHELL32.dll`. Windows system DLLs only; no libgcc_s, libwinpthread, zlib1 or codec DLLs. ### Components (from the built ffmpeg.exe) - **Encoders**: libmp3lame, aac, alac, flac, libopus, libvorbis, wmav2, pcm_s16le, pcm_s16be, pcm_s24le, pcm_s24be, pcm_s32le, pcm_s32be, pcm_f32le, pcm_u8, mjpeg (only for test inputs / cover generation). - **Decoders**: mp3float, mp3, aac, aac_fixed, aac_latm, alac, flac, vorbis, opus, wmav1, wmav2, wmapro, wmalossless, amrnb, amrwb, ac3, ac3_fixed, eac3, gsm, adpcm_ima_wav, adpcm_ms, pcm_alaw, pcm_mulaw, pcm_s8, pcm_s8_planar, pcm_u8, pcm_s16le/be, pcm_s16le_planar, pcm_u16le/be, pcm_s24le/be, pcm_s24le_planar, pcm_u24le/be, pcm_s32le/be, pcm_s32le_planar, pcm_u32le/be, pcm_s64le/be, pcm_f16le, pcm_f24le, pcm_f32le/be, pcm_f64le/be, mjpeg, png, bmp, wrapped_avframe. - **Demuxers**: aac, ac3, aiff, amr, amrnb, amrwb, asf, avi, bmp_pipe, caf, eac3, f32le, flac, gsm, image2, image2pipe, jpeg_pipe, matroska/webm, mjpeg, mov/mp4/m4a/3gp/3g2/mj2, mp3, mpegts, ogg, png_pipe, s16be, s16le, s24le, w64, wav. Input device: lavfi. - **Muxers**: adts, aiff, asf, flac, image2, ipod, mjpeg, mov, mp3, mp4, null, ogg, opus, s16le, w64, wav. - **Filters**: aformat, anull, apad, aresample, asetpts, atrim, loudnorm, volume, anullsrc, sine, abuffer, abuffersink, buffer, buffersink, format, null, scale, setpts, trim, testsrc, testsrc2; plus crop, hflip, vflip, rotate, transpose pulled in by the ffmpeg CLI (autorotate). - **Protocols**: file, pipe (input and output). No network. - **Parsers**: mpegaudio, aac, aac_latm, flac, vorbis, opus, ac3, amr, gsm, mjpeg, png, bmp. **BSFs**: aac_adtstoasc, opus_metadata, null (plus dependencies). ### Round-trip tests (`tools/ffmpeg/test-ffmpeg.sh`, 104 pass / 0 fail) Inputs from lavfi `sine=frequency=440:duration=5`, stereo 44.1 kHz (opus at 48 kHz): mp3, m4a (aac), wav, flac, ogg (vorbis), opus, aiff, m4a (alac), wma (wmav2), and mp4 with an mjpeg video track (testsrc2) + aac. Every input converted to every target (10 x 9 = 90 conversions) with `-vn -map 0:a`. Each output is non-empty, ffprobe reports the expected codec, and duration is within 0.1 s of 5 s (largest deviation 0.068 s, wma -> opus). | Target | Codec | Result | |---|---|---| | mp3 | mp3 (libmp3lame) | pass (10/10 inputs) | | m4a | aac | pass (10/10) | | wav | pcm_s16le | pass (10/10) | | flac | flac | pass (10/10) | | ogg | vorbis | pass (10/10) | | opus | opus (libopus) | pass (10/10) | | aiff | pcm_s16be | pass (10/10) | | m4a | alac | pass (10/10) | | wma | wmav2 | pass (10/10) | AMR-NB input: skipped, no AMR encoder in an LGPL-2.1 build (decoders present). ### Cover art pass-through Source: mp3 + JPEG cover (`-map 0 -map 1 -c copy -disposition:v:0 attached_pic -id3v2_version 3`). Converted with `-map 0:a -map 0:v? -c:v copy -disposition:v:0 attached_pic`. | Target | Cover kept | |---|---| | mp3 | yes | | m4a (aac) | yes | | m4a (alac) | yes | | flac | yes | | aiff | yes, only with `-write_id3v2 1` | | wma (asf) | **no**: the asf muxer writes the image as an ordinary 1-frame mjpeg video stream (no attached_pic, not WM/Picture). The app should drop the video stream for WMA. | | wav | no, muxer refuses video streams (map without the image) | | ogg / opus | no, muxer refuses mjpeg (needs METADATA_BLOCK_PICTURE; not supported by the muxer) | ### Other checks - `-af loudnorm=I=-16:TP=-1.5:LRA=11` (wav -> mp3): pass, 5.000 s. - Raw PCM: `-f s16le -ar 44100 -ac 2 -i raw.pcm -c:a libmp3lame -b:a 192k`: pass, 5.000 s. - `atrim=0:2,asetpts=PTS-STARTPTS,volume=0.5,aresample=48000,aformat=sample_fmts=s16` -> flac: pass, 2.000 s. ## Gotchas found - `--disable-postproc` no longer exists in 9.0 (libpostproc was removed). - `lavfi` is an input device, so it needs libavdevice with `--enable-indev=lavfi` (`--disable-devices` first); a `lavfi` demuxer does not exist. - lavfi video sources need the `wrapped_avframe` decoder. - `libopus` rejects 44.1 kHz; do not pass `-ar 44100` with `-c:a libopus` (leave `-ar` off or use 48000). - MSYS2 git needs `safe.directory` for a checkout made from WSL (the script passes `-c safe.directory`).