1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-12-28 20:53:54 +02:00

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_vulkan vulkan;
pl_gpu gpu; pl_gpu gpu;
pl_renderer renderer; pl_renderer renderer;
pl_tex tex[4]; pl_tex tex[8];
/* settings */ /* settings */
char *out_format_string; char *out_format_string;
enum AVPixelFormat out_format;
char *w_expr; char *w_expr;
char *h_expr; char *h_expr;
AVRational target_sar; AVRational target_sar;
@ -215,6 +216,8 @@ static int find_scaler(AVFilterContext *avctx,
return AVERROR(EINVAL); return AVERROR(EINVAL);
} }
static void libplacebo_uninit(AVFilterContext *avctx);
static int libplacebo_init(AVFilterContext *avctx) static int libplacebo_init(AVFilterContext *avctx)
{ {
LibplaceboContext *s = avctx->priv; LibplaceboContext *s = avctx->priv;
@ -229,6 +232,18 @@ static int libplacebo_init(AVFilterContext *avctx)
if (!s->log) if (!s->log)
return AVERROR(ENOMEM); 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 */ /* Note: s->vulkan etc. are initialized later, when hwctx is available */
return 0; return 0;
} }
@ -320,6 +335,7 @@ static int process_frames(AVFilterContext *avctx, AVFrame *out, AVFrame *in)
LibplaceboContext *s = avctx->priv; LibplaceboContext *s = avctx->priv;
struct pl_render_params params; struct pl_render_params params;
enum pl_tone_map_mode tonemapping_mode = s->tonemapping_mode; 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; enum pl_gamut_mode gamut_mode = s->gamut_mode;
struct pl_frame image, target; struct pl_frame image, target;
ok = pl_map_avframe_ex(s->gpu, &image, pl_avframe_params( 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, .map_dovi = s->apply_dovi,
)); ));
ok &= pl_map_avframe_ex(s->gpu, &target, pl_avframe_params( if (outdesc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
.frame = out, ok &= pl_map_avframe_ex(s->gpu, &target, pl_avframe_params(
.map_dovi = false, .frame = out,
)); .map_dovi = false,
));
} else {
ok &= pl_frame_recreate_from_avframe(s->gpu, &target, s->tex + 4, out);
}
if (!ok) { if (!ok) {
err = AVERROR_EXTERNAL; 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_render_image(s->renderer, &image, &target, &params);
pl_unmap_avframe(s->gpu, &image); 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 */ /* Flush the command queues for performance */
pl_gpu_flush(s->gpu); pl_gpu_flush(s->gpu);
@ -516,10 +542,7 @@ static int libplacebo_query_format(AVFilterContext *ctx)
int err = 0; int err = 0;
LibplaceboContext *s = ctx->priv; LibplaceboContext *s = ctx->priv;
const AVPixFmtDescriptor *desc = NULL; const AVPixFmtDescriptor *desc = NULL;
AVFilterFormats *in_fmts = NULL; AVFilterFormats *formats = NULL;
static const enum AVPixelFormat out_fmts[] = {
AV_PIX_FMT_VULKAN, AV_PIX_FMT_NONE,
};
RET(init_vulkan(ctx)); RET(init_vulkan(ctx));
@ -534,14 +557,24 @@ static int libplacebo_query_format(AVFilterContext *ctx)
#endif #endif
if (pl_test_pixfmt(s->gpu, pixfmt)) { 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; return err;
} }
} }
RET(ff_formats_ref(in_fmts, &ctx->inputs[0]->outcfg.formats)); RET(ff_formats_ref(formats, &ctx->inputs[0]->outcfg.formats));
RET(ff_formats_ref(ff_make_format_list(out_fmts),
&ctx->outputs[0]->incfg.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; return 0;
@ -572,17 +605,15 @@ static int libplacebo_config_output(AVFilterLink *outlink)
AVHWFramesContext *hwfc; AVHWFramesContext *hwfc;
AVVulkanFramesContext *vkfc; AVVulkanFramesContext *vkfc;
AVRational scale_sar; 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, 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_original_aspect_ratio,
s->force_divisible_by); 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) if (inlink->sample_aspect_ratio.num)
scale_sar = av_mul_q(scale_sar, inlink->sample_aspect_ratio); 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; outlink->sample_aspect_ratio = scale_sar;
} }
if (s->out_format_string) { if (outlink->format != AV_PIX_FMT_VULKAN)
s->vkctx.output_format = av_get_pix_fmt(s->out_format_string); return 0;
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;
}
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)); RET(ff_vk_filter_config_output(outlink));
hwfc = (AVHWFramesContext *) outlink->hw_frames_ctx->data; hwfc = (AVHWFramesContext *) outlink->hw_frames_ctx->data;
vkfc = hwfc->hwctx; vkfc = hwfc->hwctx;