mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-03 01:02:19 +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);
|
guint8 * dest, const guint8 * src);
|
||||||
static void colorspace_convert_lookup_fastpath (ColorspaceConvert * convert);
|
static void colorspace_convert_lookup_fastpath (ColorspaceConvert * convert);
|
||||||
static void colorspace_convert_lookup_getput (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 *
|
ColorspaceConvert *
|
||||||
|
@ -72,6 +75,7 @@ colorspace_convert_new (GstVideoFormat to_format, ColorSpaceColorSpec to_spec,
|
||||||
convert->height = height;
|
convert->height = height;
|
||||||
convert->width = width;
|
convert->width = width;
|
||||||
convert->convert = colorspace_convert_generic;
|
convert->convert = colorspace_convert_generic;
|
||||||
|
convert->dither16 = colorspace_dither_none;
|
||||||
|
|
||||||
if (gst_video_format_get_component_depth (to_format, 0) > 8 ||
|
if (gst_video_format_get_component_depth (to_format, 0) > 8 ||
|
||||||
gst_video_format_get_component_depth (from_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->tmpline = g_malloc (sizeof (guint8) * (width + 8) * 4);
|
||||||
convert->tmpline16 = g_malloc (sizeof (guint16) * (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) {
|
if (to_format == GST_VIDEO_FORMAT_RGB8_PALETTED) {
|
||||||
/* build poor man's palette, taken from ffmpegcolorspace */
|
/* build poor man's palette, taken from ffmpegcolorspace */
|
||||||
|
@ -137,6 +142,7 @@ colorspace_convert_free (ColorspaceConvert * convert)
|
||||||
g_free (convert->palette);
|
g_free (convert->palette);
|
||||||
g_free (convert->tmpline);
|
g_free (convert->tmpline);
|
||||||
g_free (convert->tmpline16);
|
g_free (convert->tmpline16);
|
||||||
|
g_free (convert->errline);
|
||||||
|
|
||||||
g_free (convert);
|
g_free (convert);
|
||||||
}
|
}
|
||||||
|
@ -148,6 +154,23 @@ colorspace_convert_set_interlaced (ColorspaceConvert * convert,
|
||||||
convert->interlaced = interlaced;
|
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
|
void
|
||||||
colorspace_convert_set_palette (ColorspaceConvert * convert,
|
colorspace_convert_set_palette (ColorspaceConvert * convert,
|
||||||
const guint32 * palette)
|
const guint32 * palette)
|
||||||
|
@ -1681,6 +1704,7 @@ colorspace_convert_generic (ColorspaceConvert * convert, guint8 * dest,
|
||||||
for (j = 0; j < convert->height; j++) {
|
for (j = 0; j < convert->height; j++) {
|
||||||
convert->getline16 (convert, convert->tmpline16, src, j);
|
convert->getline16 (convert, convert->tmpline16, src, j);
|
||||||
convert->matrix16 (convert);
|
convert->matrix16 (convert);
|
||||||
|
convert->dither16 (convert, j);
|
||||||
convert->putline16 (convert, dest, convert->tmpline16, j);
|
convert->putline16 (convert, dest, convert->tmpline16, j);
|
||||||
}
|
}
|
||||||
} else {
|
} 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 */
|
/* Fast paths */
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,12 @@ typedef enum {
|
||||||
COLOR_SPEC_YUV_BT709
|
COLOR_SPEC_YUV_BT709
|
||||||
} ColorSpaceColorSpec;
|
} ColorSpaceColorSpec;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DITHER_NONE,
|
||||||
|
DITHER_VERTERR,
|
||||||
|
DITHER_HALFTONE
|
||||||
|
} ColorSpaceDitherMethod;
|
||||||
|
|
||||||
struct _ColorspaceComponent {
|
struct _ColorspaceComponent {
|
||||||
int offset;
|
int offset;
|
||||||
int stride;
|
int stride;
|
||||||
|
@ -44,6 +50,7 @@ struct _ColorspaceConvert {
|
||||||
gint width, height;
|
gint width, height;
|
||||||
gboolean interlaced;
|
gboolean interlaced;
|
||||||
gboolean use_16bit;
|
gboolean use_16bit;
|
||||||
|
gboolean dither;
|
||||||
|
|
||||||
GstVideoFormat from_format;
|
GstVideoFormat from_format;
|
||||||
ColorSpaceColorSpec from_spec;
|
ColorSpaceColorSpec from_spec;
|
||||||
|
@ -53,6 +60,7 @@ struct _ColorspaceConvert {
|
||||||
|
|
||||||
guint8 *tmpline;
|
guint8 *tmpline;
|
||||||
guint16 *tmpline16;
|
guint16 *tmpline16;
|
||||||
|
guint16 *errline;
|
||||||
|
|
||||||
int dest_offset[4];
|
int dest_offset[4];
|
||||||
int dest_stride[4];
|
int dest_stride[4];
|
||||||
|
@ -67,11 +75,13 @@ struct _ColorspaceConvert {
|
||||||
void (*getline16) (ColorspaceConvert *convert, guint16 *dest, const guint8 *src, int j);
|
void (*getline16) (ColorspaceConvert *convert, guint16 *dest, const guint8 *src, int j);
|
||||||
void (*putline16) (ColorspaceConvert *convert, guint8 *dest, const guint16 *src, int j);
|
void (*putline16) (ColorspaceConvert *convert, guint8 *dest, const guint16 *src, int j);
|
||||||
void (*matrix16) (ColorspaceConvert *convert);
|
void (*matrix16) (ColorspaceConvert *convert);
|
||||||
|
void (*dither16) (ColorspaceConvert *convert, int j);
|
||||||
};
|
};
|
||||||
|
|
||||||
ColorspaceConvert * colorspace_convert_new (GstVideoFormat to_format,
|
ColorspaceConvert * colorspace_convert_new (GstVideoFormat to_format,
|
||||||
ColorSpaceColorSpec from_spec, GstVideoFormat from_format,
|
ColorSpaceColorSpec from_spec, GstVideoFormat from_format,
|
||||||
ColorSpaceColorSpec to_spec, int width, int height);
|
ColorSpaceColorSpec to_spec, int width, int height);
|
||||||
|
void colorspace_convert_set_dither (ColorspaceConvert * convert, int type);
|
||||||
void colorspace_convert_set_interlaced (ColorspaceConvert *convert,
|
void colorspace_convert_set_interlaced (ColorspaceConvert *convert,
|
||||||
gboolean interlaced);
|
gboolean interlaced);
|
||||||
void colorspace_convert_set_palette (ColorspaceConvert *convert,
|
void colorspace_convert_set_palette (ColorspaceConvert *convert,
|
||||||
|
|
|
@ -46,6 +46,12 @@ GST_DEBUG_CATEGORY (colorspace_debug);
|
||||||
#define GST_CAT_DEFAULT colorspace_debug
|
#define GST_CAT_DEFAULT colorspace_debug
|
||||||
GST_DEBUG_CATEGORY (colorspace_performance);
|
GST_DEBUG_CATEGORY (colorspace_performance);
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PROP_0,
|
||||||
|
PROP_DITHER
|
||||||
|
};
|
||||||
|
|
||||||
#define CSP_VIDEO_CAPS \
|
#define CSP_VIDEO_CAPS \
|
||||||
"video/x-raw-yuv, width = "GST_VIDEO_SIZE_RANGE" , " \
|
"video/x-raw-yuv, width = "GST_VIDEO_SIZE_RANGE" , " \
|
||||||
"height="GST_VIDEO_SIZE_RANGE",framerate="GST_VIDEO_FPS_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);
|
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,
|
static gboolean gst_csp_set_caps (GstBaseTransform * btrans,
|
||||||
GstCaps * incaps, GstCaps * outcaps);
|
GstCaps * incaps, GstCaps * outcaps);
|
||||||
static gboolean gst_csp_get_unit_size (GstBaseTransform * btrans,
|
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 _QRAWYUV; /* "video/x-raw-yuv" */
|
||||||
static GQuark _QALPHAMASK; /* "alpha_mask" */
|
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 */
|
/* copies the given caps */
|
||||||
static GstCaps *
|
static GstCaps *
|
||||||
gst_csp_caps_remove_format_info (GstCaps * caps)
|
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");
|
_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
|
static void
|
||||||
gst_csp_finalize (GObject * obj)
|
gst_csp_finalize (GObject * obj)
|
||||||
{
|
{
|
||||||
|
@ -415,6 +459,9 @@ gst_csp_class_init (GstCspClass * klass)
|
||||||
GstBaseTransformClass *gstbasetransform_class =
|
GstBaseTransformClass *gstbasetransform_class =
|
||||||
(GstBaseTransformClass *) klass;
|
(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;
|
gobject_class->finalize = gst_csp_finalize;
|
||||||
|
|
||||||
gstbasetransform_class->transform_caps =
|
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->transform = GST_DEBUG_FUNCPTR (gst_csp_transform);
|
||||||
|
|
||||||
gstbasetransform_class->passthrough_on_same_caps = TRUE;
|
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
|
static void
|
||||||
|
@ -434,6 +487,44 @@ gst_csp_init (GstCsp * space, GstCspClass * klass)
|
||||||
space->to_format = GST_VIDEO_FORMAT_UNKNOWN;
|
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
|
static gboolean
|
||||||
gst_csp_get_unit_size (GstBaseTransform * btrans, GstCaps * caps, guint * size)
|
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))
|
space->to_format == GST_VIDEO_FORMAT_UNKNOWN))
|
||||||
goto unknown_format;
|
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),
|
colorspace_convert_convert (space->convert, GST_BUFFER_DATA (outbuf),
|
||||||
GST_BUFFER_DATA (inbuf));
|
GST_BUFFER_DATA (inbuf));
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,7 @@ struct _GstCsp {
|
||||||
ColorSpaceColorSpec to_spec;
|
ColorSpaceColorSpec to_spec;
|
||||||
|
|
||||||
ColorspaceConvert *convert;
|
ColorspaceConvert *convert;
|
||||||
|
gboolean dither;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstCspClass
|
struct _GstCspClass
|
||||||
|
|
Loading…
Reference in a new issue