History

lavfi/vf_libplacebo: split and refactor logic

This commit contains no functional change. The goal is merely to separate the highly intertwined `filter_frame` and `process_frames` functions into their separate concerns, specifically to separate frame uploading (which is now done directly in `filter_frame`) from emitting a frame (which is now done by a dedicated function `output_frame`). The overall idea here is to be able to ultimately call `output_frame` multiple times, to e.g. emit several output frames for a single input frame.

Niklas Haas committed 3 years ago

Commit 2d5e1371 parent 482d8131 file · +93 −79Browse files

Unified · Split

libavfilter/vf_libplacebo.c+93−79
@@ -28,6 +28,14 @@ · 27 unmodified lines
2828 #include <libplacebo/utils/libav.h>
2929 #include <libplacebo/vulkan.h>
3030
31+/* Backwards compatibility with older libplacebo */
32+#if PL_API_VER < 276
33+static inline AVFrame *pl_get_mapped_avframe(const struct pl_frame *frame)
34+{
35+ return frame->user_data;
36+}
37+#endif
38+
3139 enum {
3240 TONE_MAP_AUTO,
3341 TONE_MAP_CLIP,
@@ -555,35 +563,27 @@ fail: · 521 unmodified lines
555563 return err;
556564 }
557565
558−static int process_frames(AVFilterContext *avctx, AVFrame *out, AVFrame *in)
566+static void update_crops(AVFilterContext *ctx,
567+ struct pl_frame *image,
568+ struct pl_frame *target,
569+ const double target_pts)
559570 {
560− int err = 0, ok;
561− LibplaceboContext *s = avctx->priv;
562− const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->format);
563− struct pl_frame image, target;
564− ok = pl_map_avframe_ex(s->gpu, &image, pl_avframe_params(
565− .frame = in,
566− .tex = s->tex,
567− .map_dovi = s->apply_dovi,
568− ));
569−
570− if (outdesc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
571− ok &= pl_map_avframe_ex(s->gpu, &target, pl_avframe_params(
572− .frame = out,
573− .map_dovi = false,
574− ));
575− } else {
576− ok &= pl_frame_recreate_from_avframe(s->gpu, &target, s->tex + 4, out);
577− }
571+ LibplaceboContext *s = ctx->priv;
572+ const AVFrame *in = pl_get_mapped_avframe(image);
573+ const AVFilterLink *inlink = ctx->inputs[0];
574+ const double in_pts = in->pts * av_q2d(inlink->time_base);
578575
579− if (!ok) {
580− err = AVERROR_EXTERNAL;
581− goto fail;
582− }
576+ s->var_values[VAR_IN_T] = s->var_values[VAR_T] = in_pts;
577+ s->var_values[VAR_OUT_T] = s->var_values[VAR_OT] = target_pts;
578+ s->var_values[VAR_N] = inlink->frame_count_out;
583579
584− if (!s->apply_filmgrain)
585− image.film_grain.type = PL_FILM_GRAIN_NONE;
580+ /* Clear these explicitly to avoid leaking previous frames' state */
581+ s->var_values[VAR_CROP_W] = s->var_values[VAR_CW] = NAN;
582+ s->var_values[VAR_CROP_H] = s->var_values[VAR_CH] = NAN;
583+ s->var_values[VAR_POS_W] = s->var_values[VAR_PW] = NAN;
584+ s->var_values[VAR_POS_H] = s->var_values[VAR_PH] = NAN;
586585
586+ /* Evaluate crop/pos dimensions first, and placement second */
587587 s->var_values[VAR_CROP_W] = s->var_values[VAR_CW] =
588588 av_expr_eval(s->crop_w_pexpr, s->var_values, NULL);
589589 s->var_values[VAR_CROP_H] = s->var_values[VAR_CH] =
@@ -593,72 +593,39 @@ static int process_frames(AVFilterContext *avctx, AVFrame *out, AVFrame *in) · 3 unmodified lines
593593 s->var_values[VAR_POS_H] = s->var_values[VAR_PH] =
594594 av_expr_eval(s->pos_h_pexpr, s->var_values, NULL);
595595
596− image.crop.x0 = av_expr_eval(s->crop_x_pexpr, s->var_values, NULL);
597− image.crop.y0 = av_expr_eval(s->crop_y_pexpr, s->var_values, NULL);
598− image.crop.x1 = image.crop.x0 + s->var_values[VAR_CROP_W];
599− image.crop.y1 = image.crop.y0 + s->var_values[VAR_CROP_H];
596+ image->crop.x0 = av_expr_eval(s->crop_x_pexpr, s->var_values, NULL);
597+ image->crop.y0 = av_expr_eval(s->crop_y_pexpr, s->var_values, NULL);
598+ image->crop.x1 = image->crop.x0 + s->var_values[VAR_CROP_W];
599+ image->crop.y1 = image->crop.y0 + s->var_values[VAR_CROP_H];
600600
601− target.crop.x0 = av_expr_eval(s->pos_x_pexpr, s->var_values, NULL);
602− target.crop.y0 = av_expr_eval(s->pos_y_pexpr, s->var_values, NULL);
603− target.crop.x1 = target.crop.x0 + s->var_values[VAR_POS_W];
604− target.crop.y1 = target.crop.y0 + s->var_values[VAR_POS_H];
601+ target->crop.x0 = av_expr_eval(s->pos_x_pexpr, s->var_values, NULL);
602+ target->crop.y0 = av_expr_eval(s->pos_y_pexpr, s->var_values, NULL);
603+ target->crop.x1 = target->crop.x0 + s->var_values[VAR_POS_W];
604+ target->crop.y1 = target->crop.y0 + s->var_values[VAR_POS_H];
605605
606606 if (s->target_sar.num) {
607− float aspect = pl_rect2df_aspect(&target.crop) * av_q2d(s->target_sar);
608− pl_rect2df_aspect_set(&target.crop, aspect, s->pad_crop_ratio);
609− }
610−
611− pl_render_image(s->renderer, &image, &target, &s->params);
612− pl_unmap_avframe(s->gpu, &image);
613−
614− if (outdesc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
615− pl_unmap_avframe(s->gpu, &target);
616− } else if (!pl_download_avframe(s->gpu, &target, out)) {
617− err = AVERROR_EXTERNAL;
618− goto fail;
607+ float aspect = pl_rect2df_aspect(&target->crop) * av_q2d(s->target_sar);
608+ pl_rect2df_aspect_set(&target->crop, aspect, s->pad_crop_ratio);
619609 }
620−
621− /* Flush the command queues for performance */
622− pl_gpu_flush(s->gpu);
623− return 0;
624−
625−fail:
626− pl_unmap_avframe(s->gpu, &image);
627− pl_unmap_avframe(s->gpu, &target);
628− return err;
629610 }
630611
631−static int filter_frame(AVFilterLink *link, AVFrame *in)
612+/* Construct and emit an output frame for `image` */
613+static int output_frame(AVFilterContext *ctx, struct pl_frame *image)
632614 {
633− int err, changed_csp;
634− AVFilterContext *ctx = link->dst;
615+ int err = 0, ok, changed_csp;
635616 LibplaceboContext *s = ctx->priv;
636617 AVFilterLink *outlink = ctx->outputs[0];
637−
618+ const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(outlink->format);
638619 AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
639− if (!out) {
640− err = AVERROR(ENOMEM);
641− goto fail;
642− }
643−
644− pl_log_level_update(s->log, get_log_level());
620+ const AVFrame *in = pl_get_mapped_avframe(image);
621+ struct pl_frame target;
622+ if (!out)
623+ return AVERROR(ENOMEM);
645624
646625 RET(av_frame_copy_props(out, in));
647626 out->width = outlink->w;
648627 out->height = outlink->h;
649628
650− /* Dynamic variables */
651− s->var_values[VAR_IN_T] = s->var_values[VAR_T] =
652− in->pts == AV_NOPTS_VALUE ? NAN : in->pts * av_q2d(link->time_base);
653− s->var_values[VAR_OUT_T] = s->var_values[VAR_OT] =
654− out->pts == AV_NOPTS_VALUE ? NAN : out->pts * av_q2d(outlink->time_base);
655− s->var_values[VAR_N] = link->frame_count_out;
656− /* Will be evaluated/set by `process_frames` */
657− s->var_values[VAR_CROP_W] = s->var_values[VAR_CW] = NAN;
658− s->var_values[VAR_CROP_H] = s->var_values[VAR_CH] = NAN;
659− s->var_values[VAR_POS_W] = s->var_values[VAR_PW] = NAN;
660− s->var_values[VAR_POS_H] = s->var_values[VAR_PH] = NAN;
661−
662629 if (s->apply_dovi && av_frame_get_side_data(in, AV_FRAME_DATA_DOVI_METADATA)) {
663630 /* Output of dovi reshaping is always BT.2020+PQ, so infer the correct
664631 * output colorspace defaults */
@@ -694,18 +661,65 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) · 29 unmodified lines
694661 if (s->apply_filmgrain)
695662 av_frame_remove_side_data(out, AV_FRAME_DATA_FILM_GRAIN_PARAMS);
696663
697− RET(process_frames(ctx, out, in));
664+ /* Map, render and unmap output frame */
665+ if (outdesc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
666+ ok = pl_map_avframe_ex(s->gpu, &target, pl_avframe_params(
667+ .frame = out,
668+ .map_dovi = false,
669+ ));
670+ } else {
671+ ok = pl_frame_recreate_from_avframe(s->gpu, &target, s->tex + 4, out);
672+ }
673+ if (!ok) {
674+ err = AVERROR_EXTERNAL;
675+ goto fail;
676+ }
698677
699− av_frame_free(&in);
678+ update_crops(ctx, image, &target, out->pts * av_q2d(outlink->time_base));
679+ pl_render_image(s->renderer, image, &target, &s->params);
700680
681+ if (outdesc->flags & AV_PIX_FMT_FLAG_HWACCEL) {
682+ pl_unmap_avframe(s->gpu, &target);
683+ } else if (!pl_download_avframe(s->gpu, &target, out)) {
684+ err = AVERROR_EXTERNAL;
685+ goto fail;
686+ }
701687 return ff_filter_frame(outlink, out);
702688
703689 fail:
704− av_frame_free(&in);
705690 av_frame_free(&out);
706691 return err;
707692 }
708693
694+static int filter_frame(AVFilterLink *link, AVFrame *in)
695+{
696+ int ret, ok;
697+ AVFilterContext *ctx = link->dst;
698+ LibplaceboContext *s = ctx->priv;
699+ struct pl_frame image;
700+
701+ pl_log_level_update(s->log, get_log_level());
702+
703+ /* Map input frame */
704+ ok = pl_map_avframe_ex(s->gpu, &image, pl_avframe_params(
705+ .frame = in,
706+ .tex = s->tex,
707+ .map_dovi = s->apply_dovi,
708+ ));
709+ av_frame_free(&in);
710+
711+ if (!s->apply_filmgrain)
712+ image.film_grain.type = PL_FILM_GRAIN_NONE;
713+
714+ if (!ok)
715+ return AVERROR_EXTERNAL;
716+
717+ ret = output_frame(ctx, &image);
718+
719+ pl_unmap_avframe(s->gpu, &image);
720+ return ret;
721+}
722+
709723 static int libplacebo_query_format(AVFilterContext *ctx)
710724 {
711725 int err;

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t