08080f062c
First code on daedalus-decoder per the Phase 1 decisions merged 2026-05-24.
Repo skeleton only — no Vulkan pipeline yet, no shaders, no libavcodec
intercept. Establishes the build shape so subsequent work has a place
to land.
Layout:
LICENSE BSD-2-Clause (matches daedalus-fourier)
.gitignore build/, CMake artefacts, *.spv
CMakeLists.txt top-level — finds daedalus-fourier
≥0.1.0 via pkg-config (per §9.6
decision: find_package, pinned to
tagged release; .pc consumed via
pkg_check_modules until we ship a
CMake config), Vulkan via
find_package, builds static lib
+ smoke test, GNUInstallDirs install
include/daedalus_decoder.h public API surface:
- daedalus_decoder_{create,destroy,
version,has_qpu}
- daedalus_decoder_set_output_format
(NV12 default, RGBA opt-in per §5)
- daedalus_decoder_append_mb +
struct daedalus_decoder_mb_input
(matches §3 per-MB descriptor)
- daedalus_decoder_flush_frame
(per-frame submit + wait)
- daedalus_decoder_export_dmabuf
(Vulkan-native VkImage export per
§9.4 decision)
Dimensions are CODED frame size
(mod-16), not displayed — caller
translates from SPS + crop offsets.
src/internal.h internal mb_desc struct (matches
shader std430 layout, to be nailed
down once shaders exist) + per-ctx
state
src/daedalus_decoder.c stub bodies:
- create/destroy with proper resource
lifecycle
- append_mb validates + writes CPU
staging buffers (no GPU yet)
- flush_frame returns -2 (not
implemented) — Phase 1 work
- export_dmabuf returns -1
- has_qpu / version diagnostics
tests/test_smoke.c link + lifecycle test: bad dims
reject, OOB MB reject, null inputs
reject, raster-order enforcement,
mid-frame format-change reject,
incomplete-frame flush reject.
On hosts without V3D7 Vulkan,
SKIPs gracefully (returns 0).
Verified on hertz (Pi 5 / V3D 7.1 / Mesa V3DV via daedalus-fourier
0.1.0):
$ cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
$ cmake --build build
$ ctest --test-dir build --output-on-failure
Test #1: smoke ... Passed
$ ./build/test_smoke
daedalus-decoder version: 0.0.1
ctx created: 1920x1088, has_qpu=1
smoke OK
Note the coded-vs-displayed dims trap: 1080p H.264 has coded height
1088 with 8 rows cropped via SPS frame_cropping_*. Header docstring
on daedalus_decoder_create() spells this out so future callers don't
hit the multiple-of-16 reject (smoke test caught it during scaffold
write).
Next: Phase 1 implementation begins — IDCT 4×4 / 8×8 frame-scaled
dispatch (reusing daedalus-fourier shaders per Appendix A), intra
prediction wavefront, reconstruct stage, NV12 output via dmabuf
export. Smoke test grows from "ctx lifecycle works" to
"I-frame-only Baseline decode bit-exact vs FFmpeg reference".
101 lines
3.5 KiB
C
101 lines
3.5 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
/*
|
|
* Scaffold smoke test — verifies the daedalus-decoder library links
|
|
* cleanly against daedalus-fourier and the lifecycle entry points
|
|
* don't immediately crash. No actual decoding work yet.
|
|
*
|
|
* Returns 0 on success, non-zero on any unexpected behaviour.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "daedalus_decoder.h"
|
|
|
|
#define EXPECT(cond, msg) do { \
|
|
if (!(cond)) { \
|
|
fprintf(stderr, "EXPECT FAIL %s:%d: %s\n", __FILE__, __LINE__, msg); \
|
|
return 1; \
|
|
} \
|
|
} while (0)
|
|
|
|
int main(void)
|
|
{
|
|
printf("daedalus-decoder version: %s\n", daedalus_decoder_version());
|
|
|
|
/* Create / destroy null is a no-op. */
|
|
daedalus_decoder_destroy(NULL);
|
|
|
|
/* Bad dimensions rejected. */
|
|
EXPECT(daedalus_decoder_create(0, 0 ) == NULL, "zero dims must reject");
|
|
EXPECT(daedalus_decoder_create(1919, 1088) == NULL, "non-16-multiple width must reject");
|
|
EXPECT(daedalus_decoder_create(1920, 1079) == NULL, "non-16-multiple height must reject");
|
|
|
|
/* Valid 1088p create. */
|
|
daedalus_decoder *dec = daedalus_decoder_create(1920, 1088);
|
|
if (!dec) {
|
|
/* Vulkan init failure on this host — degrades to skip, not fail.
|
|
* (CI runners without V3D7 will hit this; the smoke test
|
|
* shouldn't gate on hardware presence.) */
|
|
fprintf(stderr, "SKIP: daedalus_decoder_create returned NULL "
|
|
"(Vulkan / V3D7 unavailable on this host)\n");
|
|
return 0;
|
|
}
|
|
|
|
printf("ctx created: 1920x1088, has_qpu=%d\n",
|
|
daedalus_decoder_has_qpu(dec));
|
|
|
|
/* set_output_format mid-frame on virgin ctx is allowed
|
|
* (mbs_appended == 0). */
|
|
EXPECT(daedalus_decoder_set_output_format(dec, DAEDALUS_DECODER_OUTPUT_RGBA) == 0,
|
|
"switch to RGBA on virgin ctx");
|
|
EXPECT(daedalus_decoder_set_output_format(dec, DAEDALUS_DECODER_OUTPUT_NV12) == 0,
|
|
"switch back to NV12");
|
|
|
|
/* Append rejects out-of-bounds + null inputs. */
|
|
int16_t coeffs[384] = {0};
|
|
struct daedalus_decoder_mb_input mb = {0};
|
|
mb.coeffs = coeffs;
|
|
|
|
mb.mb_x = 0; mb.mb_y = 0;
|
|
EXPECT(daedalus_decoder_append_mb(dec, NULL) == -1, "null mb rejects");
|
|
{
|
|
struct daedalus_decoder_mb_input mb2 = mb;
|
|
mb2.coeffs = NULL;
|
|
EXPECT(daedalus_decoder_append_mb(dec, &mb2) == -1, "null coeffs rejects");
|
|
}
|
|
{
|
|
struct daedalus_decoder_mb_input mb2 = mb;
|
|
mb2.mb_x = 9999; mb2.mb_y = 9999;
|
|
EXPECT(daedalus_decoder_append_mb(dec, &mb2) == -1, "OOB coords reject");
|
|
}
|
|
|
|
/* Append first MB at raster index 0 — should succeed. */
|
|
EXPECT(daedalus_decoder_append_mb(dec, &mb) == 0, "append (0,0)");
|
|
|
|
/* Skipping (0,1) and appending (1,0) violates raster order — reject. */
|
|
{
|
|
struct daedalus_decoder_mb_input mb2 = mb;
|
|
mb2.mb_x = 0; mb2.mb_y = 1;
|
|
EXPECT(daedalus_decoder_append_mb(dec, &mb2) == -1,
|
|
"out-of-raster-order rejects");
|
|
}
|
|
|
|
/* In-order: (1,0). */
|
|
mb.mb_x = 1; mb.mb_y = 0;
|
|
EXPECT(daedalus_decoder_append_mb(dec, &mb) == 0, "append (1,0)");
|
|
|
|
/* Flush an incomplete frame: should fail because mbs_appended != n_mbs. */
|
|
EXPECT(daedalus_decoder_flush_frame(dec, NULL, 0, NULL, 0) == -1,
|
|
"incomplete-frame flush rejects");
|
|
|
|
/* set_output_format mid-frame (mbs_appended > 0) must reject. */
|
|
EXPECT(daedalus_decoder_set_output_format(dec, DAEDALUS_DECODER_OUTPUT_RGBA) == -1,
|
|
"mid-frame format change rejects");
|
|
|
|
daedalus_decoder_destroy(dec);
|
|
|
|
printf("smoke OK\n");
|
|
return 0;
|
|
}
|