mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-11-05 16:38:17 +00:00
* fix(ffmpeg): bound QSV encoder retries Limit QSV frame submission to 100 retries and synchronization to 10 retries so persistent SDK warnings return an error to the caller. Retain queued buffers when synchronization reaches its retry limit, and allow later calls to retry without latching an error. Wait 1 ms between retryable submission warnings on Windows: the original av_usleep(500) becomes Sleep(0), exhausting the retry budget before even a brief device-busy interval can end. Preserve non-Windows wait behavior and the existing negative SDK result handling. Validated against FFmpeg 7.1.1 on Intel UHD 730 with 42 fault/control cases, synchronization-timeout recovery and close cleanup, real H.264 and HEVC encoding, and separate QSV hardware decoding. Four concurrent 1080p encoders completed 2400 frames without errors. * fix(ffmpeg): handle undersized QSV HEVC buffers Reserve at least three bytes per aligned pixel for HEVC output, following Intel's documented workaround for underestimated bitstream capacity. Check the size before assigning it to AVPacket's integer capacity. Report negative synchronization results before reading output metadata or draining the FIFO, keeping failed tasks owned until encoder close. On Intel UHD 730, the existing code fails at input 242 with real desktop captures; the patched code encodes and decodes all 1,200 inputs. Inputs and PTS match, and the first 241 encoded frames are byte-identical. H.264 also passes 300 frames, and restoring the small buffer verifies error handling. * fix(ffmpeg): refresh QSV HEVC capacity after reset and shorten sync waits * fix(ffmpeg): apply QSV buffer sizing to H.264 * fix: backport FFmpeg hybrid MP4 finalization fix Backport FFmpeg commit 36896af64a9ecf6835758186e7161a2e954c364d so hybrid MP4 finalization writes the final moov before hiding the original fragmented index. Preserve recoverable fragments when the final index cannot be written.
68 lines
2.5 KiB
Diff
68 lines
2.5 KiB
Diff
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
|
|
--- a/libavcodec/qsvenc.c
|
|
+++ b/libavcodec/qsvenc.c
|
|
@@ -43,6 +43,9 @@
|
|
#include "qsv_internal.h"
|
|
#include "qsvenc.h"
|
|
#include "refstruct.h"
|
|
+
|
|
+#define QSV_MAX_ENCODE_RETRIES 100
|
|
+#define QSV_SYNC_TIMEOUT_US 2000000
|
|
|
|
struct profile_names {
|
|
mfxU16 profile;
|
|
@@ -2468,6 +2471,7 @@
|
|
QSVFrame *qsv_frame = NULL;
|
|
mfxEncodeCtrl* enc_ctrl = NULL;
|
|
int ret;
|
|
+ int retries = 0;
|
|
|
|
if (frame) {
|
|
ret = submit_frame(q, frame, &qsv_frame);
|
|
@@ -2538,6 +2542,18 @@
|
|
|
|
do {
|
|
ret = MFXVideoENCODE_EncodeFrameAsync(q->session, enc_ctrl, surf, pkt.bs, pkt.sync);
|
|
+ if ((ret == MFX_WRN_DEVICE_BUSY || ret == MFX_WRN_IN_EXECUTION) &&
|
|
+ retries++ >= QSV_MAX_ENCODE_RETRIES) {
|
|
+ av_log(avctx, AV_LOG_ERROR, "QSV encoder submission retry limit exceeded\n");
|
|
+ ret = AVERROR_EXTERNAL;
|
|
+ goto free;
|
|
+ }
|
|
+#ifdef _WIN32
|
|
+ // Sub-millisecond waits become Sleep(0) on Windows.
|
|
+ if (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_WRN_IN_EXECUTION)
|
|
+ av_usleep(1000);
|
|
+#else
|
|
if (ret == MFX_WRN_DEVICE_BUSY)
|
|
av_usleep(500);
|
|
+#endif
|
|
} while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_WRN_IN_EXECUTION);
|
|
@@ -2656,12 +2672,23 @@
|
|
mfxExtAVCEncodedFrameInfo *enc_info;
|
|
mfxExtBuffer **enc_buf;
|
|
enum AVPictureType pict_type;
|
|
-
|
|
- av_fifo_read(q->async_fifo, &qpkt, 1);
|
|
+ int64_t sync_deadline = av_gettime_relative() + QSV_SYNC_TIMEOUT_US;
|
|
+
|
|
+ // The SDK may still use these buffers after a synchronization timeout.
|
|
+ av_fifo_peek(q->async_fifo, &qpkt, 1, 0);
|
|
|
|
do {
|
|
- ret = MFXVideoCORE_SyncOperation(q->session, *qpkt.sync, 1000);
|
|
+ int64_t remaining = sync_deadline - av_gettime_relative();
|
|
+ if (remaining <= 0) {
|
|
+ av_log(avctx, AV_LOG_ERROR, "QSV encoder synchronization timed out\n");
|
|
+ return AVERROR_EXTERNAL;
|
|
+ }
|
|
+ ret = MFXVideoCORE_SyncOperation(q->session, *qpkt.sync,
|
|
+ FFMIN(1000, (remaining + 999) / 1000));
|
|
+ if (ret == MFX_WRN_IN_EXECUTION)
|
|
+ av_usleep(1000);
|
|
} while (ret == MFX_WRN_IN_EXECUTION);
|
|
+ av_fifo_drain2(q->async_fifo, 1);
|
|
|
|
qpkt.pkt.dts = av_rescale_q(qpkt.bs->DecodeTimeStamp, (AVRational){1, 90000}, avctx->time_base);
|
|
qpkt.pkt.pts = av_rescale_q(qpkt.bs->TimeStamp, (AVRational){1, 90000}, avctx->time_base);
|