[MOVED FROM BAD 60/68] colorspace: Add dithering
authorDavid Schleef <ds@schleef.org>
Mon, 21 Feb 2011 06:43:56 +0000 (22:43 -0800)
committerWim Taymans <wim.taymans@collabora.co.uk>
Wed, 15 Jun 2011 14:12:56 +0000 (16:12 +0200)
Dithering only happens when a 16-bit-per-channel format is
involved.

gst/colorspace/colorspace.c
gst/colorspace/colorspace.h
gst/colorspace/gstcolorspace.c
gst/colorspace/gstcolorspace.h

index d98ad20..1079866 100644 (file)
@@ -32,6 +32,9 @@ static void colorspace_convert_generic (ColorspaceConvert * convert,
     guint8 * dest, const guint8 * src);
 static void colorspace_convert_lookup_fastpath (ColorspaceConvert * convert);
 static void colorspace_convert_lookup_getput (ColorspaceConvert * convert);
+static void colorspace_dither_none (ColorspaceConvert * convert, int j);
+static void colorspace_dither_verterr (ColorspaceConvert * convert, int j);
+static void colorspace_dither_halftone (ColorspaceConvert * convert, int j);
 
 
 ColorspaceConvert *
@@ -72,6 +75,7 @@ colorspace_convert_new (GstVideoFormat to_format, ColorSpaceColorSpec to_spec,
   convert->height = height;
   convert->width = width;
   convert->convert = colorspace_convert_generic;
+  convert->dither16 = colorspace_dither_none;
 
   if (gst_video_format_get_component_depth (to_format, 0) > 8 ||
       gst_video_format_get_component_depth (from_format, 0) > 8) {
@@ -105,6 +109,7 @@ colorspace_convert_new (GstVideoFormat to_format, ColorSpaceColorSpec to_spec,
 
   convert->tmpline = g_malloc (sizeof (guint8) * (width + 8) * 4);
   convert->tmpline16 = g_malloc (sizeof (guint16) * (width + 8) * 4);
+  convert->errline = g_malloc (sizeof (guint16) * width * 4);
 
   if (to_format == GST_VIDEO_FORMAT_RGB8_PALETTED) {
     /* build poor man's palette, taken from ffmpegcolorspace */
@@ -137,6 +142,7 @@ colorspace_convert_free (ColorspaceConvert * convert)
   g_free (convert->palette);
   g_free (convert->tmpline);
   g_free (convert->tmpline16);
+  g_free (convert->errline);
 
   g_free (convert);
 }
@@ -149,6 +155,23 @@ colorspace_convert_set_interlaced (ColorspaceConvert * convert,
 }
 
 void
+colorspace_convert_set_dither (ColorspaceConvert * convert, int type)
+{
+  switch (type) {
+    case 0:
+    default:
+      convert->dither16 = colorspace_dither_none;
+      break;
+    case 1:
+      convert->dither16 = colorspace_dither_verterr;
+      break;
+    case 2:
+      convert->dither16 = colorspace_dither_halftone;
+      break;
+  }
+}
+
+void
 colorspace_convert_set_palette (ColorspaceConvert * convert,
     const guint32 * palette)
 {
@@ -1681,6 +1704,7 @@ colorspace_convert_generic (ColorspaceConvert * convert, guint8 * dest,
     for (j = 0; j < convert->height; j++) {
       convert->getline16 (convert, convert->tmpline16, src, j);
       convert->matrix16 (convert);
+      convert->dither16 (convert, j);
       convert->putline16 (convert, dest, convert->tmpline16, j);
     }
   } else {
@@ -1692,6 +1716,44 @@ colorspace_convert_generic (ColorspaceConvert * convert, guint8 * dest,
   }
 }
 
+static void
+colorspace_dither_none (ColorspaceConvert * convert, int j)
+{
+}
+
+static void
+colorspace_dither_verterr (ColorspaceConvert * convert, int j)
+{
+  int i;
+  guint16 *tmpline = convert->tmpline16;
+  guint16 *errline = convert->errline;
+
+  for (i = 0; i < 4 * convert->width; i++) {
+    tmpline[i] += errline[i];
+    errline[i] = tmpline[i] & 0xff;
+  }
+}
+
+static void
+colorspace_dither_halftone (ColorspaceConvert * convert, int j)
+{
+  int i;
+  guint16 *tmpline = convert->tmpline16;
+  static guint16 halftone[8][8] = {
+    {0, 128, 32, 160, 8, 136, 40, 168},
+    {192, 64, 224, 96, 200, 72, 232, 104},
+    {48, 176, 16, 144, 56, 184, 24, 152},
+    {240, 112, 208, 80, 248, 120, 216, 88},
+    {12, 240, 44, 172, 4, 132, 36, 164},
+    {204, 76, 236, 108, 196, 68, 228, 100},
+    {60, 188, 28, 156, 52, 180, 20, 148},
+    {252, 142, 220, 92, 244, 116, 212, 84}
+  };
+
+  for (i = 0; i < convert->width * 4; i++) {
+    tmpline[i] += halftone[(i >> 2) & 7][j & 7];
+  }
+}
 
 /* Fast paths */
 
index fe72524..05bcc18 100644 (file)
@@ -35,6 +35,12 @@ typedef enum {
   COLOR_SPEC_YUV_BT709
 } ColorSpaceColorSpec;
 
+typedef enum {
+  DITHER_NONE,
+  DITHER_VERTERR,
+  DITHER_HALFTONE
+} ColorSpaceDitherMethod;
+
 struct _ColorspaceComponent {
   int offset;
   int stride;
@@ -44,6 +50,7 @@ struct _ColorspaceConvert {
   gint width, height;
   gboolean interlaced;
   gboolean use_16bit;
+  gboolean dither;
 
   GstVideoFormat from_format;
   ColorSpaceColorSpec from_spec;
@@ -53,6 +60,7 @@ struct _ColorspaceConvert {
 
   guint8 *tmpline;
   guint16 *tmpline16;
+  guint16 *errline;
 
   int dest_offset[4];
   int dest_stride[4];
@@ -67,11 +75,13 @@ struct _ColorspaceConvert {
   void (*getline16) (ColorspaceConvert *convert, guint16 *dest, const guint8 *src, int j);
   void (*putline16) (ColorspaceConvert *convert, guint8 *dest, const guint16 *src, int j);
   void (*matrix16) (ColorspaceConvert *convert);
+  void (*dither16) (ColorspaceConvert *convert, int j);
 };
 
 ColorspaceConvert * colorspace_convert_new (GstVideoFormat to_format,
     ColorSpaceColorSpec from_spec, GstVideoFormat from_format,
     ColorSpaceColorSpec to_spec, int width, int height);
+void colorspace_convert_set_dither (ColorspaceConvert * convert, int type);
 void colorspace_convert_set_interlaced (ColorspaceConvert *convert,
     gboolean interlaced);
 void colorspace_convert_set_palette (ColorspaceConvert *convert,
index 84c9af9..658bc8a 100644 (file)
@@ -46,6 +46,12 @@ GST_DEBUG_CATEGORY (colorspace_debug);
 #define GST_CAT_DEFAULT colorspace_debug
 GST_DEBUG_CATEGORY (colorspace_performance);
 
+enum
+{
+  PROP_0,
+  PROP_DITHER
+};
+
 #define CSP_VIDEO_CAPS                                         \
   "video/x-raw-yuv, width = "GST_VIDEO_SIZE_RANGE" , "                 \
   "height="GST_VIDEO_SIZE_RANGE",framerate="GST_VIDEO_FPS_RANGE","     \
@@ -86,6 +92,12 @@ GST_STATIC_PAD_TEMPLATE ("sink",
 
 GType gst_csp_get_type (void);
 
+static void gst_csp_set_property (GObject * object,
+    guint property_id, const GValue * value, GParamSpec * pspec);
+static void gst_csp_get_property (GObject * object,
+    guint property_id, GValue * value, GParamSpec * pspec);
+static void gst_csp_dispose (GObject * object);
+
 static gboolean gst_csp_set_caps (GstBaseTransform * btrans,
     GstCaps * incaps, GstCaps * outcaps);
 static gboolean gst_csp_get_unit_size (GstBaseTransform * btrans,
@@ -97,6 +109,25 @@ static GQuark _QRAWRGB;         /* "video/x-raw-rgb" */
 static GQuark _QRAWYUV;         /* "video/x-raw-yuv" */
 static GQuark _QALPHAMASK;      /* "alpha_mask" */
 
+
+static GType
+dither_method_get_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {DITHER_NONE, "No dithering (default)", "none"},
+      {DITHER_VERTERR, "Vertical error propogation", "verterr"},
+      {DITHER_HALFTONE, "Half-tone", "halftone"},
+      {0, NULL, NULL}
+    };
+
+    gtype = g_enum_register_static ("GstColorspaceDitherMethod", values);
+  }
+  return gtype;
+}
+
 /* copies the given caps */
 static GstCaps *
 gst_csp_caps_remove_format_info (GstCaps * caps)
@@ -395,6 +426,19 @@ gst_csp_base_init (gpointer klass)
   _QALPHAMASK = g_quark_from_string ("alpha_mask");
 }
 
+void
+gst_csp_dispose (GObject * object)
+{
+  GstCsp *csp;
+
+  g_return_if_fail (GST_IS_CSP (object));
+  csp = GST_CSP (object);
+
+  /* clean up as possible.  may be called multiple times */
+
+  G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
 static void
 gst_csp_finalize (GObject * obj)
 {
@@ -415,6 +459,9 @@ gst_csp_class_init (GstCspClass * klass)
   GstBaseTransformClass *gstbasetransform_class =
       (GstBaseTransformClass *) klass;
 
+  gobject_class->set_property = gst_csp_set_property;
+  gobject_class->get_property = gst_csp_get_property;
+  gobject_class->dispose = gst_csp_dispose;
   gobject_class->finalize = gst_csp_finalize;
 
   gstbasetransform_class->transform_caps =
@@ -425,6 +472,12 @@ gst_csp_class_init (GstCspClass * klass)
   gstbasetransform_class->transform = GST_DEBUG_FUNCPTR (gst_csp_transform);
 
   gstbasetransform_class->passthrough_on_same_caps = TRUE;
+
+  g_object_class_install_property (gobject_class, PROP_DITHER,
+      g_param_spec_enum ("dither", "Dither", "Apply dithering while converting",
+          dither_method_get_type (), DITHER_NONE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
 }
 
 static void
@@ -434,6 +487,44 @@ gst_csp_init (GstCsp * space, GstCspClass * klass)
   space->to_format = GST_VIDEO_FORMAT_UNKNOWN;
 }
 
+void
+gst_csp_set_property (GObject * object, guint property_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstCsp *csp;
+
+  g_return_if_fail (GST_IS_CSP (object));
+  csp = GST_CSP (object);
+
+  switch (property_id) {
+    case PROP_DITHER:
+      csp->dither = g_value_get_enum (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+void
+gst_csp_get_property (GObject * object, guint property_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstCsp *csp;
+
+  g_return_if_fail (GST_IS_CSP (object));
+  csp = GST_CSP (object);
+
+  switch (property_id) {
+    case PROP_DITHER:
+      g_value_set_enum (value, csp->dither);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
 static gboolean
 gst_csp_get_unit_size (GstBaseTransform * btrans, GstCaps * caps, guint * size)
 {
@@ -465,6 +556,12 @@ gst_csp_transform (GstBaseTransform * btrans, GstBuffer * inbuf,
           space->to_format == GST_VIDEO_FORMAT_UNKNOWN))
     goto unknown_format;
 
+  if (space->dither) {
+    colorspace_convert_set_dither (space->convert, 1);
+  } else {
+    colorspace_convert_set_dither (space->convert, 0);
+  }
+
   colorspace_convert_convert (space->convert, GST_BUFFER_DATA (outbuf),
       GST_BUFFER_DATA (inbuf));
 
index c97705c..71245b8 100644 (file)
@@ -56,6 +56,7 @@ struct _GstCsp {
   ColorSpaceColorSpec to_spec;
 
   ColorspaceConvert *convert;
+  gboolean dither;
 };
 
 struct _GstCspClass