video-blend: Add support for blending on top of 16 bit per component formats
authorSebastian Dröge <sebastian@centricular.com>
Thu, 12 Mar 2020 13:18:22 +0000 (15:18 +0200)
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 27 Mar 2020 08:55:45 +0000 (08:55 +0000)
With this we can support every currently supported video format for
blending.

gst-libs/gst/video/video-blend.c
gst-libs/gst/video/video-overlay-composition.h

index 097269f..3970990 100644 (file)
@@ -269,10 +269,10 @@ gst_video_blend_scale_linear_RGBA (GstVideoInfo * src, GstBuffer * src_buffer,
 #define OVER11(alphaG, alphaA, colorA, alphaB, colorB, alphaD) \
   ((colorA * alphaG + colorB * (255 - alphaA)) / 255)
 
-#define BLENDC(op, global_alpha, aa, ca, ab, cb, dest_alpha) \
+#define BLENDC(op, max, global_alpha, aa, ca, ab, cb, dest_alpha) \
 G_STMT_START { \
-  int c = op(global_alpha, aa, ca, ab, cb, dest_alpha); \
-  cb = MIN(c, 255); \
+  int c = op((global_alpha), (aa), (ca), (ab), (cb), (dest_alpha)); \
+  cb = MIN(c, (max)); \
 } G_STMT_END
 
 
@@ -295,6 +295,7 @@ gst_video_blend (GstVideoFrame * dest,
   gint src_xoff = 0, src_yoff = 0;
   guint8 *tmpdestline = NULL, *tmpsrcline = NULL;
   gboolean src_premultiplied_alpha, dest_premultiplied_alpha;
+  gint bpp;
   void (*matrix) (guint8 * tmpline, guint width);
   const GstVideoFormatInfo *sinfo, *dinfo, *dunpackinfo, *sunpackinfo;
 
@@ -339,11 +340,12 @@ gst_video_blend (GstVideoFrame * dest,
 
   g_assert (GST_VIDEO_FORMAT_INFO_BITS (sunpackinfo) == 8);
 
-  if (GST_VIDEO_FORMAT_INFO_BITS (dunpackinfo) != 8)
+  if (GST_VIDEO_FORMAT_INFO_BITS (dunpackinfo) != 8
+      && GST_VIDEO_FORMAT_INFO_BITS (dunpackinfo) != 16)
     goto unpack_format_not_supported;
 
-  tmpdestline = g_malloc (sizeof (guint8) * (dest_width + 8) * 4);
-  tmpsrcline = g_malloc (sizeof (guint8) * (src_width + 8) * 4);
+  /* Source is always 8 bit but destination might be 8 or 16 bit */
+  bpp = 4 * (GST_VIDEO_FORMAT_INFO_BITS (dunpackinfo) / 8);
 
   matrix = matrix_identity;
   if (GST_VIDEO_INFO_IS_RGB (&src->info) != GST_VIDEO_INFO_IS_RGB (&dest->info)) {
@@ -383,6 +385,9 @@ gst_video_blend (GstVideoFrame * dest,
   if (y + src_height > dest_height)
     src_height = dest_height - y;
 
+  tmpsrcline = g_malloc (sizeof (guint8) * (src_width + 8) * 4);
+  tmpdestline = g_malloc (sizeof (guint8) * (dest_width + 8) * bpp);
+
   /* Mainloop doing the needed conversions, and blending */
   for (i = y; i < y + src_height; i++, src_yoff++) {
 
@@ -392,58 +397,86 @@ gst_video_blend (GstVideoFrame * dest,
         src_xoff, src_yoff, src_width);
 
     /* FIXME: use the x parameter of the unpack func once implemented */
-    tmpdestline += 4 * x;
+    tmpdestline += bpp * x;
 
     matrix (tmpsrcline, src_width);
 
-#define BLENDLOOP(op, alpha_val)                                                              \
+#define BLENDLOOP(op, dest_type, max, shift, alpha_val)                                       \
   G_STMT_START {                                                                              \
     for (j = 0; j < src_width * 4; j += 4) {                                                  \
-      guint8 asrc, adst;                                                                      \
-      gint final_alpha;                                                                       \
+      guint asrc, adst;                                                                       \
+      guint final_alpha;                                                                      \
+      dest_type * dest = (dest_type *) tmpdestline;                                           \
                                                                                               \
-      asrc = tmpsrcline[j] * alpha_val / 255;                                                 \
-      if (!asrc)                                                                              \
+      asrc = ((guint) tmpsrcline[j]) * alpha_val / 255;                                       \
+      asrc = asrc << shift;                                                                   \
+      if (asrc == 0)                                                                          \
         continue;                                                                             \
                                                                                               \
-      adst = tmpdestline[j];                                                                  \
-      final_alpha = asrc + adst * (255 - asrc) / 255;                                         \
-      tmpdestline[j] = final_alpha;                                                           \
+      adst = dest[j];                                                                         \
+      final_alpha = asrc + adst * (max - asrc) / max;                                         \
+      dest[j] = final_alpha;                                                                  \
       if (final_alpha == 0)                                                                   \
         final_alpha = 1;                                                                      \
                                                                                               \
-      BLENDC (op, alpha_val, asrc, tmpsrcline[j + 1], adst, tmpdestline[j + 1], final_alpha); \
-      BLENDC (op, alpha_val, asrc, tmpsrcline[j + 2], adst, tmpdestline[j + 2], final_alpha); \
-      BLENDC (op, alpha_val, asrc, tmpsrcline[j + 3], adst, tmpdestline[j + 3], final_alpha); \
+      BLENDC (op, max, alpha_val, asrc, tmpsrcline[j + 1] << shift, adst, dest[j + 1], final_alpha); \
+      BLENDC (op, max, alpha_val, asrc, tmpsrcline[j + 2] << shift, adst, dest[j + 2], final_alpha); \
+      BLENDC (op, max, alpha_val, asrc, tmpsrcline[j + 3] << shift, adst, dest[j + 3], final_alpha); \
     }                                                                                         \
   } G_STMT_END
 
-    if (G_LIKELY (global_alpha == 1.0)) {
-      if (src_premultiplied_alpha && dest_premultiplied_alpha) {
-        BLENDLOOP (OVER11, 255);
-      } else if (!src_premultiplied_alpha && dest_premultiplied_alpha) {
-        BLENDLOOP (OVER01, 255);
-      } else if (src_premultiplied_alpha && !dest_premultiplied_alpha) {
-        BLENDLOOP (OVER10, 255);
+    if (bpp == 4) {
+      if (G_LIKELY (global_alpha_val == 255)) {
+        if (src_premultiplied_alpha && dest_premultiplied_alpha) {
+          BLENDLOOP (OVER11, guint8, 255, 0, 255);
+        } else if (!src_premultiplied_alpha && dest_premultiplied_alpha) {
+          BLENDLOOP (OVER01, guint8, 255, 0, 255);
+        } else if (src_premultiplied_alpha && !dest_premultiplied_alpha) {
+          BLENDLOOP (OVER10, guint8, 255, 0, 255);
+        } else {
+          BLENDLOOP (OVER00, guint8, 255, 0, 255);
+        }
       } else {
-        BLENDLOOP (OVER00, 255);
+        if (src_premultiplied_alpha && dest_premultiplied_alpha) {
+          BLENDLOOP (OVER11, guint8, 255, 0, global_alpha_val);
+        } else if (!src_premultiplied_alpha && dest_premultiplied_alpha) {
+          BLENDLOOP (OVER01, guint8, 255, 0, global_alpha_val);
+        } else if (src_premultiplied_alpha && !dest_premultiplied_alpha) {
+          BLENDLOOP (OVER10, guint8, 255, 0, global_alpha_val);
+        } else {
+          BLENDLOOP (OVER00, guint8, 255, 0, global_alpha_val);
+        }
       }
     } else {
-      if (src_premultiplied_alpha && dest_premultiplied_alpha) {
-        BLENDLOOP (OVER11, global_alpha_val);
-      } else if (!src_premultiplied_alpha && dest_premultiplied_alpha) {
-        BLENDLOOP (OVER01, global_alpha_val);
-      } else if (src_premultiplied_alpha && !dest_premultiplied_alpha) {
-        BLENDLOOP (OVER10, global_alpha_val);
+      g_assert (bpp == 8);
+
+      if (G_LIKELY (global_alpha_val == 255)) {
+        if (src_premultiplied_alpha && dest_premultiplied_alpha) {
+          BLENDLOOP (OVER11, guint16, 65535, 8, 255);
+        } else if (!src_premultiplied_alpha && dest_premultiplied_alpha) {
+          BLENDLOOP (OVER01, guint16, 65535, 8, 255);
+        } else if (src_premultiplied_alpha && !dest_premultiplied_alpha) {
+          BLENDLOOP (OVER10, guint16, 65535, 8, 255);
+        } else {
+          BLENDLOOP (OVER00, guint16, 65535, 8, 255);
+        }
       } else {
-        BLENDLOOP (OVER00, global_alpha_val);
+        if (src_premultiplied_alpha && dest_premultiplied_alpha) {
+          BLENDLOOP (OVER11, guint16, 65535, 8, global_alpha_val);
+        } else if (!src_premultiplied_alpha && dest_premultiplied_alpha) {
+          BLENDLOOP (OVER01, guint16, 65535, 8, global_alpha_val);
+        } else if (src_premultiplied_alpha && !dest_premultiplied_alpha) {
+          BLENDLOOP (OVER10, guint16, 65535, 8, global_alpha_val);
+        } else {
+          BLENDLOOP (OVER00, guint16, 65535, 8, global_alpha_val);
+        }
       }
     }
 
 #undef BLENDLOOP
 
     /* undo previous pointer adjustments to pass right pointer to g_free */
-    tmpdestline -= 4 * x;
+    tmpdestline -= bpp * x;
 
     /* FIXME
      * #if G_BYTE_ORDER == LITTLE_ENDIAN
index 062dae7..7981e02 100644 (file)
@@ -119,10 +119,7 @@ typedef enum {
  *
  * Since: 1.2
  */
-#define GST_VIDEO_OVERLAY_COMPOSITION_BLEND_FORMATS \
-    "{ BGRx, RGBx, xRGB, xBGR, RGBA, BGRA, ARGB, ABGR, RGB, BGR," \
-     " I420, YV12, AYUV, YUY2, UYVY, v308, Y41B, Y42B, Y444," \
-     " NV12, NV21, A420, YUV9, YVU9, IYU1, GRAY8 }"
+#define GST_VIDEO_OVERLAY_COMPOSITION_BLEND_FORMATS GST_VIDEO_FORMATS_ALL
 
 GST_VIDEO_API
 GType                        gst_video_overlay_rectangle_get_type (void);