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.
This commit is contained in:
Nirbheek Chauhan 2019-06-14 02:32:50 +05:30
parent eaade96409
commit abd80b6561

View file

@ -861,19 +861,20 @@ _should_draw_background (GstVideoAggregator * vagg, gboolean bg_transparent)
return draw; return draw;
} }
static BlendFunction static gboolean
_draw_background (GstVideoAggregator * vagg, GstVideoFrame * outframe) _draw_background (GstVideoAggregator * vagg, GstVideoFrame * outframe,
BlendFunction * composite)
{ {
GstCompositor *comp = GST_COMPOSITOR (vagg); GstCompositor *comp = GST_COMPOSITOR (vagg);
BlendFunction composite = comp->blend;
*composite = comp->blend;
/* If one of the frames to be composited completely obscures the background, /* 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 * 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 * 'blend' BlendFunction in that case because it only changes if we have to
* overlay on top of a transparent background. */ * overlay on top of a transparent background. */
if (!_should_draw_background (vagg, if (!_should_draw_background (vagg,
comp->background == COMPOSITOR_BACKGROUND_TRANSPARENT)) comp->background == COMPOSITOR_BACKGROUND_TRANSPARENT))
return composite; return FALSE;
switch (comp->background) { switch (comp->background) {
case COMPOSITOR_BACKGROUND_CHECKER: case COMPOSITOR_BACKGROUND_CHECKER:
@ -905,12 +906,24 @@ _draw_background (GstVideoAggregator * vagg, GstVideoFrame * outframe)
} }
} }
/* use overlay to keep background transparent */ /* use overlay to keep background transparent */
composite = comp->overlay; *composite = comp->overlay;
break; 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 static GstFlowReturn
@ -919,6 +932,8 @@ gst_compositor_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
GList *l; GList *l;
BlendFunction composite; BlendFunction composite;
GstVideoFrame out_frame, *outframe; GstVideoFrame out_frame, *outframe;
gboolean drew_background;
guint drawn_pads = 0;
if (!gst_video_frame_map (&out_frame, &vagg->info, outbuf, GST_MAP_WRITE)) { if (!gst_video_frame_map (&out_frame, &vagg->info, outbuf, GST_MAP_WRITE)) {
GST_WARNING_OBJECT (vagg, "Could not map output buffer"); GST_WARNING_OBJECT (vagg, "Could not map output buffer");
@ -926,7 +941,7 @@ gst_compositor_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
} }
outframe = &out_frame; outframe = &out_frame;
composite = _draw_background (vagg, outframe); drew_background = _draw_background (vagg, outframe, &composite);
GST_OBJECT_LOCK (vagg); GST_OBJECT_LOCK (vagg);
for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) { for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
@ -952,9 +967,18 @@ gst_compositor_aggregate_frames (GstVideoAggregator * vagg, GstBuffer * outbuf)
} }
if (prepared_frame != NULL) { if (prepared_frame != NULL) {
composite (prepared_frame, /* If this is the first pad we're drawing, and we didn't draw the
compo_pad->xpos, * background, and @prepared_frame has the same format, height, and width
compo_pad->ypos, compo_pad->alpha, outframe, blend_mode); * 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); GST_OBJECT_UNLOCK (vagg);