From 5be09d7edff924e7486d743e9d15edf07f555341 Mon Sep 17 00:00:00 2001 From: Mikhail Burakov Date: Mon, 18 Nov 2024 06:34:31 +0100 Subject: WIP --- encode_context.c | 45 ++++++++++++++++---- main.c | 126 ------------------------------------------------------- main.cc | 76 +++++++++++++++++++++++++++++++++ makefile | 15 ++++--- util.h | 48 +++++++++++++++++---- 5 files changed, 164 insertions(+), 146 deletions(-) delete mode 100644 main.c create mode 100644 main.cc diff --git a/encode_context.c b/encode_context.c index 7fc1142..bef2f17 100644 --- a/encode_context.c +++ b/encode_context.c @@ -29,6 +29,7 @@ #include #include "io_context.h" +#include "queue.h" #include "util.h" struct EncodeContext { @@ -44,6 +45,11 @@ struct EncodeContext { VAConfigAttribValEncHEVCBlockSizes hevc_block_sizes; VAContextID context_id; + struct EncodeContextFrame** frames; + size_t frames_count; + + struct Queue input; + struct Queue reuse; mtx_t mutex; cnd_t cond; @@ -318,19 +324,44 @@ rollback_encode_context: struct EncodeContextFrame* EncodeContextDequeue( struct EncodeContext* encode_context) { - (void)encode_context; - // TODO(mburakov): Implement this! - return NULL; + if (!atomic_load_explicit(&encode_context->running, memory_order_relaxed)) { + LOG("Encode context is not running"); + return false; + } + + if (mtx_lock(&encode_context->mutex) != thrd_success) { + LOG("Failed to lock mutex"); + return false; + } + + void* item; + if (&QueuePop(encode_context->reuse, )) + +rollback_lock: + assert(mtx_unlock(&encode_context->mutex)); + return false; } bool EncodeContextQueue(struct EncodeContext* encode_context, struct EncodeContextFrame* encode_context_frame, bool encode) { - (void)encode_context; - (void)encode_context_frame; - (void)encode; - // TODO(mburakov): Implement this! + if (mtx_lock(&encode_context->mutex) != thrd_success) { + LOG("Failed to lock mutex"); + return false; + } + + struct Queue* queue = + encode ? &encode_context->input : &encode_context->reuse; + if (!QueuePush(queue, encode_context_frame)) { + LOG("Failed to queue frame (%s)", strerror(errno)); + goto rollback_lock; + } + return true; + +rollback_lock: + assert(mtx_unlock(&encode_context->mutex)); + return false; } void EncodeContextDestroy(struct EncodeContext* encode_context) { diff --git a/main.c b/main.c deleted file mode 100644 index addb003..0000000 --- a/main.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2024 Mikhail Burakov. This file is part of streamer. - * - * streamer is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * streamer is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with streamer. If not, see . - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "audio_context.h" -#include "io_context.h" -#include "proto.h" -#include "util.h" -#include "video_context.h" - -static volatile sig_atomic_t g_signal; -static void OnSignal(int status) { g_signal = status; } - -static bool SetupSignalHandler(int sig, void (*func)(int)) { - struct sigaction sa = { - .sa_handler = func, - }; - if (sigemptyset(&sa.sa_mask) || sigaddset(&sa.sa_mask, sig)) { - LOG("Failed to configure signal set (%s)", strerror(errno)); - return false; - } - if (sigaction(sig, &sa, NULL)) { - LOG("Failed to set signal action (%s)", strerror(errno)); - return false; - } - return true; -} - -static void HandleClientSession(struct IoContext* io_context) { - struct VideoContext* video_context = VideoContextCreate(io_context); - if (!video_context) { - LOG("Failed to create video context"); - return; - } - - struct AudioContext* audio_context = NULL; - while (!g_signal) { - struct Proto* proto = IoContextRead(io_context); - if (!proto) { - LOG("Failed to read proto"); - goto leave; - } - - switch (proto->header->type) { - case kProtoTypeHello: - if (audio_context) { - LOG("Audio reconfiguration prohibited"); - proto->Destroy(proto); - goto leave; - } - audio_context = AudioContextCreate(io_context, proto); - if (!audio_context) { - LOG("Failed to create audio context"); - goto leave; - } - break; - case kProtoTypePing: - case kProtoTypeUhid: - break; - default: - LOG("Unexpected proto received"); - proto->Destroy(proto); - goto leave; - } - } - -leave: - if (audio_context) AudioContextDestroy(audio_context); - VideoContextDestroy(video_context); -} - -int main(int argc, char* argv[]) { - pw_init(&argc, &argv); - if (argc < 2) { - LOG("Usage: streamer "); - goto leave; - } - - int port = atoi(argv[1]); - if (0 >= port || port > UINT16_MAX) { - LOG("Invalid port \"%s\"", argv[1]); - goto leave; - } - - SetupSignalHandler(SIGINT, OnSignal); - SetupSignalHandler(SIGPIPE, SIG_IGN); - SetupSignalHandler(SIGTERM, OnSignal); - - while (!g_signal) { - struct IoContext* io_context = IoContextCreate((uint16_t)port); - if (!io_context) { - LOG("Failed to create io context"); - goto leave; - } - - HandleClientSession(io_context); - IoContextDestroy(io_context); - } - -leave: - pw_deinit(); - bool result = g_signal == SIGINT || g_signal == SIGTERM; - return result ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/main.cc b/main.cc new file mode 100644 index 0000000..ba723a1 --- /dev/null +++ b/main.cc @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2024 Mikhail Burakov. This file is part of streamer. + * + * streamer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * streamer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with streamer. If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#include + +#include "util.h" + +namespace { + +volatile sig_atomic_t g_signal; +void OnSignal(int status) { g_signal = status; } + +void SetupSignalHandler(int sig, void (*func)(int)) { + struct sigaction sa {}; + sa.sa_handler = func; + if (sigemptyset(&sa.sa_mask) || sigaddset(&sa.sa_mask, sig)) { + throw std::system_error(errno, std::system_category(), + FROM_HERE "Failed to configure signal set"); + } + if (sigaction(sig, &sa, NULL)) { + throw std::system_error(errno, std::system_category(), + FROM_HERE "Failed to set signal action"); + } +} + +} // namespace + +int main(int argc, char* argv[]) { + try { + if (argc < 2) { + throw std::runtime_error(FROM_HERE "Usage: streamer "); + } + + int port = std::atoi(argv[1]); + if (0 >= port || port > UINT16_MAX) { + throw std::runtime_error(FROM_HERE "Invalid port number"); + } + + pw_init(&argc, &argv); + Defer defer_pw_deinit([] { pw_deinit(); }); + + SetupSignalHandler(SIGINT, OnSignal); + SetupSignalHandler(SIGPIPE, SIG_IGN); + SetupSignalHandler(SIGTERM, OnSignal); + + while (!g_signal) { + // BLAH + } + + return EXIT_SUCCESS; + } catch (const std::exception& ex) { + std::cerr << ex.what() << std::endl; + return EXIT_FAILURE; + } +} diff --git a/makefile b/makefile index 2b6cdbd..69aa1f7 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,6 @@ bin:=$(notdir $(shell pwd)) -src:=$(wildcard *.c) -obj:=$(src:.c=.o) +src:=$(wildcard *.cc) +obj:=$(src:.cc=.o) libs:=\ egl \ @@ -21,6 +21,9 @@ res:=\ luma.glsl \ chroma.glsl +CXXFLAGS+=\ + -std=c++20 + obj:=$(patsubst %,%.o,$(protocols)) $(obj) headers:=$(patsubst %,%.h,$(protocols)) @@ -36,15 +39,15 @@ LDFLAGS+= \ all: $(bin) $(bin): $(obj) - $(CC) $^ $(LDFLAGS) -o $@ + $(CXX) $^ $(LDFLAGS) -o $@ -%.o: %.c *.h $(res) $(headers) - $(CC) -c $< $(CFLAGS) -o $@ +%.o: %.cc *.h $(res) $(headers) + $(CXX) -c $< $(CFLAGS) $(CXXFLAGS) -o $@ %.h: $(protocols_dir)/%.xml wayland-scanner client-header $< $@ -%.c: $(protocols_dir)/%.xml +%.cc: $(protocols_dir)/%.xml wayland-scanner private-code $< $@ clean: diff --git a/util.h b/util.h index 62e7c4e..bba74a2 100644 --- a/util.h +++ b/util.h @@ -18,15 +18,49 @@ #ifndef STREAMER_UTIL_H_ #define STREAMER_UTIL_H_ -#define MIN(a, b) ((a) < (b) ? (a) : (b)) -#define MAX(a, b) ((a) > (b) ? (a) : (b)) - -#define LENGTH(x) (sizeof(x) / sizeof *(x)) - #define STR_IMPL(x) #x #define STR(x) STR_IMPL(x) +#define FROM_HERE __FILE__ ":" STR(__LINE__) " " + +template +struct Defer { + Defer(T&& op) : op_{op} {} + ~Defer() { op_(); } + const T& op_; +}; + +template +Defer(T&&) -> Defer; + +template +struct PodCloser { + struct pointer { + decltype(dflt) value_; + pointer() : value_{dflt} {} + pointer(decltype(nullptr)) : value_{dflt} {} + pointer(decltype(dflt) value) : value_{value} {} + explicit operator bool() const { return value_ != dflt; } + friend bool operator==(pointer, pointer) = default; + operator decltype(dflt)() const { return value_; } + }; + void operator()(const pointer ptr) { + if (ptr.value_ != dflt) closer(ptr.value_); + } +}; + +template +struct ClassOf; + +template +struct ClassOf { + using T = C; +}; -#define LOG(x, ...) \ - fprintf(stderr, __FILE__ ":" STR(__LINE__) " " x "\n", ##__VA_ARGS__) +template +inline auto Trampoline(T* head, Args... tail) { + using C = ClassOf::T; + auto self = static_cast(head); + return (self->*fun)(tail...); +} #endif // STREAMER_UTIL_H_ -- cgit v1.2.3