avfilter/vf_libplacebo: fix format query

We need to construct the output format list separatedly from the input
format list, because we need to adhere to two extra requirements:

1. Big-endian output formats are always unsupported (runtime error)
2. Combining 'vulkan' with an explicit out_format that is not supported
   by the vulkan frame allocation code is illegal and will crash (abort)

As a free side benefit, this rewrite fixes a possible memory leak in the
`fail` path that was present in the old code.

Signed-off-by: Niklas Haas <git@haasn.dev>
This commit is contained in:
Niklas Haas 2023-02-07 15:09:18 +01:00
parent 58d6426870
commit 62dfa54688
1 changed files with 35 additions and 17 deletions

View File

@ -547,10 +547,10 @@ fail:
static int libplacebo_query_format(AVFilterContext *ctx) static int libplacebo_query_format(AVFilterContext *ctx)
{ {
int err = 0; int err;
LibplaceboContext *s = ctx->priv; LibplaceboContext *s = ctx->priv;
const AVPixFmtDescriptor *desc = NULL; const AVPixFmtDescriptor *desc = NULL;
AVFilterFormats *formats = NULL; AVFilterFormats *infmts = NULL, *outfmts = NULL;
RET(init_vulkan(ctx)); RET(init_vulkan(ctx));
@ -564,29 +564,47 @@ static int libplacebo_query_format(AVFilterContext *ctx)
continue; continue;
#endif #endif
if (pl_test_pixfmt(s->gpu, pixfmt)) { if (!pl_test_pixfmt(s->gpu, pixfmt))
if ((err = ff_add_format(&formats, pixfmt)) < 0) continue;
return err;
RET(ff_add_format(&infmts, pixfmt));
/* Filter for supported output pixel formats */
if (desc->flags & AV_PIX_FMT_FLAG_BE)
continue; /* BE formats are not supported by pl_download_avframe */
/* Mask based on user specified format */
if (s->out_format != AV_PIX_FMT_NONE) {
if (pixfmt == AV_PIX_FMT_VULKAN && av_vkfmt_from_pixfmt(s->out_format)) {
/* OK */
} else if (pixfmt == s->out_format) {
/* OK */
} else {
continue; /* Not OK */
}
} }
RET(ff_add_format(&outfmts, pixfmt));
} }
RET(ff_formats_ref(formats, &ctx->inputs[0]->outcfg.formats)); if (!infmts || !outfmts) {
if (s->out_format) {
if (s->out_format != AV_PIX_FMT_NONE) { av_log(s, AV_LOG_ERROR, "Invalid output format '%s'!\n",
/* Support only requested format, and hwaccel (vulkan) */ av_get_pix_fmt_name(s->out_format));
const enum AVPixelFormat out_fmts[] = { }
s->out_format, AV_PIX_FMT_VULKAN, AV_PIX_FMT_NONE, err = AVERROR(EINVAL);
}; goto fail;
RET(ff_formats_ref(ff_make_format_list(out_fmts),
&ctx->outputs[0]->incfg.formats));
} else {
/* Support all formats */
RET(ff_formats_ref(formats, &ctx->outputs[0]->incfg.formats));
} }
RET(ff_formats_ref(infmts, &ctx->inputs[0]->outcfg.formats));
RET(ff_formats_ref(outfmts, &ctx->outputs[0]->incfg.formats));
return 0; return 0;
fail: fail:
if (infmts && !infmts->refcount)
ff_formats_unref(&infmts);
if (outfmts && !outfmts->refcount)
ff_formats_unref(&outfmts);
return err; return err;
} }