mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
[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:
parent
1b3697cfe3
commit
f53d15156b
4 changed files with 170 additions and 0 deletions
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@ struct _GstCsp {
|
|||
ColorSpaceColorSpec to_spec;
|
||||
|
||||
ColorspaceConvert *convert;
|
||||
gboolean dither;
|
||||
};
|
||||
|
||||
struct _GstCspClass
|
||||
|
|
Loading…
Reference in a new issue