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

Showing the changes to libavfilter (1 of 1 file). Show all

Unified · Split

libavfilter/vf_libplacebo.c+93−79
@@ -28,6 +28,14 @@ · 27 unmodified lines
28#include <libplacebo/utils/libav.h>28#include <libplacebo/utils/libav.h>
29#include <libplacebo/vulkan.h>29#include <libplacebo/vulkan.h>
30 30
31/* Backwards compatibility with older libplacebo */
32#if PL_API_VER < 276
33static inline AVFrame *pl_get_mapped_avframe(const struct pl_frame *frame)
34{
35 return frame->user_data;
36}
37#endif
38
31enum {39enum {
32 TONE_MAP_AUTO,40 TONE_MAP_AUTO,
33 TONE_MAP_CLIP,41 TONE_MAP_CLIP,
@@ -555,35 +563,27 @@ fail: · 521 unmodified lines
555 return err;563 return err;
556}564}
557 565
558static int process_frames(AVFilterContext *avctx, AVFrame *out, AVFrame *in)566static void update_crops(AVFilterContext *ctx,
567 struct pl_frame *image,
568 struct pl_frame *target,
569 const double target_pts)
559{570{
560 int err = 0, ok;571 LibplaceboContext *s = ctx->priv;
561 LibplaceboContext *s = avctx->priv;572 const AVFrame *in = pl_get_mapped_avframe(image);
562 const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(out->format);573 const AVFilterLink *inlink = ctx->inputs[0];
563 struct pl_frame image, target;574 const double in_pts = in->pts * av_q2d(inlink->time_base);
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 }
578 575
579 if (!ok) {576 s->var_values[VAR_IN_T] = s->var_values[VAR_T] = in_pts;
580 err = AVERROR_EXTERNAL;577 s->var_values[VAR_OUT_T] = s->var_values[VAR_OT] = target_pts;
581 goto fail;578 s->var_values[VAR_N] = inlink->frame_count_out;
582 }
583 579
584 if (!s->apply_filmgrain)580 /* Clear these explicitly to avoid leaking previous frames' state */
585 image.film_grain.type = PL_FILM_GRAIN_NONE;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;
586 585
586 /* Evaluate crop/pos dimensions first, and placement second */
587 s->var_values[VAR_CROP_W] = s->var_values[VAR_CW] =587 s->var_values[VAR_CROP_W] = s->var_values[VAR_CW] =
588 av_expr_eval(s->crop_w_pexpr, s->var_values, NULL);588 av_expr_eval(s->crop_w_pexpr, s->var_values, NULL);
589 s->var_values[VAR_CROP_H] = s->var_values[VAR_CH] =589 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
593 s->var_values[VAR_POS_H] = s->var_values[VAR_PH] =593 s->var_values[VAR_POS_H] = s->var_values[VAR_PH] =
594 av_expr_eval(s->pos_h_pexpr, s->var_values, NULL);594 av_expr_eval(s->pos_h_pexpr, s->var_values, NULL);
595 595
596 image.crop.x0 = av_expr_eval(s->crop_x_pexpr, s->var_values, NULL);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);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];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];599 image->crop.y1 = image->crop.y0 + s->var_values[VAR_CROP_H];
600 600
601 target.crop.x0 = av_expr_eval(s->pos_x_pexpr, s->var_values, NULL);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);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];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];604 target->crop.y1 = target->crop.y0 + s->var_values[VAR_POS_H];
605 605
606 if (s->target_sar.num) {606 if (s->target_sar.num) {
607 float aspect = pl_rect2df_aspect(&target.crop) * av_q2d(s->target_sar);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);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;
619 }609 }
620
621 /* Flush the command queues for performance */
622 pl_gpu_flush(s->gpu);
623 return 0;
624
625fail:
626 pl_unmap_avframe(s->gpu, &image);
627 pl_unmap_avframe(s->gpu, &target);
628 return err;
629}610}
630 611
631static int filter_frame(AVFilterLink *link, AVFrame *in)612/* Construct and emit an output frame for `image` */
613static int output_frame(AVFilterContext *ctx, struct pl_frame *image)
632{614{
633 int err, changed_csp;615 int err = 0, ok, changed_csp;
634 AVFilterContext *ctx = link->dst;
635 LibplaceboContext *s = ctx->priv;616 LibplaceboContext *s = ctx->priv;
636 AVFilterLink *outlink = ctx->outputs[0];617 AVFilterLink *outlink = ctx->outputs[0];
637 618 const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(outlink->format);
638 AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);619 AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h);
639 if (!out) {620 const AVFrame *in = pl_get_mapped_avframe(image);
640 err = AVERROR(ENOMEM);621 struct pl_frame target;
641 goto fail;622 if (!out)
642 }623 return AVERROR(ENOMEM);
643
644 pl_log_level_update(s->log, get_log_level());
645 624
646 RET(av_frame_copy_props(out, in));625 RET(av_frame_copy_props(out, in));
647 out->width = outlink->w;626 out->width = outlink->w;
648 out->height = outlink->h;627 out->height = outlink->h;
649 628
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
662 if (s->apply_dovi && av_frame_get_side_data(in, AV_FRAME_DATA_DOVI_METADATA)) {629 if (s->apply_dovi && av_frame_get_side_data(in, AV_FRAME_DATA_DOVI_METADATA)) {
663 /* Output of dovi reshaping is always BT.2020+PQ, so infer the correct630 /* Output of dovi reshaping is always BT.2020+PQ, so infer the correct
664 * output colorspace defaults */631 * output colorspace defaults */
@@ -694,18 +661,65 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) · 29 unmodified lines
694 if (s->apply_filmgrain)661 if (s->apply_filmgrain)
695 av_frame_remove_side_data(out, AV_FRAME_DATA_FILM_GRAIN_PARAMS);662 av_frame_remove_side_data(out, AV_FRAME_DATA_FILM_GRAIN_PARAMS);
696 663
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 }
698 677
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);
700 680
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 }
701 return ff_filter_frame(outlink, out);687 return ff_filter_frame(outlink, out);
702 688
703fail:689fail:
704 av_frame_free(&in);
705 av_frame_free(&out);690 av_frame_free(&out);
706 return err;691 return err;
707}692}
708 693
694static 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
709static int libplacebo_query_format(AVFilterContext *ctx)723static int libplacebo_query_format(AVFilterContext *ctx)
710{724{
711 int err;725 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