diff --git a/tools/chatgui/src/call_video_cadence.h b/tools/chatgui/src/call_video_cadence.h index dfbaad84..134eade2 100644 --- a/tools/chatgui/src/call_video_cadence.h +++ b/tools/chatgui/src/call_video_cadence.h @@ -1,17 +1,20 @@ #pragma once #include -// Сетка 30 fps с допуском четверти периода: дрожание PTS не превращает 30 fps в 15. +// Бюджет 30 fps с запасом четверти кадра на дрожание PTS, без накопления после паузы. class CallVideoCadence { - int64_t origin = -1, lastSlot = -1; + int64_t lastPts = -1, credit = 1250000; public: bool accept(int64_t pts) { - if (origin < 0) origin = pts; - if (pts < origin) return false; - const int64_t elapsed = pts - origin; - const int64_t slot = (elapsed / 1000000) * 30 + ((elapsed % 1000000) * 30 + 250000) / 1000000; - if (slot <= lastSlot) return false; - lastSlot = slot; + if (lastPts >= 0) { + if (pts <= lastPts) return false; + const int64_t elapsed = pts - lastPts; + credit = elapsed >= 41667 ? 1250000 : credit + elapsed * 30; + if (credit > 1250000) credit = 1250000; + } + lastPts = pts; + if (credit < 1000000) return false; + credit -= 1000000; return true; } }; diff --git a/tools/chatgui/tests/test_call_video_encoder.cpp b/tools/chatgui/tests/test_call_video_encoder.cpp index 81bfd67b..5b802529 100644 --- a/tools/chatgui/tests/test_call_video_encoder.cpp +++ b/tools/chatgui/tests/test_call_video_encoder.cpp @@ -51,6 +51,19 @@ private slots: QVERIFY(jittered.accept(30000000)); // Долгая пауза не создаёт догоняющий burst. QVERIFY(!jittered.accept(30001000)); } + void captureCadenceDrift() { + CallVideoCadence camera; + // Квантование камерой до миллисекунд и медленный уход фазы относительно сетки 30 fps. + for (int i = 0; i < 18000; i++) { + const int64_t pts = 1000000 + (i * 33340LL / 1000) * 1000 + (i % 2 ? -1500 : 1500); + QVERIFY2(camera.accept(pts), qPrintable(QString("Dropped camera frame %1 at %2").arg(i).arg(pts))); + QVERIFY(!camera.accept(pts)); + } + CallVideoCadence fast; + int accepted = 0; + for (int i = 0; i < 24000; i++) if (fast.accept(1000000 + i * 25000LL)) accepted++; + QCOMPARE(accepted, 18000); // Допуск не превращает ограничение 30 fps в 40 fps. + } void initTestCase() { debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); debug_set_category_level(DEBUG_CATEGORY_CALL, DEBUG_LEVEL_DEBUG); av_log_set_level(AV_LOG_ERROR);