diff options
Diffstat (limited to 'gst')
-rw-r--r-- | gst/virtualdub/Makefile.am | 11 | ||||
-rw-r--r-- | gst/virtualdub/gstvirtualdub.c | 122 | ||||
-rw-r--r-- | gst/virtualdub/gstvirtualdub.h | 38 | ||||
-rw-r--r-- | gst/virtualdub/gstxsharpen.c | 461 |
4 files changed, 632 insertions, 0 deletions
diff --git a/gst/virtualdub/Makefile.am b/gst/virtualdub/Makefile.am new file mode 100644 index 00000000..072727b4 --- /dev/null +++ b/gst/virtualdub/Makefile.am @@ -0,0 +1,11 @@ +plugindir = $(libdir)/gst + +plugin_LTLIBRARIES = libgstvirtualdub.la + +libgstvirtualdub_la_SOURCES = gstvirtualdub.c gstxsharpen.c +libgstvirtualdub_la_CFLAGS = $(GST_CFLAGS) +libgstvirtualdub_la_LIBADD = +libgstvirtualdub_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + +noinst_HEADERS = gstvirtualdub.h + diff --git a/gst/virtualdub/gstvirtualdub.c b/gst/virtualdub/gstvirtualdub.c new file mode 100644 index 00000000..d83ccd2c --- /dev/null +++ b/gst/virtualdub/gstvirtualdub.c @@ -0,0 +1,122 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * EffecTV: + * Copyright (C) 2001 FUKUCHI Kentarou + * + * EffecTV is free software. We release this product under the terms of the + * GNU General Public License version 2. The license is included in the file + * COPYING. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + */ + +#include <string.h> +#include <gst/gst.h> +#include "gstvirtualdub.h" + + +struct _elements_entry { + gchar *name; + GType (*type) (void); + GstElementDetails *details; + gboolean (*factoryinit) (GstElementFactory *factory); +}; + +static struct _elements_entry _elements[] = { + { "xsharpen", gst_xsharpen_get_type, &gst_xsharpen_details, NULL }, + { NULL, 0 }, +}; + + +GstPadTemplate* +gst_virtualdub_src_factory (void) +{ + static GstPadTemplate *templ = NULL; + if (!templ) { + templ = GST_PAD_TEMPLATE_NEW ( + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "virtualdub_src", + "video/raw", + "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("RGB ")), + "bpp", GST_PROPS_INT (32), + "depth", GST_PROPS_INT (32), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "red_mask", GST_PROPS_INT (0xff0000), + "green_mask", GST_PROPS_INT (0xff00), + "blue_mask", GST_PROPS_INT (0xff), + "width", GST_PROPS_INT_RANGE (16, 4096), + "height", GST_PROPS_INT_RANGE (16, 4096) + ) + ); + } + return templ; +} + +GstPadTemplate* +gst_virtualdub_sink_factory (void) +{ + static GstPadTemplate *templ = NULL; + if (!templ) { + templ = GST_PAD_TEMPLATE_NEW ( + "sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "virtualdub_sink", + "video/raw", + "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("RGB ")), + "bpp", GST_PROPS_INT (32), + "depth", GST_PROPS_INT (32), + "endianness", GST_PROPS_INT (G_BYTE_ORDER), + "red_mask", GST_PROPS_INT (0xff0000), + "green_mask", GST_PROPS_INT (0xff00), + "blue_mask", GST_PROPS_INT (0xff), + "width", GST_PROPS_INT_RANGE (16, 4096), + "height", GST_PROPS_INT_RANGE (16, 4096) + ) + ); + } + return templ; +} + +static gboolean +plugin_init (GModule * module, GstPlugin * plugin) +{ + GstElementFactory *factory; + gint i = 0; + + while (_elements[i].name) { + factory = gst_element_factory_new (_elements[i].name, + (_elements[i].type) (), + _elements[i].details); + + if (!factory) { + g_warning ("gst_virtualdub_new failed for `%s'", + _elements[i].name); + continue; + } + gst_element_factory_add_pad_template (factory, gst_virtualdub_src_factory ()); + gst_element_factory_add_pad_template (factory, gst_virtualdub_sink_factory ()); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + if (_elements[i].factoryinit) { + _elements[i].factoryinit (factory); + } + i++; + } + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "virtualdub", + plugin_init +}; diff --git a/gst/virtualdub/gstvirtualdub.h b/gst/virtualdub/gstvirtualdub.h new file mode 100644 index 00000000..e441e1b4 --- /dev/null +++ b/gst/virtualdub/gstvirtualdub.h @@ -0,0 +1,38 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * Filter: + * Copyright (C) 2000 Donald A. Graft + * + * EffecTV is free software. We release this product under the terms of the + * GNU General Public License version 2. The license is included in the file + * COPYING. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + */ + +#include <gst/gst.h> + +typedef unsigned int Pixel; +typedef unsigned int Pixel32; +typedef unsigned char Pixel8; +typedef int PixCoord; +typedef int PixDim; +typedef int PixOffset; + + +#define R_MASK (0x00ff0000) +#define G_MASK (0x0000ff00) +#define B_MASK (0x000000ff) +#define R_SHIFT (16) +#define G_SHIFT (8) +#define B_SHIFT (0) + + +GType gst_xsharpen_get_type (void); +extern GstElementDetails gst_xsharpen_details; + +extern GstPadTemplate *gst_virtualdub_sink_factory (); +extern GstPadTemplate *gst_virtualdub_src_factory (); diff --git a/gst/virtualdub/gstxsharpen.c b/gst/virtualdub/gstxsharpen.c new file mode 100644 index 00000000..bced666f --- /dev/null +++ b/gst/virtualdub/gstxsharpen.c @@ -0,0 +1,461 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * + * Filter: + * Copyright (C) 2000 Donald A. Graft + * + * Port done with help of transcode xsharpen filter by Tilmann Bitterberg + * + * EffecTV is free software. We release this product under the terms of the + * GNU General Public License version 2. The license is included in the file + * COPYING. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + */ + +#include <string.h> +#include <gst/gst.h> +#include "gstvirtualdub.h" + +#define GST_TYPE_XSHARPEN \ + (gst_xsharpen_get_type()) +#define GST_XSHARPEN(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_XSHARPEN,GstXsharpen)) +#define GST_XSHARPEN_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstXsharpen)) +#define GST_IS_XSHARPEN(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_XSHARPEN)) +#define GST_IS_XSHARPEN_CLASS(obj) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_XSHARPEN)) + +typedef struct _GstXsharpen GstXsharpen; +typedef struct _GstXsharpenClass GstXsharpenClass; + +struct _GstXsharpen +{ + GstElement element; + + GstPad *sinkpad, *srcpad; + + gint width, height; + gint strength, strengthinv, threshold; + gint srcpitch, dstpitch; +}; + +struct _GstXsharpenClass +{ + GstElementClass parent_class; +}; + +GstElementDetails gst_xsharpen_details = { + "", + "Filter/Video/Effect", + "Apply a sharpen effect on video" + VERSION, + "Jeremy SIMON <jsimon13@yahoo.fr>", + "(C) 2000 Donald Graft", +}; + + +/* Filter signals and args */ +enum +{ + /* FILL ME */ + ARG_STRENGTH, + ARG_THRESHOLD, + LAST_SIGNAL +}; + +enum +{ + ARG_0, +}; + +static void gst_xsharpen_class_init (GstXsharpenClass * klass); +static void gst_xsharpen_init (GstXsharpen * sharpen); + +static void gst_xsharpen_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_xsharpen_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static void gst_xsharpen_chain (GstPad * pad, GstBuffer * buf); + +static GstElementClass *parent_class = NULL; + +GType gst_xsharpen_get_type (void) +{ + static GType xsharpen_type = 0; + + if (!xsharpen_type) { + static const GTypeInfo xsharpen_info = { + sizeof (GstXsharpenClass), NULL, + NULL, + (GClassInitFunc) gst_xsharpen_class_init, + NULL, + NULL, + sizeof (GstXsharpen), + 0, + (GInstanceInitFunc) gst_xsharpen_init, + }; + + xsharpen_type = g_type_register_static (GST_TYPE_ELEMENT, "GstXsharpen", &xsharpen_info, 0); + } + return xsharpen_type; +} + +static void +gst_xsharpen_class_init (GstXsharpenClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_ELEMENT); + + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_STRENGTH, + g_param_spec_int("strength", "strength", "strength", + 0, 255, 255, (GParamFlags)G_PARAM_READWRITE )); + + g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_THRESHOLD, + g_param_spec_int("threshold", "threshold", "threshold", + 0, 255, 255, (GParamFlags)G_PARAM_READWRITE )); + + gobject_class->set_property = gst_xsharpen_set_property; + gobject_class->get_property = gst_xsharpen_get_property; +} + +static GstPadConnectReturn +gst_xsharpen_sinkconnect (GstPad * pad, GstCaps * caps) +{ + GstXsharpen *sharpen; + + sharpen = GST_XSHARPEN (gst_pad_get_parent (pad)); + + if (!GST_CAPS_IS_FIXED (caps)) + return GST_PAD_CONNECT_DELAYED; + + gst_caps_get_int (caps, "width", &sharpen->width); + gst_caps_get_int (caps, "height", &sharpen->height); + + sharpen->strengthinv = 255 - sharpen->strength; + + sharpen->dstpitch = sharpen->srcpitch = sharpen->width * sizeof (Pixel32); + + if (gst_pad_try_set_caps (sharpen->srcpad, caps)) { + return GST_PAD_CONNECT_OK; + } + + return GST_PAD_CONNECT_REFUSED; +} + +static void +gst_xsharpen_init (GstXsharpen * sharpen) +{ + sharpen->sinkpad = gst_pad_new_from_template (gst_virtualdub_sink_factory (), "sink"); + gst_pad_set_chain_function (sharpen->sinkpad, gst_xsharpen_chain); + gst_pad_set_connect_function (sharpen->sinkpad, gst_xsharpen_sinkconnect); + gst_element_add_pad (GST_ELEMENT (sharpen), sharpen->sinkpad); + + sharpen->srcpad = gst_pad_new_from_template (gst_virtualdub_src_factory (), "src"); + gst_element_add_pad (GST_ELEMENT (sharpen), sharpen->srcpad); +} + +static void +gst_xsharpen_chain (GstPad * pad, GstBuffer * buf) +{ + GstXsharpen *xsharpen; + GstBuffer *outbuf; + gint x, y; + gint r, g, b, R, G, B; + Pixel32 p, min, max; + gint luma, lumac, lumamax, lumamin, mindiff, maxdiff; + Pixel32 *src_buf, *dst_buf, *src, *dst; + + xsharpen = GST_XSHARPEN (gst_pad_get_parent (pad)); + + outbuf = gst_buffer_new (); + GST_BUFFER_SIZE (outbuf) = ( xsharpen->width * xsharpen->height * sizeof (Pixel32)); + GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf)); + + GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf); + + src_buf = (Pixel32 *)GST_BUFFER_DATA (buf); + dst_buf = (Pixel32 *)GST_BUFFER_DATA (outbuf); + min = max = 0; + + /* First copy through the four border lines. */ + src = src_buf; + dst = dst_buf; + for (x = 0; x < xsharpen->width; x++) + { + dst[x] = src[x]; + } + + src = (Pixel *)((char *)src_buf + (xsharpen->height - 1) * xsharpen->srcpitch); + dst = (Pixel *)((char *)dst_buf + (xsharpen->height - 1) * xsharpen->dstpitch); + + for (x = 0; x < xsharpen->width; x++) + { + dst[x] = src[x]; + } + + src = src_buf; + dst = dst_buf; + + for (y = 0; y < xsharpen->height; y++) + { + dst[0] = src[0]; + dst[xsharpen->width-1] = src[xsharpen->width-1]; + src = (Pixel *)((char *)src + xsharpen->srcpitch); + dst = (Pixel *)((char *)dst + xsharpen->dstpitch); + } + + /* Now calculate and store the pixel luminances for the remaining pixels. */ + src = src_buf; + for (y = 0; y < xsharpen->height; y++) + { + for (x = 0; x < xsharpen->width; x++) + { + r = (src[x] >> 16) & 0xff; + g = (src[x] >> 8) & 0xff; + b = src[x] & 0xff; + luma = (55 * r + 182 * g + 19 * b) >> 8; + src[x] &= 0x00ffffff; + src[x] |= (luma << 24); + } + src = (Pixel *)((char *)src + xsharpen->srcpitch); + } + + /* Finally run the 3x3 rank-order sharpening kernel over the pixels. */ + src = (Pixel *)((char *)src_buf + xsharpen->srcpitch); + dst = (Pixel *)((char *)dst_buf + xsharpen->dstpitch); + + for (y = 1; y < xsharpen->height - 1; y++) + { + for (x = 1; x < xsharpen->width - 1; x++) + { + /* Find the brightest and dimmest pixels in the 3x3 window + surrounding the current pixel. */ + + lumamax = -1; + lumamin = 1000; + + p = ((Pixel32 *)((char *)src - xsharpen->srcpitch))[x-1]; + luma = p >> 24; + if (luma > lumamax) + { + lumamax = luma; + max = p; + } + if (luma < lumamin) + { + lumamin = luma; + min = p; + } + + p = ((Pixel32 *)((char *)src - xsharpen->srcpitch))[x]; + luma = p >> 24; + if (luma > lumamax) + { + lumamax = luma; + max = p; + } + if (luma < lumamin) + { + lumamin = luma; + min = p; + } + + p = ((Pixel32 *)((char *)src - xsharpen->srcpitch))[x+1]; + luma = p >> 24; + if (luma > lumamax) + { + lumamax = luma; + max = p; + } + if (luma < lumamin) + { + lumamin = luma; + min = p; + } + + p = src[x-1]; + luma = p >> 24; + if (luma > lumamax) + { + lumamax = luma; + max = p; + } + if (luma < lumamin) + { + lumamin = luma; + min = p; + } + + p = src[x]; + lumac = luma = p >> 24; + if (luma > lumamax) + { + lumamax = luma; + max = p; + } + if (luma < lumamin) + { + lumamin = luma; + min = p; + } + + p = src[x+1]; + luma = p >> 24; + if (luma > lumamax) + { + lumamax = luma; + max = p; + } + if (luma < lumamin) + { + lumamin = luma; + min = p; + } + + p = ((Pixel32 *)((char *)src + xsharpen->srcpitch))[x-1]; + luma = p >> 24; + if (luma > lumamax) + { + lumamax = luma; + max = p; + } + if (luma < lumamin) + { + lumamin = luma; + min = p; + } + + p = ((Pixel32 *)((char *)src + xsharpen->srcpitch))[x]; + luma = p >> 24; + if (luma > lumamax) + { + lumamax = luma; + max = p; + } + if (luma < lumamin) + { + lumamin = luma; + min = p; + } + + p = ((Pixel32 *)((char *)src + xsharpen->srcpitch))[x+1]; + luma = p >> 24; + if (luma > lumamax) + { + lumamax = luma; + max = p; + } + if (luma < lumamin) + { + lumamin = luma; + min = p; + } + + /* Determine whether the current pixel is closer to the + brightest or the dimmest pixel. Then compare the current + pixel to that closest pixel. If the difference is within + threshold, map the current pixel to the closest pixel; + otherwise pass it through. */ + + p = -1; + if (xsharpen->strength != 0) + { + mindiff = lumac - lumamin; + maxdiff = lumamax - lumac; + if (mindiff > maxdiff) + { + if (maxdiff < xsharpen->threshold) + { + p = max; + } + } + else + { + if (mindiff < xsharpen->threshold) + { + p = min; + } + } + } + + if (p == -1) + { + dst[x] = src[x]; + } + else + { + R = (src[x] >> 16) & 0xff; + G = (src[x] >> 8) & 0xff; + B = src[x] & 0xff; + r = (p >> 16) & 0xff; + g = (p >> 8) & 0xff; + b = p & 0xff; + r = (xsharpen->strength * r + xsharpen->strengthinv * R) / 255; + g = (xsharpen->strength * g + xsharpen->strengthinv * G) / 255; + b = (xsharpen->strength * b + xsharpen->strengthinv * B) / 255; + dst[x] = (r << 16) | (g << 8) | b; + } + } + src = (Pixel *)((char *)src + xsharpen->srcpitch); + dst = (Pixel *)((char *)dst + xsharpen->dstpitch); + } + + gst_buffer_unref (buf); + + gst_pad_push (xsharpen->srcpad, outbuf); +} + +static void +gst_xsharpen_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstXsharpen *xsharpen; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_XSHARPEN (object)); + + xsharpen = GST_XSHARPEN (object); + + switch (prop_id) { + case ARG_STRENGTH: + xsharpen->strength = g_value_get_int (value); + xsharpen->strengthinv = 255 - xsharpen->strength; + case ARG_THRESHOLD: + xsharpen->threshold = g_value_get_int (value); + default: + break; + } +} + +static void +gst_xsharpen_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstXsharpen *xsharpen; + + /* it's not null if we got it, but it might not be ours */ + g_return_if_fail (GST_IS_XSHARPEN (object)); + + xsharpen = GST_XSHARPEN (object); + + switch (prop_id) { + case ARG_STRENGTH: + g_value_set_int (value, xsharpen->strength ); + break; + case ARG_THRESHOLD: + g_value_set_int (value, xsharpen->threshold ); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} |