Skip to main content

check_gain_map_roundtrip

Function check_gain_map_roundtrip 

Source
pub fn check_gain_map_roundtrip<E, D>(enc: E, dec: D) -> Conformance
where E: EncoderConfig, D: DecoderConfig, <E::Job as EncodeJob>::Enc: Encoder<Error = E::Error>,
Expand description

The gain-map encode/decode contract (docs/gainmap-pipeline-scope-2026-06-08.md Phases 1, 2 and 4, tracked in zencodec#24), for every declared/undeclared combination of EncodeCapabilities::gain_map and DecodeCapabilities::gain_map:

Encoder undeclared ⇒ with_gain_map_pixels and with_gain_map_encoded must fail with UnsupportedOperation::GainMapEncode (the trait default) — a dropped gain map is lost HDR, so silence is the one forbidden outcome.

Encoder declared ⇒ for each case of the test matrix (1-channel forward, 3-channel forward, 1-channel backward-direction — sub-resolution 10×7 maps on a 20×14 RGB8 base, ISO 21496-1 params with only dyadic values, PQ alternate CICP):

  • with_gain_map_pixels accepts the map and the base still encodes; with_gain_map_encoded with a foreign format is rejected (the documented mismatch error — any error, it is the codec’s own).
  • Decoder declared ⇒ probe() reports the map (gain_map presence not Absent, and when Available its geometry/channels/params match; supplements.gain_map set); the default BaseOnly decode carries no DecodedGainMap extra (opt-in only) and its base pixels equal the input when the encoder is lossless; Components surfaces a DecodedGainMap whose geometry, channels, params (exact), alternate CICP and pixels (byte-exact when lossless, else within a mean-abs-error sanity bound) match; with_extract_gain_map(true) yields the identical map; ReconstructHdr { None } without reconstructs_hdr either surfaces the components with the base still labelled SDR, or fails with UnsupportedOperation — never an SDR buffer labelled PQ/HLG; with reconstructs_hdr it must succeed with an HDR-labelled buffer and the envelope (mastering_display + content_light_level) on source_color.
  • Transcode (Phase 4): the Components map is fed back through a fresh with_gain_map_pixels, decoded again, and must match the first generation (metadata exactly; pixels byte-exact when lossless).
  • push_rows path (when the encoder declares it): the same map attached to an incremental push_rows + finish encode surfaces identically — the streaming encoder is a separate code path in real codecs, and a job-level setting is easy to leave behind there.
  • Decoder undeclared ⇒ a Components decode of the same file either decodes the base with no DecodedGainMap extra (a hidden capability is a lie) or fails with UnsupportedOperation.

Skipped (Ok) only for the undeclared/undeclared pair once the loud rejection is verified. All violations across the matrix are collected and reported together. Not covered: the own-format with_gain_map_encoded fast path (the payload shape is container-specific — a bare AV1 OBU vs a whole JPEG — so a codec tests it with its own fixture), 10/12-bit maps, and the positive reconstructs_hdr branch against the testkit’s own codecs (the reference declines to reconstruct, as zencodec carries no HDR math). Part of check_all.