/* 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 * * 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 #include #include #include #include #include #include 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 \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 [args]\n\n" "commands:\n" " parse 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); 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; } ffmpeg_loader_cleanup(&fm); log_cleanup(); return rc; }