compositor: Skip background if transparent and obscured
authorNirbheek Chauhan <nirbheek@centricular.com>
Sun, 26 May 2019 15:47:20 +0000 (17:47 +0200)
committerNirbheek Chauhan <nirbheek@centricular.com>
Thu, 13 Jun 2019 15:01:50 +0000 (20:31 +0530)
If the background is transparent and obscured by a pad that may or may
not have alpha, we can still skip drawing it entirely

AYUV 1080p ! compositor background=transparent ! fakesink - 75% faster

gst/compositor/compositor.c

index fee1936..6bd6fca 100644 (file)
@@ -314,7 +314,7 @@ clamp_rectangle (gint x, gint y, gint w, gint h, gint outer_width,
 /* Call this with the lock taken */
 static gboolean
 _pad_obscures_rectangle (GstVideoAggregator * vagg, GstVideoAggregatorPad * pad,
-    GstVideoRectangle rect)
+    GstVideoRectangle rect, gboolean rect_transparent)
 {
   GstVideoRectangle pad_rect;
   GstCompositorPad *cpad = GST_COMPOSITOR_PAD (pad);
@@ -325,8 +325,10 @@ _pad_obscures_rectangle (GstVideoAggregator * vagg, GstVideoAggregatorPad * pad,
 
   /* Can't obscure if it's transparent and if the format has an alpha component
    * we'd have to inspect every pixel to know if the frame is opaque, so assume
-   * it doesn't obscure. */
-  if (cpad->alpha != 1.0 || GST_VIDEO_INFO_HAS_ALPHA (&pad->info))
+   * it doesn't obscure. As a bonus, if the rectangle is fully transparent, we
+   * can also obscure it if we have alpha components on the pad */
+  if (!rect_transparent &&
+      (cpad->alpha != 1.0 || GST_VIDEO_INFO_HAS_ALPHA (&pad->info)))
     return FALSE;
 
   pad_rect.x = cpad->xpos;
@@ -393,7 +395,7 @@ gst_compositor_pad_prepare_frame (GstVideoAggregatorPad * pad,
    * higher-zorder frames */
   l = g_list_find (GST_ELEMENT (vagg)->sinkpads, pad)->next;
   for (; l; l = l->next) {
-    if (_pad_obscures_rectangle (vagg, l->data, frame_rect)) {
+    if (_pad_obscures_rectangle (vagg, l->data, frame_rect, FALSE)) {
       frame_obscured = TRUE;
       break;
     }
@@ -837,7 +839,7 @@ _negotiated_caps (GstAggregator * agg, GstCaps * caps)
 }
 
 static gboolean
-_should_draw_background (GstVideoAggregator * vagg)
+_should_draw_background (GstVideoAggregator * vagg, gboolean bg_transparent)
 {
   GstVideoRectangle bg_rect;
   gboolean draw = TRUE;
@@ -849,7 +851,7 @@ _should_draw_background (GstVideoAggregator * vagg)
   /* Check if the background is completely obscured by a pad
    * TODO: Also skip if it's obscured by a combination of pads */
   for (GList * l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
-    if (_pad_obscures_rectangle (vagg, l->data, bg_rect)) {
+    if (_pad_obscures_rectangle (vagg, l->data, bg_rect, bg_transparent)) {
       draw = FALSE;
       break;
     }
@@ -865,8 +867,11 @@ _draw_background (GstVideoAggregator * vagg, GstVideoFrame * outframe)
   BlendFunction composite = comp->blend;
 
   /* If one of the frames to be composited completely obscures the background,
-   * don't bother drawing the background at all. */
-  if (!_should_draw_background (vagg))
+   * 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;
 
   switch (comp->background) {