/* Реальный 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; }