The ABI, correctness, ownership, and release-matrix bootstrap; Android compile/emulator phases; iOS compile and XCFramework integration; and Windows/macOS desktop closure are complete. Remaining integration and platform work includes:
- migrating go-avebi from its temporary backend fork to go-ffmpeg-ffi and rerunning its playback and resource matrix;
- Samsung Galaxy Tab A9+ physical runtime, MediaCodec, thermal, and sustained H.264/H.265 30/60 FPS qualification;
- signed runtime, VideoToolbox, audio, lifecycle, and sustained-load tests on a named physical iPhone; and
- native Windows ARM64 runtime evidence when a suitable runner is available.
The sections below retain the completed bootstrap plan and the evidence gates used to earn current support. Current claims are summarized in support.md.
- Adopt the
go-ffmpeg-ffirepository, package, and module identity. - Preserve the complete ffgo Git history, Apache-2.0 license, and upstream attribution.
- Record the exact upstream commit from which the hard fork starts.
- Carry the known FFmpeg 6 audio-layout,
swr_convert, callback, and FFmpeg 6/7 ABI corrections into a traceable baseline. - Replace inherited compatibility, coverage, platform, and performance claims that have not been verified.
- Add the hard-fork, Codex-assistance, and human-review disclosures.
Complete when a clean clone builds under the new module path and no public document presents inherited claims as go-ffmpeg-ffi guarantees.
- Centralize library discovery and registration instead of binding the complete
API from package
init()functions. - Read the complete core and optional-library version tuple before selecting an ABI family.
- Inventory every direct FFmpeg structure access and move verified layouts into
internal/abi; no private magic offsets remain. - Generate or verify layouts for FFmpeg 6, 7, 8, and 9 against matching headers.
- Establish a pinned Linux amd64 gate for the latest patch of the 6.0, 6.1, 7.0, 7.1, 8.0, 8.1, and 9.0 release lines.
- Version the C shim by operating system, architecture, shim API, and FFmpeg family; add a startup handshake and reject mismatches.
- Reject mixed families, FFmpeg 4, future development majors, and unknown layouts with a diagnostic error before unsafe field access.
- Decide whether FFmpeg 5.1 earns a narrowly scoped Debian 12 legacy tier, a CI job, and a sunset date. Otherwise remove it from the matrix.
Complete when every target family initializes through the same loader and all unsupported combinations fail closed.
- Model the complete FFmpeg send/receive protocol, including
EAGAINretry. - Flush once and drain delayed video and audio output through FFmpeg EOF.
- Preserve packets for every selected stream rather than losing interleaved data.
- Propagate decode, encode, flush, mux, and trailer errors consistently.
- Add focused fixtures for delayed codecs, multiple streams, seeking, EOF, and truncated input.
Complete when reference counts and timestamps demonstrate that normal and delayed frames are neither lost nor duplicated.
- Define owned, borrowed, clone,
Into, and zero-copy lifetimes. - Correct plane access,
extended_data, pooling, and native cleanup. - Pass callback handles as integer tokens, recover callback panics, and retain the original Go error.
- Add context-aware open/read operations and make close unblock pending I/O.
- Document object-level concurrency guarantees.
- Test repeated open/decode/seek/close, malformed and custom I/O, callback failure, cancellation, and concurrent independent decoders.
Complete when stress runs show no invalid callback pointers, leaked handles, unbounded native memory, file-descriptor growth, or blocked shutdowns.
PR 2 establishes the Linux amd64 release-line gate. PR 5 expands that same matrix with the complete behavioral, resource, and downstream integration suite, using the latest patched release pinned for each line:
| Line | Initial pin | Required |
|---|---|---|
| 5.1 | 5.1.10 |
Only if the legacy tier is accepted. |
| 6.0 | 6.0.1 |
Yes. |
| 6.1 | 6.1.6 |
Yes. |
| 7.0 | 7.0.3 |
Yes. |
| 7.1 | 7.1.5 |
Yes. |
| 8.0 | 8.0.3 |
Yes. |
| 8.1 | 8.1.2 |
Yes. |
| 9.0 | 9.0.1 |
Yes. |
These pins were checked on 2026-08-13 against the official FFmpeg release index.
Testing every release line catches header and build differences without running every historical patch that shares the same stable library ABI. A scheduled job checks for newer patch releases; pin updates remain explicit and reviewable.
Each required matrix job:
- builds a shared FFmpeg test configuration and the matching shim;
- verifies tarball signatures or checksums and records the configure flags;
- asserts the actual loaded versions and shim handshake;
- runs unit and integration tests with
CGO_ENABLED=0; - exercises decode, encode, audio resampling, custom I/O, seek, flush, and error paths with audio-only and audio/video media;
- runs repeated lifecycle and parallel-decoder stress tests;
- records goroutines, callback handles, file descriptors, RSS, and native allocations, with sanitizer or Valgrind coverage for the C shim;
- tests no-shim behavior separately for features that are genuinely optional.
CI-only FFmpeg builds may enable GPL codecs needed by inherited tests. They are not distributed. Prebuilt release shims remain subject to the LGPL-only policy in Architecture.
Local validation repeats the matrix from versioned directories inside the
workspace, never a transient system path. For each FFmpeg line it first tests
go-ffmpeg-ffi, then points a go-avebi integration checkout at the local module
with a workspace-only replace in that checkout. The existing go-ebiten-mcp
examples run against the same media fixture containing both video and sound so
decoding, audio conversion, playback, seeking, shutdown, and the callback path
are all exercised. A machine-readable result matrix records the exact Go,
FFmpeg, shim, go-avebi, and go-ebiten-mcp revisions.
Complete when every supported line passes the same required suite in CI and the local go-avebi matrix has no crashes, growing resources, or unexplained output differences.
- Set the high-level/low-level package boundary and consolidate duplicate constructors and options.
- Expose runtime diagnostics and capability discovery without leaking ABI details.
- Finish the concise user documentation and migrate only validated examples.
- Define semantic versioning, deprecation, security, and support-window policy.
- Publish reproducible shims, manifests, source/configuration material, and checksums for validated targets.
Complete when the API has an explicit compatibility promise and the first release can be reproduced from its tag.
Platform support is earned in three separate stages:
- Compile: every importable package and its tests compile for the target, with the expected public API present.
- Integrate: an external application packages the native libraries, loads FFmpeg, and exercises representative audio/video paths on the target OS.
- Qualify: named hardware passes codec, stability, and performance tests.
Passing an earlier stage does not imply a later one. In particular, emulator graphics acceleration is not evidence that a physical device provides FFmpeg MediaCodec, VideoToolbox, or 60 FPS performance.
go-ffmpeg-ffi remains independent of Ebitengine. Ebitengine applications are downstream integration fixtures: the binding does not import Ebitengine, expose an Ebitengine API, or make the engine part of its platform implementation.
| Order | Target | Architecture and floor | Planned evidence |
|---|---|---|---|
| 1 | Android production | arm64-v8a, Android 13 / API 33 |
Compile CI, external APK, and Samsung Galaxy Tab A9+ qualification. |
| 1 | Android emulator | x86_64, Android 13 / API 33 |
GPU-accelerated application integration; not a shipping ABI or hardware-codec benchmark. |
| 2 | iOS | iOS 13+ arm64 device; simulator arm64 and amd64 while supported by the selected Xcode |
Compile and Ebitengine XCFramework binding first; physical qualification waits for a named reference iPhone. |
| 3 | Windows | amd64, then arm64 |
Replace the Unix loader calls, add compile CI, and add native runtime evidence. |
| Continuous | macOS | amd64, arm64 |
Preserve the existing native compile/runtime jobs as regression gates. |
| Continuous | Linux | amd64, arm64 |
Preserve the primary FFmpeg release-line and stress matrix. |
PureGo treats
Android and iOS 64-bit targets as Tier 1, but requires CGO_ENABLED=1 for them.
The mobile build is therefore still PureGo-based, but it requires the Android
NDK or Xcode C toolchain. Desktop targets retain the CGO-free application-build
goal where PureGo supports it.
- Remove the blanket Android exclusions and replace them with capability-based build constraints.
- Split library open, symbol lookup, close, naming, and search policy by
platform. Android uses its native linker and packaged
.sofiles rather than desktop search paths. - Verify every enabled ABI layout against Android FFmpeg headers for each supported FFmpeg family. Do not infer layout compatibility from Linux alone.
- Keep the public API present. Operations that are genuinely unavailable on Android return a documented unsupported-capability error instead of disappearing behind build constraints.
- Pin an NDK and compile all packages and test binaries with API 33 toolchains
for
arm64-v8aandx86_64. Native FFmpeg libraries are not required for the compile-only gate. - Compare the exported API with the Linux reference so a green mobile build cannot be produced by accidentally excluding most of the module.
Complete when go list ./..., package builds, and test compilation succeed for
both Android targets with the intended public surface and without an Ebitengine
dependency.
Current master evidence (13 August 2026): this compile gate passes for API 33
arm64 and amd64, including every root package and test binary. The external
Ebitengine fixture remains a separate module.
- Maintain the external-module fixture in
integration/android-ebitenand build it withapk-ebiten-builder. Packaging FFmpeg.sofiles belongs to that fixture or its builder, not to the Go binding. - Run an Android 13 / API 33
x86_64AVD with VM acceleration and host GPU graphics where the runner exposes them. - Install and launch the APK through the connected Android automation tooling; retain screenshots, application state, logcat output, FFmpeg library/version diagnostics, and crash traces as test evidence.
- Exercise library initialization, audiovisual decode, audio conversion, frame presentation through Ebitengine, seek, EOF, cancellation, and clean shutdown with the same small redistributable fixture used by desktop tests.
- Treat emulator MediaCodec results as diagnostic only. The host GPU validates Ebitengine graphics; it does not emulate the Snapdragon video codec blocks in the reference tablet.
Complete when a reproducible APK runs through the audiovisual scenario without crashes, missing symbols, growing resources, or unexplained output differences.
Current branch evidence (12 August 2026): the API 33 x86-64 APK loads FFmpeg
8.0.3, software-decodes all 60 H.264 frames, converts and presents RGBA through
Ebitengine, software-decodes all 87 AAC frames, resamples them to 96,967 S16
stereo samples at 48 kHz, and starts an Ebitengine audio player. The current
host exposes neither /dev/kvm nor /dev/dri, so this run uses TCG and
SwiftShader and is correctness evidence only. Stable EOF, a frame-accurate seek
to one second, cancellation, and successful decoder reuse after cancellation
also pass. The probe cancels and closes its FFmpeg/audio resources on Android
onStop, then completes the full audiovisual path again after onStart in the
same process.
The reproducible prolonged/stress runner completed 20 full lifecycle cycles in one process followed by a separate 30-cycle rapid-cancellation run and a full recovery. All 20 prolonged cycles completed the H.264/AAC scenario. The rapid run interrupted video 16 times and audio 14 times; all 30 shutdowns completed, and the final audiovisual recovery passed. The prolonged run grew from 73,848 to 84,444 KiB PSS and from 173,188 to 186,432 KiB RSS as the process warmed, but cycles 10 through 20 added only 134 KiB PSS and 308 KiB RSS. Threads finished at 37 from 33 and file descriptors returned to their baseline of 124. Across the rapid run and recovery, PSS grew 967 KiB, RSS 1,668 KiB, threads by four, and file descriptors by one. The PID remained stable and the retained logs contain no probe failure, app ANR, or native crash. This closes the emulator resource-growth gate for phase B; it remains correctness and lifecycle evidence, not GPU, MediaCodec, audible-audio, thermal, or frame-rate evidence.
The Samsung Galaxy Tab A9+ is the minimum supported Android device and the physical acceptance reference. Its launch platform, Android 13 / API 33, is the OS floor; newer Android devices and framework versions must remain compatible.
- Install the exact APK already exercised by the emulator, using its
arm64-v8anative libraries. - Record device model, Android build, ABI, FFmpeg configuration and versions, selected decoders/encoders, and the MediaCodec capability report.
- Test H.264 and H.265 software and MediaCodec paths separately. A codec name or API being present is not sufficient evidence that frames stay on the hardware path.
- Measure 30 and 60 FPS workloads separately, including dropped/late frames, audiovisual drift, CPU load, memory, temperature-related throttling, and clean resource release. Screenshots prove rendered output, not frame rate.
- Report decode and encode results separately. A device can decode a profile or resolution in hardware without being able to encode the same combination.
- Run a sustained test after the short correctness case so a transient 60 FPS result is not presented as stable performance.
Compilation support is complete independently of hardware acceleration. MediaCodec and 60 FPS claims are published only for the exact codec, profile, resolution, pixel format, device, Android build, and FFmpeg configuration that passed qualification.
- Reuse the platform loader boundary established by Android, with iOS-specific signed-framework naming, application-bundle resolution, and a process-image fallback for complete statically linked FFmpeg symbols.
- Compile all packages and tests for ARM64 device and simulator targets with
Xcode and
CGO_ENABLED=1; retain Intel simulator coverage only while the supported Xcode toolchain provides it. - Verify ABI layouts against the selected iPhoneOS and simulator SDKs.
- Use an external application fixture for runtime integration; do not add an Ebitengine dependency or XCFramework packaging responsibility to the module.
- Qualify VideoToolbox and sustained codec performance on a named physical device. Simulator graphics and codec results are not physical-device qualification.
The deployment floor is iOS 13.0, matching Ebitengine and gomobile. The compile
gate covers iphoneos/arm64, iphonesimulator/arm64, and
iphonesimulator/amd64, plus a downstream Ebitengine XCFramework built from
integration/ios-ebiten. FFmpeg/shim binaries stay
the responsibility of the signed Xcode application.
No physical reference iPhone has been nominated yet. Until one is recorded and passes the signed-app runtime, codec, lifecycle, thermal, and sustained-load suite, iOS support claims stop at compilation and XCFramework integration.
The platform-neutral loader boundary is implemented while keeping library
family selection and PureGo symbol registration shared. Windows uses
LoadLibrary, GetProcAddress, and FreeLibrary; macOS uses its native dynamic
loader path. The completed closure:
- compile every package and test binary for Windows and macOS
amd64/arm64; - run the complete FFmpeg and shim suite natively on Windows
amd64; - verify the C-header ABI layout and rerun the complete suite natively on macOS Intel and Apple Silicon after the loader refactor;
- extend native runtime coverage to Windows ARM64 when a runner is available; and
- keep hardware acceleration capability-driven: D3D11VA/DXVA2 and VideoToolbox are not implied by successful compilation.
Windows amd64 now loads the public FFmpeg 9.0.1 shared build and compatible
shim through the Windows loader. Both Windows architectures pass the complete
compile gate, and both macOS architectures retain native ABI/runtime evidence.
Windows ARM64 remains compile-qualified, not runtime-qualified, until a native
runner is available.
FreeBSD remains best-effort pending a pinned native runner. WebAssembly cannot use the current dynamic-FFmpeg/PureGo architecture and would require a distinct backend. Nintendo Switch and Xbox require their proprietary SDK and program access before feasibility can be evaluated; they are not inferred from Ebitengine application support. PlayStation is not a public Ebitengine target and is not scheduled. None of these platforms is part of the Android/iOS delivery sequence.
Every PR states the affected FFmpeg lines, ownership or ABI implications, tests run, known gaps, and whether Codex assisted materially. Refactors do not hide unrelated features.