Files
JMR-devandClaude Opus 5 d45abe7409 Rebuild the FFmpeg AAR with libvorbis, and make Ogg Vorbis reachable (#254)
`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>
2026-09-06 18:31:36 -05:00

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.