Files
daedalus-v4l2/daemon/CMakeLists.txt
T
claude-noether 1e9619afe8 daemon: AV1 Sequence Header OBU synthesiser + unit test
V4L2 stateless AV1 passes the sequence header information as a
structured control (V4L2_CID_STATELESS_AV1_SEQUENCE) and ships
only tile-group bytes in the OUTPUT buffer.  libavcodec's AV1
decoder is full-bitstream, so the daemon needs to reconstruct
the OBU bytes the consumer parsed out before feeding the
assembled stream to libavcodec.

This commit lands the Sequence Header OBU half of that
reconstruction — av1_synth_sequence_header_obu().  Frame
Header / Frame OBU synthesisers + the integration that wires
the assembled OBUs into the decode hot path are separate
follow-on modules.

Module shape mirrors the H.264 NAL synthesiser (PR #1):

  - Public API: single function returning byte count or 0
    on overflow/invalid input.
  - Wire encoder uses the existing bitstream_writer (bsw_put_u
    is AV1's f(n); bsw_put_ue is bit-identical to AV1's uvlc;
    bsw_align_rbsp matches AV1's trailing_bits()).
  - AV1-specific helpers (leb128 size, min_bits_for, subsampling
    resolution per §5.5.2) are file-local statics.
  - No emulation prevention — AV1 uses leb128-sized OBUs for
    bitstream boundaries, not byte-pattern escapes.

Synthesis decisions for fields V4L2 doesn't carry are documented
verbatim in the file header (reduced_still_picture_header = 0;
single operating point at seq_level_idx = 13 / level 5.1;
color_description_present_flag = 0; chroma_sample_position = 0;
seq_choose_screen_detection_tools = 1; seq_choose_integer_mv = 1).

Rejection cases:
  - seq_profile > 2
  - bit_depth not in {8, 10, 12}
  - seq_profile = 1 + monochrome (4:4:4 forced colour)
  - seq_profile = 1 + bit_depth = 12 (only profile 2 allows it)
  - max_frame_{width,height}_minus_1 requiring > 16 length bits
  - out_cap too small to hold header + leb128 + payload

Each returns 0 to surface the mismatch loudly rather than emit
nonsense the libavcodec parser would reject downstream.

Unit test (test_av1_obu_synth.c, opt-in via DAEDALUS_BUILD_TESTS=ON)
exercises four cases bit-by-bit against a hand-computed reference:

  1. profile 0, 1080p, 8-bit, 4:2:0, order_hint on (7 bits),
     CDEF+restoration on — the common Pi 5 path.
  2. profile 0, 720p, 10-bit, monochrome — exercises high_bitdepth
     and the monochrome short-form color_config.
  3. profile 1 + bit_depth 12 → expects 0 (rejected).
  4. tiny out_cap → expects 0 (overflow).

All four green on hertz (aarch64 Arch, gcc Wall+Wextra+Wpedantic
clean).

This commit does not change daemon behaviour — av1_obu_synth.c is
built into the daemon binary so the symbols are reachable, but
no call site is wired yet.  Integration goes in the follow-on
DAEMON-AV1 patches that also synthesise the Frame Header OBU
and bracket the assembled OBUs with a Temporal Delimiter.

Refs reauktion/daedalus-v4l2#11 daemon-half; closes daedalus
backlog task #144.
2026-05-23 15:41:07 +02:00

106 lines
3.1 KiB
CMake
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# SPDX-License-Identifier: BSD-2-Clause
#
# daedalus-v4l2 userspace daemon — CMake build.
#
# Notes:
# - FFmpeg is dlopen'd at runtime (Option γ), so we link only
# -ldl + -lpthread. Headers from libavformat-dev /
# libavcodec-dev / libavutil-dev are used at compile time
# for struct definitions.
# - Strict warnings enforced.
cmake_minimum_required(VERSION 3.20)
project(daedalus_v4l2_daemon C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
if (NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
add_compile_options(-Wall -Wextra -Wpedantic
-Wno-unused-parameter)
# FFmpeg headers (we dlopen the libs but include the headers for
# struct definitions). pkg-config is the canonical way.
find_package(PkgConfig REQUIRED)
pkg_check_modules(FFMPEG REQUIRED IMPORTED_TARGET
libavformat libavcodec libavutil)
# daedalus-fourier — VC VII (V3D) + ARM NEON back-end kernel library.
# Linked statically. Today only the no-QPU smoke-test path is wired
# (a ctx_create_no_qpu at daemon startup, log-and-destroy at exit);
# follow-up patches (per daedalus-v4l2#11) substitute the
# `daedalus_recipe_dispatch_h264_*` family for libavcodec's per-MB
# pixel primitives, one cycle at a time.
#
# We bypass IMPORTED_TARGET and consume pkg-config's static variables
# (--static --libs path) directly so we control the link order:
# libdaedalus_core.a must precede -lvulkan because the static archive
# references vulkan symbols and the linker resolves left-to-right.
pkg_check_modules(DAEDALUS_FOURIER REQUIRED daedalus-fourier)
find_package(Vulkan REQUIRED)
add_executable(daedalus_v4l2_daemon
src/main.c
src/ffmpeg_loader.c
src/log.c
src/parser.c
src/decoder.c
src/chardev_client.c
src/dmabuf_capture.c
src/bitstream_writer.c
src/h264_nal_synth.c
src/av1_obu_synth.c
)
target_include_directories(daedalus_v4l2_daemon
PRIVATE
src
${CMAKE_CURRENT_SOURCE_DIR}/../include
${FFMPEG_INCLUDE_DIRS}
${DAEDALUS_FOURIER_INCLUDE_DIRS}
)
# dl for dlopen, pthread for future threading work.
target_link_directories(daedalus_v4l2_daemon
PRIVATE
${DAEDALUS_FOURIER_LIBRARY_DIRS}
)
target_link_libraries(daedalus_v4l2_daemon
PRIVATE
dl
pthread
# Order matters: libdaedalus_core.a first (so its undefined
# vulkan symbols register), then -lvulkan to satisfy them.
${DAEDALUS_FOURIER_LIBRARIES}
Vulkan::Vulkan
)
install(TARGETS daedalus_v4l2_daemon
RUNTIME DESTINATION /usr/local/bin)
# --- Unit tests (opt-in) -------------------------------------------------
#
# DAEDALUS_BUILD_TESTS=ON enables standalone test executables that run on
# the build host (no V4L2 / FFmpeg / Vulkan dependency). Used by CI to
# gate bitstream synthesis modules against regressions.
option(DAEDALUS_BUILD_TESTS "Build daemon unit tests" OFF)
if (DAEDALUS_BUILD_TESTS)
add_executable(test_av1_obu_synth
src/test_av1_obu_synth.c
src/av1_obu_synth.c
src/bitstream_writer.c
)
target_include_directories(test_av1_obu_synth PRIVATE src)
# Test binary does not link FFmpeg / Vulkan / dl — it exercises
# pure-C encoders against in-memory inputs.
enable_testing()
add_test(NAME av1_obu_synth COMMAND test_av1_obu_synth)
endif()