FFmpeg 9.1: what to re-test before you upgrade

Your pipeline has been shipping the same AAC audio for months and nobody has complained. FFmpeg 9.1 changes what comes out of -c:a aac without printing a warning, failing a job, or changing a flag in your command line. That's harder to catch than a removed option, because a removed option errors out and a different encoder just quietly sounds different.
Quick answer: FFmpeg 9.1 entered its release process on October 23, 2026 carrying the rewritten native AAC encoder that was too late for 9.0, so plain -c:a aac now produces different bytes, a tighter bitrate curve and a different loudness profile than your 9.0.x binary did, with no error to warn you. Before upgrading, encode a fixed reference set on both binaries, compare bitrate and EBU R128 loudness, and pin the exact version in your Dockerfile and CI. If you'd rather not re-run that audit every release, send the encode to FFmpeg Micro as one API call and let a managed FFmpeg build absorb the version churn.The AAC story everyone is covering is the wrong one for a pipeline
Coverage of the new encoder is all about quality: whether FFmpeg's native AAC finally beats fdkaac and qAAC. IgorC's 12-sample test on Doom9 ran the new coder against twoloop, FDK-AAC CBR, and Apple AAC in CBR and ABR at roughly 128 kbps. The Hydrogenaudio thread goes deeper: rate control, RDO and every coding tool (PNS, TNS, I/S, M/S) was reengineered, with results measured against Zimtohrli and ViSQOL.
All of that is true and none of it is your problem. Your problem is reproducibility. The new NMR coder is the default in upstream FFmpeg, so the encoder behind -c:a aac swaps under a command you haven't touched. Better-sounding output is still different output: different bytes, a different measured loudness, and a rate curve that holds much closer to the target than twoloop's did. If you archive renders, diff masters, or ship audio against a loudness spec, a point upgrade just moved the ground.
FFmpeg said plainly that the encoder rewrite missed 9.0 and would land in 9.1. That's the one sentence most upgrade checklists skipped.
What actually changes at the flag level
Three things change between 9.0.x and 9.1, and only one is about sound quality. The table is the short version; the commands below confirm it on your own files.
| What you run | On 9.0.x | On 9.1 |
|---|---|---|
| `-c:a aac -b:a 128k` | twoloop coder, loose rate variation around the target | NMR coder, strict CBR holding very close to the target |
| `-c:a aac -q:a 2` | VBR via the old quality path | Quality setting takes precedence over `b` and `aac_rc`, and the encoder's author does not recommend real VBR here |
| `-c:a aac -b:a 128k -aac_rc abr` | option not in play | ABR mode; below roughly 56 kbps stereo it lands *above* the requested rate, so use `cbr` down there |
The aac_rc option controls rate-control mode when a bitrate is set and defaults to cbr, per FFmpeg's own codec documentation. That doc is also where the sub-56 kbps ABR caveat is written down, which matters if you encode voice-only tracks at 48k or 64k for faceless-channel or podcast pipelines.
If your audio path uses -q:a for VBR, move to an explicit bitrate: the rewrite is CBR-first by design, and the VBR path through it is not where the work went.
Re-test it in three measurements, not by listening
Pick five to ten files that represent what your pipeline ingests: a screen recording with speech, a music bed, a phone-shot UGC clip, one 48 kHz stereo master, one mono voiceover. Keep them in the repo. Run the same command on both binaries and compare numbers, because ears are a bad regression test and a file-size diff tells you almost nothing.
First, capture what each build is:
ffmpeg -version | head -1
ffmpeg -buildconf > build-9.0.2.txt
ffmpeg -hide_banner -encoders | grep -i aac
Second, measure the actual bitrate and the decoded audio, not the container:
# real bitrate of the audio stream
ffprobe -v error -select_streams a:0 \
-show_entries stream=codec_name,bit_rate,sample_rate,channels \
-of default=nw=1 out.m4a
# hash of the DECODED audio, so container metadata doesn't pollute the diff
ffmpeg -v error -i out.m4a -f md5 -
Third, measure loudness the way the platforms do:
ffmpeg -nostats -i out.m4a -af ebur128=peak=true -f null - 2>&1 | tail -12
Integrated LUFS and true peak are the two numbers to log next to each file. If your spec says -14 LUFS for YouTube or -16 for a podcast feed, a half-LU shift across an encoder swap is the difference between passing and getting normalized at ingest. Check the same files at 64k and 96k, not just at 128k, because the rate control behaves differently down there, where cheap voice tracks live.
AAC output also carries encoder priming samples, which have bitten people in a completely different way: why an FFmpeg concat audio gap isn't your cut, it's AAC priming. If you're already fighting that, changing encoders in the same week is a bad idea.
9.1 is a feature branch, not a security fix
Anyone upgrading this week because of October's CVE batch is solving the wrong problem. The October 8 disclosures, plus CVE-2026-107678 published October 13, affect FFmpeg through 9.0.2, the newest stable release, with no fixed release reported. VulnCheck's advisory on the stack exhaustion via recursive free of pssh boxes in av_encryption_init_info_free() is the clearest example: an MP4 with tens of thousands of tiny pssh boxes kills the process, so an upload can crash any pipeline that runs ffmpeg or ffprobe over user-supplied MP4s. As of mid-October, release/9.0 carried no upstream fixes for CVE-2026-107675, 107676, 107677 or 107696 either, and distro trackers still list ffmpeg as vulnerable.
Moving to 9.1 gets you a new AAC encoder and a new set of Vulkan toys. It doesn't close the RTSP redirect SSRF, the SFTP host-key bypass, or the pssh crash. You end up tracking a feature branch and an unpatched hole at the same time. Our containment notes are in FFmpeg CVE October 2026: no patch exists. Contain them instead., and they apply unchanged on 9.1.
The rest of the 9.1 surface that can trip a build
Beyond audio, Phoronix's October 23 inventory lists an APV Vulkan encoder, vf_fruc_vulkan for NVIDIA Optical Flow frame-rate up-conversion, ASTC encode and decode via libastcenc with .astc and KTX 1.0 muxers, an iTerm2 inline image muxer, an MVR demuxer, a latticepal filter, DVD-Audio LPCM, and H.264 data partitioning.
The trap is that the headline items are build- and driver-dependent. A Vulkan encoder in the release notes is not a Vulkan encoder in your Alpine container, and vf_fruc_vulkan needs an NVIDIA driver your CI runner probably doesn't have. Verify presence instead of assuming it:
ffmpeg -hide_banner -hwaccels
ffmpeg -hide_banner -filters | grep -i vulkan
ffmpeg -hide_banner -muxers | grep -iE 'astc|ktx'
Run that inside the image you ship, not on your laptop. The good news: 9.1 is additive on the filter side. The flag removals that hurt were in 9.0, and our earlier read still holds, that FFmpeg 9 didn't rewrite the filter graph, so keep your workarounds.
Pin the version, or stop owning the binary
Skip pinning and you'll repeat this whole audit in six months. Pin a digest, not a tag:
FROM linuxserver/ffmpeg@sha256:<digest>
Then assert it in CI so a base-image rebuild can't move you silently:
ffmpeg -version | head -1 | grep -q 'ffmpeg version 9.0.2' || exit 1
And keep one golden-file check that encodes a committed WAV and compares the decoded MD5 against a stored value. That single test turns "the audio sounds slightly different now" into a red build.
This is the second FFmpeg migration in three months for self-hosters, so there's a third option: stop owning the upgrade cycle. The same encode runs as one call to the FFmpeg API, with no binary to pin and no CVE branch to track:
# the command you run today
ffmpeg -i input.mp4 -c:v copy -c:a aac -b:a 192k output.mp4
# the same job as one API call
curl -X POST https://api.ffmpeg-micro.com/v1/transcodes \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"inputs": [{ "url": "gs://your-bucket/input.mp4" }],
"outputFormat": "mp4",
"options": [
{ "option": "-c:v", "argument": "copy" },
{ "option": "-c:a", "argument": "aac" },
{ "option": "-b:a", "argument": "192k" }
]
}'
You submit, poll GET /v1/transcodes/{id} until status is completed, then download. No Vulkan driver matrix, no digest pinning, no deciding on a Friday whether a feature branch is worth the unpatched CVEs.
When this is the wrong call: if you need vf_fruc_vulkan on your own GPUs, if you're doing frame-exact forensic work where you must control the exact libavcodec build, or if your volume makes a self-hosted encode farm genuinely cheaper, keep the binary and keep the pin. Owning the stack is a real answer, just a job that most teams running a few video steps inside n8n or Make never signed up for.
Common pitfalls when moving to 9.1
The 9.1 pitfalls below are the ones that actually cost people a weekend, not the generic ones.
- Testing only at 128 kbps. The rate control differs most at the low end, and ABR below roughly 56 kbps stereo overshoots the requested rate.
- Comparing file sizes instead of decoded audio. Two files can be within a kilobyte and still differ in loudness.
- Leaving
-q:ain the command. Switch to an explicit-b:aplus the defaultcbrrate control. - Treating
-aac_coder twoloopas a permanent escape hatch. The upstream commit that made the new coder the default says the old coders will be removed soon, so it buys one release cycle, not forever. - Re-encoding your archive so old and new outputs match. You'll lose a generation of quality to fix a cosmetic inconsistency. Record a version boundary in your metadata instead.
- Assuming the Vulkan and ASTC features exist in your container because they're in the release notes.
FAQ
Is FFmpeg 9.1 actually released yet?
FFmpeg 9.1 entered its release process on October 23, 2026 according to Phoronix, so it's a branch moving toward a release rather than a finished stable tarball. If your package manager hasn't offered it yet, you'd be building from the branch, which is a different risk profile than installing a point release.
Does -c:a aac change by default in FFmpeg 9.1, or do I have to opt in?
Plain -c:a aac changes by default in FFmpeg 9.1, because the NMR coder is now the default in upstream FFmpeg and the series merged to master on October 4, 2026. You don't opt in, you opt out.
Will my old and new AAC files still be bit-identical?
Old and new AAC files will not be bit-identical across the 9.0.x to 9.1 boundary, because a different encoder produced them. Any pipeline that dedupes by hash, diffs masters, or asserts a golden-file checksum needs a new baseline captured on the new binary.
What's the fastest way to roll back if 9.1 audio fails review?
Rolling back means reverting to the pinned digest of your 9.0.2 image and redeploying, which is only fast if you pinned a digest instead of a floating tag before you upgraded. Pin first, upgrade second.
If you'd rather not re-measure loudness across every FFmpeg release for the rest of the pipeline's life, the FFmpeg Micro quickstart runs presigned upload, transcode, poll and download from the dashboard, with a temporary API key created on the spot. The free tier needs no card and gives you 200 tokens at sign-up, about 33 minutes of input video at one token per 10 seconds, and failed jobs are never billed.
About Javid Jamae
Founder & CEO at FFmpeg Micro
Javid is a software engineer, author, and entrepreneur with over 25 years of professional software development experience across enterprise, startup, and consulting environments. He founded FFmpeg Micro to make video processing accessible to developers through a simple, automation-first REST API.
You might also like

FFmpeg 9 Didn't Rewrite the Filter Graph. Keep Your Workarounds
The FFmpeg 9 filter graph rewrite claim, tested: we reran four documented errors on 8.1.3 and 9.0.2 to show which workarounds you can delete and which stay.

Kling 4.0 washed out on TikTok? Fix the tag, then the 9:16
Kling 4.0 TikTok washed out? Most 21:9 and 4K clips need a Rec.709 re-tag, not a tone map. ffprobe first, then the crop-vs-pad math for 9:16, 1:1 and 4:5.

Your 4K AI video isn't TikTok-ready. Convert it to 1080x1920
Convert 4K video for TikTok: downscale 10-bit AI output to 1080x1920 8-bit SDR H.264, cap the bitrate, normalize audio. FFmpeg command plus one API call.
Ready to process videos at scale?
Start using FFmpeg Micro's simple API today. No infrastructure required.
Get Started Free