From 526ee5ec8bfe2e4cd6dc796a4b5bc52063bcd693 Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 19 Oct 2026 18:23:25 +0200 Subject: [PATCH] Test queued capture gaps without dropping frames or delaying ready video --- tests/test_call_video_playout.c | 31 ++++++++++++++++++++++--- tools/chatgui/src/call_video_engine.cpp | 2 +- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/tests/test_call_video_playout.c b/tests/test_call_video_playout.c index dbcec0f4..a0d019ad 100644 --- a/tests/test_call_video_playout.c +++ b/tests/test_call_video_playout.c @@ -14,7 +14,7 @@ static void simulate(unsigned pause_ms, int cpu, int64_t quantum, int accelerate int64_t arrival = origin + i * 33333ll; if (!cpu && arrival >= origin + 1000000 && arrival < origin + 1000000 + pause_ms * 1000ll) arrival = origin + 1000000 + pause_ms * 1000ll; - frames[i] = (struct call_video_playout_frame){origin + i * 33333ll, arrival}; + frames[i] = (struct call_video_playout_frame){origin + i * 33333ll, arrival, 33333}; } unsigned shown = 0, accelerated = 0; int64_t last_show = 0, recovered_lag = INT64_MAX, audio_pts = origin - (accelerated_audio ? 150000 : 0); @@ -44,7 +44,7 @@ static void simulate(unsigned pause_ms, int cpu, int64_t quantum, int accelerate static void order_and_clock(void) { struct call_video_playout p; call_video_playout_init(&p, 9); - struct call_video_playout_frame f = {origin, origin}; + struct call_video_playout_frame f = {origin, origin, 33333}; struct call_clock_snapshot audio = {.pts_us = origin, .rate_ppm = 1000000}; CHECK(call_video_playout_poll(&p, &f, NULL, origin, &audio) == CALL_VIDEO_PLAYOUT_WAIT); audio.valid = 1; @@ -57,6 +57,31 @@ static void order_and_clock(void) { CHECK(call_video_playout_poll(&p, &f, NULL, origin + 200000, &audio) == CALL_VIDEO_PLAYOUT_SHOW); } +/* Готовые кадры могут разделяться паузой raw capture, пока decoder lookahead не пустел. */ +static void queued_capture_gap(void) { + const int64_t gaps[] = {500000, 2264933, 10000000}; + const unsigned fps[] = {15, 30, 60}; + for (unsigned i = 0; i < 3; ++i) for (unsigned j = 0; j < 3; ++j) { + struct call_video_playout p; call_video_playout_init(&p, 11); + unsigned interval = 1000000 / fps[j]; + struct call_video_playout_frame first = {origin, origin, interval}, next = {origin + gaps[i], origin, interval}; + struct call_clock_snapshot audio = {.pts_us = next.pts_us + 1000000, .valid = 1, .rate_ppm = 1000000}; + CHECK(call_video_playout_poll(&p, &first, &next, origin, &audio) == CALL_VIDEO_PLAYOUT_SHOW); + CHECK(call_video_playout_poll(&p, &next, NULL, origin, &audio) == CALL_VIDEO_PLAYOUT_WAIT); + CHECK(call_video_playout_poll(&p, &next, NULL, origin + interval, &audio) == CALL_VIDEO_PLAYOUT_SHOW); + CHECK(p.last_pts == next.pts_us && p.source_gaps == 1); + } + struct call_video_playout p; call_video_playout_init(&p, 12); + struct call_video_playout_frame f = {origin, origin, 33333}; + struct call_clock_snapshot audio = {.pts_us = origin, .valid = 1, .rate_ppm = 1000000}; + CHECK(call_video_playout_poll(&p, &f, NULL, origin, &audio) == CALL_VIDEO_PLAYOUT_SHOW); + f.pts_us += 2000000; + CHECK(call_video_playout_poll(&p, &f, NULL, origin + 33333, &audio) == CALL_VIDEO_PLAYOUT_WAIT); + audio.pts_us = f.pts_us - 40000; + CHECK(call_video_playout_poll(&p, &f, NULL, origin + 50000, &audio) == CALL_VIDEO_PLAYOUT_SHOW); + DEBUG_INFO(DEBUG_CATEGORY_CALL, "PASS queued capture gaps: 0.5/2.265/10s at 15/30/60fps, no repeated wait, no audio lead violation"); +} + int main(void) { debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); const unsigned pauses[] = {50, 100, 200, 500}; @@ -65,5 +90,5 @@ int main(void) { simulate(pauses[i], cpu, 1000, 0); simulate(pauses[i], cpu, 15625, 1); } - order_and_clock(); return 0; + order_and_clock(); queued_capture_gap(); return 0; } diff --git a/tools/chatgui/src/call_video_engine.cpp b/tools/chatgui/src/call_video_engine.cpp index e937c36f..44eae027 100644 --- a/tools/chatgui/src/call_video_engine.cpp +++ b/tools/chatgui/src/call_video_engine.cpp @@ -365,7 +365,7 @@ void CallVideoEngine::receive() { const int64_t decodedAt = nowUs(); ++decoded; decodeMax = std::max(decodeMax, decodedAt - decodeStarted); rxAgeMax = std::max(rxAgeMax, decodedAt - packet.received_us); - pictures.push_back({{packet.pts_us, packet.received_us}, image}); + pictures.push_back({{packet.pts_us, packet.received_us, 1000000u / packet.format.fps}, image}); if (packet.pts_us % 1000000 < 34000) DEBUG_DEBUG(DEBUG_CATEGORY_CALL, "video timing stage=decode call=%llu frame=%llu pts=%lld mono_us=%lld decode_us=%lld rx_age_us=%lld queue=%zu",