xsharpen video filter from Virtualdub

Original commit message from CVS:
xsharpen video filter from Virtualdub
This commit is contained in:
Jeremy Simon 2002-07-09 19:21:29 +00:00
parent 2b60d60286
commit b821822691
5 changed files with 633 additions and 1 deletions

2
common

@ -1 +1 @@
Subproject commit 1a826743b023d38a14e16cf1b3fb85eabdbb65d6
Subproject commit 4ed4b888250d1081585717504b571ebf2de72c60

View file

@ -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

View file

@ -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
};

View file

@ -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 ();

View file

@ -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;
}
}