Changes in this fork relative to upstream arthenica/ffmpeg-kit, release by release. For native toolchain/build instructions see BUILD.md; for moving from the old Maven Central artifacts see MIGRATION.md.
Critical fix — audio pipeline (all four 8.1 tiers).
- Fix (C-CRIT):
all_channel_countscrash infftools_ffmpeg_filter.c—av_opt_set_int(abuffersink, "all_channel_counts", 1)was called during filter graph initialization. FFmpeg 8.x removed this option fromabuffersink'sAVOptiontable; the call returned an error that immediately aborted the filter graph, causing every audio operation (even a trivial AAC→PCM passthrough) to fail with:Fix: removed theOption 'all_channel_counts' is not a runtime option Error reinitializing filters! Conversion failed!av_opt_set_intcall. The newAVChannelLayoutAPI in FFmpeg 8.x handles flexible channel counts without this option. Affects all four 8.1 tiers; upgrade from any 8.1.x is strongly recommended.
WhisperKit JNI quality fixes for the Full and Full GPL tiers. No change for Free or Basic tiers.
- Fix (C-1): use-after-free in
nativeFullTranscribe— null-check added foraudio_dataandlanguagebeforeGetFloatArrayElements/GetStringUTFChars; returns-1with a log instead of crashing on null input. - Fix (M-1):
nativeGetSystemInfonull guard —whisper_print_system_info()return value now guarded against NULL before passing toNewStringUTF. - Fix (M-2): dead code removed —
cs_to_srt_time()helper function was defined but never called; removed. - CI (all 12 workflows): removed dead
actions/cache/restore@v4steps that were always cache misses (real restore uses git-based checkpoint branches).
Breaking — FFmpeg 8.x audio resampling and channel conversion:
FFmpeg 8.x removed all_channel_counts as a runtime option. Both -ac N and -ar N (or any use of the aresample filter, explicit or implicit) fail with:
Option 'all_channel_counts' is not a runtime option
Error reinitializing filters! Conversion failed!
Workaround: extract raw PCM without any -af/-ar/-ac, then handle downmix and resampling in Java:
// Extract raw PCM as-is (no channel/rate conversion in FFmpeg)
FFmpegKit.execute("-i input.mp4 -vn -c:a pcm_s16le -y output.wav");
// Parse WAV header (offset 22 = numChannels s16le, offset 24 = sampleRate i32le)
// Downmix channels to mono, then linear-interpolation resample to 16000 HzThis is required for Whisper.cpp pipeline compatibility.
Quality fix release for all four tiers of the 7.1 LTS line. Includes the JNI leak fix and version string corrections from the 8.1.5 Free release.
- Fix (C-1): JNI memory leak in
registerNewNativeFFmpegPipe—GetStringUTFCharsresult was never released, leaking one JVM string buffer per FFmpeg pipe creation. Fixed by saving the return value, callingmkfifo, releasing the string, then returning. - Fix (C-2):
getVersion()returned"6.0-lts"at runtime —FFMPEG_KIT_VERSIONwas hardcoded to"6.0"inffmpegkit.h. Updated to"7.1". - Fix (M-1):
NativeLoader.loadVersion()test-mode fallback — hardcoded"6.0"updated to"7.1"so unit tests see the correct version string. - CI: removed dead
actions/cache/restore@v4steps in all four 7.1 workflows.
Quality fix release for all four tiers of the 6.0 LTS line. Supersedes 6.0.2 (which was published to Maven Central before the JNI fix below).
- Fix (C-1): JNI memory leak in
registerNewNativeFFmpegPipe—GetStringUTFCharsresult was never released, leaking one JVM string buffer per FFmpeg pipe creation. Fixed by saving the return value, callingmkfifo, releasing the string, then returning. Maven Central artifact:dev.ffmpegkit-maintained:ffmpeg-kit-free:6.0.3. - CI: removed dead
actions/cache/restore@v4steps in all four 6.0 workflows.
Free tier: bug-fix release for ffmpeg-kit-free-81. No native codec change — only JNI correctness fixes.
- Fix (C-1):
getVersion()returned"6.0-lts"at runtime —FFMPEG_KIT_VERSIONwas hardcoded to"6.0"inffmpegkit.h. Updated to"8.1". All three API paths now agree:getVersion()→"8.1-lts", Maven coordinates8.1.5,build.gradleversionName "8.1". - Fix (C-2): JNI memory leak in
registerNewNativeFFmpegPipe—GetStringUTFCharsresult was never released, leaking one JVM string buffer per FFmpeg pipe creation. Fixed by saving themkfiforeturn value, releasing the string, then returning. - Fix (M-4):
NativeLoader.loadVersion()test-mode fallback — hardcoded"6.0"updated to"8.1"so unit tests see the correct version string. - Fix: use-after-free in
nativeInitContext(WhisperKit, Full/Full GPL only) — the failure logLOGE("Failed to load Whisper model from %s", path)was emitted afterReleaseStringUTFChars, makingpatha dangling pointer. Log is now emitted before Release. - Fix: stale comment in
build-81-free.yml— copy-paste from the 7.1 workflow said "other three 7.1 tiers"; corrected to 8.1.
Basic/Full/Full GPL: no change for these tiers in this version bump.
First release with a working Whisper JNI bridge for the Full and Full GPL tiers. No code change for the Free or Basic tiers.
- Fix: Whisper was never actually built —
main-android.shloop capped at index 50; Whisper is at index 92. Extended to{1..93}; addedwhisper)case in the dependency switch. Extendedandroid.shflags loop from{0..61}to{0..92}. - New:
libwhisperkit.so— JNI shared library built conditionally (only whenlibwhisper.ais present in the prebuilt tree). Added inandroid/jni/Android.mk; links all ggml static archives with--start-group/--end-group. - New:
whisperkitjni.c— C JNI bridge wrapping the Whisper.cpp v1.7.5 C API:nativeInitContext,nativeFreeContext,nativeFullTranscribe,nativeGetSegmentCount/Text/T0/T1,nativeGetSystemInfo. - New:
WhisperKit.java— public Java API:createFromFile(),transcribe(),transcribeToSrt(),translate(),translateToSrt(), low-level segment access. Graceful degradation on Free/Basic tiers (loads the library conditionally;createFromFile()throws a descriptiveIOExceptionwhen the native library is absent). - New:
TranslationProvider— functional interface for plugging in any external translation service (DeepL, LibreTranslate, Google Translate, Azure, etc.). PowersWhisperKit.transcribeAndTranslate()andtranscribeToSrtAndTranslate(), which translate each SRT segment individually to keep timestamps in sync. - New:
DeepLTranslationProvider— batteries-included implementation for the DeepL REST API. Auto-selects the Free vs. paid endpoint from the API key format. UsesHttpsURLConnection— no extra dependencies. - New:
LibreTranslateProvider— batteries-included implementation for any LibreTranslate-compatible server (self-hosted or public). Configurable server URL and optional API key. UsesHttpsURLConnection— no extra dependencies. - New:
docs/WHISPERKIT.md— full developer documentation: model download, PCM extraction via FFmpegKit, all API methods, DeepL/LibreTranslate quickstarts, end-to-end example, thread-safety and performance notes.
Rebuild of all four tiers with NDK r27c (27.2.12479018 — current NDK LTS), the first 8.1 release to use the newer toolchain. Source identical to 8.1.2. Maven artifact for the Free tier: dev.ffmpegkit-maintained:ffmpeg-kit-free-81:8.1.4.
- NDK r26c → r27c for the entire 8.1 line (all 4 tiers). The 6.0 and 7.1 lines remain on r26c.
- Clang from NDK r27c (
clang-r510928) replaces the r26c compiler across all 8.1 native builds.
Accidental release: version bump targeting r27c but the CI workflow download URL was not yet updated at tag time, resulting in an r26c build. The Maven Central artifact ffmpeg-kit-free-81:8.1.3 exists but is functionally identical to 8.1.2 (same NDK r26c). Superseded by 8.1.4. Paid tiers were never built as 8.1.3.
A third build tree, android-8.1-lts/, targeting FFmpeg n8.1.2 (8.1 "Hoare" line, latest patch as of 2026-06-17). Same four-tier structure (Free/Basic/Full/Full GPL), same NDK r26c, same 16 KB page alignment. Free tier Maven artifact: dev.ffmpegkit-maintained:ffmpeg-kit-free-81:8.1.2.
New in this line vs 7.1:
- FFmpeg
n8.1.2— latest stable in the 8.x line - Whisper.cpp v1.7.5 (ggml-org/whisper.cpp) integrated as library index 92 in the Full and Full GPL tiers — new
scripts/android/whisper.shbuild script, cmake-based, static, withWHISPER_BUILD_TESTS/EXAMPLES/SERVER=OFF - Vulkan video codec acceleration improvements (H.264, AV1, ProRes) from upstream 8.x
Status: Free tier published on Maven Central as dev.ffmpegkit-maintained:ffmpeg-kit-free-81:8.1.2. Paid tiers (Basic/Full/Full GPL) built and available on Gumroad.
FFmpeg 8.x breaking API changes found during port — all documented in doc/APIchanges in the FFmpeg source tree. Changes were required in our copies of fftools_ffmpeg.c and fftools_ffprobe.c (these are frozen snapshots of FFmpeg's internal CLI tool source, carried in the repo since 6.0 and only updated when a new FFmpeg version removes the fields they use):
-
--disable-postprocconfigure flag removed —libpostprocwas removed from FFmpeg 8.0 entirely. Dropping the flag fromscripts/android/ffmpeg.sh(and the unusedlinux/andapple/variants for consistency). -
AVFrame.key_frameremoved (deprecated since FFmpeg 6.1) — use!!(frame->flags & AV_FRAME_FLAG_KEY). Affected:fftools_ffmpeg.c(4 sites),fftools_ffprobe.c(1 site). -
AVFrame.interlaced_frameremoved (deprecated since FFmpeg 6.1) — use!!(frame->flags & AV_FRAME_FLAG_INTERLACED). Affected:fftools_ffmpeg.c(1 site),fftools_ffprobe.c(1 site). -
AVFrame.top_field_firstremoved (deprecated since FFmpeg 6.1) — reading:!!(frame->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST); writing:frame->flags |= AV_FRAME_FLAG_TOP_FIELD_FIRSTor&= ~AV_FRAME_FLAG_TOP_FIELD_FIRST. Affected:fftools_ffmpeg.c(3 read sites, 1 write site),fftools_ffprobe.c(1 read site). -
AVCodecContext.ticks_per_frameremoved — was used in two duration-calculation expressions. In the general case (non-interlaced), effectively cancelled out (same value in numerator and denominator), replaced with1. Affected:fftools_ffmpeg.c(4 sites in 2 identical blocks). -
AVStream.nb_side_data/AVStream.side_dataremoved — stream-level packet side data moved toAVStream.codecpar->coded_side_data/nb_coded_side_data.av_stream_new_side_data()also removed, replaced byav_packet_side_data_new(&codecpar->coded_side_data, &codecpar->nb_coded_side_data, type, size, 0)(available since FFmpeg 7.0). Affected:fftools_ffmpeg.c(3 blocks, 5 sites total),fftools_ffprobe.c(1 block),fftools_ffmpeg_demux.c(1 site). -
av_stream_get_side_data()removed — replaced byav_packet_side_data_get(codecpar->coded_side_data, nb_coded_side_data, type)which returns aconst AVPacketSideData *(access.datafor the payload). Affected:fftools_ffmpeg_filter.c(1 site — display matrix auto-rotation). -
AV_CODEC_CAP_SUBFRAMESremoved — this codec capability flag was eliminated in FFmpeg 8.0. The only use was a diagnostic log line infftools_opt_common.c; the entireifblock was removed. Affected:fftools_opt_common.c(1 site). -
AVFilter.process_commandmember removed from public struct — this function pointer was part of the internalAVFilterstruct exposed publicly; it was removed in FFmpeg 8.x as part of filter API cleanup. The only use was a ternaryfilter->process_command ? 'C' : '.'in a diagnostic listing infftools_opt_common.c. Replaced with literal0(always outputs'.'). Affected:fftools_opt_common.c(1 site). -
AVFrame.pkt_pos/AVFrame.pkt_sizeremoved — were used in ffprobe's frame output to print the originating packet's byte position and size. No equivalent exists onAVFramein FFmpeg 8.x (this information is now only available at demux time onAVPacket). Replaced withprint_str_opt("pkt_pos", "N/A")/print_str_opt("pkt_size", "N/A")— these fields will show as N/A in ffprobe output for frames decoded with this build. Affected:fftools_ffprobe.c(2 sites). -
FF_PROFILE_UNKNOWNrenamed toAV_PROFILE_UNKNOWN— part of a broaderFF_PROFILE_*→AV_PROFILE_*rename in FFmpeg 8.0. Affected:fftools_ffprobe.c(1 site). -
AVHDRVividColorToneMappingParamsthree-spline fields restructured — the individual spline parameters (three_Spline_TH_mode,three_Spline_TH_enable_MB,three_Spline_TH_enable,three_Spline_TH_Delta1,three_Spline_TH_Delta2,three_Spline_enable_Strength) were direct fields on the parent struct in FFmpeg 7.x. In FFmpeg 8.x they are now per-element fields (th_mode,th_enable_mb,th_enable,th_delta1,th_delta2,enable_strength) inside the newAVHDRVivid3SplineParamssub-struct, accessible viatm_params->three_spline[j](note also: lowercasesin the array field name). Affected:fftools_ffprobe.c(1 block).
Other port fixes (non-API):
--disable-postprocconfigure abort — this was the first build failure: FFmpeg configure exits immediately with "Unknown option" for any unrecognised flag, so this single stale flag blocked the entire FFmpeg compile step.src/main/cpp/directory missing from git — the JNI source tree (ffmpegkit.c,fftools_*.c/h,AndroidManifest.xml, all Java sources) was not included when theandroid-8.1-lts/directory was initially set up. Copied fromandroid-7.1-lts/, which carries the same codebase.- All
.shscripts missing execute bit — the entireandroid-8.1-lts/scripts/tree was added to git with mode100644instead of100755, causingandroid.shto fail with "Permission denied" (exit 126) before any build work started. Fixed withgit update-index --chmod=+xon all.shfiles. android/gradlewmissing execute bit — same root cause:android-8.1-lts/android/gradlewwas tracked at mode100644instead of100755, causing./gradlew: Permission deniedat the Gradle AAR assembly step (afterndk-buildhad already succeeded). Fixed withgit update-index --chmod=+x android-8.1-lts/android/gradlew.
A second build tree, android-7.1-lts/, coexists with the original android-6.0-lts/. Same four tiers (Free/Basic/Full/Full GPL), same NDK r26c, same 16 KB page size alignment — FFmpeg updated to n7.1.5. Free tier published on Maven Central as dev.ffmpegkit-maintained:ffmpeg-kit-free-71:7.1.5; paid tiers available on Gumroad.
Port findings — all four tiers compiled cleanly against FFmpeg n7.1.5 with only two generic fixes needed:
- All four tiers (Free/Basic/Full/Full GPL) compile cleanly against FFmpeg
n7.1.5, with only two generic fixes needed, neither library-specific:scripts/android/ffmpeg.sh:emms.hmoved fromlibavutil/x86/emms.htolibavutil/emms.hupstream between 6.0 and 7.1 — updated the path our script manually copies it from/to.ffmpegkit.c/ffprobekit.c(FFmpegKit's own JNI bridge files, not copied from upstream FFmpeg): both callstrlen/strcpywithout#include <string.h>— a latent bug that happened to compile under 6.0 because some FFmpeg header transitively pulled it in; that path is gone in 7.1, exposing it. Added the missing include directly.
- An initial audit (before any of this was attempted) predicted a large, risky JNI wrapper rewrite would be needed, because upstream's
fftools/ffmpeg.cshrank from 4196 to 1017 lines between 6.0 and 7.1 with logic moved into newffmpeg_dec.c/ffmpeg_enc.c/ffmpeg_sched.cfiles. That turned out not to apply to us: those new files are internal to upstream's own standaloneffmpegCLI binary, never compiled as a library — FFmpegKit's wrapper has always had its own independent fork of the transcode logic (fftools_ffmpeg.c, unchanged in this fork since 6.0) that only depends on the real public API (libavcodec/libavformat/libavutil), which stayed compatible. The bitfield-truncation warning patch (-Wno-error=single-bit-bitfield-constant-conversioninAndroid.mk) is also still needed for the same reason — our copy offftools_ffmpeg_mux_init.cis unchanged, even though upstream's own version fixed it (int→unsignedbitfields) in the part of the file we don't carry forward. - Runtime-verified, not just compile-checked: a temporary local test app (
test-app/, gitignored, not part of the repo) confirmed on a real Pixel 7 Pro (arm64-v8a) that the Free tier's ported.aaractually works —FFmpegKitConfig.getFFmpegVersion()reportsn7.1.5,FFmpegKit.execute("-version")runs and returns success, zeroUnsatisfiedLinkError. - An attempt to automate this same check in CI via an instrumented test (
android-7.1-lts/.../src/androidTest/.../SmokeTest.java+.github/workflows/port-71-smoketest.yml) hit a hard platform wall: the modern Android Emulator categorically refuses to boot anarm64-v8asystem image on anx86_64host —FATAL: Avd's CPU Architecture 'arm64' is not supported by the QEMU2 emulator on x86_64 host— confirmed identically on both a GitHub Actions runner and a local Windows machine. Switching to a genuine ARM64 GitHub-hosted runner (ubuntu-24.04-arm, free for public repos, matching host/guest architecture) avoids that specific error but hit a second blocker first: that image doesn't auto-configureANDROID_HOME/ANDROID_SDK_ROOTat all (tracked upstream: actions/runner-images#11460). Not pursued further since the real-device path above already gave a conclusive answer; both diagnostic files are left in the repo in case the CI-emulator path is worth revisiting later.
Closes the two "known gaps" from v6.0.0-lts-android below. Not yet shipped as a downloadable .aar — push a new v* tag to trigger the CI build and cut a release once these are ready to ship.
Added
- Real CI build:
.github/workflows/build.ymlnow actually runs./android.sh --full ...onubuntu-24.04(NDK r26c, JDK 17, arm64-v8a only) instead of the previous placeholder, triggered onv*tags. Produces a downloadableffmpeg-kit-full-arm64-v8aartifact. - CI step that enforces 16 KB ELF segment alignment on every built
.soand fails the build if any library isn't aligned. -Wl,-z,max-page-size=16384/-Wl,-z,common-page-size=16384added to the native linker flags (scripts/function-android.shget_ldflags()for the FFmpeg libraries, and a newandroid/jni/Application.mkforlibffmpegkit.so).- Three more build tiers alongside the original
fullbuild (renamed Full,build.yml), each its own workflow/cache/ci-cache-*branch so none of them ever share a cache namespace or mix artifacts:- Full GPL (
build-gpl.yml, $39 on Gumroad):--full --enable-gpl, addsx264/x265/xvidcore/libvidstab/rubberband. Changes the AAR's license to GPL-3.0 — confirmed via a dedicated CI step that checks the GPLv3 text both atandroid/ffmpeg-kit-android-lib/src/main/res/raw/license.txtand inside the built.aar'sres/raw/license.txt. - Basic (
build-basic.yml, $19 on Gumroad):--fullminuskvazaar(H.265 encode) and four niche blocks (OCR:tesseract+leptonica; subtitle/text rendering:libass+harfbuzz+freetype+fontconfig+fribidi, which also drops FFmpeg'sdrawtextfilter;srt;chromaprint).openh264(H.264 encode) is deliberately kept — it's the single most common use case, an earlier draft dropped it too and that made the tier much less useful. - Free (
build-free.yml, Maven Central, no charge): software-only (no--enable-android-media-codec), explicit--enable-libaom --enable-dav1d --enable-libvpx --enable-opus --enable-libvorbis --enable-speexinstead of--full-minus-something, since it's a much smaller set. No H.264/H.265 encode, no TLS, no images beyond what FFmpeg needs internally, no subtitles/OCR/SRT/fingerprinting. - See README § Available tiers for the full per-tier feature table shown to customers.
- Full GPL (
- Maven Central publishing for the Free tier:
com.vanniktech.maven.publish(pinned to 0.34.0 — 0.35+ requires AGP 8.13+, all four tiers are pinned to AGP 8.6.0) applied toffmpeg-kit-android-lib/build.gradle, coordinatesdev.ffmpegkit-maintained:ffmpeg-kit-free, full POM metadata for Central Portal validation.build-free.ymlgained aPublish to Maven Centralstep gated onstartsWith(github.ref, 'refs/tags/')(notworkflow_dispatch) since a Central Portal release can't be un-published. Credentials viaOSSRH_USERNAME/OSSRH_PASSWORD(Sonatype user token) andGPG_PRIVATE_KEY/GPG_PASSPHRASE(in-memory signing key) repo secrets. Namespacedev.ffmpegkit-maintainedverified directly on the Central Portal (not theio.github.<org>auto-verification path, which only covers personal GitHub usernames, not organizations).
Changed
compileSdk/targetSdkbumped from 33 to 35 (Android 15) inandroid/ffmpeg-kit-android-lib/build.gradle.- Android Gradle Plugin bumped 8.1.0 → 8.6.0, Gradle wrapper 8.2.1 → 8.7 (required for clean compileSdk 35 support; verified locally with
./gradlew :ffmpeg-kit-android-lib:assembleRelease). ndkVersionfield in the Gradle module corrected to26.2.11394342(r26c) to match what's actually used; this field doesn't drive the native build itself (that'sandroid.sh/ndk-build), it was just stale.- Removed the manual
android.publishing.singleVariant('release') { withJavadocJar(); withSourcesJar() }block fromffmpeg-kit-android-lib/build.gradle:com.vanniktech.maven.publishauto-configures the exact same thing for Android libraries, and having both threw "singleVariant publishing DSL used multiple times ... is not allowed" at configuration time../gradlew :ffmpeg-kit-android-lib:assembleReleaseverified to still produce an identical AAR with the plugin handling it alone. - Groovy gotcha while wiring up the plugin:
publishToMavenCentral(automaticRelease: true)fails ("Could not find method ... for arguments [{automaticRelease=true}]") because Groovy's named-argument-via-map sugar only applies to methods that accept aMap, not a plainBooleanparameter — the correct call is the positionalpublishToMavenCentral(true).
CI build fixes (getting the from-source build actually green on NDK r26c / Ubuntu 24.04)
Each of these surfaced one at a time as the CI build progressed further with each fix:
yes | sdkmanager --licensesfailed under GitHub Actions' defaultbash -e -o pipefail:yesgets a broken-pipe exit oncesdkmanagerstops reading, whichpipefailturned into a step failure even though licenses were accepted fine. Wrapped withset +o pipefail/set -o pipefail.- Missing apt prerequisites (
groffbroke libiconv's man-page build target; restored the rest of upstream's proven list:doxygen cmake autogen autopoint gtk-doc-tools libtasn1-bin) and an incomplete arch restriction (--disable-arm-v7aalone still built the neon variant; added--disable-arm-v7a-neon). - NDK r24+ clang turned
-Wimplicit-function-declaration(libaom neon intrinsics) and-Wincompatible-function-pointer-types(SDL's GLES2 typedefs) into hard errors by default. Downgraded both to warnings centrally inget_common_cflags(). cpu_featuresv0.8.0'sCMakeLists.txtdeclares an oldcmake_minimum_requiredthat current CMake refuses outright ("Compatibility with CMake < 3.5 has been removed"). Added-DCMAKE_POLICY_VERSION_MINIMUM=3.5to the sharedandroid_ndk_cmake()helper and to libaom's separate cmake invocation.- That same policy fix didn't cover
cpu_features' own vendored googletest sub-build (a separate nestedcmakeinvocation with the identical issue). Disabled it outright with-DBUILD_TESTING=OFFinstead of chasing the flag through a nested process. get_common_linked_libraries()included-L.../toolchains/llvm/prebuilt/linux-x86_64/lib— the NDK's host-side lib dir, not a target-arch one. libvpx's configure does a-staticlink probe as part of its toolchain capability check, andld.lldpicked up the host'slibc++abi.athere and rejected it ("is incompatible with aarch64linux" → "Toolchain is unable to link executables"). Removed that path; the target toolchain lib dir + target sysroot already cover everything needed for aarch64 linking.fftools_ffmpeg_mux_init.cassigns the literal1to several 1-bit signed bitfields (truncates to-1, harmless but now clang-flagged) during the always-runndk-buildstep forlibffmpegkit.soitself — found via an isolated--enable-libass-only test build that reaches that samendk-buildstep in ~10 minutes instead of waiting on the other ~25 libraries--fullenables. Fixed with-Wno-error=single-bit-bitfield-constant-conversioninMY_CFLAGSinandroid/jni/Android.mk.- The actual cause of a
--fullattempt hanging for ~6h until GitHub's own hard timeout killed it (conclusion: cancelled, no error — confirmed via direct API check onrun_started_at/updated_at; the bitfield fix above was real but unrelated to this):--fullenablesgnutls,lame, andlibass, each independently cascadingset_virtual_library "libiconv" 1.--disable-lib-gnutlsthen callsset_library "gnutls" 0, which cascadesset_virtual_library "libiconv" 0too — unconditionally wiping whatlame/libasshad just enabled.libiconv's "OK" flag then never gets set, andmain-android.sh's dependency-resolution loop (which only exits once every enabled library reaches "completed") spins forever re-printingINFO: Skipping <lib>, dependencies built=...for every library still waiting on it (fontconfig,lame,libass,libxml2) — confirmed via the actualbuild.log: 198,019 such lines (~6,600 repeats of the full pass) by the time it was cancelled. Fixed by makingset_virtual_library()ignore disable calls entirely ($2 == 0returns immediately) — these are shared platform-capability flags multiple unrelated libraries request independently, so one consumer being disabled must never cascade-disable a dependency another still-enabled consumer needs. Verified via the same isolated test build with--disable-lib-gnutlsadded (the exact flag that triggers it) and a 15-minute step timeout, so a still-broken fix would fail fast rather than risk another multi-hour hang.
CI tooling
- Added a failure-diagnostics step that dumps the toolchain env vars and the most recently modified
config.logfiles undersrc/, since the only log we printed before (src/ffmpeg/ffbuild/config.log) doesn't cover failures in the other ~30 libraries thefullvariant builds. - Cached
~/.ndk(keyed on the fixed NDK version) andprebuilt/+src/(keyed on a hash ofandroid.sh+scripts/**, norestore-keysfallback — android.sh's incremental build only checks whetherprebuilt/<arch>/<lib>exists, not what flags built it, so a stale cache from a different script version must not be silently reused) to avoid recompiling already-succeeded libraries on every retry. Turned outactions/cache's save step is skipped entirely when the job is cancelled or times out — exactly the failure mode above — so it had never actually saved anything across several attempts; added a second, independent checkpoint mechanism inbuild.ymlthat pushesprebuilt/+src/to aci-cachebranch every 2 minutes in the background, since agit pushthat already succeeded survives a later kill. - Added
.github/workflows/test-harfbuzz.yml, aworkflow_dispatch-only diagnostic that isolateslibass's dependency chain (freetype,fribidi,fontconfig,harfbuzz) plus the nativendk-buildstep, sharingbuild.yml's exact cache key so a clean run there also primes the cache for the next full build. Used to find and verify the bitfield fix above in ~10 minutes instead of multi-hour--fullround trips. Delete once no longer needed for this kind of triage.
First release of the maintained fork.
Added
- Prebuilt
ffmpeg-kit-6.0-lts-arm64-v8a.aar, compiled against NDK r26c (26.2.11394342), available from Releases. - Android-only native build pipeline (
android.shand supporting scripts), imported from upstream and kept buildable independent of the other platform scripts upstream shipped. docs/BUILD.md— WSL2/Ubuntu build guide for producing the.aarfrom source.CONTRIBUTING.mdand license upgrade to LGPL-3.0.
Changed
- Project scope narrowed to Android only — see README § Scope for rationale. iOS/macOS/tvOS/Linux/Flutter/React Native sources from upstream are not carried into this fork.
Known gaps (tracked, not yet shipped)
compileSdk/targetSdkare still 33 inandroid/ffmpeg-kit-android-lib/build.gradle; bumping to 35 (Android 15) is planned but not done.- 16 KB memory page size alignment is documented as a manual check (BUILD.md § 8) but not yet verified or enforced in CI.
- Only
arm64-v8ais published as a prebuilt release; other ABIs must be built from source. - Maven Central publication is in progress; the local
.aaris the only distribution method for now.
See README § Compatibility for the current state of these items.