/* SPDX-License-Identifier: BSD-2-Clause */ /* * av1_obu_synth.h — synthesise AV1 OBU bytes from the V4L2 stateless * AV1 controls. * * V4L2 stateless AV1 (per drivers/media/v4l2-core/v4l2-h264.c-style * contract) passes the OUTPUT buffer as bare tile-group bitstream and * the sequence / frame-header information as structured controls * (V4L2_CID_STATELESS_AV1_SEQUENCE, V4L2_CID_STATELESS_AV1_FRAME, ...). * libavcodec's AV1 decoder is full-bitstream, so the daemon has to * reconstruct the OBUs that the consumer parsed out and prepend them * to the tile-group bytes before handing the assembled stream to * libavcodec. * * This header covers Sequence Header (§5.5.1), Temporal Delimiter * (§5.6), and Frame Header (§5.9) OBUs. All share the same wire * conventions: * - No emulation prevention (AV1 uses leb128 sized fields instead). * - obu_has_size_field = 1 in the OBU header byte. * - obu_extension_flag = 0 (no temporal_id / spatial_id encoding). * - trailing_bits() finalises the payload to a byte boundary the same * way H.264's rbsp_trailing_bits does — bsw_align_rbsp covers it. * * Synthesis decisions for fields V4L2 doesn't carry are documented in * the .c file (search for "synthesis default"). */ #ifndef DAEDALUS_AV1_OBU_SYNTH_H #define DAEDALUS_AV1_OBU_SYNTH_H #include #include #include /* * Encode an AV1 Sequence Header OBU (header byte + leb128 size + RBSP) * into @out. Returns total bytes written, or 0 on overflow / malformed * input (e.g. inconsistent bit_depth vs seq_profile). @out_cap must * be at least 32 bytes for any reasonable sequence header; 64 bytes * is a generous upper bound. * * The caller is expected to bracket the resulting bytes with a * Temporal Delimiter OBU (1 byte: 0x12 0x00) before any Frame OBU so * that libavcodec's AV1 parser sees a well-formed access unit; the * temporal-delimiter byte is trivial and not produced here. */ size_t av1_synth_sequence_header_obu(const struct v4l2_ctrl_av1_sequence *seq, uint8_t *out, size_t out_cap); /* * Encode an AV1 Temporal Delimiter OBU into @out. Always exactly 2 * bytes: 0x12 (obu_type=TEMPORAL_DELIMITER, has_size_field=1) followed * by 0x00 (leb128(0) — zero-payload). Returns 2 on success, 0 if * @out_cap < 2. * * Per AV1 spec §5.6 every temporal unit MUST start with a Temporal * Delimiter OBU when temporal_delimiter_obus_present is implied — the * libavcodec AV1 parser uses TD OBUs as access-unit boundaries when * fed full-bitstream input. */ size_t av1_synth_temporal_delimiter_obu(uint8_t *out, size_t out_cap); /* * Integration status (2026-05-23): * * The Sequence / Frame Header / Temporal Delimiter encoders below are * standalone primitives. They are NOT yet called from decoder.c — the * AV1 decode hot path still passes the OUTPUT buffer straight to * libavcodec, which only works if the V4L2 consumer happens to be * sending a fully-OBU'd access unit (i.e. is not strictly following * the V4L2 stateless AV1 "tile-group bytes only" contract). * * Wiring these primitives in requires a separate kernel-side change: * * - extend daedalus_v4l2_proto.h with a `struct daedalus_av1_meta` * mirroring v4l2_ctrl_av1_sequence + v4l2_ctrl_av1_frame * - update kernel/daedalus_v4l2_main.c to capture * V4L2_CID_STATELESS_AV1_{SEQUENCE,FRAME} at device_run time and * ship the meta alongside the bitstream over the chardev * - update daemon/src/chardev_client.c to receive the meta * - update daemon/src/decoder.c to: synth TD + SH + FH OBUs, wrap * the OUTPUT bytes as an OBU_TILE_GROUP, concat in that order, * hand the assembled bitstream to libavcodec * * Tracked as a follow-on; see daedalus-v4l2 task notes. */ /* * Encode an AV1 Frame Header OBU from the V4L2 stateless frame control * (and the matching sequence control, which provides fields the * frame-header encoder branches on per §5.9.1). * * Scope (this revision — libva-v4l2-request common-case path): * - Frame types KEY / INTER / INTRA_ONLY. SWITCH frames return 0 * (caller should fall back to libavcodec native parsing). * - segmentation_params() emits the "segmentation disabled" path * when V4L2_AV1_SEGMENTATION_FLAG_ENABLED is 0. Enabled * segmentation returns 0. * - loop_restoration_params(): only RESTORE_NONE on all planes * supported. Other restoration types return 0. * - global_motion: only IDENTITY warp model emitted. Non-IDENTITY * entries return 0. * - film_grain_params(): treated as "not present" — only valid when * the sequence header has film_grain_params_present = 0. If the * sequence claims film grain is present this revision returns 0 * (the per-frame film-grain coding is a separate follow-on). * * Out-of-scope branches return 0 so the caller can surface a coverage * warning and fall back to direct libavcodec parsing of the original * bitstream where possible. * * @out_cap must be at least 128 bytes for any reasonable frame header; * 256 bytes is a safe upper bound for the supported subset. */ size_t av1_synth_frame_header_obu(const struct v4l2_ctrl_av1_sequence *seq, const struct v4l2_ctrl_av1_frame *fr, uint8_t *out, size_t out_cap); #endif /* DAEDALUS_AV1_OBU_SYNTH_H */