Browse Source

Persist broadcast QP controls and verify smooth rate feedback

stream-multiview
evgeny 6 days ago
parent
commit
fae794d39e
  1. 8
      tools/chatgui/ffmpeg/build_ffmpeg.sh
  2. 22
      tools/chatgui/tests/test_stream_publish.cpp

8
tools/chatgui/ffmpeg/build_ffmpeg.sh

@ -7,7 +7,7 @@ SRC_DIR="$BUILD_DIR/src"
INSTALL_DIR="$BUILD_DIR/install"
JOBS=$(nproc 2>/dev/null || echo 4)
AMF_HEADERS_VERSION="${AMF_HEADERS_VERSION:-1.5.3}"
FFMPEG_PROFILE_MARKER="$INSTALL_DIR/share/utun-chatgui-ffmpeg-minimal-v3"
FFMPEG_PROFILE_MARKER="$INSTALL_DIR/share/utun-chatgui-ffmpeg-minimal-v4"
case "$(uname -s)" in
Linux) PLATFORM=linux ;;
@ -64,6 +64,7 @@ check_cmd nasm
check_cmd pkg-config
check_cmd git
check_cmd curl
check_cmd patch
# ============================================================================
# Step 1: Codec libraries (static .a, built with -fPIC)
@ -229,6 +230,11 @@ if [ ! -d "$FFMPEG_SRC" ]; then
fi
cd "$SRC_DIR/ffmpeg"
AMF_QP_PATCH="$SCRIPT_DIR/patches/ffmpeg-7.1.2-amf-live-qp.patch"
if ! grep -q 'utun_qp_applied' libavcodec/amfenc.c; then
log "Apply live AMF QP ceiling support..."
patch --batch --forward -p1 < "$AMF_QP_PATCH" || die "Failed to apply live AMF QP ceiling patch"
fi
log "Configure FFmpeg..."
CONFIGURE_ARGS=(

22
tools/chatgui/tests/test_stream_publish.cpp

@ -4,6 +4,7 @@
#include <QTimer>
#include <QLabel>
#include <QComboBox>
#include <QSpinBox>
#include <QCheckBox>
#include <QButtonGroup>
#include <QPushButton>
@ -22,6 +23,7 @@
#include <pthread.h>
#endif
#include "../src/live_video_encoder.h"
#include "../src/stream_qp_control.h"
#include "../src/stream_publish_engine.h"
#include "../src/stream_publish_window.h"
#include "../src/sound_manager.h"
@ -257,6 +259,8 @@ private slots:
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);
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);
@ -268,6 +272,7 @@ private slots:
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());
StreamPublishEngine reopenedEngine;
StreamPublishWindow reopened(&reopenedEngine, group, nullptr, saved);
QSignalSpy changes(&reopened, &StreamPublishWindow::settingsChanged);
@ -275,6 +280,8 @@ private slots:
auto boxes = reopened.findChildren<QComboBox*>();
QCOMPARE(boxes[1]->currentData().toList(), selectedMode);
QCOMPARE(boxes[3]->currentData().toInt(), 4000000);
QCOMPARE(reopened.findChild<QSpinBox*>("streamMaxQp")->value(), 25);
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());
@ -287,6 +294,21 @@ private slots:
StreamPublishWindow restoredAuto(&reopenedEngine, group, nullptr, automatic);
QCOMPARE(restoredAuto.findChildren<QComboBox*>()[3]->currentIndex(), 0);
}
void qpAdaptationFollowsBitrateWithoutSpikes() {
StreamQpControl qp; qp.reset(28, 1000000, true, 0);
QCOMPARE(qp.update(1000000, 1000000), 28); // До двух секунд одиночный KEY не меняет потолок.
QCOMPARE(qp.update(0, 2000000), 29);
QCOMPARE(qp.update(1000000, 4000000), 30); // Не более одного пункта за интервал.
for (int64_t now = 6000000; now <= 12000000; now += 2000000) qp.update(250000, now);
QCOMPARE(qp.limit(), 31); // Сглаживание не дёргает QP около целевого битрейта.
for (int64_t now = 14000000; now <= 30000000; now += 2000000) qp.update(10000, now);
QCOMPARE(qp.limit(), 28); // Возвращаем выбранный потолок, не снижаем его дальше.
qp.reset(28, 1000000, false, 0); QCOMPARE(qp.update(10000000, 2000000), 28);
qp.reset(50, 1000000, true, 0);
QCOMPARE(qp.update(1000000, 2000000), 51); QCOMPARE(qp.update(1000000, 4000000), 51);
qp.reset(24, 4000000, true, 10000000);
QCOMPARE(qp.update(1000, 11000000), 24); QCOMPARE(qp.bitrate(), uint64_t(0));
}
void proportionalScreenModes_data() {
QTest::addColumn<QSize>("source"); QTest::addColumn<QSize>("maximum"); QTest::addColumn<QSize>("reduced");
QTest::newRow("full-hd") << QSize(1920, 1080) << QSize(1920, 1080) << QSize(1280, 720);

Loading…
Cancel
Save