From 921417138f3c4c36b703e05f05ba69a42079bec6 Mon Sep 17 00:00:00 2001 From: Nirbheek Chauhan Date: Fri, 14 Jun 2019 02:32:50 +0530 Subject: [PATCH] compositor: Copy frames as-is when possible The blend functions for alpha formats need to do more work than just doing a memcpy, so we can do a memcpy when we know that a blend is not actually needed. 1080p AYUV ! compositor background=transparent ! fakesink - 56% faster Specifically, when we don't draw the background and the first pad we draw completely covers the output frame, we can just copy it as-is. The rest of the pads (if any) will get composited on top normally. --- gst/compositor/compositor.c | 44 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/gst/compositor/compositor.c b/gst/compositor/compositor.c index 9332bdc..09f970f 100644 --- a/gst/compositor/compositor.c +++ b/gst/compositor/compositor.c @@ -863,19 +863,20 @@ _should_draw_background (GstVideoAggregator * vagg, gboolean bg_transparent) return draw; } -static BlendFunction -_draw_background (GstVideoAggregator * vagg, GstVideoFrame * outframe) +static gboolean +_draw_background (GstVideoAggregator * vagg, GstVideoFrame * outframe, + BlendFunction * composite) { GstCompositor *comp = GST_COMPOSITOR (vagg); - BlendFunction composite = comp->blend; + *composite = comp->blend; /* If one of the frames to be composited completely obscures the background, * don't bother drawing the background at all. We can also always use the * 'blend' BlendFunction in that case because it only changes if we have to * overlay on top of a transparent background. */ if (!_should_draw_background (vagg, comp->background == COMPOSITOR_BACKGROUND_TRANSPARENT)) - return composite; + return FALSE; switch (comp->background) { case COMPOSITOR_BACKGROUND_CHECKER: @@ -907,12 +908,24 @@ _draw_background (GstVideoAggregator * vagg, GstVideoFrame * outframe) } } /* use overlay to keep background transparent */ - composite = comp->overlay; + *composite = comp->overlay; break; } } - return composite; + return TRUE; +} + +static gboolean +frames_can_copy (const GstVideoFrame * frame1, const GstVideoFrame * frame2) +{ + if (GST_VIDEO_FRAME_FORMAT (frame1) != GST_VIDEO_FRAME_FORMAT (frame2)) + return FALSE; + if (GST_VIDEO_FRAME_HEIGHT (frame1) != GST_VIDEO_FRAME_HEIGHT (frame2)) + return FALSE; + if (GST_VIDEO_FRAME_WIDTH (frame1) != GST_VIDEO_FRAME_WIDTH (frame2)) + return FALSE; + return TRUE; } static GstFlowReturn @@ -921,6 +934,8 @@ gst_compositor_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf) GList *l; BlendFunction composite; GstVideoFrame out_frame, *outframe; + gboolean drew_background; + guint drawn_pads = 0; if (!gst_video_frame_map (&out_frame, &vagg->info, outbuf, GST_MAP_WRITE)) { GST_WARNING_OBJECT (vagg, "Could not map output buffer"); @@ -928,7 +943,7 @@ gst_compositor_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf) } outframe = &out_frame; - composite = _draw_background (vagg, outframe); + drew_background = _draw_background (vagg, outframe, &composite); GST_OBJECT_LOCK (vagg); for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) { @@ -954,9 +969,18 @@ gst_compositor_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf) } if (prepared_frame != NULL) { - composite (prepared_frame, - compo_pad->xpos, - compo_pad->ypos, compo_pad->alpha, outframe, blend_mode); + /* If this is the first pad we're drawing, and we didn't draw the + * background, and @prepared_frame has the same format, height, and width + * as @outframe, then we can just copy it as-is. Subsequent pads (if any) + * will be composited on top of it. */ + if (drawn_pads == 0 && !drew_background && + frames_can_copy (prepared_frame, outframe)) + gst_video_frame_copy (outframe, prepared_frame); + else + composite (prepared_frame, + compo_pad->xpos, + compo_pad->ypos, compo_pad->alpha, outframe, blend_mode); + drawn_pads++; } } GST_OBJECT_UNLOCK (vagg); -- 2.7.4