cog: Add color matrix selection to cogcolorspace
authorDavid Schleef <ds@schleef.org>
Thu, 8 Oct 2009 21:33:28 +0000 (14:33 -0700)
committerDavid Schleef <ds@schleef.org>
Sat, 24 Oct 2009 18:38:42 +0000 (11:38 -0700)
Eventually hook it up to caps via gstvideo

ext/cog/Makefile.am
ext/cog/cogframe.h
ext/cog/cogvirtframe.c
ext/cog/cogvirtframe.h
ext/cog/generate_tables.c
ext/cog/gstcogcolorspace.c
ext/cog/gstlogoinsert.c

index dff47fab9548d5b4180ee7f76ed230a637ba9924..95c6e8fe28b68ac8eb1c2995cf3ee3ad5696bfb0 100644 (file)
@@ -36,6 +36,7 @@ libgstcog_la_SOURCES = \
        gstcms.c
 
 noinst_PROGRAMS = generate_tables
+generate_tables_SOURCES = generate_tables.c gstcms.c
 generate_tables_CFLAGS = $(GST_CFLAGS)
 generate_tables_LDADD = $(GST_LIBS)
 
index 488c96859c459fd1a49ab1c02935ce4fadb78f2d..2aa7a02f5727c87e6b1ace935bce109a271ac4f0 100644 (file)
@@ -13,6 +13,12 @@ typedef struct _CogUpsampledFrame CogUpsampledFrame;
 typedef void (*CogFrameFreeFunc)(CogFrame *frame, void *priv);
 typedef void (*CogFrameRenderFunc)(CogFrame *frame, void *dest, int component, int i);
 
+typedef enum _CogColorMatrix {
+  COG_COLOR_MATRIX_UNKNOWN = 0,
+  COG_COLOR_MATRIX_HDTV,
+  COG_COLOR_MATRIX_SDTV
+} CogColorMatrix;
+
 /* bit pattern:
  *  0x100 - 0: normal, 1: indirect (packed)
  *  0x001 - horizontal chroma subsampling: 0: 1, 1: 2
index 1ff6cdd3c629e1004052a16fa02e891866dbd076..21d0e4c4a36eb96f046bac34d6866ddb628fc22c 100644 (file)
@@ -1330,6 +1330,31 @@ color_matrix_RGB_to_YCbCr (CogFrame * frame, void *_dest, int component, int i)
 
 }
 
+
+static const int cog_ycbcr_to_rgb_matrix_6bit_sdtv[] = {
+  75, 0, 102, -14267,
+  75, -25, -52, 8677,
+  75, 129, 0, -17717,
+};
+
+static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
+  42, 0, 153, -57068,
+  42, -100, -208, 34707,
+  42, 4, 0, -70870,
+};
+
+static const int cog_ycbcr_to_rgb_matrix_6bit_hdtv[] = {
+  75, 0, 115, -15878,
+  75, -14, -34, 4920,
+  75, 135, 0, -18497,
+};
+
+static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
+  42, 0, 203, -63514,
+  42, -55, -136, 19681,
+  42, 29, 0, -73988,
+};
+
 static void
 color_matrix_YCbCr_to_RGB_6bit (CogFrame * frame, void *_dest, int component,
     int i)
@@ -1338,6 +1363,7 @@ color_matrix_YCbCr_to_RGB_6bit (CogFrame * frame, void *_dest, int component,
   uint8_t *src1;
   uint8_t *src2;
   uint8_t *src3;
+  int *matrix = frame->virt_priv2;
 
   src1 = cog_virt_frame_get_line (frame->virt_frame1, 0, i);
   src2 = cog_virt_frame_get_line (frame->virt_frame1, 1, i);
@@ -1348,20 +1374,22 @@ color_matrix_YCbCr_to_RGB_6bit (CogFrame * frame, void *_dest, int component,
       /* m1 = 1.1644;
        * m2 = 0;
        * m3 = 1.596; */
-      orc_matrix2_u8 (dest, src1, src3, 75, 102, -14269 + 32, frame->width);
+      orc_matrix2_u8 (dest, src1, src3, matrix[0], matrix[2], matrix[3] + 32,
+          frame->width);
       break;
     case 1:
       /* m1 = 1.1644;
        * m2 = -0.39176;
        * m3 = -0.81297; */
-      orc_matrix3_u8 (dest, src1, src2, src3, 75, -25, -52, 8677 + 32,
-          frame->width);
+      orc_matrix3_u8 (dest, src1, src2, src3, matrix[4], matrix[5], matrix[6],
+          matrix[7] + 32, frame->width);
       break;
     case 2:
       /* m1 = 1.1644;
        * m2 = 2.0172;
        * m3 = 0; */
-      orc_matrix2_u8 (dest, src1, src2, 75, 129, -17718 + 32, frame->width);
+      orc_matrix2_u8 (dest, src1, src2,
+          matrix[8], matrix[9], matrix[11] + 32, frame->width);
       break;
     default:
       break;
@@ -1376,6 +1404,7 @@ color_matrix_YCbCr_to_RGB_8bit (CogFrame * frame, void *_dest, int component,
   uint8_t *src1;
   uint8_t *src2;
   uint8_t *src3;
+  int *matrix = frame->virt_priv2;
 
   src1 = cog_virt_frame_get_line (frame->virt_frame1, 0, i);
   src2 = cog_virt_frame_get_line (frame->virt_frame1, 1, i);
@@ -1383,23 +1412,26 @@ color_matrix_YCbCr_to_RGB_8bit (CogFrame * frame, void *_dest, int component,
 
   switch (component) {
     case 0:
+
       /* m1 = 1.1644;
        * m2 = 0;
        * m3 = 1.596; */
-      orc_matrix2_11_u8 (dest, src1, src3, 42, 153, 128, 8, frame->width);
+      orc_matrix2_11_u8 (dest, src1, src3,
+          matrix[0], matrix[2], 128, 8, frame->width);
       break;
     case 1:
       /* m1 = 1.1644;
        * m2 = -0.39176;
        * m3 = -0.81297; */
-      orc_matrix3_100_u8 (dest, src1, src2, src3, 42, -100, -208, 128, 8,
-          frame->width);
+      orc_matrix3_100_u8 (dest, src1, src2, src3,
+          matrix[4], matrix[5], matrix[6], 128, 8, frame->width);
       break;
     case 2:
       /* m1 = 1.1644;
        * m2 = 2.0172;
        * m3 = 0; */
-      orc_matrix2_12_u8 (dest, src1, src2, 42, 4, 128, 8, frame->width);
+      orc_matrix2_12_u8 (dest, src1, src2,
+          matrix[8], matrix[9], 128, 8, frame->width);
       break;
     default:
       break;
@@ -1407,24 +1439,37 @@ color_matrix_YCbCr_to_RGB_8bit (CogFrame * frame, void *_dest, int component,
 }
 
 CogFrame *
-cog_virt_frame_new_color_matrix_YCbCr_to_RGB (CogFrame * vf, int bits)
+cog_virt_frame_new_color_matrix_YCbCr_to_RGB (CogFrame * vf,
+    CogColorMatrix color_matrix, int bits)
 {
   CogFrame *virt_frame;
+  //int *matrix = frame->virt_priv2;
 
   virt_frame = cog_frame_new_virtual (NULL, COG_FRAME_FORMAT_U8_444,
       vf->width, vf->height);
   virt_frame->virt_frame1 = vf;
   if (bits <= 6) {
     virt_frame->render_line = color_matrix_YCbCr_to_RGB_6bit;
+    if (color_matrix == COG_COLOR_MATRIX_HDTV) {
+      virt_frame->virt_priv2 = (void *) cog_ycbcr_to_rgb_matrix_6bit_hdtv;
+    } else {
+      virt_frame->virt_priv2 = (void *) cog_ycbcr_to_rgb_matrix_6bit_sdtv;
+    }
   } else {
     virt_frame->render_line = color_matrix_YCbCr_to_RGB_8bit;
+    if (color_matrix == COG_COLOR_MATRIX_HDTV) {
+      virt_frame->virt_priv2 = (void *) cog_ycbcr_to_rgb_matrix_8bit_hdtv;
+    } else {
+      virt_frame->virt_priv2 = (void *) cog_ycbcr_to_rgb_matrix_8bit_sdtv;
+    }
   }
 
   return virt_frame;
 }
 
 CogFrame *
-cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf)
+cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf,
+    CogColorMatrix color_matrix)
 {
   CogFrame *virt_frame;
 
@@ -1432,6 +1477,7 @@ cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf)
       vf->width, vf->height);
   virt_frame->virt_frame1 = vf;
   virt_frame->render_line = color_matrix_RGB_to_YCbCr;
+  virt_frame->param1 = color_matrix;
 
   return virt_frame;
 }
index c4625c3159a04d31decac852b7da571b01b32f63..eca491446f62bbd5ddaac01c2075c034cc9526b6 100644 (file)
@@ -27,8 +27,8 @@ CogFrame *cog_virt_frame_new_pack_AYUV (CogFrame *vf);
 CogFrame *cog_virt_frame_new_pack_v216 (CogFrame *vf);
 CogFrame *cog_virt_frame_new_pack_v210 (CogFrame *vf);
 CogFrame *cog_virt_frame_new_pack_RGB (CogFrame *vf);
-CogFrame *cog_virt_frame_new_color_matrix_YCbCr_to_RGB (CogFrame *vf, int bits);
-CogFrame * cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf);
+CogFrame *cog_virt_frame_new_color_matrix_YCbCr_to_RGB (CogFrame *vf, CogColorMatrix color_matrix, int bits);
+CogFrame * cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf, CogColorMatrix color_matrix);
 CogFrame *cog_virt_frame_new_subsample (CogFrame *vf, CogFrameFormat format);
 
 CogFrame * cog_virt_frame_new_convert_u8 (CogFrame *vf);
index 562ba9bdf2c8d0f5a9189276a8da0b54cba2c19e..a04946d9ea92d58afbf464ec5cf229d7ade891fb 100644 (file)
@@ -4,6 +4,8 @@
 #include <glib.h>
 #include <math.h>
 
+#include "gstcms.h"
+
 #define SCALE 256
 
 void
@@ -66,5 +68,67 @@ main (int argc, char *argv[])
   g_print ("};\n");
   g_print ("\n");
 
+
+  {
+    int cm, bits;
+
+    for (cm = 0; cm < 2; cm++) {
+      for (bits = 6; bits <= 8; bits += 2) {
+
+        ColorMatrix matrix;
+
+        /*
+         * At this point, everything is in YCbCr
+         * All components are in the range [0,255]
+         */
+        color_matrix_set_identity (&matrix);
+
+        /* offset required to get input video black to (0.,0.,0.) */
+        /* we don't do this because the code does it for us */
+        color_matrix_offset_components (&matrix, -16, -128, -128);
+
+        color_matrix_scale_components (&matrix, (1 / 219.0), (1 / 224.0),
+            (1 / 224.0));
+
+        /* colour matrix, YCbCr -> RGB */
+        /* Requires Y in [0,1.0], Cb&Cr in [-0.5,0.5] */
+        if (cm) {
+          color_matrix_YCbCr_to_RGB (&matrix, 0.2126, 0.0722);  /* HD */
+        } else {
+          color_matrix_YCbCr_to_RGB (&matrix, 0.2990, 0.1140);  /* SD */
+        }
+
+        /*
+         * We are now in RGB space
+         */
+
+        /* scale to output range. */
+        color_matrix_scale_components (&matrix, 255.0, 255.0, 255.0);
+
+        /* because we're doing 8-bit matrix coefficients */
+        color_matrix_scale_components (&matrix, 1 << bits, 1 << bits,
+            1 << bits);
+
+        g_print ("static const int cog_ycbcr_to_rgb_matrix_%dbit_%s[] = {\n",
+            bits, cm ? "hdtv" : "sdtv");
+        g_print ("  %d, %d, %d, %d,\n",
+            (int) rint (matrix.m[0][0] - ((bits == 8) ? 256 : 0)),
+            (int) rint (matrix.m[0][1]),
+            (int) rint (matrix.m[0][2] - ((bits == 8) ? 256 : 0)),
+            (int) rint (matrix.m[0][3]));
+        g_print ("  %d, %d, %d, %d,\n",
+            (int) rint (matrix.m[1][0] - ((bits == 8) ? 256 : 0)),
+            (int) rint (matrix.m[1][1]),
+            (int) rint (matrix.m[1][2]), (int) rint (matrix.m[1][3]));
+        g_print ("  %d, %d, %d, %d,\n",
+            (int) rint (matrix.m[2][0] - ((bits == 8) ? 256 : 0)),
+            (int) rint (matrix.m[2][1] - ((bits == 8) ? 512 : 0)),
+            (int) rint (matrix.m[2][2]), (int) rint (matrix.m[2][3]));
+        g_print ("};\n");
+      }
+    }
+  }
+
+
   return 0;
 }
index 697f424c3f1b0c135f6c1b0cf10c5c6a07cadce8..1663a848fdf5cfaba520423d56787f0c0a0d9209 100644 (file)
@@ -57,6 +57,7 @@ struct _GstCogcolorspace
   GstBaseTransform base_transform;
 
   int quality;
+  CogColorMatrix color_matrix;
 };
 
 struct _GstCogcolorspaceClass
@@ -75,11 +76,13 @@ enum
 };
 
 #define DEFAULT_QUALITY 5
+#define DEFAULT_COLOR_MATRIX COG_COLOR_MATRIX_UNKNOWN
 
 enum
 {
   PROP_0,
-  PROP_QUALITY
+  PROP_QUALITY,
+  PROP_COLOR_MATRIX
 };
 
 static void gst_cogcolorspace_set_property (GObject * object, guint prop_id,
@@ -119,31 +122,26 @@ static GstStaticPadTemplate gst_cogcolorspace_src_template =
 GST_BOILERPLATE (GstCogcolorspace, gst_cogcolorspace, GstBaseTransform,
     GST_TYPE_BASE_TRANSFORM);
 
-#if 0
 GType
-gst_cogcolorspace_get_type (void)
+gst_cog_color_matrix_get_type (void)
 {
-  static GType compress_type = 0;
-
-  if (!compress_type) {
-    static const GTypeInfo compress_info = {
-      sizeof (GstCogcolorspaceClass),
-      gst_cogcolorspace_base_init,
-      NULL,
-      gst_cogcolorspace_class_init,
-      NULL,
-      NULL,
-      sizeof (GstCogcolorspace),
-      0,
-      gst_cogcolorspace_init,
-    };
-
-    compress_type = g_type_register_static (GST_TYPE_BASE_TRANSFORM,
-        "GstCogcolorspace", &compress_info, 0);
+  static gsize id = 0;
+  static const GEnumValue values[] = {
+    {COG_COLOR_MATRIX_UNKNOWN, "unknown",
+        "Unknown color matrix (works like sdtv)"},
+    {COG_COLOR_MATRIX_HDTV, "hdtv", "High Definition TV color matrix (BT.709)"},
+    {COG_COLOR_MATRIX_SDTV, "sdtv",
+        "Standard Definition TV color matrix (BT.470)"},
+    {0, NULL, NULL}
+  };
+
+  if (g_once_init_enter (&id)) {
+    GType tmp = g_enum_register_static ("CogColorMatrix", values);
+    g_once_init_leave (&id, tmp);
   }
-  return compress_type;
+
+  return (GType) id;
 }
-#endif
 
 static void
 gst_cogcolorspace_base_init (gpointer g_class)
@@ -178,7 +176,12 @@ gst_cogcolorspace_class_init (GstCogcolorspaceClass * colorspace_class)
 
   g_object_class_install_property (gobject_class, PROP_QUALITY,
       g_param_spec_int ("quality", "Quality", "Quality",
-          0, 10, DEFAULT_QUALITY, G_PARAM_READWRITE));
+          0, 10, DEFAULT_QUALITY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_COLOR_MATRIX,
+      g_param_spec_enum ("color-matrix", "Color Matrix",
+          "Color matrix for YCbCr <-> RGB conversion",
+          gst_cog_color_matrix_get_type (),
+          DEFAULT_COLOR_MATRIX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   base_transform_class->transform = gst_cogcolorspace_transform;
   base_transform_class->transform_caps = gst_cogcolorspace_transform_caps;
@@ -194,6 +197,7 @@ gst_cogcolorspace_init (GstCogcolorspace * colorspace,
   GST_DEBUG ("gst_cogcolorspace_init");
 
   colorspace->quality = DEFAULT_QUALITY;
+  colorspace->color_matrix = DEFAULT_COLOR_MATRIX;
 }
 
 static void
@@ -212,6 +216,11 @@ gst_cogcolorspace_set_property (GObject * object, guint prop_id,
       colorspace->quality = g_value_get_int (value);
       GST_OBJECT_UNLOCK (colorspace);
       break;
+    case PROP_COLOR_MATRIX:
+      GST_OBJECT_LOCK (colorspace);
+      colorspace->color_matrix = g_value_get_enum (value);
+      GST_OBJECT_UNLOCK (colorspace);
+      break;
     default:
       break;
   }
@@ -232,6 +241,11 @@ gst_cogcolorspace_get_property (GObject * object, guint prop_id, GValue * value,
       g_value_set_int (value, colorspace->quality);
       GST_OBJECT_UNLOCK (colorspace);
       break;
+    case PROP_COLOR_MATRIX:
+      GST_OBJECT_LOCK (colorspace);
+      g_value_set_enum (value, colorspace->color_matrix);
+      GST_OBJECT_UNLOCK (colorspace);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -430,7 +444,8 @@ gst_cogcolorspace_transform (GstBaseTransform * base_transform,
 
   if (gst_video_format_is_yuv (out_format) &&
       gst_video_format_is_rgb (in_format)) {
-    frame = cog_virt_frame_new_color_matrix_RGB_to_YCbCr (frame);
+    frame = cog_virt_frame_new_color_matrix_RGB_to_YCbCr (frame,
+        compress->color_matrix);
   }
 
   frame = cog_virt_frame_new_subsample (frame, new_subsample);
@@ -438,7 +453,7 @@ gst_cogcolorspace_transform (GstBaseTransform * base_transform,
   if (gst_video_format_is_rgb (out_format) &&
       gst_video_format_is_yuv (in_format)) {
     frame = cog_virt_frame_new_color_matrix_YCbCr_to_RGB (frame,
-        (compress->quality > 5) ? 8 : 6);
+        compress->color_matrix, (compress->quality >= 5) ? 8 : 6);
   }
 
   switch (out_format) {
index 52f79e0bc2291d3ff974a89470118464201aadff..9eb91417223df0cd968f436ef411c417db97a013 100644 (file)
@@ -265,7 +265,7 @@ gst_logoinsert_transform_ip (GstBaseTransform * base_transform, GstBuffer * buf)
     li->alpha_frame = cog_frame_realize (f);
 
     f = cog_virt_frame_new_unpack (cog_frame_ref (li->ayuv_frame));
-    f = cog_virt_frame_new_color_matrix_RGB_to_YCbCr (f);
+    f = cog_virt_frame_new_color_matrix_RGB_to_YCbCr (f, COG_COLOR_MATRIX_SDTV);
     f = cog_virt_frame_new_subsample (f, frame->format);
     li->overlay_frame = cog_frame_realize (f);
   }