xsharpen video filter from Virtualdub
authorJeremy Simon <jsimon13@yahoo.fr>
Tue, 9 Jul 2002 19:21:29 +0000 (19:21 +0000)
committerJeremy Simon <jsimon13@yahoo.fr>
Tue, 9 Jul 2002 19:21:29 +0000 (19:21 +0000)
Original commit message from CVS:
xsharpen video filter from Virtualdub

common
gst/virtualdub/Makefile.am [new file with mode: 0644]
gst/virtualdub/gstvirtualdub.c [new file with mode: 0644]
gst/virtualdub/gstvirtualdub.h [new file with mode: 0644]
gst/virtualdub/gstxsharpen.c [new file with mode: 0644]

diff --git a/common b/common
index 1a82674..4ed4b88 160000 (submodule)
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit 1a826743b023d38a14e16cf1b3fb85eabdbb65d6
+Subproject commit 4ed4b888250d1081585717504b571ebf2de72c60
diff --git a/gst/virtualdub/Makefile.am b/gst/virtualdub/Makefile.am
new file mode 100644 (file)
index 0000000..072727b
--- /dev/null
@@ -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 (file)
index 0000000..d83ccd2
--- /dev/null
@@ -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 (file)
index 0000000..e441e1b
--- /dev/null
@@ -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 (file)
index 0000000..bced666
--- /dev/null
@@ -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;
+  }
+}