build-aux: Fix incorrect HEVC vertical resolution on AMD VCN

AMD VCN uses a different surface alignment compared to other GPUs for
encoding, which required an upstream fix in Mesa, libva, FFmpeg, and
the VCN firmware.

This commit adds the FFmpeg patches to the flatpak build of OBS which
is currently using FFmpeg version n7.1, however the patches were applied
upstream after that release. libva API version 1.21 or higher is also
required, which is satisfied by using KDE runtime 6.8.

The incorrect 1920x1088 HEVC output resolution (instead of 1920x1080)
resulted in streaming disconnects for Twitch Enhanced Broadcsating
Linux users. Local file recording when using AMD VAAPI HEVC also
outputs 1088 instead of 1080. This commit fixes both cases.

Please refer to [1], [2], and [3] for context. The patches are taken
from [2].

Note that the fix is applicable to flatpak builds only. Standalone and
Debian package builds depend on the host library versions and will
still have the problem until a version of FFmpeg with the fix is used.

[1]: https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=11222
[2]: https://patchwork.ffmpeg.org/project/ffmpeg/list/?series=13168
[3]: https://gitlab.freedesktop.org/mesa/mesa/-/issues/10985
This commit is contained in:
Alex Luccisano 2024-12-16 10:29:50 -05:00 committed by Ryan Foster
parent d31271834f
commit 4efc6bf0d8
3 changed files with 154 additions and 0 deletions

View File

@ -36,6 +36,13 @@
"tag": "2024-09-05",
"commit": "45b7d2cfac0e2ac256d458c7466a925b0a94de35"
},
{
"type": "patch",
"paths": [
"patches/ffmpeg/0001-lavc-vaapi_encode-Query-surface-alignment.patch",
"patches/ffmpeg/0002-lavc-vaapi_encode_h265-Use-surface-alignment.patch"
]
},
{
"type": "shell",
"commands": [

View File

@ -0,0 +1,115 @@
From bcfbf2bac8f9eeeedc407b40596f5c7aaa0d5b47 Mon Sep 17 00:00:00 2001
From: David Rosca <nowrep@gmail.com>
Date: Tue, 22 Oct 2024 17:26:58 +0200
Subject: [PATCH 1/2] lavc/vaapi_encode: Query surface alignment
It needs to create temporary config to query surface attribute.
Signed-off-by: Timo Rothenpieler <timo@rothenpieler.org>
---
libavcodec/vaapi_encode.c | 66 +++++++++++++++++++++++++++++++++++++++
libavcodec/vaapi_encode.h | 4 +++
2 files changed, 70 insertions(+)
diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c
index b593d976ef..8960e6b20a 100644
--- a/libavcodec/vaapi_encode.c
+++ b/libavcodec/vaapi_encode.c
@@ -1133,6 +1133,68 @@ fail:
return err;
}
+static av_cold int vaapi_encode_surface_alignment(av_unused AVCodecContext *avctx)
+{
+#if VA_CHECK_VERSION(1, 21, 0)
+ VAAPIEncodeContext *ctx = avctx->priv_data;
+ VASurfaceAttrib *attr_list = NULL;
+ unsigned int attr_count = 0;
+ VAConfigID va_config;
+ VAStatus vas;
+ int err = 0;
+
+ vas = vaCreateConfig(ctx->hwctx->display,
+ ctx->va_profile, ctx->va_entrypoint,
+ NULL, 0, &va_config);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to create temp encode pipeline "
+ "configuration: %d (%s).\n", vas, vaErrorStr(vas));
+ return AVERROR(EIO);
+ }
+
+ vas = vaQuerySurfaceAttributes(ctx->hwctx->display, va_config,
+ 0, &attr_count);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
+ "%d (%s).\n", vas, vaErrorStr(vas));
+ err = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ attr_list = av_malloc(attr_count * sizeof(*attr_list));
+ if (!attr_list) {
+ err = AVERROR(ENOMEM);
+ goto fail;
+ }
+
+ vas = vaQuerySurfaceAttributes(ctx->hwctx->display, va_config,
+ attr_list, &attr_count);
+ if (vas != VA_STATUS_SUCCESS) {
+ av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: "
+ "%d (%s).\n", vas, vaErrorStr(vas));
+ err = AVERROR_EXTERNAL;
+ goto fail;
+ }
+
+ for (unsigned int i = 0; i < attr_count; i++) {
+ if (attr_list[i].type == VASurfaceAttribAlignmentSize) {
+ ctx->surface_alignment_width =
+ 1 << (attr_list[i].value.value.i & 0xf);
+ ctx->surface_alignment_height =
+ 1 << ((attr_list[i].value.value.i & 0xf0) >> 4);
+ break;
+ }
+ }
+
+fail:
+ av_freep(&attr_list);
+ vaDestroyConfig(ctx->hwctx->display, va_config);
+ return err;
+#else
+ return 0;
+#endif
+}
+
static const VAAPIEncodeRCMode vaapi_encode_rc_modes[] = {
// Bitrate Quality
// | Maxrate | HRD/VBV
@@ -2111,6 +2173,10 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx)
if (err < 0)
goto fail;
+ err = vaapi_encode_surface_alignment(avctx);
+ if (err < 0)
+ goto fail;
+
if (ctx->codec->get_encoder_caps) {
err = ctx->codec->get_encoder_caps(avctx);
if (err < 0)
diff --git a/libavcodec/vaapi_encode.h b/libavcodec/vaapi_encode.h
index 40a3f4e064..8e3eab9f27 100644
--- a/libavcodec/vaapi_encode.h
+++ b/libavcodec/vaapi_encode.h
@@ -260,6 +260,10 @@ typedef struct VAAPIEncodeContext {
* This is a RefStruct reference.
*/
VABufferID *coded_buffer_ref;
+
+ // Surface alignment required by driver.
+ int surface_alignment_width;
+ int surface_alignment_height;
} VAAPIEncodeContext;
typedef struct VAAPIEncodeType {
--
2.43.0

View File

@ -0,0 +1,32 @@
From d0facac679faf45d3356dff2e2cb382580d7a521 Mon Sep 17 00:00:00 2001
From: David Rosca <nowrep@gmail.com>
Date: Tue, 22 Oct 2024 17:26:59 +0200
Subject: [PATCH 2/2] lavc/vaapi_encode_h265: Use surface alignment
This is needed to correctly set conformance window crop with Mesa AMD.
Signed-off-by: Timo Rothenpieler <timo@rothenpieler.org>
---
libavcodec/vaapi_encode_h265.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c
index 2283bcc0b4..44d9fdbbd5 100644
--- a/libavcodec/vaapi_encode_h265.c
+++ b/libavcodec/vaapi_encode_h265.c
@@ -951,8 +951,10 @@ static av_cold int vaapi_encode_h265_get_encoder_caps(AVCodecContext *avctx)
"min CB size %dx%d.\n", priv->ctu_size, priv->ctu_size,
priv->min_cb_size, priv->min_cb_size);
- base_ctx->surface_width = FFALIGN(avctx->width, priv->min_cb_size);
- base_ctx->surface_height = FFALIGN(avctx->height, priv->min_cb_size);
+ base_ctx->surface_width = FFALIGN(avctx->width,
+ FFMAX(priv->min_cb_size, priv->common.surface_alignment_width));
+ base_ctx->surface_height = FFALIGN(avctx->height,
+ FFMAX(priv->min_cb_size, priv->common.surface_alignment_height));
base_ctx->slice_block_width = base_ctx->slice_block_height = priv->ctu_size;
--
2.43.0