video-blend: fix blending of rectangles partially or fully outside of the video
authorVineeth T M <vineeth.tm@samsung.com>
Mon, 10 Nov 2014 11:06:35 +0000 (16:36 +0530)
committerTim-Philipp Müller <tim@centricular.com>
Sun, 16 Nov 2014 13:55:22 +0000 (13:55 +0000)
In case of overlay being completely or partially outside
the video frame, the offset calculations are not right,
which resulted in the overlay not being displayed as
expected, or crashes due to invalid memory access.

When the overlay rectangle is completely outside,
we need not render the overlay at all.

For partial display of overlay rectangles, src_yoff
was not being calculated, hence it was always clipping
the bottom half of the overlay, By calculating the
src_yoff, now the overlay is clipped properly.

https://bugzilla.gnome.org/show_bug.cgi?id=739281

gst-libs/gst/video/video-blend.c

index a9433b1fe459cbac1dc27303f31e9080ce85cba4..dd17402cb471cfe661aab1b70d337b44799af141 100644 (file)
@@ -263,8 +263,8 @@ gboolean
 gst_video_blend (GstVideoFrame * dest,
     GstVideoFrame * src, gint x, gint y, gfloat global_alpha)
 {
-  guint i, j, global_alpha_val, src_width, src_height, dest_width, dest_height;
-  gint xoff;
+  gint i, j, global_alpha_val, src_width, src_height, dest_width, dest_height;
+  gint src_xoff = 0, src_yoff = 0;
   guint8 *tmpdestline = NULL, *tmpsrcline = NULL;
   gboolean src_premultiplied_alpha, dest_premultiplied_alpha;
   void (*matrix) (guint8 * tmpline, guint width);
@@ -292,6 +292,12 @@ gst_video_blend (GstVideoFrame * dest,
 
   ensure_debug_category ();
 
+  /* In case overlay is completely outside the video, dont render */
+  if (x + src_width <= 0 || y + src_height <= 0
+      || x >= dest_width || y >= dest_height) {
+    goto nothing_to_do;
+  }
+
   dinfo = gst_video_format_get_info (GST_VIDEO_FRAME_FORMAT (dest));
   sinfo = gst_video_format_get_info (GST_VIDEO_FRAME_FORMAT (src));
 
@@ -326,17 +332,18 @@ gst_video_blend (GstVideoFrame * dest,
     }
   }
 
-  xoff = 0;
-
-  /* adjust src pointers for negative sizes */
+  /* If we're here we know that the overlay image fully or
+   * partially overlaps with the video frame */
+  /* adjust src image for negative offsets */
   if (x < 0) {
-    src_width -= -x;
+    src_xoff = -x;
+    src_width -= src_xoff;
     x = 0;
-    xoff = -x;
   }
 
   if (y < 0) {
-    src_height -= -y;
+    src_yoff = -y;
+    src_height -= src_yoff;
     y = 0;
   }
 
@@ -348,12 +355,12 @@ gst_video_blend (GstVideoFrame * dest,
     src_height = dest_height - y;
 
   /* Mainloop doing the needed conversions, and blending */
-  for (i = y; i < y + src_height; i++) {
+  for (i = y; i < y + src_height; i++, src_yoff++) {
 
     dinfo->unpack_func (dinfo, 0, tmpdestline, dest->data, dest->info.stride,
         0, i, dest_width);
     sinfo->unpack_func (sinfo, 0, tmpsrcline, src->data, src->info.stride,
-        xoff, i - y, src_width - xoff);
+        src_xoff, src_yoff, src_width);
 
     matrix (tmpsrcline, src_width);
 
@@ -428,4 +435,10 @@ unpack_format_not_supported:
         gst_video_format_to_string (dinfo->unpack_format));
     return FALSE;
   }
+nothing_to_do:
+  {
+    GST_LOG
+        ("Overlay completely outside the video surface, hence not rendering");
+    return TRUE;
+  }
 }