From 474ccfd0534e03cfcde94fe0f94e3028ed65366a Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Sun, 19 Jan 2025 10:49:22 -0500 Subject: Add DVD boilerplate - Work on FFmpeg hwframes context support - Raspberry Pi testing - Update color_palette Signed-off-by: Andrew Opalach --- .gitignore | 2 + docs/references/references.txt | 8 ++- flake.lock | 12 ++-- flake.nix | 27 ++++++-- hardware/cmsb-001/configuration.nix | 36 ++++++---- src/buffer/video.c | 3 +- src/cache/handlers/file.c | 4 +- src/cache/handlers/file.h | 2 +- src/codec/ffmpeg/decoder.c | 99 +++++++++++++++++++-------- src/codec/ffmpeg/decoder.h | 5 +- src/fruits/cmc/cmc.c | 12 ++-- src/fruits/cmsrv/cmsrv.c | 6 +- src/fruits/cmv/cmv.c | 34 +++++---- src/fruits/ctv/ctv.c | 4 +- src/liana/handlers.c | 14 ++++ src/liana/handlers/dvd.h | 5 ++ src/liana/handlers/dvd_client.c | 38 +++++++++++ src/liana/handlers/dvd_server.c | 133 ++++++++++++++++++++++++++++++++++-- src/liana/meson.build | 10 +++ src/liana/vcr.c | 2 +- src/portal/py/modules/__init__.py | 8 +-- src/portal/scripts/create_vendor.sh | 10 +-- src/render/renderer_libplacebo.c | 2 +- src/screen/screen.c | 4 +- src/server/server.c | 2 +- src/util/color_palette.c | 42 +++++++++--- 26 files changed, 411 insertions(+), 113 deletions(-) create mode 100644 src/liana/handlers/dvd_client.c diff --git a/.gitignore b/.gitignore index 29412b1..56b6a8c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ compile_commands.json data/ docs/**/*.html env/bin/ +result src/portal/cpy/portal.c src/portal/cpy/portal.h src/portal/py/config.py @@ -57,6 +58,7 @@ subprojects/stela/ subprojects/vulkan.wrap subprojects/vulkan/ subprojects/wayland-protocols.wrap +subprojects/wayland-protocols/ subprojects/wlr-protocols.wrap subprojects/wlr-protocols/ subprojects/wuffs/ diff --git a/docs/references/references.txt b/docs/references/references.txt index 2ce8329..f2430d1 100644 --- a/docs/references/references.txt +++ b/docs/references/references.txt @@ -61,8 +61,14 @@ Terminal * https://www.amp-what.com/ * https://www.unicode.org/charts/beta/nameslist/n_2B00.html +Code +---- +C +~ +* https://beej.us/guide/bgc/html/split/index.html + Python ------- +~~~~~~ * https://stackoverflow.com/questions/38243682/whats-the-standard-way-to-package-a-python-project-with-dependencies // vim: set syntax=asciidoc: diff --git a/flake.lock b/flake.lock index e83384c..3a2e0ce 100644 --- a/flake.lock +++ b/flake.lock @@ -23,11 +23,11 @@ ] }, "locked": { - "lastModified": 1736883540, - "narHash": "sha256-dgPgoPUSg8cGAMqbhQRkww665sZtgzpWXxWjlyqhv94=", + "lastModified": 1737221749, + "narHash": "sha256-igllW0yG+UbetvhT11jnt9RppSHXYgMykYhZJeqfHs0=", "owner": "nix-community", "repo": "home-manager", - "rev": "0dfec9deb275854a56c97c356c40ef72e3a2e632", + "rev": "97d7946b5e107dd03cc82f21165251d4e0159655", "type": "github" }, "original": { @@ -91,11 +91,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1736883708, - "narHash": "sha256-uQ+NQ0/xYU0N1CnXsa2zghgNaOPxWpMJXSUJJ9W7140=", + "lastModified": 1737062831, + "narHash": "sha256-Tbk1MZbtV2s5aG+iM99U8FqwxU/YNArMcWAv6clcsBc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "eb62e6aa39ea67e0b8018ba8ea077efe65807dc8", + "rev": "5df43628fdf08d642be8ba5b3625a6c70731c19c", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 759db1d..fbfde71 100644 --- a/flake.nix +++ b/flake.nix @@ -42,6 +42,7 @@ nixpkgs.lib.genAttrs [ "x86_64-linux" "i686-linux" + "aarch64-linux" ] (system: function (import nixpkgs { inherit system; @@ -140,6 +141,15 @@ maintainers = []; }; }; + # https://cryptoisland.blog/posts/2024/12/09/flake-based-recipe-for-offline-dev-shells-in-nixos/ + # lib.strings.makeLibraryPath for PKG_CONFIG_PATH and LD_LIBRARY_PATH? + shellWrapper = with pkgs; let + shell = devShells.${system}.default; + in pkgs.writeScriptBin "camu-devshell" '' + export PATH=${pkgs.lib.makeBinPath shell.nativeBuildInputs}:${pkgs.lib.makeBinPath shell.buildInputs}:$PATH + ${shell.shellHook} + ${pkgs.bashInteractive}/bin/bash $@ + ''; }); devShells = forAllDevSystems (pkgs: rec { @@ -300,13 +310,16 @@ in nixosSystem { system = system; modules = [ - ({ pkgs, ... }: { nixpkgs.overlays = [ - (self: super: { - camu = packages.${system}.default.overrideAttrs (oldAttrs: { - #mesonFlags = ["-Dsink-for-rpi=true"]; - }); - }) - ];}) + ({ pkgs, ... }: { + nixpkgs.overlays = [ + (self: super: { + camu = packages.${system}.default.overrideAttrs (oldAttrs: { + #mesonFlags = ["-Dsink-for-rpi=true"]; + }); + }) + ]; + environment.systemPackages = [ packages.${system}.shellWrapper ]; + }) nixos-hardware.nixosModules.raspberry-pi-3 ./hardware/cmsb-001/configuration.nix ]; diff --git a/hardware/cmsb-001/configuration.nix b/hardware/cmsb-001/configuration.nix index 53217cd..a4fb9bb 100644 --- a/hardware/cmsb-001/configuration.nix +++ b/hardware/cmsb-001/configuration.nix @@ -1,4 +1,6 @@ # https://citizen428.net/blog/installing-nixos-raspberry-pi-3/ +# https://faint.day/blog/raspberry-pi-3-hardware-accelerated-video-playback/ +# https://github.com/jc-kynesim/rpi-ffmpeg/tree/dev/7.1/rpi_import_2 { config, lib, pkgs, modulesPath, ... }: { imports = [ #"${modulesPath}/installer/sd-card/sd-image.nix" @@ -42,12 +44,15 @@ "i2c_bcm2835" "reset-raspberrypi" ]; - boot.initrd.kernelModules = []; + boot.extraModulePackages = [ config.boot.kernelPackages.v4l2loopback ]; + boot.kernelModules = [ "v4l2loopback" ]; boot.kernelParams = [ "mitigations=off" "file_caps=1" ]; boot.blacklistedKernelModules = [ "snd_bcm2835" ]; hardware.enableRedistributableFirmware = true; - hardware.graphics.enable = true; + hardware.graphics = { + enable = true; + }; console = { font = "Lat2-Terminus16"; @@ -114,6 +119,7 @@ }) mesa-demos vulkan-tools + v4l-utils cage nfs-utils mpv @@ -127,18 +133,24 @@ source = "${pkgs.cage}/bin/cage"; setuid = true; }; - }; - - services.cage = { - enable = true; - user = "naunet"; - environment = { - WLR_LIBINPUT_NO_DEVICES = "1"; + "mount.nfs" = { + owner = "root"; + group = "root"; + source = "${pkgs.nfs-utils.out}/bin/mount.nfs"; + setuid = true; }; - program = "${pkgs.camu}/bin/cmv"; }; - systemd.services."cage-tty1".serviceConfig.StandardOutput = lib.mkForce "journal+console"; - systemd.services."cage-tty1".wantedBy = []; + + #services.cage = { + # enable = true; + # user = "naunet"; + # environment = { + # WLR_LIBINPUT_NO_DEVICES = "1"; + # }; + # program = "${pkgs.camu}/bin/cmv"; + #}; + #systemd.services."cage-tty1".serviceConfig.StandardOutput = lib.mkForce "journal+console"; + #systemd.services."cage-tty1".wantedBy = []; # https://pablo.tools/blog/computers/nixos-generate-raspberry-images/ #sdImage = { diff --git a/src/buffer/video.c b/src/buffer/video.c index 01f317e..bb217af 100644 --- a/src/buffer/video.c +++ b/src/buffer/video.c @@ -257,8 +257,9 @@ bool camu_video_buffer_read(struct camu_video_buffer *buf, void *out, bool *weig } } - u8 ret = buf->queue->read(buf->queue, base, out); u8 flow = al_atomic_load(u8)(&buf->flow, AL_ATOMIC_ACQUIRE); + if (flow == ERRORED) return false; + u8 ret = buf->queue->read(buf->queue, base, out); if (ret == CAMU_QUEUE_ERR) { buf->callback(buf->userdata, CAMU_BUFFER_ERRORED); al_atomic_store(u8)(&buf->flow, ERRORED, AL_ATOMIC_RELEASE); diff --git a/src/cache/handlers/file.c b/src/cache/handlers/file.c index c09aac0..9ac8933 100644 --- a/src/cache/handlers/file.c +++ b/src/cache/handlers/file.c @@ -30,7 +30,7 @@ static void handler_file_free(struct cch_handler **handler) *handler = NULL; } -struct cch_entry *cch_handler_file_create(str *path) +struct cch_entry *cch_handler_file_create(str *path, str *liana) { struct cch_backing *backing = cch_backing_file_create(path, 0); if (!backing) return NULL; @@ -48,6 +48,6 @@ struct cch_entry *cch_handler_file_create(str *path) entry->handler->wait_for_range = handler_file_wait_for_range; entry->handler->free = handler_file_free; entry->handler->entry = entry; - al_str_from(&entry->handler->liana, "codec"); + al_str_clone(&entry->handler->liana, liana); return entry; } diff --git a/src/cache/handlers/file.h b/src/cache/handlers/file.h index 85e1c7f..4704387 100644 --- a/src/cache/handlers/file.h +++ b/src/cache/handlers/file.h @@ -10,4 +10,4 @@ struct cch_handler_file { struct cch_backing *backing; }; -struct cch_entry *cch_handler_file_create(str *path); +struct cch_entry *cch_handler_file_create(str *path, str *liana); diff --git a/src/codec/ffmpeg/decoder.c b/src/codec/ffmpeg/decoder.c index c2d95ce..b502e88 100644 --- a/src/codec/ffmpeg/decoder.c +++ b/src/codec/ffmpeg/decoder.c @@ -14,13 +14,53 @@ static s32 get_buffer2(AVCodecContext *context, AVFrame *pic, s32 flags) return ret; } +static s32 init_hwframe_context(struct camu_ff_decoder *av, AVCodecContext *context, AVBufferRef *hw_device_context) +{ + AVBufferRef *hw_frames_ref; + if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_context))) { + al_log_error("ff_decoder", "Failed to create hardware frame context."); + return -1; + } + + AVHWFramesContext *frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data); + frames_ctx->format = av->hw_pix_fmt; + frames_ctx->sw_format = av->codec_context->sw_pix_fmt; + frames_ctx->width = av->codec_context->width; + frames_ctx->height = av->codec_context->height; + frames_ctx->initial_pool_size = 20; + + s32 ret = av_hwframe_ctx_init(hw_frames_ref); + if (ret < 0) { + al_log_error("ff_decoder", "Failed to initialize hardware frame context (%s).", av_err2str(ret)); + av_buffer_unref(&hw_frames_ref); + return ret; + } + + context->hw_frames_ctx = av_buffer_ref(hw_frames_ref); + + av_buffer_unref(&hw_frames_ref); + + return ret; +} + static enum AVPixelFormat get_hw_format(AVCodecContext *context, const enum AVPixelFormat *pix_fmts) { struct camu_ff_decoder *av = (struct camu_ff_decoder *)context->opaque; const enum AVPixelFormat *fmt = pix_fmts; for (; *fmt != AV_PIX_FMT_NONE; fmt++) { - if (*fmt == av->hw_pix_fmt) return *fmt; + if (*fmt == av->hw_pix_fmt) { + if (av->use_frames_context) { + av->hw_context = NULL; + s32 ret = av_hwdevice_ctx_create(&av->hw_context, AV_HWDEVICE_TYPE_VAAPI, NULL, NULL, 0); + if (ret < 0 || !av->hw_context) { + al_log_error("ff_decoder", "Failed to initialize VAAPI device (%s).", av_err2str(ret)); + break; + } + init_hwframe_context(av, av->codec_context, av->hw_context); + } + return *fmt; + } } al_log_error("ff_decoder", "Failed to get HW surface format."); @@ -29,14 +69,9 @@ static enum AVPixelFormat get_hw_format(AVCodecContext *context, const enum AVPi } #endif -static void close_internal(struct camu_ff_decoder *av) +static s32 init_hwdevice_context(struct camu_ff_decoder *av, AVCodecContext *context) { - if (av->codec_context) avcodec_free_context(&av->codec_context); -} - -static s32 init_hw_decoder(struct camu_ff_decoder *av, AVCodecContext *context, const enum AVHWDeviceType device_type) -{ - s32 ret = av_hwdevice_ctx_create(&av->hw_context, device_type, NULL, NULL, 0); + s32 ret = av_hwdevice_ctx_create(&av->hw_context, av->hw_device_type, NULL, NULL, 0); if (ret < 0) { al_log_error("ff_decoder", "Failed to create specified HW device."); return ret; @@ -44,11 +79,16 @@ static s32 init_hw_decoder(struct camu_ff_decoder *av, AVCodecContext *context, context->hw_device_ctx = av_buffer_ref(av->hw_context); - al_log_info("ff_decoder", "Using %s hardware decoding.", av_hwdevice_get_type_name(device_type)); + al_log_info("ff_decoder", "Using %s hardware decoding.", av_hwdevice_get_type_name(av->hw_device_type)); return ret; } +static void close_internal(struct camu_ff_decoder *av) +{ + if (av->codec_context) avcodec_free_context(&av->codec_context); +} + static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *renderer, struct camu_codec_stream *stream, void (*callback)(void *, struct camu_codec_frame *), void *userdata) { @@ -69,49 +109,51 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend goto err; } - enum AVHWDeviceType device_type = AV_HWDEVICE_TYPE_NONE; + av->hw_device_type = AV_HWDEVICE_TYPE_NONE; #ifdef CAMU_FF_DECODER_HWACCEL if (codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { -#ifdef _WIN32 +#ifdef _WIN32 // TEMP const char *hw_device = "vulkan"; #else const char *hw_device = "vaapi"; #endif - device_type = av_hwdevice_find_type_by_name(hw_device); - if (device_type == AV_HWDEVICE_TYPE_NONE) { + av->hw_device_type = av_hwdevice_find_type_by_name(hw_device); + if (av->hw_device_type == AV_HWDEVICE_TYPE_NONE) { al_log_info("ff_decoder", "Hardware device type \"%s\" not supported.", hw_device); al_log_info("ff_decoder", "Types available on this system:"); - while ((device_type = av_hwdevice_iterate_types(device_type)) != AV_HWDEVICE_TYPE_NONE) { - al_log_info("ff_decoder", "\t%s", av_hwdevice_get_type_name(device_type)); + while ((av->hw_device_type = av_hwdevice_iterate_types(av->hw_device_type)) != AV_HWDEVICE_TYPE_NONE) { + al_log_info("ff_decoder", "\t%s", av_hwdevice_get_type_name(av->hw_device_type)); } } } #endif - if (device_type != AV_HWDEVICE_TYPE_NONE) { - bool supports_frames_context = false; + if (av->hw_device_type != AV_HWDEVICE_TYPE_NONE) { + av->use_frames_context = false; for (s32 i = 0; ; i++) { const AVCodecHWConfig *config = avcodec_get_hw_config(codec, i); if (!config) { - if (supports_frames_context) { + if (av->use_frames_context) { al_log_warn("ff_decoder", "Selected hardware decoder (%s) only supports" "hardware frames for %s, which is unimplemented.", - av_hwdevice_get_type_name(device_type), codec->name); + av_hwdevice_get_type_name(av->hw_device_type), codec->name); } else { al_log_warn("ff_decoder", "Selected hardware decoder (%s) does not support %s.", - av_hwdevice_get_type_name(device_type), codec->name); + av_hwdevice_get_type_name(av->hw_device_type), codec->name); } - device_type = AV_HWDEVICE_TYPE_NONE; + av->hw_device_type = AV_HWDEVICE_TYPE_NONE; break; } if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX) { - supports_frames_context = true; + av->hw_pix_fmt = config->pix_fmt; + av->use_frames_context = true; } if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) { - if (config->device_type == device_type) { + if (config->device_type == av->hw_device_type) { av->hw_pix_fmt = config->pix_fmt; + av->use_frames_context = false; break; } } @@ -134,7 +176,7 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend av->renderer = renderer; av->codec_context->opaque = av; av->codec_context->get_buffer2 = get_buffer2; - if (device_type != AV_HWDEVICE_TYPE_NONE) { + if (av->hw_device_type != AV_HWDEVICE_TYPE_NONE) { av->codec_context->get_format = get_hw_format; } } @@ -142,7 +184,7 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend (void)renderer; #endif - if (stream->duration > 0 && device_type == AV_HWDEVICE_TYPE_NONE) { + if (stream->duration > 0 && av->hw_device_type == AV_HWDEVICE_TYPE_NONE) { s32 cpus = 0; if (av->codec_context->codec_type == AVMEDIA_TYPE_VIDEO) { cpus = av_cpu_count(); @@ -154,8 +196,9 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend al_log_debug("ff_decoder", "Using %i threads for decoder.", cpus); } - if ((device_type != AV_HWDEVICE_TYPE_NONE) && - (init_hw_decoder(av, av->codec_context, device_type) < 0)) { + if ((av->hw_device_type != AV_HWDEVICE_TYPE_NONE) && + (init_hwdevice_context(av, av->codec_context) < 0)) { + av->hw_pix_fmt = AV_PIX_FMT_NONE; return false; } @@ -166,7 +209,7 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend const char *long_name = codec->long_name ? codec->long_name : codec->name; s64 kbps = codecpar->bit_rate > 0 ? codecpar->bit_rate / 1000L : 0L; - al_log_info("ff_decoder", "Codec: %s (%s) %ldkbps.", codec->name, long_name, kbps); + al_log_info("ff_decoder", "Codec: %s (%s) %lldkbps.", codec->name, long_name, kbps); av->callback = callback; av->userdata = userdata; diff --git a/src/codec/ffmpeg/decoder.h b/src/codec/ffmpeg/decoder.h index 8d707f3..827afd2 100644 --- a/src/codec/ffmpeg/decoder.h +++ b/src/codec/ffmpeg/decoder.h @@ -5,7 +5,8 @@ #include "../codec.h" -#if !(defined _WIN32 && defined CAMU_RENDERER_OPENGL) +// We need EGL for hwaccel on OpenGL. +#if !(defined CAMU_RENDERER_OPENGL && !defined STELA_USE_EGL) //#define CAMU_FF_DECODER_HWACCEL #endif @@ -15,6 +16,8 @@ struct camu_ff_decoder { struct camu_renderer *renderer; AVBufferRef *hw_context; enum AVPixelFormat hw_pix_fmt; + enum AVHWDeviceType hw_device_type; + bool use_frames_context; void (*callback)(void *, struct camu_codec_frame *); void *userdata; }; diff --git a/src/fruits/cmc/cmc.c b/src/fruits/cmc/cmc.c index af3e567..7691f99 100644 --- a/src/fruits/cmc/cmc.c +++ b/src/fruits/cmc/cmc.c @@ -114,10 +114,10 @@ static void client_callback(void *userdata, u8 op, void *opaque) static struct cmc c = { 0 }; -#ifndef _WIN32 -static bool parse_cmd(s32 argc, char *argv[]) -#else +#ifdef NAUNET_ON_WINDOWS static bool parse_cmd(s32 argc, wchar_t **argv) +#else +static bool parse_cmd(s32 argc, char *argv[]) #endif { if (argc < 2) { @@ -153,10 +153,10 @@ static bool parse_cmd(s32 argc, wchar_t **argv) return true; } -#ifndef _WIN32 -s32 main(s32 argc, char *argv[]) -#else +#ifdef NAUNET_ON_WINDOWS s32 wmain(s32 argc, wchar_t **argv) +#else +s32 main(s32 argc, char *argv[]) #endif { if (!nn_common_init()) return EXIT_FAILURE; diff --git a/src/fruits/cmsrv/cmsrv.c b/src/fruits/cmsrv/cmsrv.c index 4cd1691..5b65275 100644 --- a/src/fruits/cmsrv/cmsrv.c +++ b/src/fruits/cmsrv/cmsrv.c @@ -144,10 +144,10 @@ static void sigint_handler(s32 signum) nn_signal_send(&s.quit_signal); } -#ifndef _WIN32 -s32 main(s32 argc, char *argv[]) -#else +#ifdef NAUNET_ON_WINDOWS s32 wmain(s32 argc, wchar_t **argv) +#else +s32 main(s32 argc, char *argv[]) #endif { (void)argc; diff --git a/src/fruits/cmv/cmv.c b/src/fruits/cmv/cmv.c index 55d7d55..65fc086 100644 --- a/src/fruits/cmv/cmv.c +++ b/src/fruits/cmv/cmv.c @@ -2,6 +2,7 @@ #include #include +#include "../../util/color_palette.h" #include "../../sink/desktop.h" #include "../../server/common.h" #include "../../codec/ffmpeg/common.h" @@ -12,11 +13,9 @@ #include "../common.h" -#ifndef CAMU_SINK_ONLY -#ifndef _WIN32 +#if !defined CAMU_SINK_ONLY && !defined NAUNET_ON_WINDOWS static str CMV_UNIX_PATH = al_str_c("/tmp/cmv_sock"); #endif -#endif struct cmv { struct nn_event_loop loop; @@ -67,10 +66,10 @@ static void sigint_handler(int signum) goto out; \ } while (0) -#ifndef _WIN32 -s32 main(s32 argc, char *argv[]) -#else +#ifdef NAUNET_ON_WINDOWS s32 wmain(s32 argc, wchar_t **argv) +#else +s32 main(s32 argc, char *argv[]) #endif { if (!nn_common_init() || !stl_global_init(false)) { @@ -85,6 +84,15 @@ s32 wmain(s32 argc, wchar_t **argv) camu_ff_set_default_log_callback(); #endif + str home; + al_str_from(&home, getenv("HOME")); + + str color_palette; + al_str_clone(&color_palette, &home); + al_str_cat(&color_palette, &al_str_c("/.config/colors.json")); + camu_color_palette_init(&color_palette); + al_str_free(&color_palette); + nn_event_loop_init(&c.loop); u8 type; @@ -92,10 +100,10 @@ s32 wmain(s32 argc, wchar_t **argv) #ifndef CAMU_SINK_ONLY bool local = argc > 1; if (local) { -#ifndef _WIN32 - type = NNWT_SOCKET_UNIX; addr = &CMV_UNIX_PATH; -#else +#ifdef NAUNET_ON_WINDOWS type = NNWT_SOCKET_TCP; addr = &CAMU_LOCALHOST; +#else + type = NNWT_SOCKET_UNIX; addr = &CMV_UNIX_PATH; #endif camu_server_init(&c.server, &c.loop); c.server.meta_callback = server_meta_callback; @@ -128,14 +136,14 @@ s32 wmain(s32 argc, wchar_t **argv) #ifndef CAMU_SINK_ONLY if (local) { for (s32 i = 1; i < argc; i++) { -#ifndef _WIN32 - str arg = al_str_cr(argv[i]); -#else +#ifdef NAUNET_ON_WINDOWS str arg; if (!al_wstr_to_str(&al_wstr_cr(argv[i]), &arg)) { al_log_error("cmv", "Failed to parse argument #%i.", i); continue; } +#else + str arg = al_str_cr(argv[i]); #endif struct nn_packet *packet = nn_packet_create(); #ifdef CAMU_HAVE_PORTAL @@ -178,6 +186,8 @@ s32 wmain(s32 argc, wchar_t **argv) out: nn_event_loop_destroy(&c.loop); + al_str_free(&home); + #ifdef CAMU_HAVE_FFMPEG camu_ff_free_default_log_callback(); #endif diff --git a/src/fruits/ctv/ctv.c b/src/fruits/ctv/ctv.c index ded4182..c9be50f 100644 --- a/src/fruits/ctv/ctv.c +++ b/src/fruits/ctv/ctv.c @@ -2,10 +2,10 @@ #include #include +#include "../../libsink/sink.h" #include "../../screen/screen.h" #include "../../render/renderer_libplacebo.h" #include "../../mixer/mixer.h" -#include "../../libsink/sink.h" #include "../../mixer/audio_null.h" #include "../../mixer/audio_miniaudio.h" #include "../../sink/common.h" @@ -66,7 +66,7 @@ static void to_be_removed_inline_create_client(struct ctv *c, GLFMDisplay *displ al_str_from(&c->sink.default_list, "default"); c->sink.callback = sink_callback; c->sink.userdata = c; - camu_sink_connect(&c->sink, NNWT_SOCKET_TCP, CAMU_TEST_IP, CAMU_PORT, al_str_c("ctv")); + camu_sink_connect(&c->sink, NNWT_SOCKET_TCP, &CAMU_TEST_IP, CAMU_PORT, &al_str_c("ctv")); nn_thread_create(&c->thread, event_loop_thread, c); } diff --git a/src/liana/handlers.c b/src/liana/handlers.c index e52d8bb..38e5bfa 100644 --- a/src/liana/handlers.c +++ b/src/liana/handlers.c @@ -4,6 +4,9 @@ #ifdef CACHE_HAVE_CDIO #include "handlers/cdio.h" #endif +#ifdef LIANA_HAVE_DVD +#include "handlers/dvd.h" +#endif struct lia_handler_entry liana_handlers[] = { { @@ -23,6 +26,17 @@ struct lia_handler_entry liana_handlers[] = { #endif #ifdef LIANA_CLIENT .create_client_handler = lia_cdio_client_create +#endif + }, +#endif +#ifdef LIANA_HAVE_DVD + { + .name = al_str_c("dvd"), +#ifdef LIANA_SERVER + .create_server_handler = lia_dvd_server_create, +#endif +#ifdef LIANA_CLIENT + .create_client_handler = lia_dvd_client_create, #endif } #endif diff --git a/src/liana/handlers/dvd.h b/src/liana/handlers/dvd.h index 788c30e..4b71ec8 100644 --- a/src/liana/handlers/dvd.h +++ b/src/liana/handlers/dvd.h @@ -1,9 +1,14 @@ #pragma once +#include + #include "../handler.h" struct lia_dvd_server { struct lia_server_handler handler; + struct cch_handle *handle; + dvdnav_t *dvdnav; + struct nn_buffer buffer; }; struct lia_dvd_client { diff --git a/src/liana/handlers/dvd_client.c b/src/liana/handlers/dvd_client.c new file mode 100644 index 0000000..53beac1 --- /dev/null +++ b/src/liana/handlers/dvd_client.c @@ -0,0 +1,38 @@ +#include "dvd.h" + +static bool dvd_client_init(struct lia_client_handler *handler, struct camu_renderer *renderer, + struct camu_codec_stream *stream) +{ + struct lia_dvd_client *dvd = (struct lia_dvd_client *)handler; + (void)renderer; + dvd->handler.stream = stream; + return true; +} + +static bool dvd_client_handle_packet(struct lia_client_handler *handler, struct nn_packet *packet) +{ + struct lia_dvd_client *dvd = (struct lia_dvd_client *)handler; + (void)dvd; + (void)packet; + return true; +} + +static void dvd_client_flush(struct lia_client_handler *handler) +{ + (void)handler; +} + +static void dvd_client_free(struct lia_client_handler **handler) +{ + (void)handler; +} + +struct lia_client_handler *lia_dvd_client_create(void) +{ + struct lia_dvd_client *dvd = al_alloc_object(struct lia_dvd_client); + dvd->handler.init = dvd_client_init; + dvd->handler.handle_packet = dvd_client_handle_packet; + dvd->handler.flush = dvd_client_flush; + dvd->handler.free = dvd_client_free; + return (struct lia_client_handler *)dvd; +} diff --git a/src/liana/handlers/dvd_server.c b/src/liana/handlers/dvd_server.c index a487de4..afb2c07 100644 --- a/src/liana/handlers/dvd_server.c +++ b/src/liana/handlers/dvd_server.c @@ -1,21 +1,140 @@ + #include "dvd.h" +static s32 dvd_stream_read(void *userdata, void *buffer, s32 size) +{ + struct lia_dvd_server *dvd = (struct lia_dvd_server *)userdata; + return cch_handle_read(dvd->handle, buffer, size); +} + +static s32 dvd_stream_seek(void *userdata, u64 pos) +{ + struct lia_dvd_server *dvd = (struct lia_dvd_server *)userdata; + cch_handle_seek(dvd->handle, pos, SEEK_SET); + return 0; +} + +static dvdnav_stream_cb cb = { + .pf_read = dvd_stream_read, + .pf_seek = dvd_stream_seek +}; + +#define DVD_LANGUAGE "en" + static bool dvd_server_init(struct lia_server_handler *handler, struct cch_handle *handle) { struct lia_dvd_server *dvd = (struct lia_dvd_server *)handler; + dvd->handle = handle; + + dvd->dvdnav = NULL; + dvdnav_open_stream2(&dvd->dvdnav, dvd, NULL, &cb); + + //if (dvdnav_set_readahead_flag(dvdnav, DVD_READ_CACHE) != DVDNAV_STATUS_OK) { + // dvdnav_err_to_string(dvdnav)) + //} + + if (dvdnav_menu_language_select(dvd->dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK || + dvdnav_audio_language_select(dvd->dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK || + dvdnav_spu_language_select(dvd->dvdnav, DVD_LANGUAGE) != DVDNAV_STATUS_OK) { + } + + //if (dvdnav_set_PGC_positioning_flag(dvdnav, 1) != DVDNAV_STATUS_OK) { + //} + + nn_buffer_init(&dvd->buffer); + nn_buffer_ensure_space(&dvd->buffer, DVD_VIDEO_LB_LEN); + return true; } +static void dvd_server_write_info(struct lia_server_handler *handler, struct nn_packet *packet) +{ + (void)handler; + (void)packet; +} + +static void dvd_server_subscribe(struct lia_server_handler *handler, s32 mask) +{ + (void)handler; + (void)mask; +} + +static u64 dvd_server_get_duration(struct lia_server_handler *handler) +{ + (void)handler; + return 0; +} + +static bool dvd_server_seek(struct lia_server_handler *handler, u64 pos) +{ + (void)handler; + (void)pos; + return false; +} + +static void dvd_server_step(struct lia_server_handler *handler) +{ + struct lia_dvd_server *dvd = (struct lia_dvd_server *)handler; + s32 event, length; + s32 ret = dvdnav_get_next_block(dvd->dvdnav, nn_buffer_get_ptr(&dvd->buffer, 0), &event, &length); + if (ret == DVDNAV_STATUS_ERR) { + return; + } + switch (event) { + case DVDNAV_BLOCK_OK: + break; + case DVDNAV_NOP: + break; + case DVDNAV_STILL_FRAME: + break; + case DVDNAV_WAIT: + break; + case DVDNAV_SPU_CLUT_CHANGE: + break; + case DVDNAV_SPU_STREAM_CHANGE: + break; + case DVDNAV_AUDIO_STREAM_CHANGE: + break; + case DVDNAV_HIGHLIGHT: + break; + case DVDNAV_VTS_CHANGE: + break; + case DVDNAV_CELL_CHANGE: + break; + case DVDNAV_NAV_PACKET: + break; + case DVDNAV_HOP_CHANNEL: + break; + case DVDNAV_STOP: + break; + default: + break; + } +} + +static void dvd_server_write_packet(struct lia_server_handler *handler, struct nn_packet *packet) +{ + (void)handler; + (void)packet; +} + +static void dvd_server_free(struct lia_server_handler **handler) +{ + struct lia_dvd_server *dvd = (struct lia_dvd_server *)*handler; + al_free(dvd); + *handler = NULL; +} + struct lia_server_handler *lia_dvd_server_create(void) { struct lia_dvd_server *dvd = al_alloc_object(struct lia_dvd_server); dvd->handler.init = dvd_server_init; -// dvd->handler.write_info = dvd_server_write_info; -// dvd->handler.subscribe = dvd_server_subscribe; -// dvd->handler.get_duration = dvd_server_get_duration; -// dvd->handler.seek = dvd_server_seek; -// dvd->handler.step = dvd_server_step; -// dvd->handler.write_packet = dvd_server_write_packet; -// dvd->handler.free = dvd_server_free; + dvd->handler.write_info = dvd_server_write_info; + dvd->handler.subscribe = dvd_server_subscribe; + dvd->handler.get_duration = dvd_server_get_duration; + dvd->handler.seek = dvd_server_seek; + dvd->handler.step = dvd_server_step; + dvd->handler.write_packet = dvd_server_write_packet; + dvd->handler.free = dvd_server_free; return (struct lia_server_handler *)dvd; } diff --git a/src/liana/meson.build b/src/liana/meson.build index b68ba8b..beb6f68 100644 --- a/src/liana/meson.build +++ b/src/liana/meson.build @@ -18,6 +18,16 @@ if cache_have_cdio liana_client_src += ['handlers/cdio_client.c'] endif +libdvdcss = dependency('libdvdcss') +libdvdread = dependency('dvdread') +libdvdnav = dependency('dvdnav') +if libdvdcss.found() and libdvdread.found() and libdvdnav.found() + liana_server_src += ['handlers/dvd_server.c'] + liana_client_src += ['handlers/dvd_client.c'] + liana_deps += [libdvdcss, libdvdread, libdvdnav] + liana_args += ['-DLIANA_HAVE_DVD'] +endif + liana_server = declare_dependency(sources: liana_server_src, dependencies: liana_deps, compile_args: [liana_args, '-DLIANA_SERVER']) liana_client = declare_dependency(sources: liana_client_src, diff --git a/src/liana/vcr.c b/src/liana/vcr.c index c5b704e..47beed9 100644 --- a/src/liana/vcr.c +++ b/src/liana/vcr.c @@ -241,7 +241,7 @@ static void update_metrics(struct lia_vcr *vcr, u32 size) vcr->metric.current_frame = 0Lu; if (diff > 2500000Lu) { // We are buffering fast enough for it to not matter. - al_log_debug("vcr", "Ignoring %lu bytes in metrics.", frame); + al_log_debug("vcr", "Ignoring %llu bytes in metrics.", frame); return; } f32 kbps = (frame / 125.f) / (diff / 1000000.f); diff --git a/src/portal/py/modules/__init__.py b/src/portal/py/modules/__init__.py index cc34b82..fee4c22 100644 --- a/src/portal/py/modules/__init__.py +++ b/src/portal/py/modules/__init__.py @@ -3,9 +3,9 @@ import config from modules.youtube import YoutubeModule #from modules.twitter import TwitterScrapeModule #from modules.pixiv_app import PixivAppModule -from modules.pixiv_web import PixivWebModule -from modules.fanbox import FanboxModule -from modules.instagram import InstagramModule +#from modules.pixiv_web import PixivWebModule +#from modules.fanbox import FanboxModule +#from modules.instagram import InstagramModule #from modules.patreon import PatreonModule ALL_MODULES = { @@ -16,7 +16,7 @@ ALL_MODULES = { # 'twitter': (TwitterScrapeModule(config.TWITTER_COOKIES_PATH), []), # 'pixiv_web': (PixivWebModule(config.PIXIV_SESSID, config.PIXIV_USERID), []), # 'pixiv_app': (PixivAppModule(config.PIXIV_REFRESH_TOKEN), []), - 'fanbox': (FanboxModule(config.FANBOX_SESSID, config.FANBOX_CF_CLEARANCE), []), +# 'fanbox': (FanboxModule(config.FANBOX_SESSID, config.FANBOX_CF_CLEARANCE), []), # 'instagram': (InstagramModule( # config.INSTAGRAM_USER_AGENT, config.INSTAGRAM_SETTINGS_PATH, # config.INSTAGRAM_SESSION_ID), []), diff --git a/src/portal/scripts/create_vendor.sh b/src/portal/scripts/create_vendor.sh index 833d143..87b0b5d 100755 --- a/src/portal/scripts/create_vendor.sh +++ b/src/portal/scripts/create_vendor.sh @@ -24,13 +24,9 @@ cd instagrapi/ pip3 install . --upgrade --target=../vendor cd ../ -#cd CyberDropDownloader/ -#pip3 install . --upgrade --target=../vendor -#cd ../ -# -#cd gallery-dl/ -#pip3 install . --upgrade --target=../vendor -#cd ../ +cd gallery-dl/ +pip3 install . --upgrade --target=../vendor +cd ../ cd ../ rm -r venv diff --git a/src/render/renderer_libplacebo.c b/src/render/renderer_libplacebo.c index 2539e1f..a15adfd 100644 --- a/src/render/renderer_libplacebo.c +++ b/src/render/renderer_libplacebo.c @@ -11,7 +11,7 @@ #include "renderer_libplacebo.h" #include "queue_libplacebo.h" -static f32 clear_color[4] = { 0.0f, 0.0f, 0.0f, 1.f }; +static f32 clear_color[4] = { 0.f, 0.f, 0.f, 1.f }; static void renderer_lp_resize(struct camu_renderer *renderer, s32 *width, s32 *height, bool double_swap) { diff --git a/src/screen/screen.c b/src/screen/screen.c index e6f9970..61bbc77 100644 --- a/src/screen/screen.c +++ b/src/screen/screen.c @@ -338,8 +338,8 @@ bool camu_screen_create_renderer(struct camu_screen *scr, struct camu_renderer * scr->window->vk_get_extensions, #elif defined CAMU_RENDERER_OPENGL #ifdef STELA_USE_EGL - scr->window->display, - scr->window->context, + scr->window->egl_display, + scr->window->egl_context, #endif scr->window->get_gl_proc_address, scr->window->gl_loader_load, diff --git a/src/server/server.c b/src/server/server.c index bdc1f96..794030a 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -403,7 +403,7 @@ static void handle_add_command(struct camu_server *server, struct lia_list *list case CAMU_RESOURCE_FILE: { str path; nn_packet_read_str(packet, &path); - entry = cch_handler_file_create(&path); + entry = cch_handler_file_create(&path, &al_str_c("codec")); if (!entry) return; struct camu_resource_file *file = al_alloc_object(struct camu_resource_file); al_str_clone(&file->path, &path); diff --git a/src/util/color_palette.c b/src/util/color_palette.c index 886ba8e..02af36f 100644 --- a/src/util/color_palette.c +++ b/src/util/color_palette.c @@ -1,3 +1,5 @@ +#include + #include "color_palette.h" struct camu_color_palette global_color_palette = { 0 }; @@ -33,7 +35,7 @@ static char *normal_colors[16] = { bool camu_color_palette_init(str *path) { struct nn_file file; - if (!nn_file_open(&file, path, 0)) { + if (!nn_file_open(&file, path, NNWT_FILE_READONLY)) { return false; } str s; @@ -41,30 +43,54 @@ bool camu_color_palette_init(str *path) nn_file_close(&file); json_error_t error; json_t *root = json_loadb(s.data, s.length, 0, &error); - if (!root) return false; + if (!root) { + al_log_error("color_palette", "Failed to load %.*s as a json (%s).", + al_str_fmt(path), error.text); + return false; + } json_t *special = json_object_get(root, "special"); + if (!special) { + al_log_error("color_palette", "\"special\" field missing from the color palette."); + return false; + } json_t *colors = json_object_get(root, "colors"); - if (!special || !colors) return false; + if (!colors) { + al_log_error("color_palette", "\"colors\" field missing from the color palette."); + return false; + } json_t *object; - bool to_long_error; const char *color; u32 value; + u32 index; + bool to_long_error; for (u32 i = 0; i < ARRAY_SIZE(special_colors); i++) { object = json_object_get(special, special_colors[i]); - if (!object) return false; + if (!object) { + al_log_error("color_palette", "Couldn't find special color: %s.", special_colors[i]); + return false; + } color = json_string_value(object); - value = (u32)al_str_to_long(&al_str_w((char *)color, 1, 6), 16, &to_long_error); + index = color[0] == '#' ? 1 : 0; + value = (u32)al_str_to_long(&al_str_w((char *)color, index, 6), 16, &to_long_error); if (!to_long_error) { global_color_palette.colors[i] = value; + } else { + al_log_warn("color_palette", "%s is not a valid hex color.", normal_colors[i]); } } for (u32 i = 0; i < ARRAY_SIZE(normal_colors); i++) { object = json_object_get(colors, normal_colors[i]); - if (!object) return false; + if (!object) { + al_log_error("color_palette", "Couldn't find color: %s.", normal_colors[i]); + return false; + } color = json_string_value(object); - value = (u32)al_str_to_long(&al_str_w((char *)color, 1, 6), 16, &to_long_error); + index = color[0] == '#' ? 1 : 0; + value = (u32)al_str_to_long(&al_str_w((char *)color, index, 6), 16, &to_long_error); if (!to_long_error) { global_color_palette.colors[i + 2] = value; + } else { + al_log_warn("color_palette", "%s is not a valid hex color.", normal_colors[i]); } } return true; -- cgit v1.2.3-101-g0448