From c3b17ccc6251ec26ac3a06ed2571b45489ce7f46 Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Tue, 13 Jun 2023 15:44:13 +0200 Subject: [PATCH] lavfi/vf_libplacebo: move input-specific state to struct In anticipation of a refactor which will enable multiple input support. Note: the renderer is also input-specific because it maintains a frame cache, HDR peak detection state and mixing cache, all of which are tied to a specific input stream. --- libavfilter/vf_libplacebo.c | 80 ++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 28 deletions(-) diff --git a/libavfilter/vf_libplacebo.c b/libavfilter/vf_libplacebo.c index a048424cec..10fd432745 100644 --- a/libavfilter/vf_libplacebo.c +++ b/libavfilter/vf_libplacebo.c @@ -113,6 +113,16 @@ enum var_name { VAR_VARS_NB }; +/* per-input dynamic filter state */ +typedef struct LibplaceboInput { + pl_renderer renderer; + pl_queue queue; + AVFilterLink *link; + AVFifo *out_pts; ///< timestamps of wanted output frames + int64_t status_pts; + int status; +} LibplaceboInput; + typedef struct LibplaceboContext { /* lavfi vulkan*/ FFVulkanContext vkctx; @@ -121,14 +131,10 @@ typedef struct LibplaceboContext { pl_log log; pl_vulkan vulkan; pl_gpu gpu; - pl_renderer renderer; - pl_queue queue; pl_tex tex[4]; - /* filter state */ - AVFifo *out_pts; ///< timestamps of wanted output frames - int64_t status_pts; - int status; + /* input state */ + LibplaceboInput input; /* settings */ char *out_format_string; @@ -536,8 +542,6 @@ static int libplacebo_init(AVFilterContext *avctx) RET(av_expr_parse(&s->pos_h_pexpr, s->pos_h_expr, var_names, NULL, NULL, NULL, NULL, 0, s)); - /* Initialize dynamic filter state */ - s->out_pts = av_fifo_alloc2(1, sizeof(int64_t), AV_FIFO_FLAG_AUTO_GROW); if (strcmp(s->fps_string, "none") != 0) RET(av_parse_video_rate(&s->fps, s->fps_string)); @@ -564,6 +568,28 @@ static void unlock_queue(void *priv, uint32_t qf, uint32_t qidx) } #endif +static int input_init(AVFilterContext *avctx, AVFilterLink *link, + LibplaceboInput *input) +{ + LibplaceboContext *s = avctx->priv; + + input->out_pts = av_fifo_alloc2(1, sizeof(int64_t), AV_FIFO_FLAG_AUTO_GROW); + if (!input->out_pts) + return AVERROR(ENOMEM); + input->queue = pl_queue_create(s->gpu); + input->renderer = pl_renderer_create(s->log, s->gpu); + input->link = link; + + return 0; +} + +static void input_uninit(LibplaceboInput *input) +{ + pl_renderer_destroy(&input->renderer); + pl_queue_destroy(&input->queue); + av_fifo_freep2(&input->out_pts); +} + static int init_vulkan(AVFilterContext *avctx, const AVVulkanDeviceContext *hwctx) { int err = 0; @@ -620,10 +646,7 @@ static int init_vulkan(AVFilterContext *avctx, const AVVulkanDeviceContext *hwct goto fail; } - /* Create the renderer */ s->gpu = s->vulkan->gpu; - s->renderer = pl_renderer_create(s->log, s->gpu); - s->queue = pl_queue_create(s->gpu); /* Parse the user shaders, if requested */ if (s->shader_bin_len) @@ -634,6 +657,9 @@ static int init_vulkan(AVFilterContext *avctx, const AVVulkanDeviceContext *hwct RET(parse_shader(avctx, buf, buf_len)); } + /* Initialize inputs */ + RET(input_init(avctx, avctx->inputs[0], &s->input)); + /* fall through */ fail: if (buf) @@ -649,8 +675,7 @@ static void libplacebo_uninit(AVFilterContext *avctx) pl_tex_destroy(s->gpu, &s->tex[i]); for (int i = 0; i < s->num_hooks; i++) pl_mpv_user_shader_destroy(&s->hooks[i]); - pl_renderer_destroy(&s->renderer); - pl_queue_destroy(&s->queue); + input_uninit(&s->input); pl_vulkan_destroy(&s->vulkan); pl_log_destroy(&s->log); ff_vk_uninit(&s->vkctx); @@ -664,7 +689,6 @@ static void libplacebo_uninit(AVFilterContext *avctx) av_expr_free(s->pos_y_pexpr); av_expr_free(s->pos_w_pexpr); av_expr_free(s->pos_h_pexpr); - av_fifo_freep2(&s->out_pts); } static int libplacebo_process_command(AVFilterContext *ctx, const char *cmd, @@ -826,7 +850,7 @@ static int output_frame_mix(AVFilterContext *ctx, } update_crops(ctx, mix, &target, ref_sig, out->pts * av_q2d(outlink->time_base)); - pl_render_image_mix(s->renderer, mix, &target, &s->params); + pl_render_image_mix(s->input.renderer, mix, &target, &s->params); if (outdesc->flags & AV_PIX_FMT_FLAG_HWACCEL) { pl_unmap_avframe(s->gpu, &target); @@ -886,7 +910,7 @@ static int libplacebo_activate(AVFilterContext *ctx) while ((ret = ff_inlink_consume_frame(inlink, &in)) > 0) { in->opaque = s; - pl_queue_push(s->queue, &(struct pl_source_frame) { + pl_queue_push(s->input.queue, &(struct pl_source_frame) { .pts = in->pts * av_q2d(inlink->time_base), .duration = in->duration * av_q2d(inlink->time_base), .first_field = pl_field_from_avframe(in), @@ -899,19 +923,19 @@ static int libplacebo_activate(AVFilterContext *ctx) if (!s->fps.num) { /* Internally queue an output frame for the same PTS */ av_assert1(!av_cmp_q(inlink->time_base, outlink->time_base)); - av_fifo_write(s->out_pts, &in->pts, 1); + av_fifo_write(s->input.out_pts, &in->pts, 1); } } if (ret < 0) return ret; - if (!s->status && ff_inlink_acknowledge_status(inlink, &status, &pts)) { + if (!s->input.status && ff_inlink_acknowledge_status(inlink, &status, &pts)) { pts = av_rescale_q_rnd(pts, inlink->time_base, outlink->time_base, AV_ROUND_UP); - pl_queue_push(s->queue, NULL); /* Signal EOF to pl_queue */ - s->status = status; - s->status_pts = pts; + pl_queue_push(s->input.queue, NULL); /* Signal EOF to pl_queue */ + s->input.status = status; + s->input.status_pts = pts; } if (ff_outlink_frame_wanted(outlink)) { @@ -920,22 +944,22 @@ static int libplacebo_activate(AVFilterContext *ctx) if (s->fps.num) { pts = outlink->frame_count_out; - } else if (av_fifo_peek(s->out_pts, &pts, 1, 0) < 0) { + } else if (av_fifo_peek(s->input.out_pts, &pts, 1, 0) < 0) { /* No frames queued */ - if (s->status) { - pts = s->status_pts; + if (s->input.status) { + pts = s->input.status_pts; } else { ff_inlink_request_frame(inlink); return 0; } } - if (s->status && pts >= s->status_pts) { - ff_outlink_set_status(outlink, s->status, s->status_pts); + if (s->input.status && pts >= s->input.status_pts) { + ff_outlink_set_status(outlink, s->input.status, s->input.status_pts); return 0; } - ret = pl_queue_update(s->queue, &mix, pl_queue_params( + ret = pl_queue_update(s->input.queue, &mix, pl_queue_params( .pts = pts * av_q2d(outlink->time_base), .radius = pl_frame_mix_radius(&s->params), .vsync_duration = av_q2d(av_inv_q(outlink->frame_rate)), @@ -947,7 +971,7 @@ static int libplacebo_activate(AVFilterContext *ctx) return 0; case PL_QUEUE_OK: if (!s->fps.num) - av_fifo_drain2(s->out_pts, 1); + av_fifo_drain2(s->input.out_pts, 1); return output_frame_mix(ctx, &mix, pts); case PL_QUEUE_ERR: return AVERROR_EXTERNAL;