From 31905b5468f533cf1f4fe6596d3b16a1c76e9839 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Wed, 1 May 2024 15:16:14 +0200 Subject: [PATCH] frame stream refactor, i like it now --- src/content/frame_stream2.hpp | 59 ++++++++++++++++++------- src/content/sdl_video_frame_stream2.cpp | 2 +- src/content/sdl_video_frame_stream2.hpp | 11 +++-- src/main.cpp | 2 +- src/object_store_ui.cpp | 1 - 5 files changed, 50 insertions(+), 25 deletions(-) diff --git a/src/content/frame_stream2.hpp b/src/content/frame_stream2.hpp index 98d044e8..85c55231 100644 --- a/src/content/frame_stream2.hpp +++ b/src/content/frame_stream2.hpp @@ -18,31 +18,38 @@ //}; template -struct FrameStream2Reader { +struct FrameStream2 { // get number of available frames - virtual int32_t getSize(void) = 0; + [[nodiscard]] virtual int32_t size(void) = 0; // get next frame // TODO: optional instead? // data sharing? -> no, data is copied for each fsr, if concurency supported - virtual std::optional getNext(void) = 0; + [[nodiscard]] virtual std::optional pop(void) = 0; + + // returns true if there are readers (or we dont know) + virtual bool push(const FrameType& value) = 0; }; // needs count frames queue size // having ~1-2sec buffer size is often sufficent template -struct QueuedFrameStream2Reader : public FrameStream2Reader { +struct QueuedFrameStream2 : public FrameStream2 { using frame_type = FrameType; rigtorp::SPSCQueue _queue; - explicit QueuedFrameStream2Reader(size_t queue_size) : _queue(queue_size) {} + // discard values if queue full + // will block if not lossy and full on push + const bool _lossy {true}; - [[nodiscard]] int32_t getSize(void) override { + explicit QueuedFrameStream2(size_t queue_size, bool lossy = true) : _queue(queue_size), _lossy(lossy) {} + + int32_t size(void) override { return _queue.size(); } - [[nodiscard]] std::optional getNext(void) override { + std::optional pop(void) override { auto* ret_ptr = _queue.front(); if (ret_ptr == nullptr) { return std::nullopt; @@ -55,14 +62,21 @@ struct QueuedFrameStream2Reader : public FrameStream2Reader { return ret; } + + bool push(const FrameType& value) override { + if (_lossy) { + [[maybe_unused]] auto _ = _queue.try_emplace(value); + // TODO: maybe return ? + } else { + _queue.push(value); + } + return true; + } }; template -struct MultiplexedQueuedFrameStream2Writer { - using ReaderType = QueuedFrameStream2Reader; - - // TODO: expose - const size_t _queue_size {10}; +struct QueuedFrameStream2Multiplexer : public FrameStream2 { + using ReaderType = QueuedFrameStream2; // pointer stability std::vector> _readers; @@ -70,9 +84,9 @@ struct MultiplexedQueuedFrameStream2Writer { // a simple lock here is ok, since this tends to be a rare operation, // except for the push, which is always on the same thread - ReaderType* aquireReader(void) { + ReaderType* aquireReader(size_t queue_size = 10, bool lossy = true) { std::lock_guard lg{_readers_lock}; - return _readers.emplace_back(std::make_unique(_queue_size)).get(); + return _readers.emplace_back(std::make_unique(queue_size, lossy)).get(); } void releaseReader(ReaderType* reader) { @@ -85,13 +99,26 @@ struct MultiplexedQueuedFrameStream2Writer { } } + // stream interface + + int32_t size(void) override { + // TODO: return something sensible? + return -1; + } + + std::optional pop(void) override { + assert(false && "tried to pop from a multiplexer"); + return std::nullopt; + } + // returns true if there are readers - bool pushValue(const FrameType& value) { + bool push(const FrameType& value) override { std::lock_guard lg{_readers_lock}; bool have_readers{false}; for (auto& it : _readers) { - [[maybe_unused]] auto _ = it->_queue.try_emplace(value); + [[maybe_unused]] auto _ = it->push(value); have_readers = true; // even if queue full, we still continue believing in them + // maybe consider push return value? } return have_readers; } diff --git a/src/content/sdl_video_frame_stream2.cpp b/src/content/sdl_video_frame_stream2.cpp index 99e638fc..f75e6fc6 100644 --- a/src/content/sdl_video_frame_stream2.cpp +++ b/src/content/sdl_video_frame_stream2.cpp @@ -105,7 +105,7 @@ SDLVideoCameraContent::SDLVideoCameraContent(void) { }; // creates surface copies - someone_listening = pushValue(new_frame_non_owning); + someone_listening = push(new_frame_non_owning); } SDL_ReleaseCameraFrame(_camera.get(), sdl_frame_next); diff --git a/src/content/sdl_video_frame_stream2.hpp b/src/content/sdl_video_frame_stream2.hpp index f39be994..56a62e57 100644 --- a/src/content/sdl_video_frame_stream2.hpp +++ b/src/content/sdl_video_frame_stream2.hpp @@ -1,7 +1,6 @@ #pragma once #include "./frame_stream2.hpp" -#include "SDL_surface.h" #include @@ -43,10 +42,10 @@ struct SDLVideoFrame { SDLVideoFrame& operator=(const SDLVideoFrame& other) = delete; }; -using SDLVideoFrameStream2Writer = MultiplexedQueuedFrameStream2Writer; -using SDLVideoFrameStream2Reader = SDLVideoFrameStream2Writer::ReaderType; +using SDLVideoFrameStream2Multiplexer = QueuedFrameStream2Multiplexer; +using SDLVideoFrameStream2 = SDLVideoFrameStream2Multiplexer::ReaderType; -struct SDLVideoCameraContent : protected SDLVideoFrameStream2Writer { +struct SDLVideoCameraContent : protected SDLVideoFrameStream2Multiplexer { // meh, empty default std::unique_ptr _camera {nullptr, &SDL_CloseCamera}; std::atomic _thread_should_quit {false}; @@ -60,7 +59,7 @@ struct SDLVideoCameraContent : protected SDLVideoFrameStream2Writer { ~SDLVideoCameraContent(void); // make only some of writer public - using SDLVideoFrameStream2Writer::aquireReader; - using SDLVideoFrameStream2Writer::releaseReader; + using SDLVideoFrameStream2Multiplexer::aquireReader; + using SDLVideoFrameStream2Multiplexer::releaseReader; }; diff --git a/src/main.cpp b/src/main.cpp index 7947fe70..bb04459c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,7 +70,7 @@ int main(int argc, char** argv) { auto* reader = vcc.aquireReader(); for (size_t i = 0; i < 20; i++) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); - auto new_frame_opt = reader->getNext(); + auto new_frame_opt = reader->pop(); if (new_frame_opt.has_value()) { std::cout << "video frame was " << new_frame_opt.value().surface->w << "x" << new_frame_opt.value().surface->h << " " << new_frame_opt.value().timestampNS << "ns\n"; } diff --git a/src/object_store_ui.cpp b/src/object_store_ui.cpp index 94ca25ff..602c79a3 100644 --- a/src/object_store_ui.cpp +++ b/src/object_store_ui.cpp @@ -21,7 +21,6 @@ void ObjectStoreUI::render(void) { ImGui::Separator(); if (ImGui::BeginMenu("ObjectStore")) { if (ImGui::MenuItem("Inspector")) { - //_show_add_friend_window = true; _ee.show_window = true; } ImGui::EndMenu();