Files
LibreMediaConverter/bin/README.md
T
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

4.0 KiB

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 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:

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:

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.

GPL-3.0 obliges us to ship corresponding source with the binary. The recipe in ../tools/ffmpeg is that source, and it remains the authority: this archive is its output, not a substitute for it.

Rebuilding

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.