videobox: Add support for direct RGB<->AYUV conversion
authorSebastian Dröge <sebastian.droege@collabora.co.uk>
Wed, 7 Apr 2010 14:11:11 +0000 (16:11 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Wed, 7 Apr 2010 14:12:51 +0000 (16:12 +0200)
gst/videobox/gstvideobox.c

index ec10db8f3b367c86daaeb25db57657549807f717..8223c3bb19e0eb8da694e78ecf43cd92685ebd09 100644 (file)
@@ -900,6 +900,196 @@ copy_rgb32 (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
   }
 }
 
+static void
+copy_rgb32_ayuv (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
+    gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
+    gint dest_y, GstVideoFormat src_format, const guint8 * src,
+    gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
+    gint w, gint h)
+{
+  gint i, j;
+  gint src_stride, dest_stride;
+  gboolean in_alpha;
+  gint in_bpp;
+  gint p_in[4];
+  gboolean packed_in = (src_format == GST_VIDEO_FORMAT_RGB
+      || src_format == GST_VIDEO_FORMAT_BGR);
+  gint matrix[12];
+  gint a;
+  gint y, u, v;
+  gint r, g, b;
+
+  src_stride = (packed_in) ? GST_ROUND_UP_4 (3 * src_width) : 4 * src_width;
+  dest_stride = 4 * dest_width;
+  in_bpp = (packed_in) ? 3 : 4;
+
+  _argb_order (src_format, p_in, &in_alpha);
+
+  memcpy (matrix,
+      (dest_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
+      cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  dest = dest + dest_y * dest_stride + dest_x * 4;
+  src = src + src_y * src_stride + src_x * in_bpp;
+
+  if (in_alpha) {
+    w *= 4;
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        a = (src[j + p_in[0]] * i_alpha) >> 8;
+        r = src[j + p_in[1]];
+        g = src[j + p_in[2]];
+        b = src[j + p_in[3]];
+
+        y = APPLY_MATRIX (matrix, 0, r, g, b);
+        u = APPLY_MATRIX (matrix, 1, r, g, b);
+        v = APPLY_MATRIX (matrix, 2, r, g, b);
+
+        dest[j + 0] = a;
+        dest[j + 1] = CLAMP (y, 0, 255);
+        dest[j + 2] = CLAMP (u, 0, 255);
+        dest[j + 3] = CLAMP (v, 0, 255);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else if (!packed_in) {
+    w *= 4;
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        a = i_alpha & 0xff;
+        r = src[j + p_in[1]];
+        g = src[j + p_in[2]];
+        b = src[j + p_in[3]];
+
+        y = APPLY_MATRIX (matrix, 0, r, g, b);
+        u = APPLY_MATRIX (matrix, 1, r, g, b);
+        v = APPLY_MATRIX (matrix, 2, r, g, b);
+
+        dest[j + 0] = a;
+        dest[j + 1] = CLAMP (y, 0, 255);
+        dest[j + 2] = CLAMP (u, 0, 255);
+        dest[j + 3] = CLAMP (v, 0, 255);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else {
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j++) {
+        a = i_alpha & 0xff;
+        r = src[in_bpp * j + p_in[1]];
+        g = src[in_bpp * j + p_in[2]];
+        b = src[in_bpp * j + p_in[3]];
+
+        y = APPLY_MATRIX (matrix, 0, r, g, b);
+        u = APPLY_MATRIX (matrix, 1, r, g, b);
+        v = APPLY_MATRIX (matrix, 2, r, g, b);
+
+        dest[4 * j + 0] = a;
+        dest[4 * j + 1] = CLAMP (y, 0, 255);
+        dest[4 * j + 2] = CLAMP (u, 0, 255);
+        dest[4 * j + 3] = CLAMP (v, 0, 255);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  }
+}
+
+static void
+copy_ayuv_rgb32 (guint i_alpha, GstVideoFormat dest_format, guint8 * dest,
+    gboolean dest_sdtv, gint dest_width, gint dest_height, gint dest_x,
+    gint dest_y, GstVideoFormat src_format, const guint8 * src,
+    gboolean src_sdtv, gint src_width, gint src_height, gint src_x, gint src_y,
+    gint w, gint h)
+{
+  gint i, j;
+  gint src_stride, dest_stride;
+  gboolean out_alpha;
+  gint out_bpp;
+  gint p_out[4];
+  gboolean packed_out = (dest_format == GST_VIDEO_FORMAT_RGB
+      || dest_format == GST_VIDEO_FORMAT_BGR);
+  gint matrix[12];
+  gint a;
+  gint y, u, v;
+  gint r, g, b;
+
+  dest_stride = (packed_out) ? GST_ROUND_UP_4 (3 * dest_width) : 4 * dest_width;
+  src_stride = 4 * src_width;
+  out_bpp = (packed_out) ? 3 : 4;
+
+  _argb_order (dest_format, p_out, &out_alpha);
+
+  memcpy (matrix,
+      (src_sdtv) ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
+      cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
+
+  dest = dest + dest_y * dest_stride + dest_x * out_bpp;
+  src = src + src_y * src_stride + src_x * 4;
+
+  if (out_alpha) {
+    w *= 4;
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        a = (src[j + 0] * i_alpha) >> 8;
+        y = src[j + 1];
+        u = src[j + 2];
+        v = src[j + 3];
+
+        r = APPLY_MATRIX (matrix, 0, y, u, v);
+        g = APPLY_MATRIX (matrix, 1, y, u, v);
+        b = APPLY_MATRIX (matrix, 2, y, u, v);
+
+        dest[j + p_out[0]] = a;
+        dest[j + p_out[1]] = CLAMP (r, 0, 255);
+        dest[j + p_out[2]] = CLAMP (g, 0, 255);
+        dest[j + p_out[3]] = CLAMP (b, 0, 255);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else if (!packed_out) {
+    w *= 4;
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j += 4) {
+        y = src[j + 1];
+        u = src[j + 2];
+        v = src[j + 3];
+
+        r = APPLY_MATRIX (matrix, 0, y, u, v);
+        g = APPLY_MATRIX (matrix, 1, y, u, v);
+        b = APPLY_MATRIX (matrix, 2, y, u, v);
+
+        dest[j + p_out[1]] = CLAMP (r, 0, 255);
+        dest[j + p_out[2]] = CLAMP (g, 0, 255);
+        dest[j + p_out[3]] = CLAMP (b, 0, 255);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  } else {
+    for (i = 0; i < h; i++) {
+      for (j = 0; j < w; j++) {
+        y = src[4 * j + 1];
+        u = src[4 * j + 2];
+        v = src[4 * j + 3];
+
+        r = APPLY_MATRIX (matrix, 0, y, u, v);
+        g = APPLY_MATRIX (matrix, 1, y, u, v);
+        b = APPLY_MATRIX (matrix, 2, y, u, v);
+
+        dest[out_bpp * j + p_out[1]] = CLAMP (r, 0, 255);
+        dest[out_bpp * j + p_out[2]] = CLAMP (g, 0, 255);
+        dest[out_bpp * j + p_out[3]] = CLAMP (b, 0, 255);
+      }
+      dest += dest_stride;
+      src += src_stride;
+    }
+  }
+}
+
 #define DEFAULT_LEFT      0
 #define DEFAULT_RIGHT     0
 #define DEFAULT_TOP       0
@@ -1275,11 +1465,56 @@ gst_video_box_transform_caps (GstBaseTransform * trans,
   gint width, height;
 
   to = gst_caps_copy (from);
+  /* Just to be sure... */
+  gst_caps_truncate (to);
   structure = gst_caps_get_structure (to, 0);
 
-  /* For I420/AYUV we support conversion, for all
-   * 24/32bpp RGBs we support conversion and for
-   * everything else we only support passthrough
+  /* Transform width/height */
+  if (video_box->autocrop) {
+    gst_structure_remove_field (structure, "width");
+    gst_structure_remove_field (structure, "height");
+  } else {
+    /* calculate width and height */
+    if (gst_structure_get_int (structure, "width", &width)) {
+      if (direction == GST_PAD_SINK) {
+        width -= video_box->box_left;
+        width -= video_box->box_right;
+      } else {
+        width += video_box->box_left;
+        width += video_box->box_right;
+      }
+      if (width <= 0)
+        width = 1;
+
+      GST_DEBUG_OBJECT (trans, "New caps width: %d", width);
+      gst_structure_set (structure, "width", G_TYPE_INT, width, NULL);
+    }
+
+    if (gst_structure_get_int (structure, "height", &height)) {
+      if (direction == GST_PAD_SINK) {
+        height -= video_box->box_top;
+        height -= video_box->box_bottom;
+      } else {
+        height += video_box->box_top;
+        height += video_box->box_bottom;
+      }
+
+      if (height <= 0)
+        height = 1;
+
+      GST_DEBUG_OBJECT (trans, "New caps height: %d", height);
+      gst_structure_set (structure, "height", G_TYPE_INT, height, NULL);
+    }
+  }
+
+  /* Supported conversions:
+   * I420->AYUV
+   * AYUV->I420
+   * AYUV->xRGB (24bpp, 32bpp, incl. alpha)
+   * xRGB->xRGB (24bpp, 32bpp, from/to all variants, incl. alpha)
+   * xRGB->AYUV (24bpp, 32bpp, incl. alpha)
+   *
+   * Passthrough only for everything else.
    */
   name = gst_structure_get_name (structure);
   if (g_str_equal (name, "video/x-raw-yuv")) {
@@ -1290,12 +1525,15 @@ gst_video_box_transform_caps (GstBaseTransform * trans,
             fourcc == GST_STR_FOURCC ("I420"))) {
       GValue list = { 0, };
       GValue val = { 0, };
+      GstStructure *s2;
 
       /* get rid of format */
       gst_structure_remove_field (structure, "format");
       gst_structure_remove_field (structure, "color-matrix");
       gst_structure_remove_field (structure, "chroma-site");
 
+      s2 = gst_structure_copy (structure);
+
       g_value_init (&list, GST_TYPE_LIST);
       g_value_init (&val, GST_TYPE_FOURCC);
       gst_value_set_fourcc (&val, GST_STR_FOURCC ("AYUV"));
@@ -1303,9 +1541,23 @@ gst_video_box_transform_caps (GstBaseTransform * trans,
       g_value_reset (&val);
       gst_value_set_fourcc (&val, GST_STR_FOURCC ("I420"));
       gst_value_list_append_value (&list, &val);
-      g_value_reset (&val);
+      g_value_unset (&val);
       gst_structure_set_value (structure, "format", &list);
       g_value_unset (&list);
+
+      gst_structure_set_name (s2, "video/x-raw-rgb");
+      g_value_init (&list, GST_TYPE_LIST);
+      g_value_init (&val, G_TYPE_INT);
+      g_value_set_int (&val, 32);
+      gst_value_list_append_value (&list, &val);
+      g_value_reset (&val);
+      g_value_set_int (&val, 24);
+      gst_value_list_append_value (&list, &val);
+      g_value_unset (&val);
+      gst_structure_set_value (s2, "depth", &list);
+      gst_structure_set_value (s2, "bpp", &list);
+      g_value_unset (&list);
+      gst_caps_append_structure (to, s2);
     }
   } else if (g_str_equal (name, "video/x-raw-rgb")) {
     gint bpp;
@@ -1314,6 +1566,7 @@ gst_video_box_transform_caps (GstBaseTransform * trans,
         (bpp == 32 || bpp == 24)) {
       GValue list = { 0, };
       GValue val = { 0, };
+      GstStructure *s2;
 
       /* get rid of format */
       gst_structure_remove_field (structure, "depth");
@@ -1323,6 +1576,8 @@ gst_video_box_transform_caps (GstBaseTransform * trans,
       gst_structure_remove_field (structure, "blue_mask");
       gst_structure_remove_field (structure, "alpha_mask");
 
+      s2 = gst_structure_copy (structure);
+
       g_value_init (&list, GST_TYPE_LIST);
       g_value_init (&val, G_TYPE_INT);
       g_value_set_int (&val, 32);
@@ -1330,48 +1585,15 @@ gst_video_box_transform_caps (GstBaseTransform * trans,
       g_value_reset (&val);
       g_value_set_int (&val, 24);
       gst_value_list_append_value (&list, &val);
-      g_value_reset (&val);
+      g_value_unset (&val);
       gst_structure_set_value (structure, "depth", &list);
       gst_structure_set_value (structure, "bpp", &list);
       g_value_unset (&list);
-    }
-  }
-
-  /* otherwise caps nego will fail: */
-  if (video_box->autocrop) {
-    gst_structure_remove_field (structure, "width");
-    gst_structure_remove_field (structure, "height");
-  } else {
-    /* calculate width and height */
-    if (gst_structure_get_int (structure, "width", &width)) {
-      if (direction == GST_PAD_SINK) {
-        width -= video_box->box_left;
-        width -= video_box->box_right;
-      } else {
-        width += video_box->box_left;
-        width += video_box->box_right;
-      }
-      if (width <= 0)
-        width = 1;
-
-      GST_DEBUG_OBJECT (trans, "New caps width: %d", width);
-      gst_structure_set (structure, "width", G_TYPE_INT, width, NULL);
-    }
-
-    if (gst_structure_get_int (structure, "height", &height)) {
-      if (direction == GST_PAD_SINK) {
-        height -= video_box->box_top;
-        height -= video_box->box_bottom;
-      } else {
-        height += video_box->box_top;
-        height += video_box->box_bottom;
-      }
 
-      if (height <= 0)
-        height = 1;
-
-      GST_DEBUG_OBJECT (trans, "New caps height: %d", height);
-      gst_structure_set (structure, "height", G_TYPE_INT, height, NULL);
+      gst_structure_set_name (s2, "video/x-raw-yuv");
+      gst_structure_set (s2, "format", GST_TYPE_FOURCC, GST_STR_FOURCC ("AYUV"),
+          NULL);
+      gst_caps_append_structure (to, s2);
     }
   }
 
@@ -1424,6 +1646,18 @@ gst_video_box_select_processing_functions (GstVideoBox * video_box)
         case GST_VIDEO_FORMAT_I420:
           video_box->copy = copy_i420_ayuv;
           break;
+        case GST_VIDEO_FORMAT_ARGB:
+        case GST_VIDEO_FORMAT_ABGR:
+        case GST_VIDEO_FORMAT_RGBA:
+        case GST_VIDEO_FORMAT_BGRA:
+        case GST_VIDEO_FORMAT_xRGB:
+        case GST_VIDEO_FORMAT_xBGR:
+        case GST_VIDEO_FORMAT_RGBx:
+        case GST_VIDEO_FORMAT_BGRx:
+        case GST_VIDEO_FORMAT_RGB:
+        case GST_VIDEO_FORMAT_BGR:
+          video_box->copy = copy_rgb32_ayuv;
+          break;
         default:
           break;
       }
@@ -1466,6 +1700,9 @@ gst_video_box_select_processing_functions (GstVideoBox * video_box)
         case GST_VIDEO_FORMAT_RGB:
         case GST_VIDEO_FORMAT_BGR:
           video_box->copy = copy_rgb32;
+          break;
+        case GST_VIDEO_FORMAT_AYUV:
+          video_box->copy = copy_ayuv_rgb32;
         default:
           break;
       }