88b2ebfaa9
First incremental step toward H.264 daemon-rewrite (daedalus-v4l2#11):
make the daedalus-fourier kernel library available to the daemon
process so subsequent patches can substitute its primitives
(IDCT 4×4, IDCT 8×8, luma vertical deblock, etc.) for libavcodec's
per-MB pixel math.
This patch does NOT yet dispatch any kernels. It only:
- Adds `pkg_check_modules(DAEDALUS_FOURIER REQUIRED daedalus-fourier)`
to the daemon's CMakeLists, with explicit link ordering
(libdaedalus_core.a must precede -lvulkan because the static
archive references vulkan symbols and the linker resolves
left-to-right). We bypass IMPORTED_TARGET because pkg-config's
Requires.private chain leaves CMake's dependency graph reordering
the archive after -lvulkan, breaking the static link.
- Calls daedalus_ctx_create_no_qpu() at daemon startup, logs the
substrate-availability line, destroys the context at exit.
no_qpu mode skips V3D Vulkan probe — proves linkage works
without depending on shader-path resolution (which is a
separate piece of work, since v3d_runner currently loads
.spv files from cwd-relative paths and consumer would need
a search path override).
Sample journal line:
[2026-05-21 17:59:35.271 INFO] daedalus-fourier: linked, ctx alive
(no_qpu mode; has_qpu=0)
Build-test verified on hertz (Pi 5 dev host) against an installed
copy of daedalus-fourier r35+gd87239d (from marfrit/daedalus-fourier
PR #1). Binary links cleanly, --help prints, daemon mode opens
chardev (fails predictably on hertz which has no daedalus_v4l2
kmod; on higgs this is the existing working path).
Follow-up patches per daedalus-v4l2#11:
1. Instrument the existing libavcodec decode path to count
per-frame IDCT blocks / deblock edges / MC tiles so we have
a baseline of what work the daemon dispatches for a typical
YouTube H.264 stream.
2. Substitute daedalus-fourier kernels one at a time, measuring
CPU saved per substitution.
3. Wire shader path resolution into daedalus_ctx_create() for
the QPU substrate (V3D opportunistic helper paths).
Wire protocol unchanged. DAEDALUS_PROTO_VERSION stays at 0.
163 lines
3.8 KiB
C
163 lines
3.8 KiB
C
/* SPDX-License-Identifier: BSD-2-Clause */
|
|
/*
|
|
* main.c — daedalus-v4l2 userspace daemon entry point.
|
|
*
|
|
* Phase 8.3 mode of operation: CLI tool.
|
|
* daedalus_v4l2_daemon parse <file>
|
|
*
|
|
* Phase 8.4+ adds the daemon mode that opens the chardev
|
|
* /dev/daedalus-v4l2 and services REQ_DECODE etc.
|
|
*/
|
|
#include "ffmpeg_loader.h"
|
|
#include "parser.h"
|
|
#include "chardev_client.h"
|
|
#include "log.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
#include <libavutil/log.h>
|
|
|
|
#include <daedalus.h>
|
|
|
|
static volatile sig_atomic_t g_terminate = 0;
|
|
|
|
static void on_signal(int sig)
|
|
{
|
|
(void) sig;
|
|
g_terminate = 1;
|
|
}
|
|
|
|
static int install_signal_handlers(void)
|
|
{
|
|
struct sigaction sa = { 0 };
|
|
sa.sa_handler = on_signal;
|
|
sigemptyset(&sa.sa_mask);
|
|
if (sigaction(SIGINT, &sa, NULL) < 0 ||
|
|
sigaction(SIGTERM, &sa, NULL) < 0) {
|
|
log_err("sigaction: %s", strerror(errno));
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int cmd_parse(struct ffmpeg_loader *fm, int argc, char **argv)
|
|
{
|
|
if (argc < 1) {
|
|
fprintf(stderr, "usage: parse <path-to-media-file>\n");
|
|
return 2;
|
|
}
|
|
int rc = daedalus_parse_file(fm, argv[0]);
|
|
return rc < 0 ? 1 : 0;
|
|
}
|
|
|
|
static int cmd_daemon(struct ffmpeg_loader *fm, int argc, char **argv)
|
|
{
|
|
struct chardev_client cli;
|
|
int rc;
|
|
|
|
(void) argc;
|
|
(void) argv;
|
|
|
|
rc = chardev_client_open(&cli, fm, &g_terminate);
|
|
if (rc < 0) {
|
|
log_err("chardev_client_open: %d", rc);
|
|
return 1;
|
|
}
|
|
rc = chardev_client_run(&cli);
|
|
chardev_client_close(&cli);
|
|
return rc < 0 ? 1 : 0;
|
|
}
|
|
|
|
static void usage(const char *progname)
|
|
{
|
|
fprintf(stderr,
|
|
"usage: %s <command> [args]\n\n"
|
|
"commands:\n"
|
|
" parse <file> Phase 8.3: demux+enumerate frames\n"
|
|
" daemon Phase 8.4: open /dev/daedalus-v4l2 and\n"
|
|
" service REQ_DECODE from the kernel\n"
|
|
"\n"
|
|
"options:\n"
|
|
" -v, --verbose enable debug logging\n"
|
|
" -h, --help this message\n",
|
|
progname);
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int verbose = 0;
|
|
int i;
|
|
|
|
for (i = 1; i < argc; i++) {
|
|
if (strcmp(argv[i], "-v") == 0 ||
|
|
strcmp(argv[i], "--verbose") == 0)
|
|
verbose = 1;
|
|
else if (strcmp(argv[i], "-h") == 0 ||
|
|
strcmp(argv[i], "--help") == 0) {
|
|
usage(argv[0]);
|
|
return 0;
|
|
} else {
|
|
break; /* first non-option = command */
|
|
}
|
|
}
|
|
if (i >= argc) {
|
|
usage(argv[0]);
|
|
return 2;
|
|
}
|
|
|
|
log_init(verbose ? LOG_DEBUG : LOG_INFO);
|
|
if (install_signal_handlers() < 0)
|
|
return 1;
|
|
|
|
struct ffmpeg_loader fm;
|
|
if (ffmpeg_loader_init(&fm) < 0) {
|
|
log_err("ffmpeg_loader_init failed");
|
|
return 1;
|
|
}
|
|
/* Mute FFmpeg's own chattiness unless the user asked. */
|
|
fm.av_log_set_level(verbose ? AV_LOG_INFO : AV_LOG_WARNING);
|
|
|
|
/*
|
|
* Initialise daedalus-fourier early so we can log substrate
|
|
* availability up front. daedalus_ctx_create_no_qpu() skips
|
|
* the V3D Vulkan probe — we're not dispatching any kernels
|
|
* yet, this is just the linkage sanity check + a marker in the
|
|
* journal that the binary is wired against the right
|
|
* daedalus-fourier version. Future work (per daedalus-v4l2#11)
|
|
* promotes to daedalus_ctx_create() once shader-path resolution
|
|
* is wired through the public API.
|
|
*/
|
|
daedalus_ctx *df_ctx = daedalus_ctx_create_no_qpu();
|
|
if (df_ctx) {
|
|
log_info("daedalus-fourier: linked, ctx alive (no_qpu mode; "
|
|
"has_qpu=%d)",
|
|
daedalus_ctx_has_qpu(df_ctx));
|
|
} else {
|
|
log_warn("daedalus-fourier: ctx_create_no_qpu returned NULL "
|
|
"(out of memory?) — continuing without backend kernels");
|
|
}
|
|
|
|
int rc;
|
|
const char *cmd = argv[i++];
|
|
if (strcmp(cmd, "parse") == 0) {
|
|
rc = cmd_parse(&fm, argc - i, argv + i);
|
|
} else if (strcmp(cmd, "daemon") == 0) {
|
|
rc = cmd_daemon(&fm, argc - i, argv + i);
|
|
} else {
|
|
fprintf(stderr, "unknown command: %s\n", cmd);
|
|
usage(argv[0]);
|
|
rc = 2;
|
|
}
|
|
|
|
if (df_ctx)
|
|
daedalus_ctx_destroy(df_ctx);
|
|
ffmpeg_loader_cleanup(&fm);
|
|
log_cleanup();
|
|
return rc;
|
|
}
|