avfilter/vf_libplacebo: support more output formats

Rather than hard-coding AV_PIX_FMT_VULKAN, expand this to the full list
of formats supported by <libplacebo/utils/libav.h>. We re-use the
existing `format` option to allow selecting specific software formats in
addition to specific vulkan hwframe formats.

Some minor changes are necessary to account for the fact that
`ff_vk_filter_config_output` is now only called optionally, the fact
that the output format must now be parsed before `query_format` gets
called, and the fact that we need to call a different function to
retrieve data from the `pl_frame` in the non-hwaccel case.

Signed-off-by: Niklas Haas <git@haasn.dev>
This commit is contained in:
Niklas Haas 2022-11-23 14:24:00 +01:00
parent becbb22eb0
commit 48c385fb4c

View File

@ -62,10 +62,11 @@ typedef struct LibplaceboContext {
pl_vulkan vulkan;
pl_gpu gpu;
pl_renderer renderer;
pl_tex tex[4];
pl_tex tex[8];
/* settings */
char *out_format_string;
enum AVPixelFormat out_format;
char *w_expr;
char *h_expr;
AVRational target_sar;
@ -215,6 +216,8 @@ static int find_scaler(AVFilterContext *avctx,
return AVERROR(EINVAL);
}
static void libplacebo_uninit(AVFilterContext *avctx);
static int libplacebo_init(AVFilterContext *avctx)
{
LibplaceboContext *s = avctx->priv;
@ -229,6 +232,18 @@ static int libplacebo_init(AVFilterContext *avctx)
if (!s->log)
return AVERROR(ENOMEM);
if (s->out_format_string) {
s->out_format = av_get_pix_fmt(s->out_format_string);
if (s->out_format == AV_PIX_FMT_NONE) {
av_log(avctx, AV_LOG_ERROR, "Invalid output format: %s\n",
s->out_format_string);
libplacebo_uninit(avctx);
return AVERROR(EINVAL);
}
} else {
s->out_format = AV_PIX_FMT_NONE;
}
/* Note: s->vulkan etc. are initialized later, when hwctx is available */
return 0;
}
@ -320,6 +335,7 @@ static int process_frames(AVFilterContext *avctx, AVFrame *out, AVFrame *in)
LibplaceboContext *s = avctx->priv;
struct pl_render_params params;
enum pl_tone_map_mode tonemapping_mode = s->tonemapping_mode;
const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->format);
enum pl_gamut_mode gamut_mode = s->gamut_mode;
struct pl_frame image, target;
ok = pl_map_avframe_ex(s->gpu, &image, pl_avframe_params(
@ -328,10 +344,14 @@ static int process_frames(AVFilterContext *avctx, AVFrame *out, AVFrame *in)
.map_dovi = s->apply_dovi,
));
ok &= pl_map_avframe_ex(s->gpu, &target, pl_avframe_params(
.frame = out,
.map_dovi = false,
));
if (outdesc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
ok &= pl_map_avframe_ex(s->gpu, &target, pl_avframe_params(
.frame = out,
.map_dovi = false,
));
} else {
ok &= pl_frame_recreate_from_avframe(s->gpu, &target, s->tex + 4, out);
}
if (!ok) {
err = AVERROR_EXTERNAL;
@ -434,7 +454,13 @@ static int process_frames(AVFilterContext *avctx, AVFrame *out, AVFrame *in)
pl_render_image(s->renderer, &image, &target, &params);
pl_unmap_avframe(s->gpu, &image);
pl_unmap_avframe(s->gpu, &target);
if (outdesc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
pl_unmap_avframe(s->gpu, &target);
} else if (!pl_download_avframe(s->gpu, &target, out)) {
err = AVERROR_EXTERNAL;
goto fail;
}
/* Flush the command queues for performance */
pl_gpu_flush(s->gpu);
@ -516,10 +542,7 @@ static int libplacebo_query_format(AVFilterContext *ctx)
int err = 0;
LibplaceboContext *s = ctx->priv;
const AVPixFmtDescriptor *desc = NULL;
AVFilterFormats *in_fmts = NULL;
static const enum AVPixelFormat out_fmts[] = {
AV_PIX_FMT_VULKAN, AV_PIX_FMT_NONE,
};
AVFilterFormats *formats = NULL;
RET(init_vulkan(ctx));
@ -534,14 +557,24 @@ static int libplacebo_query_format(AVFilterContext *ctx)
#endif
if (pl_test_pixfmt(s->gpu, pixfmt)) {
if ((err = ff_add_format(&in_fmts, pixfmt)) < 0)
if ((err = ff_add_format(&formats, pixfmt)) < 0)
return err;
}
}
RET(ff_formats_ref(in_fmts, &ctx->inputs[0]->outcfg.formats));
RET(ff_formats_ref(ff_make_format_list(out_fmts),
&ctx->outputs[0]->incfg.formats));
RET(ff_formats_ref(formats, &ctx->inputs[0]->outcfg.formats));
if (s->out_format != AV_PIX_FMT_NONE) {
/* Support only requested format, and hwaccel (vulkan) */
const enum AVPixelFormat out_fmts[] = {
s->out_format, AV_PIX_FMT_VULKAN, AV_PIX_FMT_NONE,
};
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));
}
return 0;
@ -572,17 +605,15 @@ static int libplacebo_config_output(AVFilterLink *outlink)
AVHWFramesContext *hwfc;
AVVulkanFramesContext *vkfc;
AVRational scale_sar;
int *out_w = &s->vkctx.output_width;
int *out_h = &s->vkctx.output_height;
RET(ff_scale_eval_dimensions(s, s->w_expr, s->h_expr, inlink, outlink,
out_w, out_h));
&outlink->w, &outlink->h));
ff_scale_adjust_dimensions(inlink, out_w, out_h,
ff_scale_adjust_dimensions(inlink, &outlink->w, &outlink->h,
s->force_original_aspect_ratio,
s->force_divisible_by);
scale_sar = (AVRational){*out_h * inlink->w, *out_w * inlink->h};
scale_sar = (AVRational){outlink->h * inlink->w, outlink->w * inlink->h};
if (inlink->sample_aspect_ratio.num)
scale_sar = av_mul_q(scale_sar, inlink->sample_aspect_ratio);
@ -598,17 +629,17 @@ static int libplacebo_config_output(AVFilterLink *outlink)
outlink->sample_aspect_ratio = scale_sar;
}
if (s->out_format_string) {
s->vkctx.output_format = av_get_pix_fmt(s->out_format_string);
if (s->vkctx.output_format == AV_PIX_FMT_NONE) {
av_log(avctx, AV_LOG_ERROR, "Invalid output format.\n");
return AVERROR(EINVAL);
}
} else {
/* Default to re-using the input format */
s->vkctx.output_format = s->vkctx.input_format;
}
if (outlink->format != AV_PIX_FMT_VULKAN)
return 0;
s->vkctx.output_width = outlink->w;
s->vkctx.output_height = outlink->h;
/* Default to re-using the input format */
if (s->out_format == AV_PIX_FMT_NONE || s->out_format == AV_PIX_FMT_VULKAN) {
s->vkctx.output_format = s->vkctx.input_format;
} else {
s->vkctx.output_format = s->out_format;
}
RET(ff_vk_filter_config_output(outlink));
hwfc = (AVHWFramesContext *) outlink->hw_frames_ctx->data;
vkfc = hwfc->hwctx;