Persist broadcast QP controls and verify smooth rate feedback
This commit is contained in:
1 parent
fe86a16cac
commit
fae794d39e
2 files changed
+29
-1
No files matched your search
@@ -7,7 +7,7 @@ SRC_DIR="$BUILD_DIR/src"
|
|||||||
INSTALL_DIR="$BUILD_DIR/install"
|
INSTALL_DIR="$BUILD_DIR/install"
|
||||||
JOBS=$(nproc 2>/dev/null || echo 4)
|
JOBS=$(nproc 2>/dev/null || echo 4)
|
||||||
AMF_HEADERS_VERSION="${AMF_HEADERS_VERSION:-1.5.3}"
|
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
|
case "$(uname -s)" in
|
||||||
Linux) PLATFORM=linux ;;
|
Linux) PLATFORM=linux ;;
|
||||||
@@ -64,6 +64,7 @@ check_cmd nasm
|
|||||||
check_cmd pkg-config
|
check_cmd pkg-config
|
||||||
check_cmd git
|
check_cmd git
|
||||||
check_cmd curl
|
check_cmd curl
|
||||||
|
check_cmd patch
|
||||||
|
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
# Step 1: Codec libraries (static .a, built with -fPIC)
|
# Step 1: Codec libraries (static .a, built with -fPIC)
|
||||||
@@ -229,6 +230,11 @@ if [ ! -d "$FFMPEG_SRC" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cd "$SRC_DIR/ffmpeg"
|
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..."
|
log "Configure FFmpeg..."
|
||||||
|
|
||||||
CONFIGURE_ARGS=(
|
CONFIGURE_ARGS=(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
#include <QSpinBox>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QButtonGroup>
|
#include <QButtonGroup>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
@@ -22,6 +23,7 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#endif
|
#endif
|
||||||
#include "../src/live_video_encoder.h"
|
#include "../src/live_video_encoder.h"
|
||||||
|
#include "../src/stream_qp_control.h"
|
||||||
#include "../src/stream_publish_engine.h"
|
#include "../src/stream_publish_engine.h"
|
||||||
#include "../src/stream_publish_window.h"
|
#include "../src/stream_publish_window.h"
|
||||||
#include "../src/sound_manager.h"
|
#include "../src/sound_manager.h"
|
||||||
@@ -257,6 +259,8 @@ private slots:
|
|||||||
boxes[1]->setCurrentIndex(boxes[1]->count() - 1); // Меньший размер сохраняется при повторном открытии.
|
boxes[1]->setCurrentIndex(boxes[1]->count() - 1); // Меньший размер сохраняется при повторном открытии.
|
||||||
selectedMode = boxes[1]->currentData().toList();
|
selectedMode = boxes[1]->currentData().toList();
|
||||||
boxes[3]->setCurrentIndex(boxes[3]->findData(4000000));
|
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.findChild<QButtonGroup*>()->button(270)->click();
|
||||||
controls.findChildren<QCheckBox*>().first()->setChecked(false);
|
controls.findChildren<QCheckBox*>().first()->setChecked(false);
|
||||||
if (boxes[2]->count() > 1) boxes[2]->setCurrentIndex(boxes[2]->count() - 1);
|
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);
|
QCOMPARE(stored.value("bitrate").toInt(), 4000000); QCOMPARE(stored.value("rotation").toInt(), 270);
|
||||||
QVERIFY(!stored.value("audio").toBool());
|
QVERIFY(!stored.value("audio").toBool());
|
||||||
QVERIFY(!stored.value("show_cursor").toBool(true));
|
QVERIFY(!stored.value("show_cursor").toBool(true));
|
||||||
|
QCOMPARE(stored.value("max_qp").toInt(), 25); QVERIFY(stored.value("adaptive_qp").toBool());
|
||||||
StreamPublishEngine reopenedEngine;
|
StreamPublishEngine reopenedEngine;
|
||||||
StreamPublishWindow reopened(&reopenedEngine, group, nullptr, saved);
|
StreamPublishWindow reopened(&reopenedEngine, group, nullptr, saved);
|
||||||
QSignalSpy changes(&reopened, &StreamPublishWindow::settingsChanged);
|
QSignalSpy changes(&reopened, &StreamPublishWindow::settingsChanged);
|
||||||
@@ -275,6 +280,8 @@ private slots:
|
|||||||
auto boxes = reopened.findChildren<QComboBox*>();
|
auto boxes = reopened.findChildren<QComboBox*>();
|
||||||
QCOMPARE(boxes[1]->currentData().toList(), selectedMode);
|
QCOMPARE(boxes[1]->currentData().toList(), selectedMode);
|
||||||
QCOMPARE(boxes[3]->currentData().toInt(), 4000000);
|
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());
|
if (StreamPublishEngine::supported()) QTRY_COMPARE(boxes[2]->currentData().toInt(), stored.value("codec").toInt());
|
||||||
QCOMPARE(reopened.findChild<QButtonGroup*>()->checkedId(), 270);
|
QCOMPARE(reopened.findChild<QButtonGroup*>()->checkedId(), 270);
|
||||||
QVERIFY(!reopened.findChildren<QCheckBox*>().first()->isChecked());
|
QVERIFY(!reopened.findChildren<QCheckBox*>().first()->isChecked());
|
||||||
@@ -287,6 +294,21 @@ private slots:
|
|||||||
StreamPublishWindow restoredAuto(&reopenedEngine, group, nullptr, automatic);
|
StreamPublishWindow restoredAuto(&reopenedEngine, group, nullptr, automatic);
|
||||||
QCOMPARE(restoredAuto.findChildren<QComboBox*>()[3]->currentIndex(), 0);
|
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() {
|
void proportionalScreenModes_data() {
|
||||||
QTest::addColumn<QSize>("source"); QTest::addColumn<QSize>("maximum"); QTest::addColumn<QSize>("reduced");
|
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);
|
QTest::newRow("full-hd") << QSize(1920, 1080) << QSize(1920, 1080) << QSize(1280, 720);
|
||||||
|
|||||||
Reference in new issue
Block a user