--- /dev/null
+/* 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
+};
--- /dev/null
+/* 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;
+ }
+}