PR #25457 opened by JuliusBairaktaris URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25457 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/25457.patch
Depends on #25454, whose commit this is stacked on; only the last commit belongs to this pull request. AMF SDK 1.5.3 lets the video converter rotate by 90, 180 and 270 degrees (AMF_VIDEO_CONVERTER_ROTATE), but vpp_amf cannot request it. - `avfilter/vf_vpp_amf: add a transpose option`: clock, cclock and reversal, as in the other hardware transpose filters. The converter cannot flip, so the flip values are refused. As in vpp_qsv, w and h give the size before the rotation, and a quarter turn swaps the size and the SAR. The option is only built with SDK 1.5.3 headers; with 1.5.2 headers the filter builds without it. clock, cclock and reversal of a 1280x720 testsrc2 in NV12 are identical to transpose=1, transpose=2 and two transpose=1 (PSNR inf in all planes), and the output SAR matches transpose for anamorphic input. Tested on Windows 11, RX 9070 XT, driver 32.0.32015.7029, AMF runtime 1.5.3.0. Written with Claude Opus 5.5 in Claude Code; `Assisted-by` trailer on the commit. >From 55494ec9644d0d9ff9dad7bc7c03c5a570a44c6e Mon Sep 17 00:00:00 2001 From: Julius Bairaktaris <[email protected]> Date: Sun, 25 Oct 2026 16:46:57 +0100 Subject: [PATCH 1/2] avfilter/amf: set the output frames' sample aspect ratio The AMF filters copy all properties of the input frame to the output frame, including its sample aspect ratio, while the output link's sample aspect ratio is computed for the output size. A scaled frame therefore keeps the input's SAR: vpp_amf=w=1280:h=720:reset_sar=1 on 720x480 input with SAR 32:27 outputs frames tagged 32:27 instead of 1:1, and w=720:h=240 outputs 32:27 instead of 16:27. Set the output frames' SAR from the output link. Tested on Windows 11, RX 9070 XT, driver 32.0.32015.7029: the frame SAR of vpp_amf with reset_sar, with a non-proportional size, with a proportional size and without scaling, and of sr_amf, now matches what scale outputs for the same parameters. Assisted-by: Claude Opus 5.5 Signed-off-by: Julius Bairaktaris <[email protected]> --- libavfilter/vf_amf_common.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libavfilter/vf_amf_common.c b/libavfilter/vf_amf_common.c index e1d0b42ee37..b8591451e7e 100644 --- a/libavfilter/vf_amf_common.c +++ b/libavfilter/vf_amf_common.c @@ -173,6 +173,7 @@ static int amf_deliver_output(AVFilterContext *avctx) return ret; } out->pts = pts; + out->sample_aspect_ratio = outlink->sample_aspect_ratio; if (ctx->outputs_per_input > 1) out->duration /= ctx->outputs_per_input; -- 2.54.0 >From a252c841368a4807969bc53d400322bf7f0a94af Mon Sep 17 00:00:00 2001 From: Julius Bairaktaris <[email protected]> Date: Sun, 25 Oct 2026 16:40:49 +0100 Subject: [PATCH 2/2] avfilter/vf_vpp_amf: add a transpose option The AMF video converter can rotate by 90, 180 and 270 degrees since AMF SDK 1.5.3 (AMF_VIDEO_CONVERTER_ROTATE), but vpp_amf cannot request it. Add a transpose option with the clock, cclock and reversal values of the other hardware transpose filters; the converter cannot flip, so the flip values are refused. As in vpp_qsv, the size from w and h is the size before rotation and is swapped for a quarter turn, together with the sample aspect ratio. The option is only built with SDK 1.5.3 headers, and configuration fails if setting the property fails. Tested on Windows 11, RX 9070 XT, driver 32.0.32015.7029, AMF runtime 1.5.3.0: clock, cclock and reversal of a 1280x720 testsrc2 in NV12 are identical to transpose=1, transpose=2 and two transpose=1 (PSNR inf in all planes), and the output SAR matches transpose for anamorphic input. The filter builds with SDK 1.5.2 headers without the option. Assisted-by: Claude Opus 5.5 Signed-off-by: Julius Bairaktaris <[email protected]> --- doc/filters.texi | 15 +++++++++++++++ libavfilter/vf_amf_common.c | 9 ++++++++- libavfilter/vf_amf_common.h | 1 + libavfilter/vf_vpp_amf.c | 23 +++++++++++++++++++++++ 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/doc/filters.texi b/doc/filters.texi index 37f9123df49..3fb42bce94b 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -26259,6 +26259,21 @@ Work the same as the identical @ref{scale} filter options. @item reset_sar Works the same as the identical @ref{scale} filter option. +@item transpose +Rotate the video. The output size given by @option{w} and @option{h} is the +size before the rotation. Requires AMF SDK 1.5.3 headers at build time and a +runtime that supports rotation. +@table @samp +@item clock +Rotate by 90 degrees clockwise. + +@item cclock +Rotate by 90 degrees counterclockwise. + +@item reversal +Rotate by 180 degrees. +@end table + @item in_color_range Override input color range. diff --git a/libavfilter/vf_amf_common.c b/libavfilter/vf_amf_common.c index b8591451e7e..1b2ce7a8d84 100644 --- a/libavfilter/vf_amf_common.c +++ b/libavfilter/vf_amf_common.c @@ -32,6 +32,7 @@ #include "libavutil/hwcontext_amf.h" #include "libavutil/hwcontext_amf_internal.h" #include "scale_eval.h" +#include "transpose.h" #if CONFIG_DXVA2 #include <d3d9.h> @@ -518,6 +519,9 @@ int amf_init_filter_config(AVFilterLink *outlink, enum AVPixelFormat *in_format) if (err < 0) return err; + if (ctx->transpose == TRANSPOSE_CLOCK || ctx->transpose == TRANSPOSE_CCLOCK) + FFSWAP(int, ctx->width, ctx->height); + if (!ctx->pending) { ctx->pending = av_fifo_alloc2(1, sizeof(AVFrame*), AV_FIFO_FLAG_AUTO_GROW); if (!ctx->pending) @@ -585,7 +589,10 @@ int amf_init_filter_config(AVFilterLink *outlink, enum AVPixelFormat *in_format) if (ctx->reset_sar) outlink->sample_aspect_ratio = (AVRational){1, 1}; - else if (inlink->sample_aspect_ratio.num) { + else if (inlink->sample_aspect_ratio.num && + (ctx->transpose == TRANSPOSE_CLOCK || ctx->transpose == TRANSPOSE_CCLOCK)) { + outlink->sample_aspect_ratio = av_div_q((AVRational){outlink->h * inlink->h, outlink->w * inlink->w}, inlink->sample_aspect_ratio); + } else if (inlink->sample_aspect_ratio.num) { outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink->w, outlink->w * inlink->h}, inlink->sample_aspect_ratio); } else outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; diff --git a/libavfilter/vf_amf_common.h b/libavfilter/vf_amf_common.h index 9af3d2ddda9..4ded7f07b7b 100644 --- a/libavfilter/vf_amf_common.h +++ b/libavfilter/vf_amf_common.h @@ -64,6 +64,7 @@ typedef struct AMFFilterContext { int force_original_aspect_ratio; int force_divisible_by; int reset_sar; + int transpose; AMFComponent *component; AMFComponent *pre_converter; diff --git a/libavfilter/vf_vpp_amf.c b/libavfilter/vf_vpp_amf.c index 1369c400124..c2561220742 100644 --- a/libavfilter/vf_vpp_amf.c +++ b/libavfilter/vf_vpp_amf.c @@ -31,6 +31,7 @@ #include "AMF/components/VideoConverter.h" #include "vf_amf_common.h" +#include "transpose.h" #include "avfilter.h" #include "scale_eval.h" @@ -100,6 +101,21 @@ static int amf_filter_config_output(AVFilterLink *outlink) AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_VIDEO_CONVERTER_SCALE, (amf_int32)ctx->scale_type); AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR_UNKNOWN, "AMFConverter-SetProperty() failed with error %d\n", res); +#ifdef AMF_VIDEO_CONVERTER_ROTATE + if (ctx->transpose >= 0) { + if (ctx->transpose != TRANSPOSE_CLOCK && ctx->transpose != TRANSPOSE_CCLOCK && + ctx->transpose != TRANSPOSE_REVERSAL) { + av_log(avctx, AV_LOG_ERROR, "Only clock, cclock and reversal are supported for transpose.\n"); + return AVERROR(EINVAL); + } + AMF_ASSIGN_PROPERTY_INT64(res, ctx->component, AMF_VIDEO_CONVERTER_ROTATE, + ctx->transpose == TRANSPOSE_CLOCK ? AMF_VIDEO_CONVERTER_ROTATE_90 : + ctx->transpose == TRANSPOSE_CCLOCK ? AMF_VIDEO_CONVERTER_ROTATE_270 : + AMF_VIDEO_CONVERTER_ROTATE_180); + AMF_RETURN_IF_FALSE(avctx, res == AMF_OK, AVERROR(ENOSYS), "Rotation is not supported by the AMF runtime: %d\n", res); + } +#endif + amf_color_profile = AMF_VIDEO_CONVERTER_COLOR_PROFILE_UNKNOWN; switch(ctx->color_profile) { @@ -256,6 +272,13 @@ static const AVOption vpp_amf_options[] = { { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS }, { "reset_sar", "reset SAR to 1 and scale to square pixels if scaling proportionally", OFFSET(reset_sar), AV_OPT_TYPE_BOOL, { .i64 = 0}, 0, 1, FLAGS }, +#ifdef AMF_VIDEO_CONVERTER_ROTATE + { "transpose", "Rotate the video", OFFSET(transpose), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, TRANSPOSE_REVERSAL, FLAGS, "transpose" }, + { "clock", "Rotate clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CLOCK }, 0, 0, FLAGS, "transpose" }, + { "cclock", "Rotate counter-clockwise", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_CCLOCK }, 0, 0, FLAGS, "transpose" }, + { "reversal", "Rotate by half-turn", 0, AV_OPT_TYPE_CONST, { .i64 = TRANSPOSE_REVERSAL }, 0, 0, FLAGS, "transpose" }, +#endif + { NULL }, }; -- 2.54.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
