Reuse static screen frames across encoder changes and test rollback
This commit is contained in:
1 parent
c08415a255
commit
e4f9a48c2c
2 files changed
+21
-3
No files matched your search
@@ -133,7 +133,7 @@ bool StreamPublishEngine::openSource(const StreamPublishConfig& config) {
|
|||||||
uint64_t generation;
|
uint64_t generation;
|
||||||
{ std::lock_guard<std::mutex> guard(m->lock); generation = ++m->sourceGeneration;
|
{ std::lock_guard<std::mutex> guard(m->lock); generation = ++m->sourceGeneration;
|
||||||
m->backendOrigin = m->backendAnchor = -1; m->capturedFrames = 0; }
|
m->backendOrigin = m->backendAnchor = -1; m->capturedFrames = 0; }
|
||||||
m->session = std::make_unique<QMediaCaptureSession>(); m->sink = std::make_unique<QVideoSink>();
|
m->session = std::make_unique<QMediaCaptureSession>(); m->sink = std::make_unique<QVideoSink>(this);
|
||||||
m->session->setVideoSink(m->sink.get());
|
m->session->setVideoSink(m->sink.get());
|
||||||
connect(m->sink.get(), &QVideoSink::videoFrameChanged, this, [this, generation](const QVideoFrame& frame) {
|
connect(m->sink.get(), &QVideoSink::videoFrameChanged, this, [this, generation](const QVideoFrame& frame) {
|
||||||
if (!frame.isValid()) { DEBUG_TRACE(DEBUG_CATEGORY_VIDEO, "desktop capture sink invalid frame generation=%llu", (unsigned long long)generation); return; }
|
if (!frame.isValid()) { DEBUG_TRACE(DEBUG_CATEGORY_VIDEO, "desktop capture sink invalid frame generation=%llu", (unsigned long long)generation); return; }
|
||||||
@@ -430,7 +430,7 @@ void StreamPublishEngine::videoLoop() {
|
|||||||
}
|
}
|
||||||
bool screen = config.source.kind != StreamVideoSource::Camera;
|
bool screen = config.source.kind != StreamVideoSource::Camera;
|
||||||
if (frame.isValid()) {
|
if (frame.isValid()) {
|
||||||
if (capture <= lastPts || monotonicUs() - m->origin - capture > 250000) { skipped++; continue; }
|
if (!screen && (capture <= lastPts || monotonicUs() - m->origin - capture > 250000)) { skipped++; continue; }
|
||||||
lastImage = frame.toImage();
|
lastImage = frame.toImage();
|
||||||
if (lastImage.isNull()) {
|
if (lastImage.isNull()) {
|
||||||
DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "desktop captured frame conversion failed format=%d", frame.pixelFormat());
|
DEBUG_ERROR(DEBUG_CATEGORY_VIDEO, "desktop captured frame conversion failed format=%d", frame.pixelFormat());
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ extern "C" {
|
|||||||
}
|
}
|
||||||
#ifdef HAVE_STREAM_CAPTURE
|
#ifdef HAVE_STREAM_CAPTURE
|
||||||
#include <QWindowCapture>
|
#include <QWindowCapture>
|
||||||
|
#include <QVideoWidget>
|
||||||
|
#include <QVideoSink>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TEST_NULL_AUDIO
|
#ifdef TEST_NULL_AUDIO
|
||||||
@@ -200,6 +202,12 @@ private slots:
|
|||||||
}
|
}
|
||||||
QVERIFY(epoch); QVERIFY(gui_stream_open(202, group, inst->node_id, epoch));
|
QVERIFY(epoch); QVERIFY(gui_stream_open(202, group, inst->node_id, epoch));
|
||||||
StreamRecord out; QVERIFY(record(202, StreamRecordKind::Opened, out)); QVERIFY(record(202, StreamRecordKind::Video, out));
|
StreamRecord out; QVERIFY(record(202, StreamRecordKind::Opened, out)); QVERIFY(record(202, StreamRecordKind::Video, out));
|
||||||
|
auto* sink = engine.findChild<QVideoSink*>(); QVERIFY(sink);
|
||||||
|
// Неподвижный экран на backend, выдающем кадры только при изменениях: новых raw callbacks нет.
|
||||||
|
QObject::disconnect(sink, nullptr, &engine, nullptr);
|
||||||
|
StreamPublishWindow controls(&engine, group); controls.show();
|
||||||
|
auto* preview = controls.findChild<QVideoWidget*>(); QVERIFY(preview);
|
||||||
|
QTRY_VERIFY(preview->videoSink()->videoFrame().isValid()); controls.close(); QVERIFY(engine.running());
|
||||||
uint64_t first = out.pts; unsigned audio = 0, video = 0; uint64_t latest = first, left = 0, right = 0;
|
uint64_t first = out.pts; unsigned audio = 0, video = 0; uint64_t latest = first, left = 0, right = 0;
|
||||||
auto* decoder = opus_codec_decoder_create(48000, 2); QVERIFY(decoder);
|
auto* decoder = opus_codec_decoder_create(48000, 2); QVERIFY(decoder);
|
||||||
QElapsedTimer elapsed; elapsed.start();
|
QElapsedTimer elapsed; elapsed.start();
|
||||||
@@ -222,11 +230,21 @@ private slots:
|
|||||||
QTest::qWait(1);
|
QTest::qWait(1);
|
||||||
}
|
}
|
||||||
QVERIFY(revised); QCOMPARE(out.format.rotation, (uint16_t)90);
|
QVERIFY(revised); QCOMPARE(out.format.rotation, (uint16_t)90);
|
||||||
|
auto invalid = next; invalid.video.fps = 61;
|
||||||
|
QVERIFY(engine.reconfigure(invalid));
|
||||||
|
QTRY_COMPARE_WITH_TIMEOUT(engine.config().video.fps, 15, 5000);
|
||||||
|
QTRY_COMPARE(errors.size(), 1); errors.clear();
|
||||||
|
bool restored = false;
|
||||||
|
elapsed.restart(); while (!restored && elapsed.elapsed() < 5000) {
|
||||||
|
if (gui_stream_pull(202, out, 0, 60000000, 60000000) && out.kind == StreamRecordKind::Video && out.format.revision >= 3) restored = true;
|
||||||
|
QTest::qWait(1);
|
||||||
|
}
|
||||||
|
QVERIFY(restored);
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 10, 0)
|
||||||
next.source = {StreamVideoSource::Window, pattern.windowTitle(), {}, QVariant::fromValue(QCapturableWindow(pattern.windowHandle()))};
|
next.source = {StreamVideoSource::Window, pattern.windowTitle(), {}, QVariant::fromValue(QCapturableWindow(pattern.windowHandle()))};
|
||||||
QVERIFY(engine.reconfigure(next)); bool window = false;
|
QVERIFY(engine.reconfigure(next)); bool window = false;
|
||||||
elapsed.restart(); while (!window && elapsed.elapsed() < 5000) {
|
elapsed.restart(); while (!window && elapsed.elapsed() < 5000) {
|
||||||
if (gui_stream_pull(202, out, 0, 60000000, 60000000) && out.kind == StreamRecordKind::Video && out.format.revision >= 3) window = true;
|
if (gui_stream_pull(202, out, 0, 60000000, 60000000) && out.kind == StreamRecordKind::Video && out.format.revision >= 4) window = true;
|
||||||
QTest::qWait(1);
|
QTest::qWait(1);
|
||||||
}
|
}
|
||||||
QVERIFY(window);
|
QVERIFY(window);
|
||||||
|
|||||||
Reference in new issue
Block a user