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.
This commit is contained in:
Niklas Haas 2023-06-13 15:44:13 +02:00
parent 7be4434c88
commit c3b17ccc62
1 changed files with 52 additions and 28 deletions

View File

@ -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;