From 9e67891f7251ddb3b44545dc7a16d271f3649989 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 16 Oct 2012 13:47:24 +0200 Subject: [PATCH] videomedian: copy media to videomedian Copy the median video filter to videofilters and rename to videomedian. --- gst/videofilter/Makefile.am | 5 +- gst/videofilter/gstvideomedian.c | 318 +++++++++++++++++++++++++++++++++++++++ gst/videofilter/gstvideomedian.h | 68 +++++++++ gst/videofilter/plugin.c | 5 +- 4 files changed, 393 insertions(+), 3 deletions(-) create mode 100644 gst/videofilter/gstvideomedian.c create mode 100644 gst/videofilter/gstvideomedian.h diff --git a/gst/videofilter/Makefile.am b/gst/videofilter/Makefile.am index 4a7b9d9..0422e12 100644 --- a/gst/videofilter/Makefile.am +++ b/gst/videofilter/Makefile.am @@ -1,6 +1,6 @@ plugin_LTLIBRARIES = libgstvideofilter.la -noinst_HEADERS = gstvideoflip.h gstvideobalance.h gstgamma.h +noinst_HEADERS = gstvideoflip.h gstvideobalance.h gstgamma.h gstvideomedian.h EXTRA_DIST = gstvideotemplate.c make_filter CLEANFILES = gstvideoexample.c @@ -8,7 +8,8 @@ CLEANFILES = gstvideoexample.c libgstvideofilter_la_SOURCES = plugin.c \ gstvideoflip.c \ gstvideobalance.c \ - gstgamma.c + gstgamma.c \ + gstvideomedian.c libgstvideofilter_la_CFLAGS = $(GST_CFLAGS) \ $(GST_BASE_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) diff --git a/gst/videofilter/gstvideomedian.c b/gst/videofilter/gstvideomedian.c new file mode 100644 index 0000000..0d837cd --- /dev/null +++ b/gst/videofilter/gstvideomedian.c @@ -0,0 +1,318 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include "gstvideomedian.h" + +static GstStaticPadTemplate video_median_src_factory = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ I420, YV12 }")) + ); + +static GstStaticPadTemplate video_median_sink_factory = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ I420, YV12 }")) + ); + + +/* Median signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +enum +{ + PROP_0, + PROP_ACTIVE, + PROP_FILTERSIZE, + PROP_LUM_ONLY +}; + +#define gst_video_median_parent_class parent_class +G_DEFINE_TYPE (GstVideoMedian, gst_video_median, GST_TYPE_VIDEO_FILTER); + +static GstFlowReturn gst_video_median_transform_frame (GstVideoFilter * filter, + GstVideoFrame * in_frame, GstVideoFrame * out_frame); + +static void gst_video_median_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_video_median_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static void +gst_video_median_class_init (GstVideoMedianClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstVideoFilterClass *vfilter_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + vfilter_class = (GstVideoFilterClass *) klass; + + gobject_class->set_property = gst_video_median_set_property; + gobject_class->get_property = gst_video_median_get_property; + + /* FIXME: add long property descriptions */ + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ACTIVE, + g_param_spec_boolean ("active", "active", "active", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILTERSIZE, + g_param_spec_int ("filtersize", "filtersize", "filtersize", G_MININT, + G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LUM_ONLY, + g_param_spec_boolean ("lum-only", "lum-only", "lum-only", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&video_median_sink_factory)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&video_median_src_factory)); + gst_element_class_set_static_metadata (gstelement_class, "Median effect", + "Filter/Effect/Video", + "Apply a median filter to an image", + "Wim Taymans "); + + vfilter_class->transform_frame = + GST_DEBUG_FUNCPTR (gst_video_median_transform_frame); +} + +void +gst_video_median_init (GstVideoMedian * median) +{ + median->filtersize = 5; + median->lum_only = TRUE; + median->active = TRUE; +} + +#define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); } +#define PIX_SWAP(a,b) { unsigned char temp=(a);(a)=(b);(b)=temp; } + +static void +median_5 (guint8 * dest, gint dstride, const guint8 * src, gint sstride, + gint width, gint height) +{ + unsigned char p[5]; + int i, j, k; + + /* copy the top and bottom rows into the result array */ + for (i = 0; i < width; i++) { + dest[i] = src[i]; + dest[(height - 1) * dstride + i] = src[(height - 1) * sstride + i]; + } + + /* process the interior pixels */ + for (k = 2; k < height; k++) { + dest += dstride; + src += sstride; + + dest[0] = src[0]; + for (j = 2, i = 1; j < width; j++, i++) { + p[0] = src[i - sstride]; + p[1] = src[i - 1]; + p[2] = src[i]; + p[3] = src[i + 1]; + p[4] = src[i + sstride]; + PIX_SORT (p[0], p[1]); + PIX_SORT (p[3], p[4]); + PIX_SORT (p[0], p[3]); + PIX_SORT (p[1], p[4]); + PIX_SORT (p[1], p[2]); + PIX_SORT (p[2], p[3]); + PIX_SORT (p[1], p[2]); + dest[i] = p[2]; + } + dest[i] = src[i]; + } +} + +static void +median_9 (guint8 * dest, gint dstride, const guint8 * src, gint sstride, + gint width, gint height) +{ + unsigned char p[9]; + int i, j, k; + + /*copy the top and bottom rows into the result array */ + for (i = 0; i < width; i++) { + dest[i] = src[i]; + dest[(height - 1) * dstride + i] = src[(height - 1) * sstride + i]; + } + /* process the interior pixels */ + for (k = 2; k < height; k++) { + dest += dstride; + src += sstride; + + dest[0] = src[0]; + for (j = 2, i = 1; j < width; j++, i++) { + p[0] = src[i - sstride - 1]; + p[1] = src[i - sstride]; + p[2] = src[i - sstride + 1]; + p[3] = src[i - 1]; + p[4] = src[i]; + p[5] = src[i + 1]; + p[6] = src[i + sstride - 1]; + p[7] = src[i + sstride]; + p[8] = src[i + sstride + 1]; + PIX_SORT (p[1], p[2]); + PIX_SORT (p[4], p[5]); + PIX_SORT (p[7], p[8]); + PIX_SORT (p[0], p[1]); + PIX_SORT (p[3], p[4]); + PIX_SORT (p[6], p[7]); + PIX_SORT (p[1], p[2]); + PIX_SORT (p[4], p[5]); + PIX_SORT (p[7], p[8]); + PIX_SORT (p[0], p[3]); + PIX_SORT (p[5], p[8]); + PIX_SORT (p[4], p[7]); + PIX_SORT (p[3], p[6]); + PIX_SORT (p[1], p[4]); + PIX_SORT (p[2], p[5]); + PIX_SORT (p[4], p[7]); + PIX_SORT (p[4], p[2]); + PIX_SORT (p[6], p[4]); + PIX_SORT (p[4], p[2]); + dest[i] = p[4]; + } + dest[i] = src[i]; + } +} + +static GstFlowReturn +gst_video_median_transform_frame (GstVideoFilter * filter, + GstVideoFrame * in_frame, GstVideoFrame * out_frame) +{ + GstVideoMedian *median = GST_VIDEO_MEDIAN (filter); + + if (median->filtersize == 5) { + median_5 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0), + GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0), + GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0), + GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0), + GST_VIDEO_FRAME_WIDTH (in_frame), GST_VIDEO_FRAME_HEIGHT (in_frame)); + + if (median->lum_only) { + gst_video_frame_copy_plane (out_frame, in_frame, 1); + gst_video_frame_copy_plane (out_frame, in_frame, 2); + } else { + median_5 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 1), + GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 1), + GST_VIDEO_FRAME_PLANE_DATA (in_frame, 1), + GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1), + GST_VIDEO_FRAME_WIDTH (in_frame) / 2, + GST_VIDEO_FRAME_HEIGHT (in_frame) / 2); + median_5 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 2), + GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 2), + GST_VIDEO_FRAME_PLANE_DATA (in_frame, 2), + GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 2), + GST_VIDEO_FRAME_WIDTH (in_frame) / 2, + GST_VIDEO_FRAME_HEIGHT (in_frame) / 2); + } + } else { + median_9 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0), + GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0), + GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0), + GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0), + GST_VIDEO_FRAME_WIDTH (in_frame), GST_VIDEO_FRAME_HEIGHT (in_frame)); + + if (median->lum_only) { + gst_video_frame_copy_plane (out_frame, in_frame, 1); + gst_video_frame_copy_plane (out_frame, in_frame, 2); + } else { + median_9 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 1), + GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 1), + GST_VIDEO_FRAME_PLANE_DATA (in_frame, 1), + GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1), + GST_VIDEO_FRAME_WIDTH (in_frame) / 2, + GST_VIDEO_FRAME_HEIGHT (in_frame) / 2); + median_9 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 2), + GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 2), + GST_VIDEO_FRAME_PLANE_DATA (in_frame, 2), + GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 2), + GST_VIDEO_FRAME_WIDTH (in_frame) / 2, + GST_VIDEO_FRAME_HEIGHT (in_frame) / 2); + } + } + + return GST_FLOW_OK; +} + +static void +gst_video_median_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVideoMedian *median; + gint argvalue; + + median = GST_VIDEO_MEDIAN (object); + + switch (prop_id) { + case PROP_FILTERSIZE: + argvalue = g_value_get_int (value); + if (argvalue != 5 && argvalue != 9) { + g_warning ("median: invalid filtersize (%d), must be 5 or 9\n", + argvalue); + } else { + median->filtersize = argvalue; + } + break; + case PROP_ACTIVE: + median->active = g_value_get_boolean (value); + break; + case PROP_LUM_ONLY: + median->lum_only = g_value_get_boolean (value); + break; + default: + break; + } +} + +static void +gst_video_median_get_property (GObject * object, guint prop_id, GValue * value, + GParamSpec * pspec) +{ + GstVideoMedian *median; + + median = GST_VIDEO_MEDIAN (object); + + switch (prop_id) { + case PROP_FILTERSIZE: + g_value_set_int (value, median->filtersize); + break; + case PROP_ACTIVE: + g_value_set_boolean (value, median->active); + break; + case PROP_LUM_ONLY: + g_value_set_boolean (value, median->lum_only); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} diff --git a/gst/videofilter/gstvideomedian.h b/gst/videofilter/gstvideomedian.h new file mode 100644 index 0000000..432ab7e --- /dev/null +++ b/gst/videofilter/gstvideomedian.h @@ -0,0 +1,68 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_VIDEO_MEDIAN_H__ +#define __GST_VIDEO_MEDIAN_H__ + + +#include +#include +#include + +G_BEGIN_DECLS + +#define GST_TYPE_VIDEO_MEDIAN \ + (gst_video_median_get_type()) +#define GST_VIDEO_MEDIAN(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_MEDIAN,GstVideoMedian)) +#define GST_VIDEO_MEDIAN_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_MEDIAN,GstVideoMedianClass)) +#define GST_IS_VIDEO_MEDIAN(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_MEDIAN)) +#define GST_IS_VIDEO_MEDIAN_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_MEDIAN)) + +typedef struct _GstVideoMedian GstVideoMedian; +typedef struct _GstVideoMedianClass GstVideoMedianClass; + +struct _GstVideoMedian { + GstVideoFilter parent; + + int format; + int width; + int height; + + int filtersize; + + gboolean active; + gboolean lum_only; + + GstPad *sinkpad,*srcpad; +}; + +struct _GstVideoMedianClass { + GstVideoFilterClass parent_class; +}; + +GType gst_video_median_get_type (void); + +G_END_DECLS + +#endif /* __GST_VIDEO_MEDIAN_H__ */ diff --git a/gst/videofilter/plugin.c b/gst/videofilter/plugin.c index 212c3a5..306c3a3 100644 --- a/gst/videofilter/plugin.c +++ b/gst/videofilter/plugin.c @@ -26,6 +26,7 @@ #include "gstgamma.h" #include "gstvideoflip.h" #include "gstvideobalance.h" +#include "gstvideomedian.h" static gboolean plugin_init (GstPlugin * plugin) @@ -34,7 +35,9 @@ plugin_init (GstPlugin * plugin) && gst_element_register (plugin, "videobalance", GST_RANK_NONE, GST_TYPE_VIDEO_BALANCE) && gst_element_register (plugin, "videoflip", GST_RANK_NONE, - GST_TYPE_VIDEO_FLIP)); + GST_TYPE_VIDEO_FLIP) + && gst_element_register (plugin, "videomedian", GST_RANK_NONE, + GST_TYPE_VIDEO_MEDIAN)); } GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, -- 2.7.4