Skip to content

Add runtime-aware gain map routing predicate - #462

Open
gregbenz wants to merge 2 commits into
google:mainfrom
gregbenz:codex/gainmap-routing-predicate
Open

Add runtime-aware gain map routing predicate#462
gregbenz wants to merge 2 commits into
google:mainfrom
gregbenz:codex/gainmap-routing-predicate

Conversation

@gregbenz

Copy link
Copy Markdown
Contributor

Summary

This adds a small public API for image loaders that need to decide whether to route an in-memory image to libultrahdr:

int uhdr_is_supported_gainmap_image(const void* data, size_t size);

If it returns 1, the caller can try libultrahdr. If it returns 0, the caller can continue through its normal image path. Decode errors are still handled normally after a positive result.

The main motivation is downstream image libraries that want to enable gain-map support by default. Loaders that already have the complete input in memory can use this predicate directly, without asking applications or users to opt in or implement their own format probes. The same API works across JPEG, AVIF, and HEIF integrations.

API behavior

is_uhdr_image() remains a structural check: does the input contain a primary image, a gain-map image, and valid gain-map metadata?

The new predicate answers the narrower routing question: does the input have a gain-map form that this build and runtime are prepared to handle? For AVIF/HEIF, this also checks the required decoder families. A structurally valid image can therefore return 1 from is_uhdr_image() and 0 from uhdr_is_supported_gainmap_image().

A positive result is intentionally a routing hint, not a guarantee that every codec profile or damaged compressed stream will decode successfully. Avoiding a trial pixel decode keeps this check inexpensive.

Implementation

Both public predicates use the same stateless, borrowed-buffer structural inspection:

  • JPEG validation requires two valid JPEG ranges, supported ISO/XMP/Apple gain-map metadata, and an MPF directory that associates the exact secondary JPEG. The encoded JPEG payloads are not copied.
  • Legacy primary-size bookkeeping found in Apple-authored JPEGs is accepted because it is not needed to locate or associate the gain map.
  • AVIF/HEIF validation uses libheif's no-copy memory reader and requires an associated gain-map item with valid metadata.
  • Runtime routing is deliberately conservative. It currently accepts direct AV1/HEVC primary and gain-map items, requires the relevant decoder families to be registered, and rejects alpha-channel and derived-image layouts.
  • Parsing failures return 0. C++ exceptions are contained at the C ABI when enabled, and the implementation also builds with exceptions disabled.

This does make is_uhdr_image() stricter for malformed JPEGs with missing, ambiguous, or incorrect MPF associations. Decoder setup and decode APIs are otherwise unchanged.

The existing stateful uhdr_dec_probe() path is also unchanged. uhdr_dec_set_image() owns a copy of its input, and uhdr_dec_probe() populates state needed by a later decode; changing that lifecycle is outside the scope of this stateless dispatch API.

This patch does not add a typed result API, streaming/prefix input, a general item-graph abstraction, or pixel-level trial decoding.

Validation

  • The full release suite passes: 1,299 tests, with 1,073 passes and 226 existing or environment-dependent skips.
  • Generated ISO JPEG, Apple/XMP JPEG, AVIF, and HEIF gain-map inputs were checked through both the predicate and a real decode.
  • Ordinary JPEG, AVIF, and HEIF inputs return 0.
  • In an AVIF-only runtime, the included valid 1.5 KB HEIF gain-map fixture returns 1 structurally and 0 from the routing predicate. With HEVC available, the same fixture probes and decodes successfully.
  • JPEG-only, HEIF-disabled, exception-disabled, concurrent-call, ASan, and UBSan configurations were also checked.
  • Malformed MPF tests cover incorrect associations, duplicate mandatory tags, malformed version fields, and a displaced MPF\0 signature.

Performance

These are release-build averages over 1,000 calls on arm64 macOS 26.6.2 with Apple Clang 21. Inputs were already resident in memory, so the measurements exclude file I/O. Encoded size is included because probe cost depends more on byte and segment layout than pixel dimensions; these are representative fixture measurements, not size-independent guarantees.

Input Encoded size Routing predicate
Apple gain-map JPEG ~51 KB 15.7 us
ISO gain-map JPEG ~73 KB 102.0 us
Gain-map AVIF ~3.1 KB 12.3 us
Gain-map HEIF, decoder unavailable 1.5 KB 13.2 us
Ordinary JPEG 24 KB 3.9 us
Ordinary AVIF 275 B 4.5 us

For comparison, the previous is_uhdr_image() path measured 19.0 us for the Apple JPEG, 156.5 us for the ISO JPEG, and 33.2 us for the gain-map AVIF. The new path does not duplicate the complete encoded stream or embedded JPEG payloads, although the parsers may still allocate container and metadata structures.

The proposed name, Boolean contract, and 2.1.0 version are open to maintainer preference. The important part for downstream callers is having one compact, conservative routing decision that is safe to enable by default.

@google-cla

google-cla Bot commented Aug 27, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@gregbenz
gregbenz marked this pull request as ready for review August 27, 2026 01:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant