From 74a4135cdc7f64dc41b7585f79ed445728ea26cd Mon Sep 17 00:00:00 2001 From: evgeny Date: Tue, 20 Oct 2026 00:01:13 +0200 Subject: [PATCH] Accept faster camera capture modes and pace up to 60 fps --- tools/chatgui/src/call_video_cadence.h | 20 +++++++++----------- tools/chatgui/src/stream_video_modes.h | 5 +++-- tools/chatgui/tests/test_stream_publish.cpp | 14 ++++++++++---- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/tools/chatgui/src/call_video_cadence.h b/tools/chatgui/src/call_video_cadence.h index 19619277..34310e29 100644 --- a/tools/chatgui/src/call_video_cadence.h +++ b/tools/chatgui/src/call_video_cadence.h @@ -1,21 +1,19 @@ #pragma once #include -// Бюджет 30 fps с запасом одного кадра; интервал >=25мс запрещает burst после паузы. +// Выбор исходных кадров по фазе 1..60 fps, до encode. Дробный период не накапливает ошибку. +// Допуск четверти периода сохраняет кадры при дрожании PTS; опоздание сбрасывает фазу без burst. class CallVideoCadence { - int64_t lastPts = -1, lastAccepted = -1, credit = 1250000; + int fps; + int64_t lastPts = -1, next = -1; public: + explicit CallVideoCadence(int rate = 30) : fps(rate) {} bool accept(int64_t pts) { - if (lastPts >= 0) { - if (pts <= lastPts) return false; - const int64_t elapsed = pts - lastPts; - credit = elapsed >= 66667 ? 2000000 : credit + elapsed * 30; - if (credit > 2000000) credit = 2000000; - } + if (fps < 1 || fps > 60 || pts < 0 || pts <= lastPts || pts > INT64_MAX / fps) return false; lastPts = pts; - if (credit < 1000000 || (lastAccepted >= 0 && pts - lastAccepted < 25000)) return false; - credit -= 1000000; - lastAccepted = pts; + const int64_t scaled = pts * fps; + if (next >= 0 && scaled < next - 250000) return false; + next = next < 0 || scaled - next > 250000 ? scaled + 1000000 : next + 1000000; return true; } }; diff --git a/tools/chatgui/src/stream_video_modes.h b/tools/chatgui/src/stream_video_modes.h index e6ed70b6..577cc33b 100644 --- a/tools/chatgui/src/stream_video_modes.h +++ b/tools/chatgui/src/stream_video_modes.h @@ -40,12 +40,13 @@ inline QList stream_video_screen_modes(QSize source) { return modes; } -/* 29.97/59.94 соответствуют пределам 30/60; фактический диапазон камеры не округляется. */ +/* FPS режима — предел передачи, не команда драйверу. Быстрый capture ограничивается до encode. + * 29.97/59.94 соответствуют пределам 30/60; фактический диапазон камеры не округляется. */ inline bool stream_video_camera_supports(QSize size, double minimum, double maximum, const StreamVideoMode& mode) { return size == mode.size && size.width() >= 16 && size.height() >= 16 && size.width() <= 4096 && size.height() <= 4096 && !(size.width() % 2) && !(size.height() % 2) && std::isfinite(minimum) && std::isfinite(maximum) && minimum >= 0 && maximum > 0 && minimum <= maximum && mode.fps >= 1 && mode.fps <= 60 - && mode.fps + 0.1 >= minimum && mode.fps <= maximum + 0.1; + && mode.fps <= maximum + 0.1; } /* Объединяем одинаковые режимы разных pixel format, сохраняя границы необычных диапазонов FPS. */ diff --git a/tools/chatgui/tests/test_stream_publish.cpp b/tools/chatgui/tests/test_stream_publish.cpp index 1ed39f5c..ad8ae57f 100644 --- a/tools/chatgui/tests/test_stream_publish.cpp +++ b/tools/chatgui/tests/test_stream_publish.cpp @@ -376,18 +376,24 @@ private slots: void cameraAdvertisedModes() { QList modes; stream_video_add_camera_modes(modes, {1920, 1080}, 29.97, 29.97); - QCOMPARE(modes.size(), 1); QCOMPARE(modes.front().fps, 30); - stream_video_add_camera_modes(modes, {1920, 1080}, 29.97, 29.97); QCOMPARE(modes.size(), 1); + QCOMPARE(modes.size(), 4); QVERIFY(modes.contains({{1920, 1080}, 30})); + stream_video_add_camera_modes(modes, {1920, 1080}, 29.97, 29.97); QCOMPARE(modes.size(), 4); stream_video_add_camera_modes(modes, {1280, 720}, 15, 60); QVERIFY(modes.contains({{1280, 720}, 15})); QVERIFY(modes.contains({{1280, 720}, 60})); - QVERIFY(!modes.contains({{1920, 1080}, 60})); QVERIFY(!modes.contains({{1920, 1080}, 15})); + QVERIFY(!modes.contains({{1920, 1080}, 60})); QVERIFY(modes.contains({{1920, 1080}, 15})); stream_video_add_camera_modes(modes, {640, 480}, 7, 7); QVERIFY(modes.contains({{640, 480}, 7})); int count = modes.size(); stream_video_add_camera_modes(modes, {5120, 2880}, 30, 30); stream_video_add_camera_modes(modes, {1281, 720}, 30, 30); - stream_video_add_camera_modes(modes, {1280, 720}, 120, 120); stream_video_add_camera_modes(modes, {1280, 720}, 60, 30); QCOMPARE(modes.size(), count); + stream_video_add_camera_modes(modes, {1280, 720}, 100, 100); + QVERIFY(modes.contains({{1280, 720}, 60})); + stream_video_add_camera_modes(modes, {1920, 1080}, 50, 50); + QVERIFY(modes.contains({{1920, 1080}, 30})); QVERIFY(modes.contains({{1920, 1080}, 50})); + QVERIFY(!modes.contains({{1920, 1080}, 60})); + stream_video_add_camera_modes(modes, {640, 360}, 330, 330); + QVERIFY(modes.contains({{640, 360}, 60})); QVERIFY(modes.contains({{640, 360}, 30})); QVERIFY(!stream_video_camera_supports({640, 480}, 30, 30, {{1280, 720}, 30})); } void screenSelectionAndRefresh() {