Developers guide lines - a-schild/jave2 GitHub Wiki

Developers guide lines

For working on JAVE2 itself. If you are using the library, see Usage.

Building

mvn clean install

The library is compiled for Java 8 (maven.compiler.source 1.8), so it stays usable on old runtimes, but it is built and tested with a newer JDK, currently 17 in CI. One module, jave-core-test-java11, targets 11 instead, for tests that need APIs Java 8 does not have.

Keep to Java 8 language level in jave-core. It is the one constraint that is easy to break without noticing, since a modern JDK compiles most newer syntax happily until the source level rejects it.

Layout

Module What it is
jave-core All the java code. No binaries, platform independent
jave-core-test The test suite, which runs against real media files
jave-core-test-java11 Tests that need Java 11
jave-bom Bill of materials, versions only
jave-all-deps Core plus every platform binary
jave-example A small runnable sample
jave-nativebin-* One module per platform, each carrying one ffmpeg executable

The native binary module directories do not all match their artifact ids: the directories jave-nativebin-arm64 and jave-nativebin-arm32 publish as jave-nativebin-linux-arm64 and jave-nativebin-linux-arm32.

The binaries themselves are large and are committed to the repository. Be careful with git add -A in a dirty tree, since it is easy to stage a few hundred megabytes of executables by accident.

Tests

mvn -pl jave-core-test test

The tests transcode real files, so they are slower than unit tests and they depend on the bundled ffmpeg actually working on the machine. Some tests reach out to remote sample files and skip themselves, via Assumptions.assumeTrue, when the sample cannot be fetched, so a green run offline may be a smaller run than it looks.

BundledFFmpegVersionTest pins the version of the bundled ffmpeg, so an upgrade cannot land half done without something failing. Two limits are worth knowing: it checks only the package for the machine it runs on, keyed by os.arch, and CI runs on ubuntu-latest only, so the windows and macOS packages are not covered by an ordinary CI run. A package that is deliberately behind goes in the KNOWINGLY_BEHIND map rather than weakening the assertion.

File size assertions use assertFileSizeNear rather than an exact figure, because encoder output varies slightly between builds of ffmpeg.

Branches

  • master is the default branch and holds releases.
  • develop carries -SNAPSHOT versions. Pushing to it publishes a snapshot.

Note that workflow_dispatch only offers a workflow that exists on the default branch, so a new workflow has to reach master before it can be triggered by hand.

The ffmpeg binaries

The windows and macOS binaries come from publishers. The linux binaries are built from source in CI, by .github/workflows/build-linux-ffmpeg.yml and .github/scripts/build-ffmpeg-static.sh, for amd64, arm64 and arm32.

They are fully static musl builds, which is the point: they carry no libc dependency at all, so they run on any linux including musl based images, rather than requiring a glibc at least as new as the build machine's. Every library version in that script is pinned, so a build is reproducible and an upstream release cannot change the output silently.

The workflow has a parity gate: it compares the encoders in the new binary against the expected list and fails on any unexplained loss, with a per architecture list of losses that are known and accepted. libx265 is not built for arm32.

A few things about that script are load bearing and look like style:

  • make -j and make install are separate commands. Chained with && under set -e, a failure in the first is swallowed, which once let a broken library through.
  • Encoder lists are written to files rather than piped into grep -q or head, because with pipefail a closed pipe gives SIGPIPE and reads as a failure.

Versioning

Since 2.6.0 this project follows semantic versioning 2.0.0. Given MAJOR.MINOR.PATCH, increment the

  1. MAJOR version for incompatible API changes,
  2. MINOR version for functionality added in a backwards compatible way,
  3. PATCH version for backwards compatible bug fixes.

Removing a published artifact counts as breaking, which is why dropping the 32 bit x86 packages made 4.0.0 rather than 3.7.0.

Releasing

Publishing goes to Maven Central through the Sonatype Central Portal with central-publishing-maven-plugin. The old OSSRH service has been retired by Sonatype.

  • A push to develop publishes a snapshot, while the poms carry -SNAPSHOT.
  • Creating a GitHub release publishes the release, auto released by the plugin.

The required secrets are listed in the README.

When bumping versions across the poms, do not do it with a blind search and replace on 4.0.0: <modelVersion>4.0.0</modelVersion> is not the project version, and rewriting it makes maven refuse to read the pom at all.

Give every GitHub release real notes describing the user facing changes, and update Changelog.md in the same change as the work, not afterwards.

Documentation

The wiki and Examples.md in the repository carry the same content and are meant to stay in step. Java snippets in the documentation are worth compiling against jave-core before publishing them, which is how six wrong API calls were caught in the 4.0.0 rewrite.