Stop invalid encoder output explicitly while preserving transient backpressure retries
This commit is contained in:
1 parent
c0422a73c0
commit
322947777c
3 files changed
+15
-6
No files matched your search
@@ -123,6 +123,7 @@ bool CallVideoEncoder::encode(const QImage& image, uint64_t pts, bool forceKey,
|
|||||||
}
|
}
|
||||||
if (m_switching && frame.pts == m_switchPts) {
|
if (m_switching && frame.pts == m_switchPts) {
|
||||||
if (!frame.key) { m_error = "Replacement encoder did not start with KEY";
|
if (!frame.key) { m_error = "Replacement encoder did not start with KEY";
|
||||||
|
completion = {m_format.generation, m_request, 0};
|
||||||
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "%s", qPrintable(m_error)); return false; }
|
DEBUG_ERROR(DEBUG_CATEGORY_CALL, "%s", qPrintable(m_error)); return false; }
|
||||||
completion = {m_format.generation, m_request, m_pendingBitrate};
|
completion = {m_format.generation, m_request, m_pendingBitrate};
|
||||||
DEBUG_INFO(DEBUG_CATEGORY_CALL, "call video bitrate committed generation=%llu request=%llu bitrate=%u pts=%llu background_ms=%lld",
|
DEBUG_INFO(DEBUG_CATEGORY_CALL, "call video bitrate committed generation=%llu request=%llu bitrate=%u pts=%llu background_ms=%lld",
|
||||||
|
|||||||
@@ -307,7 +307,11 @@ void CallVideoEngine::transmit() {
|
|||||||
m->report(QString("%1 · %2×%3 · %4 kbit/s").arg(format.codec == 2 ? "H.265" : "H.264")
|
m->report(QString("%1 · %2×%3 · %4 kbit/s").arg(format.codec == 2 ? "H.265" : "H.264")
|
||||||
.arg(format.width).arg(format.height).arg(encoder.bitrate() / 1000));
|
.arg(format.width).arg(format.height).arg(encoder.bitrate() / 1000));
|
||||||
}
|
}
|
||||||
if (!encoded) { forceKey = true; m->report(encoder.error()); continue; }
|
if (!encoded) {
|
||||||
|
m->report(encoder.error());
|
||||||
|
std::lock_guard<std::mutex> guard(m->lock); m->enabled = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
// GPU может вернуть несколько уже готовых кадров: отправляем все, не добавляя очередь в TX worker.
|
// GPU может вернуть несколько уже готовых кадров: отправляем все, не добавляя очередь в TX worker.
|
||||||
if (outputs.isEmpty()) { idle(); continue; }
|
if (outputs.isEmpty()) { idle(); continue; }
|
||||||
if (outputs.size() > CALL_VIDEO_PORT_TX_FRAMES) {
|
if (outputs.size() > CALL_VIDEO_PORT_TX_FRAMES) {
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ private slots:
|
|||||||
for (auto name : {"h264_nvenc", "hevc_nvenc", "h264_amf", "hevc_amf", "h264_qsv", "hevc_qsv"})
|
for (auto name : {"h264_nvenc", "hevc_nvenc", "h264_amf", "hevc_amf", "h264_qsv", "hevc_qsv"})
|
||||||
QTest::newRow(name) << QByteArray(name) << false << false;
|
QTest::newRow(name) << QByteArray(name) << false << false;
|
||||||
QTest::newRow("batch") << QByteArray("h264_nvenc") << true << false;
|
QTest::newRow("batch") << QByteArray("h264_nvenc") << true << false;
|
||||||
QTest::newRow("rollback") << QByteArray("h264_nvenc") << false << true;
|
QTest::newRow("broken-first-key") << QByteArray("h264_nvenc") << false << true;
|
||||||
}
|
}
|
||||||
void pipeline() {
|
void pipeline() {
|
||||||
QFETCH(QByteArray, backend); QFETCH(bool, batch); QFETCH(bool, reject);
|
QFETCH(QByteArray, backend); QFETCH(bool, batch); QFETCH(bool, reject);
|
||||||
@@ -143,7 +143,12 @@ private slots:
|
|||||||
if (i == 7) { request = 1; QVERIFY(encoder.requestBitrate(1, request, 300000)); }
|
if (i == 7) { request = 1; QVERIFY(encoder.requestBitrate(1, request, 300000)); }
|
||||||
if (request && !completed && !failed) QTest::qWait(5);
|
if (request && !completed && !failed) QTest::qWait(5);
|
||||||
const uint64_t pts = 1234567 + i * 33333ull; QList<LiveEncodedFrame> output; CallVideoRateCompletion completion;
|
const uint64_t pts = 1234567 + i * 33333ull; QList<LiveEncodedFrame> output; CallVideoRateCompletion completion;
|
||||||
QVERIFY2(encoder.encode(image, pts, false, output, completion), qPrintable(encoder.error()));
|
if (!encoder.encode(image, pts, false, output, completion)) {
|
||||||
|
QVERIFY2(reject, qPrintable(encoder.error()));
|
||||||
|
QVERIFY(encoder.error().contains("did not start with KEY"));
|
||||||
|
QCOMPARE(completion.request, request); QCOMPARE(completion.bitrate, 0u);
|
||||||
|
QVERIFY(output.isEmpty()); failed = true; break;
|
||||||
|
}
|
||||||
if (completion.request) {
|
if (completion.request) {
|
||||||
QCOMPARE(completion.request, request); QCOMPARE(completion.bitrate, reject ? 0u : 300000u);
|
QCOMPARE(completion.request, request); QCOMPARE(completion.bitrate, reject ? 0u : 300000u);
|
||||||
completed = completion.bitrate != 0; failed = !completed;
|
completed = completion.bitrate != 0; failed = !completed;
|
||||||
@@ -161,9 +166,8 @@ private slots:
|
|||||||
last = frame.pts;
|
last = frame.pts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QVERIFY(shown >= 115); QCOMPARE(completed, !reject); QCOMPARE(failed, reject);
|
QCOMPARE(completed, !reject); QCOMPARE(failed, reject);
|
||||||
QCOMPARE(shown + encoder.pendingFrames(), 120u);
|
if (!reject) { QCOMPARE(shown + encoder.pendingFrames(), 120u); QCOMPARE(encoder.bitrate(), 300000u); }
|
||||||
QCOMPARE(encoder.bitrate(), reject ? 1000000u : 300000u);
|
|
||||||
if (batch) QVERIFY(maximumBatch >= 2);
|
if (batch) QVERIFY(maximumBatch >= 2);
|
||||||
qInfo("GPU pipeline %s shown=%u max_batch=%u rollback=%d", selected.constData(), shown, maximumBatch, failed);
|
qInfo("GPU pipeline %s shown=%u max_batch=%u rollback=%d", selected.constData(), shown, maximumBatch, failed);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user