Update broadcast control tests and Russian menu labels
This commit is contained in:
1 parent
35875a2c43
commit
21ab92d2b4
2 files changed
+100
-42
No files matched your search
@@ -3,10 +3,11 @@
|
||||
#include <QtTest>
|
||||
#include <QTimer>
|
||||
#include <QLabel>
|
||||
#include <QComboBox>
|
||||
#include <QSpinBox>
|
||||
#include <QCheckBox>
|
||||
#include <QButtonGroup>
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
#include <QActionGroup>
|
||||
#include <QToolButton>
|
||||
#include <QPushButton>
|
||||
#include <QMessageBox>
|
||||
#include <QJsonDocument>
|
||||
@@ -146,6 +147,19 @@ class StreamPublishTest : public QObject {
|
||||
QTimer poll;
|
||||
uint64_t group = 0;
|
||||
size_t allocations = 0;
|
||||
static QMenu* menu(QWidget& controls, const char* name) { return controls.findChild<QMenu*>(name); }
|
||||
static QVariant chosen(QMenu* menu) {
|
||||
auto* action = menu->findChild<QActionGroup*>()->checkedAction(); return action ? action->data() : QVariant();
|
||||
}
|
||||
static QList<QAction*> choices(QMenu* menu) {
|
||||
QList<QAction*> result;
|
||||
for (auto* action : menu->actions()) if (action->isCheckable()) result.append(action);
|
||||
return result;
|
||||
}
|
||||
static void choose(QMenu* menu, const QVariant& data) {
|
||||
for (auto* action : choices(menu)) if (action->data() == data) { action->trigger(); return; }
|
||||
QFAIL("Missing menu choice");
|
||||
}
|
||||
static QByteArray keyframe(int codec, int width = 160, int height = 90, uint64_t pts = 100000) {
|
||||
#ifndef HAVE_FFMPEG
|
||||
Q_UNUSED(codec); Q_UNUSED(width); Q_UNUSED(height); Q_UNUSED(pts);
|
||||
@@ -201,8 +215,8 @@ private slots:
|
||||
QVERIFY(!StreamPublishEngine::supported()); QVERIFY(StreamPublishEngine::sources().isEmpty());
|
||||
QVERIFY(engine.codecs().isEmpty()); QVERIFY(!engine.previewFrame().isValid());
|
||||
StreamPublishWindow window(&engine, group); window.show();
|
||||
auto* source = window.findChild<QComboBox*>(QStringLiteral("streamVideoSource"));
|
||||
QVERIFY(source); QCOMPARE(source->count(), 0);
|
||||
auto* source = menu(window, "streamVideoSource");
|
||||
QVERIFY(source); QCOMPARE(choices(source).size(), 0);
|
||||
QPushButton* start = nullptr;
|
||||
for (auto* button : window.findChildren<QPushButton*>())
|
||||
if (button->text() == QCoreApplication::translate("ChatGui", "Start stream")) start = button;
|
||||
@@ -264,60 +278,61 @@ private slots:
|
||||
}
|
||||
void captureSettingsSurviveReopening() {
|
||||
QString saved;
|
||||
QVariantList selectedMode;
|
||||
QSize selectedSize;
|
||||
{
|
||||
StreamPublishEngine engine;
|
||||
StreamPublishWindow controls(&engine, group);
|
||||
connect(&controls, &StreamPublishWindow::settingsChanged, this, [&saved](const QString& value) { saved = value; });
|
||||
auto boxes = controls.findChildren<QComboBox*>(); QCOMPARE(boxes.size(), 5);
|
||||
if (StreamPublishEngine::supported()) QTRY_VERIFY_WITH_TIMEOUT(boxes[2]->count() > 0, 15000);
|
||||
auto* codec = menu(controls, "streamVideoCodec");
|
||||
if (StreamPublishEngine::supported()) QTRY_VERIFY_WITH_TIMEOUT(!choices(codec).isEmpty(), 15000);
|
||||
auto sources = StreamPublishEngine::sources();
|
||||
int screen = -1;
|
||||
for (int i = 0; i < sources.size(); i++) if (sources[i].kind == StreamVideoSource::Screen && !sources[i].size.isEmpty()) { screen = i; break; }
|
||||
if (screen < 0) QSKIP("No enumerated screen for capture settings");
|
||||
boxes[0]->setCurrentIndex(screen);
|
||||
choose(menu(controls, "streamVideoSource"), screen);
|
||||
auto* cursor = controls.findChild<QCheckBox*>("streamShowCursor"); QVERIFY(cursor); QVERIFY(cursor->isChecked());
|
||||
cursor->setChecked(false);
|
||||
QSize maximum = stream_video_screen_size(sources[screen].size);
|
||||
QCOMPARE(boxes[1]->currentData().toList(), (QVariantList{maximum.width(), maximum.height(), 30}));
|
||||
QVERIFY(boxes[1]->count() >= 6);
|
||||
boxes[1]->setCurrentIndex(boxes[1]->count() - 1); // Меньший размер сохраняется при повторном открытии.
|
||||
selectedMode = boxes[1]->currentData().toList();
|
||||
boxes[3]->setCurrentIndex(boxes[3]->findData(4000000));
|
||||
controls.findChild<QSpinBox*>("streamMaxQp")->setValue(25);
|
||||
auto* resolution = menu(controls, "streamVideoResolution");
|
||||
QCOMPARE(chosen(resolution).toSize(), maximum); QCOMPARE(chosen(menu(controls, "streamVideoFps")).toInt(), 30);
|
||||
QVERIFY(choices(resolution).size() >= 2);
|
||||
choices(resolution).last()->trigger(); // Меньший размер сохраняется при повторном открытии.
|
||||
selectedSize = chosen(resolution).toSize(); choose(menu(controls, "streamVideoFps"), 60);
|
||||
choose(menu(controls, "streamVideoBitrate"), 4000000);
|
||||
choose(menu(controls, "streamMaxQp"), 23);
|
||||
controls.findChild<QCheckBox*>("streamAdaptiveQp")->setChecked(true);
|
||||
controls.findChild<QButtonGroup*>()->button(270)->click();
|
||||
controls.findChildren<QCheckBox*>().first()->setChecked(false);
|
||||
if (boxes[2]->count() > 1) boxes[2]->setCurrentIndex(boxes[2]->count() - 1);
|
||||
choose(menu(controls, "streamVideoRotation"), 270);
|
||||
choose(menu(controls, "streamAudioSource"), QVariant());
|
||||
if (choices(codec).size() > 1) choices(codec).last()->trigger();
|
||||
QVERIFY(!saved.isEmpty());
|
||||
}
|
||||
const auto stored = QJsonDocument::fromJson(saved.toUtf8()).object();
|
||||
QCOMPARE(stored.value("width").toInt(), selectedMode[0].toInt()); QCOMPARE(stored.value("fps").toInt(), 60);
|
||||
QCOMPARE(stored.value("width").toInt(), selectedSize.width()); QCOMPARE(stored.value("fps").toInt(), 60);
|
||||
QVERIFY(!stored.value("native_size").toBool());
|
||||
QCOMPARE(stored.value("bitrate").toInt(), 4000000); QCOMPARE(stored.value("rotation").toInt(), 270);
|
||||
QVERIFY(!stored.value("audio").toBool());
|
||||
QVERIFY(!stored.value("show_cursor").toBool(true));
|
||||
QCOMPARE(stored.value("max_qp").toInt(), 25); QVERIFY(stored.value("adaptive_qp").toBool());
|
||||
QCOMPARE(stored.value("max_qp").toInt(), 23); QVERIFY(stored.value("adaptive_qp").toBool());
|
||||
StreamPublishEngine reopenedEngine;
|
||||
StreamPublishWindow reopened(&reopenedEngine, group, nullptr, saved);
|
||||
QSignalSpy changes(&reopened, &StreamPublishWindow::settingsChanged);
|
||||
if (StreamPublishEngine::supported()) QTRY_VERIFY_WITH_TIMEOUT(!reopenedEngine.codecs().isEmpty(), 15000);
|
||||
auto boxes = reopened.findChildren<QComboBox*>();
|
||||
QCOMPARE(boxes[1]->currentData().toList(), selectedMode);
|
||||
QCOMPARE(boxes[3]->currentData().toInt(), 4000000);
|
||||
QCOMPARE(reopened.findChild<QSpinBox*>("streamMaxQp")->value(), 25);
|
||||
QCOMPARE(chosen(menu(reopened, "streamVideoResolution")).toSize(), selectedSize);
|
||||
QCOMPARE(chosen(menu(reopened, "streamVideoFps")).toInt(), 60);
|
||||
QCOMPARE(chosen(menu(reopened, "streamVideoBitrate")).toInt(), 4000000);
|
||||
QCOMPARE(chosen(menu(reopened, "streamMaxQp")).toInt(), 23);
|
||||
QVERIFY(reopened.findChild<QCheckBox*>("streamAdaptiveQp")->isChecked());
|
||||
if (StreamPublishEngine::supported()) QTRY_COMPARE(boxes[2]->currentData().toInt(), stored.value("codec").toInt());
|
||||
QCOMPARE(reopened.findChild<QButtonGroup*>()->checkedId(), 270);
|
||||
QVERIFY(!reopened.findChildren<QCheckBox*>().first()->isChecked());
|
||||
if (StreamPublishEngine::supported()) QTRY_COMPARE(chosen(menu(reopened, "streamVideoCodec")).toInt(), stored.value("codec").toInt());
|
||||
QCOMPARE(chosen(menu(reopened, "streamVideoRotation")).toInt(), 270);
|
||||
QVERIFY(!chosen(menu(reopened, "streamAudioSource")).isValid());
|
||||
QVERIFY(!reopened.findChild<QCheckBox*>("streamShowCursor")->isChecked());
|
||||
QVERIFY(changes.isEmpty()); // Асинхронный список кодеков не перезаписывает сохранённый выбор.
|
||||
boxes[3]->setCurrentIndex(0);
|
||||
choose(menu(reopened, "streamVideoBitrate"), 0);
|
||||
QCOMPARE(changes.size(), 1);
|
||||
auto automatic = changes.takeFirst().front().toString();
|
||||
QCOMPARE(QJsonDocument::fromJson(automatic.toUtf8()).object().value("bitrate").toInt(-1), 0);
|
||||
StreamPublishWindow restoredAuto(&reopenedEngine, group, nullptr, automatic);
|
||||
QCOMPARE(restoredAuto.findChildren<QComboBox*>()[3]->currentIndex(), 0);
|
||||
QCOMPARE(chosen(menu(restoredAuto, "streamVideoBitrate")).toInt(), 0);
|
||||
}
|
||||
void qpAdaptationFollowsBitrateWithoutSpikes() {
|
||||
StreamQpControl qp; qp.reset(28, 1000000, true, 0);
|
||||
@@ -423,8 +438,8 @@ private slots:
|
||||
}
|
||||
void screenSelectionAndRefresh() {
|
||||
StreamPublishEngine engine; StreamPublishWindow controls(&engine, group);
|
||||
auto* sourceBox = controls.findChild<QComboBox*>("streamVideoSource");
|
||||
auto* modeBox = controls.findChild<QComboBox*>("streamVideoMode");
|
||||
auto* sourceBox = menu(controls, "streamVideoSource");
|
||||
auto* resolution = menu(controls, "streamVideoResolution");
|
||||
auto sources = StreamPublishEngine::sources();
|
||||
QSignalSpy changes(&controls, &StreamPublishWindow::settingsChanged);
|
||||
QList<QByteArray> screenIds;
|
||||
@@ -432,17 +447,52 @@ private slots:
|
||||
for (int i = 0; i < sources.size(); i++) {
|
||||
if (sources[i].kind != StreamVideoSource::Screen || sources[i].size.isEmpty()) continue;
|
||||
QVERIFY(!screenIds.contains(sources[i].id)); screenIds.append(sources[i].id);
|
||||
screens++; sourceBox->setCurrentIndex(-1); changes.clear(); sourceBox->setCurrentIndex(i);
|
||||
screens++; changes.clear(); choose(sourceBox, i);
|
||||
QSize size = stream_video_screen_size(sources[i].size);
|
||||
auto mode = modeBox->currentData().toList();
|
||||
QCOMPARE(mode[0].toInt(), size.width()); QCOMPARE(mode[1].toInt(), size.height());
|
||||
QVERIFY(modeBox->currentData(Qt::UserRole + 1).toBool()); QCOMPARE(changes.size(), 1);
|
||||
QVERIFY(sourceBox->currentText().contains(sources[i].name));
|
||||
modeBox->setCurrentIndex(modeBox->count() - 1); mode = modeBox->currentData().toList(); changes.clear();
|
||||
emit engine.sourcesChanged(); QCOMPARE(modeBox->currentData().toList(), mode); QVERIFY(changes.isEmpty());
|
||||
QCOMPARE(chosen(resolution).toSize(), size); QCOMPARE(changes.size(), 1);
|
||||
QVERIFY(sourceBox->findChild<QActionGroup*>()->checkedAction()->text().contains(sources[i].name));
|
||||
choices(resolution).last()->trigger(); QSize selectedSize = chosen(resolution).toSize(); changes.clear();
|
||||
emit engine.sourcesChanged(); QCOMPARE(chosen(resolution).toSize(), selectedSize); QVERIFY(changes.isEmpty());
|
||||
}
|
||||
if (!screens) QSKIP("No enumerated screens");
|
||||
}
|
||||
void compactControlMenus() {
|
||||
StreamPublishEngine engine; StreamPublishWindow controls(&engine, group); controls.show();
|
||||
controls.resize(controls.minimumSize()); QTest::qWait(20);
|
||||
auto* bar = controls.findChild<QMenuBar*>("streamControls"); QVERIFY(bar);
|
||||
auto* start = controls.findChild<QPushButton*>("streamStart"); QVERIFY(start);
|
||||
auto* sound = controls.findChild<QToolButton*>("streamSound"); QVERIFY(sound);
|
||||
auto* buffer = controls.findChild<QWidget*>("streamBufferIndicator"); QVERIFY(buffer);
|
||||
QCOMPARE(buffer->height(), 20); QCOMPARE(buffer->width(), std::max(80, start->sizeHint().width()));
|
||||
QCOMPARE(buffer->geometry().center().y(), start->geometry().center().y());
|
||||
QVERIFY(std::abs(bar->geometry().center().y() - start->geometry().center().y()) <= 1);
|
||||
QVERIFY(bar->geometry().right() < sound->geometry().left()); QVERIFY(sound->geometry().right() < buffer->geometry().left());
|
||||
auto* qp = menu(controls, "streamMaxQp"); QCOMPARE(choices(qp).size(), 6); QCOMPARE(chosen(qp).toInt(), 28);
|
||||
auto* audio = menu(controls, "streamAudioSource");
|
||||
choose(audio, QVariant()); QVERIFY(!chosen(audio).isValid()); QVERIFY(!sound->isChecked());
|
||||
choose(audio, QString()); QVERIFY(chosen(audio).isValid()); QVERIFY(sound->isChecked());
|
||||
auto* resolution = menu(controls, "streamVideoResolution"); auto* fps = menu(controls, "streamVideoFps");
|
||||
for (auto* submenu : {resolution, fps, qp, audio}) {
|
||||
QVERIFY(!submenu->actions().first()->text().isEmpty()); QVERIFY(!submenu->actions().first()->isCheckable());
|
||||
QVERIFY(bar->rect().contains(bar->actionGeometry(submenu->menuAction())));
|
||||
}
|
||||
QTest::mouseClick(bar, Qt::LeftButton, {}, bar->actionGeometry(resolution->menuAction()).center());
|
||||
QTRY_VERIFY(resolution->isVisible());
|
||||
QTest::mouseClick(bar, Qt::LeftButton, {}, bar->actionGeometry(fps->menuAction()).center());
|
||||
QTRY_VERIFY(fps->isVisible()); QVERIFY(!resolution->isVisible());
|
||||
QTest::mouseClick(bar, Qt::LeftButton, {}, bar->actionGeometry(fps->menuAction()).center());
|
||||
QTRY_VERIFY(!fps->isVisible());
|
||||
const auto sources = engine.sources();
|
||||
for (int i = 0; i < sources.size(); i++) {
|
||||
choose(menu(controls, "streamVideoSource"), i);
|
||||
const auto modes = sources[i].kind == StreamVideoSource::Camera ? sources[i].modes : stream_video_screen_modes(sources[i].size);
|
||||
for (auto* sizeAction : choices(resolution)) {
|
||||
sizeAction->trigger(); const QSize size = chosen(resolution).toSize();
|
||||
for (auto* rate : choices(fps)) QCOMPARE(rate->isEnabled(), modes.contains({size, rate->data().toInt()}));
|
||||
if (!modes.isEmpty()) QVERIFY(modes.contains({size, chosen(fps).toInt()}));
|
||||
}
|
||||
}
|
||||
}
|
||||
void nativeScreenCapture_data() {
|
||||
QTest::addColumn<int>("codec");
|
||||
QTest::newRow("h264") << int(STREAM_MEDIA_H264);
|
||||
@@ -606,9 +656,9 @@ private slots:
|
||||
if (source.kind != StreamVideoSource::Screen || source.screen != screen) continue;
|
||||
QVERIFY(StreamPublishEngine::cursorSupported(source));
|
||||
StreamPublishWindow controls(&engine, group);
|
||||
auto* sources = controls.findChild<QComboBox*>("streamVideoSource"); QVERIFY(sources);
|
||||
auto* sources = menu(controls, "streamVideoSource"); QVERIFY(sources);
|
||||
auto all = engine.sources();
|
||||
for (int i = 0; i < all.size(); i++) if (all[i].sameSource(source)) sources->setCurrentIndex(i);
|
||||
for (int i = 0; i < all.size(); i++) if (all[i].sameSource(source)) choose(sources, i);
|
||||
auto* toggle = controls.findChild<QCheckBox*>("streamShowCursor"); QVERIFY(toggle);
|
||||
QVERIFY(!toggle->isHidden()); QVERIFY(toggle->isChecked());
|
||||
}
|
||||
@@ -933,7 +983,7 @@ private slots:
|
||||
auto* preview = controls.findChild<QVideoWidget*>(); QVERIFY(preview);
|
||||
QTRY_VERIFY(preview->videoSink()->videoFrame().isValid());
|
||||
QSignalSpy closed(&controls, &StreamPublishWindow::closed);
|
||||
auto* choice = controls.findChild<QComboBox*>(); QVERIFY(choice); choice->setFocus();
|
||||
auto* choice = controls.findChild<QMenuBar*>(); QVERIFY(choice); choice->setFocus();
|
||||
QTest::keyClick(choice, Qt::Key_Escape);
|
||||
QTRY_COMPARE(closed.count(), 1); QVERIFY(!controls.isVisible()); QVERIFY(engine.running());
|
||||
QVERIFY(record(205, StreamRecordKind::Video, out)); QVERIFY(out.pts > firstPts);
|
||||
@@ -980,7 +1030,7 @@ private slots:
|
||||
QTRY_VERIFY(preview->videoSink()->videoFrame().isValid());
|
||||
QSignalSpy closed(&controls, &StreamPublishWindow::closed);
|
||||
controls.activateWindow(); QVERIFY(QTest::qWaitForWindowActive(&controls));
|
||||
auto* sourceChoice = controls.findChild<QComboBox*>(); QVERIFY(sourceChoice); sourceChoice->setFocus();
|
||||
auto* sourceChoice = controls.findChild<QMenuBar*>(); QVERIFY(sourceChoice); sourceChoice->setFocus();
|
||||
QTest::keyClick(sourceChoice, Qt::Key_Escape);
|
||||
QTRY_COMPARE(closed.count(), 1); QVERIFY(!controls.isVisible()); QVERIFY(engine.running());
|
||||
uint64_t first = out.pts; unsigned audio = 0, video = 0; uint64_t latest = first, left = 0, right = 0;
|
||||
|
||||
@@ -154,6 +154,14 @@ Use CPU encoding instead? This may cause high CPU usage and slow down the comput
|
||||
<message><source>Cannot read video</source><translation>Не удалось прочитать видео</translation></message>
|
||||
<message><source>Could not send the call command</source><translation>Не удалось отправить команду звонка</translation></message>
|
||||
<message><source>Video source</source><translation>Источник видео</translation></message>
|
||||
<message><source>Video resolution</source><translation>Разрешение видео</translation></message>
|
||||
<message><source>Frame rate</source><translation>Частота кадров</translation></message>
|
||||
<message><source>Original resolution</source><translation>Исходное разрешение</translation></message>
|
||||
<message><source>%1 fps</source><translation>%1 кадр/с</translation></message>
|
||||
<message><source>Audio source</source><translation>Источник звука</translation></message>
|
||||
<message><source>No audio</source><translation>Без звука</translation></message>
|
||||
<message><source>Turn stream audio on</source><translation>Включить звук трансляции</translation></message>
|
||||
<message><source>Turn stream audio off</source><translation>Выключить звук трансляции</translation></message>
|
||||
<message><source>Show mouse cursor</source><translation>Показывать курсор мыши</translation></message>
|
||||
<message><source>Change cursor visibility before starting screen sharing</source><translation>Показ курсора можно изменить до начала трансляции экрана</translation></message>
|
||||
<message><source>Screen capture failed: %1</source><translation>Ошибка захвата экрана: %1</translation></message>
|
||||
|
||||
Reference in new issue
Block a user