`FFmpegCommandBuilder` has emitted `-c:a libvorbis` since the day it was written, and libvorbis was not in the AAR this app ships: the configure line omitted `--enable-libvorbis`, and `strings` on both ABIs' `libavcodec.so` named every other external encoder and not that one. The arm was unreachable from both ends, so nobody ever hit it -- but the first user to pick Ogg Vorbis would have got `Unknown encoder 'libvorbis'`. That is #238's shape again: two individually-correct facts, a builder arm and a configure line, that no test put together, and that no coverage number can see. So the binary is rebuilt rather than the arm rewritten. FFmpeg's in-tree `vorbis` encoder was already in there and was tried first; it is experimental, stereo-only, and its quality knob spans 2x its floor against libvorbis's 6x. Shipping it would have meant `-strict experimental`, a forced `-ac 2` that silently upmixes every mono source, and a slider with nowhere to go. What ships instead is the arm as originally written, `-c:a libvorbis -q:a 5`, with `OGG_VORBIS` added to the presets, `VORBIS` added to `ENCODABLE_AUDIO`, and Ogg's per-codec extension fixed so a Vorbis file is not named `.opus`. The flag is `--enable-libvorbis`, read out of ffmpeg-kit's `get_library_name()` rather than guessed: the `--enable-lame` / `--enable-opus` rule predicts `--enable-vorbis`, and that is not it. An unrecognised `--enable-*` is ignored silently, so the artifact was checked before `bin/README.md` was touched -- `libvorbis` present in both ABIs, the configure line otherwise identical, FFmpeg still n8.1.2, 10 shared libraries per ABI, every LOAD still `0x4000`. Both mutations were run on API 34 rather than predicted. Pointing the arm at `libopus` reddens the e2e test with `expected:<[audio/vorbis]> but was:<[audio/opus]>` while its `OggS` assertion still passes, which is why the track MIME is asserted and the container magic is not enough. Adding `-ac 2` back reddens it with `expected:<[1]> but was:<[2]>`: this class's own fixture is mono, so mono staying mono is an assertion rather than a claim. The unit test's load-bearing assertion inverts with this change and is rewritten to say so. It used to assert that `libvorbis` was *absent*; it now asserts the encoder name plus the two flags that must not be there. Nothing on the JVM can tell a real encoder name from a fictional one -- which is exactly how this survived four coverage waves -- so the e2e test is the only thing that proves the positive. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
95 lines
4.0 KiB
Markdown
95 lines
4.0 KiB
Markdown
# Prebuilt FFmpeg
|
|
|
|
`ffmpeg-kit-next-8.1.1.aar` is committed here deliberately, and this file records what
|
|
it is so the binary is auditable rather than opaque.
|
|
|
|
## Why it is committed
|
|
|
|
Tests must be deterministic. When CI rebuilt FFmpeg on every run, a red build could mean
|
|
"the code is broken" or "a 40-minute cross-compile hiccuped", and those are not the same
|
|
signal. Committing the artifact removes the second possibility entirely: a test run
|
|
either passes or points at real code.
|
|
|
|
It also removes roughly forty minutes from every cold CI run.
|
|
|
|
## Provenance
|
|
|
|
| | |
|
|
|---|---|
|
|
| Upstream | [arthenica/ffmpeg-kit-next](https://github.com/arthenica/ffmpeg-kit-next) v8.1.1 |
|
|
| FFmpeg | 8.1.2 |
|
|
| NDK | r27d (27.3.13750724), pinned by the upstream flake |
|
|
| API level | 33, matching the app's minSdk |
|
|
| ABIs | arm64-v8a, x86_64 |
|
|
| Shared libraries | 20 (10 per ABI) |
|
|
| SHA-256 | `c8f4491d2c626566cbf18d5035513c1a5d8049e6696531342ea030c5427df507` |
|
|
| Rebuilt | 2026-09-06, to add libvorbis (#254). Previous archive: `ae188c9a…`, same tag and FFmpeg version, one library fewer |
|
|
|
|
Configure line, read back out of the shipped `libavutil.so`:
|
|
|
|
```
|
|
--enable-asm --enable-cross-compile --enable-gpl --enable-iconv
|
|
--enable-inline-asm --enable-jni --enable-libass --enable-libdav1d
|
|
--enable-libfontconfig --enable-libfreetype --enable-libfribidi
|
|
--enable-libharfbuzz --enable-libjxl --enable-libmp3lame --enable-libopus
|
|
--enable-libsvtav1 --enable-libvorbis --enable-libvpx --enable-libx264
|
|
--enable-libx265 --enable-lto --enable-mediacodec --enable-neon
|
|
--enable-optimizations --enable-pic --enable-pthreads --enable-shared
|
|
--enable-small --enable-swscale --enable-v4l2-m2m --enable-version3
|
|
--enable-zlib
|
|
```
|
|
|
|
`--enable-libvorbis` is the one that arrived late, in #254, and the two ways to get it wrong are
|
|
worth having written down. ffmpeg-kit's `--enable-*` names are its own — `--enable-lame` for
|
|
libmp3lame, `--enable-opus` for libopus — so `--enable-vorbis` is the plausible guess and it is not
|
|
the flag; `get_library_name()` in the upstream `scripts/function.sh` calls library 9 `libvorbis`.
|
|
And an unrecognised `--enable-*` is **ignored silently**, so a build that dropped it looks exactly
|
|
like one that worked. What tells them apart is the binary:
|
|
|
|
```sh
|
|
unzip -p bin/ffmpeg-kit-next-8.1.1.aar 'jni/x86_64/libavcodec.so' > /tmp/libavcodec.so
|
|
strings /tmp/libavcodec.so | grep -x libvorbis # and the same for arm64-v8a
|
|
```
|
|
|
|
Every `.so` reports `LOAD align 0x4000`, so the archive satisfies the 16 KB page-size
|
|
requirement. Verify with:
|
|
|
|
```sh
|
|
unzip -o bin/ffmpeg-kit-next-8.1.1.aar 'jni/*' -d /tmp/aarcheck
|
|
for f in /tmp/aarcheck/jni/*/*.so; do
|
|
readelf -lW "$f" | awk -v f="$f" '$1=="LOAD"{print f, $NF}'
|
|
done | sort -u -k2
|
|
```
|
|
|
|
## Licensing
|
|
|
|
Built with `--enable-gpl` and `--enable-version3`, so this binary is **GPL-3.0** and the
|
|
distributed APK is GPL-3.0 with it. That is deliberate: x264 and x265 are the only route
|
|
to CRF and two-pass rate control, which no Android hardware encoder exposes. See
|
|
[`../LICENSES/README.md`](../LICENSES/README.md).
|
|
|
|
GPL-3.0 obliges us to ship corresponding source with the binary. The recipe in
|
|
[`../tools/ffmpeg`](../tools/ffmpeg) is that source, and it remains the authority: this
|
|
archive is its output, not a substitute for it.
|
|
|
|
## Rebuilding
|
|
|
|
```sh
|
|
cd tools/ffmpeg
|
|
podman build -t ffmpeg-kit-builder:local -f Containerfile .
|
|
mkdir -p out
|
|
podman run --name ffmpeg-build -v "$PWD/out":/work/out:Z localhost/ffmpeg-kit-builder:local full
|
|
cp out/ffmpeg-kit-next-*.aar ../../bin/
|
|
```
|
|
|
|
Update the SHA-256 above when you do. Note that replacing this file adds another ~34 MB
|
|
blob to git history permanently, so rebuild only when the FFmpeg version or the configure
|
|
flags actually change.
|
|
|
|
## F-Droid
|
|
|
|
F-Droid's scanner flags checked-in prebuilt native libraries. If the app is submitted
|
|
there, the metadata needs a `scandelete` entry for `bin/` so their build uses the recipe
|
|
in `tools/ffmpeg` rather than this archive. Nothing here prevents a from-source build;
|
|
the recipe is complete on its own.
|