Commit 527f5050ed for ffmpeg

commit 527f5050ed7151466678bd607219cef4dc7a93fb
Author: TADANO Tokumei <aimingoff@pc.nifty.jp>
Date:   Sun Aug 23 03:34:47 2026 +0900

    avfilter/v360_vulkan: calculate output size

    The former code ignores w and h options, and doesn't resize.
    This fix add resizing feature with proper aspect ratio.

    Signed-off-by: TADANO Tokumei <aimingoff@pc.nifty.jp>

diff --git a/libavfilter/vf_v360_vulkan.c b/libavfilter/vf_v360_vulkan.c
index 4111daa6bf..c4651fd62c 100644
--- a/libavfilter/vf_v360_vulkan.c
+++ b/libavfilter/vf_v360_vulkan.c
@@ -296,6 +296,130 @@ static void config_params(AVFilterContext *ctx, AVFilterLink *inlink)
     return;
 }

+static av_cold int calculate_output_size(AVFilterContext *ctx)
+{
+    V360VulkanContext   *s = ctx->priv;
+    FFVulkanContext *vkctx = &s->vkctx;
+    AVFilterLink   *inlink = ctx->inputs[0];
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(s->vkctx.output_format);
+    float sar = inlink->sample_aspect_ratio.num ?
+                (float) inlink->sample_aspect_ratio.num / inlink->sample_aspect_ratio.den : 1;
+    float  wf = (float) s->width;
+    float  hf = (float) s->height;
+    int min_w, min_h, pw, ph;
+
+    if (s->width > 0 && s->height > 0) {
+        if (sar == 1) {
+            vkctx->output_width = s->width;
+        }
+        else {
+            vkctx->output_width = lrint(wf / sar);
+            if (vkctx->output_width % 2 != 0)
+                vkctx->output_width++;
+        }
+        vkctx->output_height = s->height;
+    }
+    else if (s->width > 0 && s->height == 0) {
+        if (sar == 1) {
+            vkctx->output_width = s->width;
+        }
+        else {
+            vkctx->output_width = lrint(wf / sar);
+            if (vkctx->output_width % 2 != 0)
+                vkctx->output_width++;
+        }
+        switch (s->out) {
+        case FLAT:
+            hf = wf * s->pd.iflat_range[1] * 2.f;
+            break;
+        case EQUIRECTANGULAR:
+        case DUAL_FISHEYE:
+            hf = wf * sar / 2.f;
+            break;
+        case STEREOGRAPHIC:
+        case FISHEYE:
+            hf = wf * sar;
+            break;
+        default:
+            break;
+        }
+        vkctx->output_height = lrint(hf);
+        if (vkctx->output_height % 2 != 0)
+            vkctx->output_height++;
+    }
+    else { /* s->width == 0 */
+        vkctx->output_height = s->height;
+        if (s->height == 0) {
+            switch (s->in) {
+            case FLAT:
+                 hf = (float)inlink->h / s->pd.iflat_range[1] / 2.f;
+                break;
+            default:
+                hf = (float)inlink->h;
+                break;
+            }
+            switch (s->out) {
+            case FLAT:
+                hf = (float)inlink->h * s->pd.flat_range[1] * 2.f;
+                break;
+            default:
+                break;
+            }
+            vkctx->output_height = lrint(hf);
+            if (vkctx->output_height % 2 != 0)
+                vkctx->output_height++;
+        }
+        switch (s->out) {
+        case FLAT:
+            wf = hf * s->pd.flat_range[0] * 2.f;
+            break;
+        case EQUIRECTANGULAR:
+        case DUAL_FISHEYE:
+            wf = hf * 2.f;
+            break;
+        case STEREOGRAPHIC:
+        case FISHEYE:
+            wf = hf;
+            break;
+        default:
+            break;
+        }
+        vkctx->output_width = lrint(wf / sar);
+        if (vkctx->output_width % 2 != 0)
+            vkctx->output_width++;
+    }
+
+    if (vkctx->output_width < 1  || vkctx->output_width > INT16_MAX ||
+        vkctx->output_height < 1 || vkctx->output_height > INT16_MAX) {
+        av_log(ctx, AV_LOG_ERROR,
+               "Output dimensions %dx%d are outside the allowed range [1, %d].\n",
+               vkctx->output_width, vkctx->output_height, INT16_MAX);
+        return AVERROR(EINVAL);
+    }
+
+    pw = AV_CEIL_RSHIFT(vkctx->output_width, desc->log2_chroma_w);
+    ph = AV_CEIL_RSHIFT(vkctx->output_height, desc->log2_chroma_h);
+    switch (s->out) {
+    case EQUIRECTANGULAR:
+    case DUAL_FISHEYE:
+        min_w = 2;
+        min_h = 1;
+        break;
+    default:
+        min_w = 1;
+        min_h = 1;
+        break;
+    }
+    if (pw < min_w || ph < min_h) {
+        av_log(ctx, AV_LOG_ERROR,
+               "Output %dx%d is too small for the output projection "
+               "(requires at least %dx%d per plane).\n", pw, ph, min_w, min_h);
+        return AVERROR(EINVAL);
+    }
+
+    return 0;
+}
+
 static av_cold int init_filter(AVFilterContext *ctx, AVFrame *in)
 {
     int err;
@@ -419,6 +543,7 @@ static av_cold int v360_vulkan_config_output(AVFilterLink *outlink)
     AVFilterLink *inlink = ctx->inputs[0];

     config_params(ctx, inlink);
+    RET(calculate_output_size(ctx));

     RET(ff_vk_filter_config_output(outlink));