Sometimes, one input fully obscures another. In this case, we can skip actually rendering any input below the obscuring one. The reason I don't simply start the main render loop at `idx_start` will become apparent in the following commit. We can't use pl_frame_is_cropped() on this dummy frame, but we need to determine the reference frame before we can map the real output, so to resolve this conflict, we just reimplement the crop detection logic using the output link dimensions.
Unified · Split
| @@ -16,6 +16,8 @@ · 15 unmodified lines | ||
| 16 | 16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 17 | 17 | */ |
| 18 | 18 | |
| 19 | +#include <math.h> | |
| 20 | + | |
| 19 | 21 | #include "libavutil/avassert.h" |
| 20 | 22 | #include "libavutil/eval.h" |
| 21 | 23 | #include "libavutil/fifo.h" |
| @@ -913,10 +915,39 @@ static int output_frame(AVFilterContext *ctx, int64_t pts) · 891 unmodified lines | ||
| 913 | 915 | pl_options opts = s->opts; |
| 914 | 916 | AVFilterLink *outlink = ctx->outputs[0]; |
| 915 | 917 | const AVPixFmtDescriptor *outdesc = av_pix_fmt_desc_get(outlink->format); |
| 918 | + const double target_pts = pts * av_q2d(outlink->time_base); | |
| 916 | 919 | struct pl_frame target; |
| 917 | 920 | const AVFrame *ref = NULL; |
| 918 | 921 | AVFrame *out; |
| 919 | 922 | |
| 923 | + /* Count the number of visible inputs, by excluding frames which are fully | |
| 924 | + * obscured or which have no frames in the mix */ | |
| 925 | + int idx_start = 0, nb_visible = 0; | |
| 926 | + for (int i = 0; i < s->nb_inputs; i++) { | |
| 927 | + LibplaceboInput *in = &s->inputs[i]; | |
| 928 | + struct pl_frame dummy; | |
| 929 | + if (in->qstatus != PL_QUEUE_OK || !in->mix.num_frames) | |
| 930 | + continue; | |
| 931 | + const struct pl_frame *cur = pl_frame_mix_current(&in->mix); | |
| 932 | + update_crops(ctx, in, &dummy, target_pts); | |
| 933 | + const int x0 = roundf(FFMIN(dummy.crop.x0, dummy.crop.x1)), | |
| 934 | + y0 = roundf(FFMIN(dummy.crop.y0, dummy.crop.y1)), | |
| 935 | + x1 = roundf(FFMAX(dummy.crop.x0, dummy.crop.x1)), | |
| 936 | + y1 = roundf(FFMAX(dummy.crop.y0, dummy.crop.y1)); | |
| 937 | + | |
| 938 | + /* If an opaque frame covers entire the output, disregard all lower layers */ | |
| 939 | + const bool cropped = x0 > 0 || y0 > 0 || x1 < outlink->w || y1 < outlink->h; | |
| 940 | + if (!cropped && cur->repr.alpha == PL_ALPHA_NONE) { | |
| 941 | + idx_start = i; | |
| 942 | + nb_visible = 0; | |
| 943 | + } | |
| 944 | + nb_visible++; | |
| 945 | + } | |
| 946 | + | |
| 947 | + /* It should be impossible to call output_frame() without at least one | |
| 948 | + * valid nonempty frame mix */ | |
| 949 | + av_assert1(nb_visible > 0); | |
| 950 | + | |
| 920 | 951 | /* Use the first active input as metadata reference */ |
| 921 | 952 | for (int i = 0; i < s->nb_inputs; i++) { |
| 922 | 953 | const LibplaceboInput *in = &s->inputs[i]; |
| @@ -989,7 +1020,8 @@ static int output_frame(AVFilterContext *ctx, int64_t pts) · 66 unmodified lines | ||
| 989 | 1020 | |
| 990 | 1021 | struct pl_frame orig_target = target; |
| 991 | 1022 | bool use_linear_compositor = false; |
| 992 | − if (s->linear_tex && target.color.transfer != PL_COLOR_TRC_LINEAR && !s->disable_linear) { | |
| 1023 | + if (s->linear_tex && target.color.transfer != PL_COLOR_TRC_LINEAR && | |
| 1024 | + !s->disable_linear && nb_visible > 1) { | |
| 993 | 1025 | target = (struct pl_frame) { |
| 994 | 1026 | .num_planes = 1, |
| 995 | 1027 | .planes[0] = { |
| @@ -1017,10 +1049,10 @@ static int output_frame(AVFilterContext *ctx, int64_t pts) · 21 unmodified lines | ||
| 1017 | 1049 | FilterLink *il = ff_filter_link(ctx->inputs[i]); |
| 1018 | 1050 | FilterLink *ol = ff_filter_link(outlink); |
| 1019 | 1051 | int high_fps = av_cmp_q(il->frame_rate, ol->frame_rate) >= 0; |
| 1020 | − if (in->qstatus != PL_QUEUE_OK || !in->mix.num_frames) | |
| 1052 | + if (in->qstatus != PL_QUEUE_OK || !in->mix.num_frames || i < idx_start) | |
| 1021 | 1053 | continue; |
| 1022 | 1054 | opts->params.skip_caching_single_frame = high_fps; |
| 1023 | − update_crops(ctx, in, &target, out->pts * av_q2d(outlink->time_base)); | |
| 1055 | + update_crops(ctx, in, &target, target_pts); | |
| 1024 | 1056 | pl_render_image_mix(in->renderer, &in->mix, &target, &opts->params); |
| 1025 | 1057 | |
| 1026 | 1058 | /* Force straight output and set correct blend mode */ |