Cover desktop local preview and multiview navigation
This commit is contained in:
1 parent
e5510e9f62
commit
64064c2cbf
2 files changed
+69
-1
No files matched your search
@@ -675,6 +675,10 @@ add_executable(test_stream_view tests/test_stream_view.cpp src/streamplayer_wind
|
||||
transport/miniaudio_impl.c transport/audio_diagnostics.cpp)
|
||||
target_include_directories(test_stream_view PRIVATE ${UTUN_INCLUDE_DIRS} ${FFMPEG_INCLUDE_DIRS})
|
||||
target_link_libraries(test_stream_view PRIVATE ${QT_LIBS} ${QT_TEST_LIB} utun_voice utun pthread ${CMAKE_DL_LIBS} ${FFMPEG_TARGET} ${FFMPEG_LIBRARIES})
|
||||
if(GUI_CAPTURE_ENABLED)
|
||||
target_compile_definitions(test_stream_view PRIVATE HAVE_STREAM_CAPTURE)
|
||||
target_link_libraries(test_stream_view PRIVATE Qt6::Multimedia Qt6::MultimediaWidgets)
|
||||
endif()
|
||||
if(FFMPEG_FOUND)
|
||||
target_compile_definitions(test_stream_view PRIVATE HAVE_FFMPEG)
|
||||
endif()
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
#include <QSlider>
|
||||
#include <QPainter>
|
||||
#include <QWheelEvent>
|
||||
#ifdef HAVE_STREAM_CAPTURE
|
||||
#include <QVideoWidget>
|
||||
#include <QVideoSink>
|
||||
#include <QVideoFrame>
|
||||
#include <QVideoFrameFormat>
|
||||
#endif
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <chrono>
|
||||
@@ -444,7 +450,7 @@ private slots:
|
||||
QJsonArray sources;
|
||||
for (int i = 0; i < count; ++i) sources.append(QJsonObject{
|
||||
{"id", QString::number(inst->node_id ^ static_cast<uint64_t>(i))},
|
||||
{"epoch", QString::number(epoch, 16)}, {"name", QStringLiteral("Source %1").arg(i)}, {"self", i == 0 ? 1 : 0}});
|
||||
{"epoch", QString::number(epoch, 16)}, {"name", QStringLiteral("Source %1").arg(i)}, {"self", 0}});
|
||||
QByteArray bytes(9, '\0'); stream_write_be(reinterpret_cast<uint8_t*>(bytes.data()), group, 8); bytes[8] = valid;
|
||||
bytes += QJsonDocument(sources).toJson(QJsonDocument::Compact);
|
||||
grid.onSources(reinterpret_cast<const uint8_t*>(bytes.constData()), bytes.size());
|
||||
@@ -463,7 +469,10 @@ private slots:
|
||||
QCOMPARE(stream_publish_finish(publisher), STREAM_OK); stream_close(publisher); publisher = nullptr;
|
||||
QCOMPARE(stream_publish_open(inst, group, nullptr, &publisher), STREAM_OK);
|
||||
stream_info info{}; QCOMPARE(stream_get_info(publisher, &info), STREAM_OK); epoch = info.descriptor.source_epoch;
|
||||
QTest::mouseClick(first->findChild<VideoRenderWidget*>(), Qt::LeftButton);
|
||||
QTRY_COMPARE(grid.focusedSource(), inst->node_id);
|
||||
snapshot(1); QVERIFY(first.isNull()); QCOMPARE(grid.tileCount(), 1);
|
||||
QCOMPARE(grid.focusedSource(), uint64_t(0)); QVERIFY(!grid.isFullScreen());
|
||||
snapshot(0); QTRY_COMPARE_WITH_TIMEOUT(grid.tileCount(), 0, 3000);
|
||||
QVERIFY(grid.isVisible()); QCOMPARE(grid.gridSide(), 0);
|
||||
snapshot(1); QCOMPARE(grid.tileCount(), 1);
|
||||
@@ -474,6 +483,61 @@ private slots:
|
||||
#endif
|
||||
}
|
||||
|
||||
void gridLocalPreviewAndTileNavigation() {
|
||||
#if defined(TEST_NULL_AUDIO) && defined(HAVE_STREAM_CAPTURE)
|
||||
StreamGridWindow grid(group); grid.show(); grid.activateWindow();
|
||||
const auto own = inst->node_id ^ uint64_t(1);
|
||||
auto snapshot = [&](bool remote) {
|
||||
QJsonArray sources{QJsonObject{{"id", QString::number(own)}, {"epoch", QString::number(epoch, 16)},
|
||||
{"name", "Own preview"}, {"self", 1}}};
|
||||
if (remote) sources.append(QJsonObject{{"id", QString::number(inst->node_id)}, {"epoch", QString::number(epoch, 16)},
|
||||
{"name", "Remote fixture"}, {"self", 0}});
|
||||
QByteArray bytes(9, '\0'); stream_write_be(reinterpret_cast<uint8_t*>(bytes.data()), group, 8); bytes[8] = 1;
|
||||
bytes += QJsonDocument(sources).toJson(QJsonDocument::Compact);
|
||||
grid.onSources(reinterpret_cast<const uint8_t*>(bytes.constData()), bytes.size());
|
||||
};
|
||||
snapshot(false);
|
||||
auto* ownTile = grid.findChild<QWidget*>(QStringLiteral("streamPreview_%1").arg(own)); QVERIFY(ownTile);
|
||||
auto* preview = ownTile->findChild<QVideoWidget*>(); QVERIFY(preview);
|
||||
QVERIFY(grid.findChildren<StreamPlayerWindow*>().isEmpty()); QVERIFY(ownTile->findChildren<QSlider*>().isEmpty());
|
||||
stream_info info{}; QTest::qWait(30);
|
||||
QCOMPARE(stream_get_info(publisher, &info), STREAM_OK); QCOMPARE(info.owners, 1u);
|
||||
QVideoFrame frame(QVideoFrameFormat(QSize(16, 16), QVideoFrameFormat::Format_BGRA8888));
|
||||
QVERIFY(frame.map(QVideoFrame::WriteOnly)); memset(frame.bits(0), 0xff, frame.mappedBytes(0)); frame.unmap();
|
||||
frame.setStartTime(123000);
|
||||
grid.setLocalPreview(group, QVariant::fromValue(frame));
|
||||
QCOMPARE(preview->videoSink()->videoFrame().startTime(), qint64(123000));
|
||||
grid.setLocalPreview(group ^ 1, QVariant()); QVERIFY(preview->videoSink()->videoFrame().isValid());
|
||||
grid.setLocalPreview(group, QVariant()); QVERIFY(!preview->videoSink()->videoFrame().isValid());
|
||||
grid.setLocalPreview(group, QVariant::fromValue(frame));
|
||||
QSignalSpy manage(&grid, &StreamGridWindow::publishRequested);
|
||||
QTest::mouseClick(preview, Qt::LeftButton); QTRY_COMPARE(manage.count(), 1);
|
||||
QCOMPARE(manage.at(0).at(0).toULongLong(), group); QCOMPARE(grid.focusedSource(), uint64_t(0));
|
||||
snapshot(true);
|
||||
QPointer<StreamPlayerWindow> remote = grid.findChild<StreamPlayerWindow*>();
|
||||
QVERIFY(remote); auto* video = remote->findChild<VideoRenderWidget*>(); QVERIFY(video);
|
||||
QTRY_VERIFY(stream_get_info(publisher, &info) == STREAM_OK && info.owners == 2);
|
||||
QTest::mouseClick(video, Qt::LeftButton);
|
||||
QTRY_COMPARE(grid.focusedSource(), inst->node_id); QVERIFY(grid.isFullScreen()); QVERIFY(ownTile->isHidden());
|
||||
auto* volume = remote->findChild<QSlider*>(); QVERIFY(volume); volume->setFocus();
|
||||
QTest::keyClick(volume, Qt::Key_Escape);
|
||||
QTRY_COMPARE(grid.focusedSource(), uint64_t(0));
|
||||
QVERIFY(!grid.isFullScreen()); QVERIFY(remote->isVisible()); QVERIFY(ownTile->isVisible());
|
||||
QCOMPARE(grid.findChild<StreamPlayerWindow*>(), remote.data());
|
||||
QCOMPARE(stream_get_info(publisher, &info), STREAM_OK); QCOMPARE(info.owners, 2u);
|
||||
QTest::mouseClick(video, Qt::LeftButton); QTRY_COMPARE(grid.focusedSource(), inst->node_id);
|
||||
QTest::mouseClick(video, Qt::LeftButton); QTRY_COMPARE(grid.focusedSource(), uint64_t(0));
|
||||
video->setFrame(coordinateFrame()); zoomVideo(*video, 12000, video->rect().center());
|
||||
dragVideo(*video, video->rect().center(), video->rect().center() + QPoint(40, 20));
|
||||
QTest::qWait(20); QCOMPARE(grid.focusedSource(), uint64_t(0)); // Pan не считается кликом.
|
||||
grid.close(); QVERIFY(remote.isNull());
|
||||
QTRY_VERIFY(stream_get_info(publisher, &info) == STREAM_OK && info.owners == 1);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_STREAM, "fixture multiview local preview: reader=0 audio=0; click/Esc/drag preserved remote owner");
|
||||
#else
|
||||
QSKIP("Direct preview fixture requires Qt Multimedia and null audio");
|
||||
#endif
|
||||
}
|
||||
|
||||
void realH264RenderingAndClose() {
|
||||
#ifdef HAVE_FFMPEG
|
||||
/* Фикстура протокола выше содержит фиктивный H264; реальный decoder получает отдельную эпоху. */
|
||||
|
||||
Reference in new issue
Block a user