[FFmpeg-devel] [PATCH] avfilter/vf_libplacebo: support more output formats
Niklas Haas
ffmpeg at haasn.xyz
Wed Nov 23 15:26:53 EET 2022
From: Niklas Haas <git at haasn.dev>
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 at haasn.dev>
---
libavfilter/vf_libplacebo.c | 87 +++++++++++++++++++++++++------------
1 file changed, 59 insertions(+), 28 deletions(-)
diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c
index ce57e7539e..3678b60b7d 100644
--- a/libavfilter/vf_libplacebo.c
+++ b/libavfilter/vf_libplacebo.c
@@ -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, ¶ms);
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 */
+ 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;
--
2.38.1
More information about the ffmpeg-devel
mailing list