diff --git a/tools/chatgui/CMakeLists.txt b/tools/chatgui/CMakeLists.txt index 9f05c946..b3ac08c0 100644 --- a/tools/chatgui/CMakeLists.txt +++ b/tools/chatgui/CMakeLists.txt @@ -149,6 +149,16 @@ if(FFMPEG_FOUND) target_link_libraries(test_call_video_encoder PRIVATE chatgui_live_video ${QT_TEST_LIB} ${FFMPEG_TARGET} ${FFMPEG_LIBRARIES}) add_test(NAME test_call_video_encoder COMMAND test_call_video_encoder) set_tests_properties(test_call_video_encoder PROPERTIES TIMEOUT 120) + if(UNIX AND NOT APPLE) + add_executable(test_call_video_clock tests/test_call_video_clock.cpp src/call_video_engine.cpp) + target_link_libraries(test_call_video_clock PRIVATE chatgui_live_video) + foreach(symbol call_audio_get_clock call_video_port_open call_video_port_close call_video_port_status + call_video_port_pull call_video_port_request_key call_video_port_decoded) + target_link_options(test_call_video_clock PRIVATE "-Wl,--wrap=${symbol}") + endforeach() + add_test(NAME test_call_video_clock COMMAND test_call_video_clock) + set_tests_properties(test_call_video_clock PROPERTIES TIMEOUT 15) + endif() endif() add_library(chatgui_stream_publish STATIC src/stream_publish_engine.cpp src/stream_publish_window.cpp src/call_video_engine.cpp) target_link_libraries(chatgui_stream_publish PUBLIC chatgui_live_video) diff --git a/tools/chatgui/tests/test_call_video_clock.cpp b/tools/chatgui/tests/test_call_video_clock.cpp new file mode 100644 index 00000000..4882a81a --- /dev/null +++ b/tools/chatgui/tests/test_call_video_clock.cpp @@ -0,0 +1,55 @@ +/* Реальный RX worker и decoder: коррекции аудиочасов не разрывают цепочку P-кадров. */ +#include "../src/call_video_engine.h" +#include "../src/call_video_encoder.h" +#include "../../../src/call/call_video_port.h" +#include "../../../src/call/call_audio.h" +#include +#include +#include +#include +#include +#include +extern "C" { +#include "../../../lib/mem.h" +#include "../../../lib/debug_config.h" +} +static std::vector frames; +static call_video_format format{1, 640, 360, 30, 0, 1, 31, 4000000, 2}; +static std::atomic requests{0}, rejects{0}; +static int cursor = 0; +static int64_t start; +static int64_t nowUs() { return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); } +extern "C" int __wrap_call_audio_get_clock(uint64_t, int64_t now, call_clock_snapshot* out) { + *out = {}; out->valid = out->measured = 1; out->pts_us = 1000000 + now - start; + out->source_epoch = (now - start) / 100000 + 1; return 0; +} +extern "C" int __wrap_call_video_port_open(uint64_t, const call_video_caps*) { return 0; } +extern "C" void __wrap_call_video_port_close(uint64_t) {} +extern "C" int __wrap_call_video_port_status(uint64_t, struct call_video_port_status* out) { *out = {}; return 0; } +extern "C" void __wrap_call_video_port_request_key(uint64_t) { ++requests; } +extern "C" int __wrap_call_video_port_decoded(uint64_t, uint64_t, int accepted) { if (!accepted) ++rejects; return 0; } +extern "C" int __wrap_call_video_port_pull(uint64_t id, call_video_frame* out) { + if (cursor >= (int)frames.size() || nowUs() - start < cursor * 33333ll) return 0; + const auto& f = frames[cursor]; *out = {}; out->call_id = id; out->format = format; + out->pts_us = f.pts; out->frame_id = ++cursor; out->flags = f.key ? CALL_VIDEO_KEY : 0; + out->size = out->length = f.data.size(); auto* data = static_cast(u_malloc(out->size)); + memcpy(data, f.data.constData(), out->size); out->data = data; return 1; +} +int main(int argc, char** argv) { + QCoreApplication app(argc, argv); debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); + debug_set_category_level(DEBUG_CATEGORY_CALL, DEBUG_LEVEL_DEBUG); + CallVideoEncoder encoder; if (!encoder.open(format, 1000000)) return 2; + QImage image(640, 360, QImage::Format_RGB32); image.fill(Qt::blue); + for (int i = 0; i < 90; ++i) { + LiveEncodedFrame frame; CallVideoRateCompletion completion; + if (!encoder.encode(image, 1000000 + i * 33333ll, i == 0, frame, completion)) return 3; + frames.push_back(frame); + } + int shown = 0; CallVideoEngine engine; + QObject::connect(&engine, &CallVideoEngine::imageChanged, [&](const QImage& frame) { if (!frame.isNull()) ++shown; }); + start = nowUs(); engine.start(7); QElapsedTimer timer; timer.start(); + while (timer.elapsed() < 3200) { app.processEvents(); QThread::msleep(2); } + engine.stop(); + fprintf(stderr, "CLOCK PROBE shown=%d/90 key_requests=%d decoder_rejections=%d audio_epochs=32\n", shown, requests.load(), rejects.load()); + return shown >= 85 && requests == 0 && rejects == 0 ? 0 : 1; +}