[MOVED FROM BAD 60/68] colorspace: Add dithering

Dithering only happens when a 16-bit-per-channel format is
involved.
This commit is contained in:
David Schleef 2011-02-20 22:43:56 -08:00 committed by Wim Taymans
parent 1b3697cfe3
commit f53d15156b
4 changed files with 170 additions and 0 deletions

View 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);
}
@ -148,6 +154,23 @@ colorspace_convert_set_interlaced (ColorspaceConvert * convert,
convert->interlaced = interlaced;
}
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 */

View 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,

View 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));

View file

@ -56,6 +56,7 @@ struct _GstCsp {
ColorSpaceColorSpec to_spec;
ColorspaceConvert *convert;
gboolean dither;
};
struct _GstCspClass