From 22823c5ca26acf960e69982647b0caa0d68ae2cf Mon Sep 17 00:00:00 2001 From: Green Sky Date: Fri, 2 Jan 2026 20:47:43 +0100 Subject: [PATCH] fix sdl video sources who dont report a proper frame ts see gamescope (0fps + constant ts) --- src/debug_video_tap.cpp | 2 +- .../sdl/sdl_video_frame_stream2.cpp | 37 +++++++++++++++++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/debug_video_tap.cpp b/src/debug_video_tap.cpp index 3f40667..e2c0d29 100644 --- a/src/debug_video_tap.cpp +++ b/src/debug_video_tap.cpp @@ -200,7 +200,7 @@ float DebugVideoTap::render(void) { auto delta = int64_t(new_frame_opt.value().timestampUS) - int64_t(view._v_last_ts); view._v_last_ts = new_frame_opt.value().timestampUS; - if (view._v_interval_avg == 0) { + if (view._v_interval_avg == 0 || std::isinf(view._v_interval_avg) || std::isnan(view._v_interval_avg)) { view._v_interval_avg = delta/1'000'000.f; } else { const float r = 0.05f; diff --git a/src/frame_streams/sdl/sdl_video_frame_stream2.cpp b/src/frame_streams/sdl/sdl_video_frame_stream2.cpp index f281251..7e52ace 100644 --- a/src/frame_streams/sdl/sdl_video_frame_stream2.cpp +++ b/src/frame_streams/sdl/sdl_video_frame_stream2.cpp @@ -1,6 +1,7 @@ #include "./sdl_video_frame_stream2.hpp" #include +#include #include @@ -128,7 +129,12 @@ std::shared_ptr> SDLVideo2InputDevice::subscribe(vo std::cout << "SDLVID: camera format: " << format_name << "\n"; } - _thread = std::thread([this, camera = std::move(camera), fps](void) { + _thread = std::thread([this, camera = std::move(camera)](void) { + bool use_chrono_fallback = false; + Uint64 last_timestampUS = 0; + + double intervalUS_avg = 1.; + while (_ref > 0) { Uint64 timestampNS = 0; @@ -136,20 +142,45 @@ std::shared_ptr> SDLVideo2InputDevice::subscribe(vo SDL_Surface* sdl_frame_next = SDL_AcquireCameraFrame(camera.get(), ×tampNS); if (sdl_frame_next != nullptr) { + Uint64 timestampUS_correct = timestampNS/1000; + if (!use_chrono_fallback) { + if (timestampNS == 0 || last_timestampUS == timestampUS_correct) { + use_chrono_fallback = true; + std::cerr << "SDLVID: invalid or unreliable timestampNS from sdl, falling back to own mesurements!\n"; + timestampUS_correct = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); + } else if (last_timestampUS == 0) { + last_timestampUS = timestampUS_correct; + // HACK: skip first frame + std::cerr << "SDLVID: skipping first frame\n"; + SDL_ReleaseCameraFrame(camera.get(), sdl_frame_next); + continue; + } + } else { + timestampUS_correct = std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); + } + + if (last_timestampUS != 0 && timestampUS_correct != 0 && last_timestampUS != timestampUS_correct && last_timestampUS < timestampUS_correct) { + const double r = 0.15; + intervalUS_avg = std::clamp(intervalUS_avg * (1.-r) + (timestampUS_correct-last_timestampUS) * r, 1000., 500.*1000.); + } + SDLVideoFrame new_frame_non_owning { - timestampNS/1000, + timestampUS_correct, sdl_frame_next }; // creates surface copies push(new_frame_non_owning); + + last_timestampUS = timestampUS_correct; + SDL_ReleaseCameraFrame(camera.get(), sdl_frame_next); } // sleep for interval // TODO: do we really need half? - std::this_thread::sleep_for(std::chrono::milliseconds(int64_t((1000/fps)*0.5))); + std::this_thread::sleep_for(std::chrono::milliseconds(int64_t((intervalUS_avg/1000)*0.5))); } // camera destructor closes device here });