From f53d15156b7aa3bdc358a42469f052b4f178bbb6 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Sun, 20 Feb 2011 22:43:56 -0800 Subject: [PATCH] [MOVED FROM BAD 60/68] colorspace: Add dithering Dithering only happens when a 16-bit-per-channel format is involved. --- gst/colorspace/colorspace.c | 62 +++++++++++++++++++++++++++ gst/colorspace/colorspace.h | 10 +++++ gst/colorspace/gstcolorspace.c | 97 ++++++++++++++++++++++++++++++++++++++++++ gst/colorspace/gstcolorspace.h | 1 + 4 files changed, 170 insertions(+) diff --git a/gst/colorspace/colorspace.c b/gst/colorspace/colorspace.c index d98ad20..1079866 100644 --- a/gst/colorspace/colorspace.c +++ b/gst/colorspace/colorspace.c @@ -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 */ diff --git a/gst/colorspace/colorspace.h b/gst/colorspace/colorspace.h index fe72524..05bcc18 100644 --- a/gst/colorspace/colorspace.h +++ b/gst/colorspace/colorspace.h @@ -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, diff --git a/gst/colorspace/gstcolorspace.c b/gst/colorspace/gstcolorspace.c index 84c9af9..658bc8a 100644 --- a/gst/colorspace/gstcolorspace.c +++ b/gst/colorspace/gstcolorspace.c @@ -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)); diff --git a/gst/colorspace/gstcolorspace.h b/gst/colorspace/gstcolorspace.h index c97705c..71245b8 100644 --- a/gst/colorspace/gstcolorspace.h +++ b/gst/colorspace/gstcolorspace.h @@ -56,6 +56,7 @@ struct _GstCsp { ColorSpaceColorSpec to_spec; ColorspaceConvert *convert; + gboolean dither; }; struct _GstCspClass -- 2.7.4