From c7be863dafa7238511ebf3148d2cfc9a88fa3ea7 Mon Sep 17 00:00:00 2001 From: Green Sky Date: Wed, 2 Apr 2025 20:04:34 +0200 Subject: [PATCH] extract sdl cameras creation/deletion to service and handle events --- src/CMakeLists.txt | 2 + .../sdl/sdl_video_frame_stream2.hpp | 4 +- .../sdl/sdl_video_input_service.cpp | 114 ++++++++++++++++++ .../sdl/sdl_video_input_service.hpp | 22 ++++ src/main_screen.cpp | 64 +--------- src/main_screen.hpp | 3 + 6 files changed, 149 insertions(+), 60 deletions(-) create mode 100644 src/frame_streams/sdl/sdl_video_input_service.cpp create mode 100644 src/frame_streams/sdl/sdl_video_input_service.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5f04bfd..53274eb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -137,6 +137,8 @@ target_sources(tomato PUBLIC ./frame_streams/sdl/video_push_converter.hpp ./frame_streams/sdl/sdl_video_frame_stream2.hpp ./frame_streams/sdl/sdl_video_frame_stream2.cpp + ./frame_streams/sdl/sdl_video_input_service.hpp + ./frame_streams/sdl/sdl_video_input_service.cpp ./stream_manager_ui.hpp ./stream_manager_ui.cpp diff --git a/src/frame_streams/sdl/sdl_video_frame_stream2.hpp b/src/frame_streams/sdl/sdl_video_frame_stream2.hpp index 3e42752..9fc7a20 100644 --- a/src/frame_streams/sdl/sdl_video_frame_stream2.hpp +++ b/src/frame_streams/sdl/sdl_video_frame_stream2.hpp @@ -7,7 +7,7 @@ #include #include -// tips: you can force a SDL vido driver by setting an env: +// tips: you can force a SDL video driver by setting an env: // SDL_CAMERA_DRIVER=v4l2 // SDL_CAMERA_DRIVER=pipewire // etc. @@ -24,7 +24,7 @@ struct SDLVideo2InputDevice : public FrameStream2MultiSource { SDLVideo2InputDevice(const SDL_CameraID dev); virtual ~SDLVideo2InputDevice(void); - // we hook int multi source + // we hook into multi source std::shared_ptr> subscribe(void) override; bool unsubscribe(const std::shared_ptr>& sub) override; }; diff --git a/src/frame_streams/sdl/sdl_video_input_service.cpp b/src/frame_streams/sdl/sdl_video_input_service.cpp new file mode 100644 index 0000000..1e856a1 --- /dev/null +++ b/src/frame_streams/sdl/sdl_video_input_service.cpp @@ -0,0 +1,114 @@ +#include "./sdl_video_input_service.hpp" + +#include + +#include "../stream_manager.hpp" +#include "./sdl_video_frame_stream2.hpp" + +#include + +namespace Components { + + struct SDLVideoDevice { + SDL_CameraID device; + }; + +} // Components + +bool SDLVideoInputService::addDevice(SDL_CameraID device) { + const char *name = SDL_GetCameraName(device); + std::cout << " - Camera #" << device << ": " << name << "\n"; + + int speccount {0}; + SDL_CameraSpec** specs = SDL_GetCameraSupportedFormats(device, &speccount); + if (specs == nullptr) { + std::cout << " - no supported spec\n"; + return false; + } else { + for (int spec_i = 0; spec_i < speccount; spec_i++) { + std::cout << " - " << specs[spec_i]->width << "x" << specs[spec_i]->height << "@" << float(specs[spec_i]->framerate_numerator)/specs[spec_i]->framerate_denominator << "fps " << SDL_GetPixelFormatName(specs[spec_i]->format) << "\n"; + + } + SDL_free(specs); + + // create sink for device + ObjectHandle vsrc {_os.registry(), _os.registry().create()}; + try { + vsrc.emplace(device); + + vsrc.emplace>( + std::make_unique(device) + ); + + vsrc.emplace(Components::StreamSource::create("SDL Video '" + std::string(name) + "'")); + //vsrc.emplace(); + + _os.throwEventConstruct(vsrc); + //last_src = vsrc; + } catch (...) { + std::cerr << "SDLVIS error: failed constructing video input source\n"; + _os.registry().destroy(vsrc); + return false; + } + } + return true; +} + +bool SDLVideoInputService::removeDevice(SDL_CameraID device) { + for (const auto&& [ov, svd] : _os.registry().view().each()) { + if (svd.device == device) { + _os.throwEventDestroy(ov); + _os.registry().destroy(ov); + return true; + } + } + return false; // not found ?? +} + +SDLVideoInputService::SDLVideoInputService(ObjectStore2& os) : + _os(os) +{ + if (!SDL_InitSubSystem(SDL_INIT_CAMERA)) { + std::cerr << "SDLVIS warning: no sdl camera: " << SDL_GetError() << "\n"; + return; + } + _subsystem_init = true; + std::cout << "SDLVIS: SDL Camera Driver: " << SDL_GetCurrentCameraDriver() << "\n"; + + // sdl throws all cameras as added events anyway +#if 0 + int devcount {0}; + SDL_CameraID *devices = SDL_GetCameras(&devcount); + + std::cout << "SDLVIS: found cameras:\n"; + if (devices != nullptr) { + ObjectHandle last_src{}; + for (int i = 0; i < devcount; i++) { + addDevice(devices[i]); + } + + SDL_free(devices); + } else { + std::cout << " none\n"; + } +#endif +} + +SDLVideoInputService::~SDLVideoInputService(void) { + if (_subsystem_init) { + SDL_QuitSubSystem(SDL_INIT_CAMERA); + } +} + +bool SDLVideoInputService::handleEvent(SDL_Event& e) { + if (e.type == SDL_EVENT_CAMERA_DEVICE_ADDED) { + std::cout << "SDLVIS: camera added:\n"; + return addDevice(e.cdevice.which); + } else if (e.type == SDL_EVENT_CAMERA_DEVICE_REMOVED) { + std::cout << "SDLVIS: camera removed\n"; + return removeDevice(e.cdevice.which); + } + + return false; +} + diff --git a/src/frame_streams/sdl/sdl_video_input_service.hpp b/src/frame_streams/sdl/sdl_video_input_service.hpp new file mode 100644 index 0000000..ea5d788 --- /dev/null +++ b/src/frame_streams/sdl/sdl_video_input_service.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include + +// manages sdl camera sources +class SDLVideoInputService { + ObjectStore2& _os; + + bool _subsystem_init{false}; + + bool addDevice(SDL_CameraID device); + bool removeDevice(SDL_CameraID device); + + public: + SDLVideoInputService(ObjectStore2& os); + ~SDLVideoInputService(void); + + bool handleEvent(SDL_Event& e); +}; + diff --git a/src/main_screen.cpp b/src/main_screen.cpp index 60f06ab..6812590 100644 --- a/src/main_screen.cpp +++ b/src/main_screen.cpp @@ -69,7 +69,8 @@ MainScreen::MainScreen(const SimpleConfigModel& conf_, SDL_Renderer* renderer_, tdch(tpi), tnui(tpi), smui(os, sm), - dvt(os, sm, sdlrtu) + dvt(os, sm, sdlrtu), + sdlvis(os) { tel.subscribeAll(); @@ -201,63 +202,6 @@ MainScreen::MainScreen(const SimpleConfigModel& conf_, SDL_Renderer* renderer_, } else { std::cerr << "MS warning: no sdl audio: " << SDL_GetError() << "\n"; } - - if (SDL_InitSubSystem(SDL_INIT_CAMERA)) { - std::cout << "MS: SDL Camera Driver: " << SDL_GetCurrentCameraDriver() << "\n"; - - int devcount {0}; - SDL_CameraID *devices = SDL_GetCameras(&devcount); - - std::cout << "MS: found cameras:\n"; - if (devices != nullptr) { - ObjectHandle last_src{}; - for (int i = 0; i < devcount; i++) { - const SDL_CameraID device = devices[i]; - - const char *name = SDL_GetCameraName(device); - std::cout << " - Camera #" << i << ": " << name << "\n"; - - int speccount {0}; - SDL_CameraSpec** specs = SDL_GetCameraSupportedFormats(device, &speccount); - if (specs == nullptr) { - std::cout << " - no supported spec\n"; - } else { - for (int spec_i = 0; spec_i < speccount; spec_i++) { - std::cout << " - " << specs[spec_i]->width << "x" << specs[spec_i]->height << "@" << float(specs[spec_i]->framerate_numerator)/specs[spec_i]->framerate_denominator << "fps " << SDL_GetPixelFormatName(specs[spec_i]->format) << "\n"; - - } - SDL_free(specs); - - // create sink for device - ObjectHandle vsrc {os.registry(), os.registry().create()}; - try { - vsrc.emplace>( - std::make_unique(device) - ); - - vsrc.emplace(Components::StreamSource::create("SDL Video '" + std::string(name) + "'")); - //vsrc.emplace(); - - os.throwEventConstruct(vsrc); - last_src = vsrc; - } catch (...) { - std::cerr << "MS error: failed constructing video input source\n"; - os.registry().destroy(vsrc); - } - } - } - - //if (static_cast(last_src)) { - // last_src.emplace(); - //} - - SDL_free(devices); - } else { - std::cout << " none\n"; - } - } else { - std::cerr << "MS warning: no sdl camera: " << SDL_GetError() << "\n"; - } } MainScreen::~MainScreen(void) { @@ -361,6 +305,10 @@ bool MainScreen::handleEvent(SDL_Event& e) { _time_since_event = 0.f; } + if (sdlvis.handleEvent(e)) { + return true; + } + return false; } diff --git a/src/main_screen.hpp b/src/main_screen.hpp index 990ae04..5599c0b 100644 --- a/src/main_screen.hpp +++ b/src/main_screen.hpp @@ -45,6 +45,8 @@ #include "./tox_av_voip_model.hpp" #endif +#include "./frame_streams/sdl/sdl_video_input_service.hpp" + #include #include #include @@ -103,6 +105,7 @@ struct MainScreen final : public Screen { ToxNetprofUI tnui; StreamManagerUI smui; DebugVideoTap dvt; + SDLVideoInputService sdlvis; PluginManager pm; // last, so it gets destroyed first