2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
24 #include "gstvideomedian.h"
26 static GstStaticPadTemplate video_median_src_factory =
27 GST_STATIC_PAD_TEMPLATE ("src",
30 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ I420, YV12 }"))
33 static GstStaticPadTemplate video_median_sink_factory =
34 GST_STATIC_PAD_TEMPLATE ("sink",
37 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ I420, YV12 }"))
41 /* Median signals and args */
48 #define DEFAULT_FILTERSIZE 5
49 #define DEFAULT_LUM_ONLY TRUE
57 #define GST_TYPE_VIDEO_MEDIAN_SIZE (gst_video_median_size_get_type())
59 static const GEnumValue video_median_sizes[] = {
60 {GST_VIDEO_MEDIAN_SIZE_5, "Median of 5 neighbour pixels", "5"},
61 {GST_VIDEO_MEDIAN_SIZE_9, "Median of 9 neighbour pixels", "9"},
66 gst_video_median_size_get_type (void)
68 static GType video_median_size_type = 0;
70 if (!video_median_size_type) {
71 video_median_size_type = g_enum_register_static ("GstVideoMedianSize",
74 return video_median_size_type;
77 #define gst_video_median_parent_class parent_class
78 G_DEFINE_TYPE (GstVideoMedian, gst_video_median, GST_TYPE_VIDEO_FILTER);
80 static GstFlowReturn gst_video_median_transform_frame (GstVideoFilter * filter,
81 GstVideoFrame * in_frame, GstVideoFrame * out_frame);
83 static void gst_video_median_set_property (GObject * object, guint prop_id,
84 const GValue * value, GParamSpec * pspec);
85 static void gst_video_median_get_property (GObject * object, guint prop_id,
86 GValue * value, GParamSpec * pspec);
89 gst_video_median_class_init (GstVideoMedianClass * klass)
91 GObjectClass *gobject_class;
92 GstElementClass *gstelement_class;
93 GstVideoFilterClass *vfilter_class;
95 gobject_class = (GObjectClass *) klass;
96 gstelement_class = (GstElementClass *) klass;
97 vfilter_class = (GstVideoFilterClass *) klass;
99 gobject_class->set_property = gst_video_median_set_property;
100 gobject_class->get_property = gst_video_median_get_property;
102 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_FILTERSIZE,
103 g_param_spec_enum ("filtersize", "Filtersize", "The size of the filter",
104 GST_TYPE_VIDEO_MEDIAN_SIZE, DEFAULT_FILTERSIZE,
105 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
107 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LUM_ONLY,
108 g_param_spec_boolean ("lum-only", "Lum Only", "Only apply filter on "
109 "luminance", DEFAULT_LUM_ONLY,
110 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
112 gst_element_class_add_static_pad_template (gstelement_class,
113 &video_median_sink_factory);
114 gst_element_class_add_static_pad_template (gstelement_class,
115 &video_median_src_factory);
116 gst_element_class_set_static_metadata (gstelement_class, "Median effect",
117 "Filter/Effect/Video", "Apply a median filter to an image",
118 "Wim Taymans <wim.taymans@gmail.com>");
120 vfilter_class->transform_frame =
121 GST_DEBUG_FUNCPTR (gst_video_median_transform_frame);
125 gst_video_median_init (GstVideoMedian * median)
127 median->filtersize = DEFAULT_FILTERSIZE;
128 median->lum_only = DEFAULT_LUM_ONLY;
131 #define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); }
132 #define PIX_SWAP(a,b) { unsigned char temp=(a);(a)=(b);(b)=temp; }
135 median_5 (guint8 * dest, gint dstride, const guint8 * src, gint sstride,
136 gint width, gint height)
141 /* copy the top and bottom rows into the result array */
142 for (i = 0; i < width; i++) {
144 dest[(height - 1) * dstride + i] = src[(height - 1) * sstride + i];
147 /* process the interior pixels */
148 for (k = 2; k < height; k++) {
153 for (j = 2, i = 1; j < width; j++, i++) {
154 p[0] = src[i - sstride];
158 p[4] = src[i + sstride];
159 PIX_SORT (p[0], p[1]);
160 PIX_SORT (p[3], p[4]);
161 PIX_SORT (p[0], p[3]);
162 PIX_SORT (p[1], p[4]);
163 PIX_SORT (p[1], p[2]);
164 PIX_SORT (p[2], p[3]);
165 PIX_SORT (p[1], p[2]);
173 median_9 (guint8 * dest, gint dstride, const guint8 * src, gint sstride,
174 gint width, gint height)
179 /*copy the top and bottom rows into the result array */
180 for (i = 0; i < width; i++) {
182 dest[(height - 1) * dstride + i] = src[(height - 1) * sstride + i];
184 /* process the interior pixels */
185 for (k = 2; k < height; k++) {
190 for (j = 2, i = 1; j < width; j++, i++) {
191 p[0] = src[i - sstride - 1];
192 p[1] = src[i - sstride];
193 p[2] = src[i - sstride + 1];
197 p[6] = src[i + sstride - 1];
198 p[7] = src[i + sstride];
199 p[8] = src[i + sstride + 1];
200 PIX_SORT (p[1], p[2]);
201 PIX_SORT (p[4], p[5]);
202 PIX_SORT (p[7], p[8]);
203 PIX_SORT (p[0], p[1]);
204 PIX_SORT (p[3], p[4]);
205 PIX_SORT (p[6], p[7]);
206 PIX_SORT (p[1], p[2]);
207 PIX_SORT (p[4], p[5]);
208 PIX_SORT (p[7], p[8]);
209 PIX_SORT (p[0], p[3]);
210 PIX_SORT (p[5], p[8]);
211 PIX_SORT (p[4], p[7]);
212 PIX_SORT (p[3], p[6]);
213 PIX_SORT (p[1], p[4]);
214 PIX_SORT (p[2], p[5]);
215 PIX_SORT (p[4], p[7]);
216 PIX_SORT (p[4], p[2]);
217 PIX_SORT (p[6], p[4]);
218 PIX_SORT (p[4], p[2]);
226 gst_video_median_transform_frame (GstVideoFilter * filter,
227 GstVideoFrame * in_frame, GstVideoFrame * out_frame)
229 GstVideoMedian *median = GST_VIDEO_MEDIAN (filter);
231 if (median->filtersize == 5) {
232 median_5 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0),
233 GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0),
234 GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0),
235 GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0),
236 GST_VIDEO_FRAME_WIDTH (in_frame), GST_VIDEO_FRAME_HEIGHT (in_frame));
238 if (median->lum_only) {
239 gst_video_frame_copy_plane (out_frame, in_frame, 1);
240 gst_video_frame_copy_plane (out_frame, in_frame, 2);
242 median_5 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 1),
243 GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 1),
244 GST_VIDEO_FRAME_PLANE_DATA (in_frame, 1),
245 GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1),
246 GST_VIDEO_FRAME_WIDTH (in_frame) / 2,
247 GST_VIDEO_FRAME_HEIGHT (in_frame) / 2);
248 median_5 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 2),
249 GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 2),
250 GST_VIDEO_FRAME_PLANE_DATA (in_frame, 2),
251 GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 2),
252 GST_VIDEO_FRAME_WIDTH (in_frame) / 2,
253 GST_VIDEO_FRAME_HEIGHT (in_frame) / 2);
256 median_9 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0),
257 GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 0),
258 GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0),
259 GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 0),
260 GST_VIDEO_FRAME_WIDTH (in_frame), GST_VIDEO_FRAME_HEIGHT (in_frame));
262 if (median->lum_only) {
263 gst_video_frame_copy_plane (out_frame, in_frame, 1);
264 gst_video_frame_copy_plane (out_frame, in_frame, 2);
266 median_9 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 1),
267 GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 1),
268 GST_VIDEO_FRAME_PLANE_DATA (in_frame, 1),
269 GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 1),
270 GST_VIDEO_FRAME_WIDTH (in_frame) / 2,
271 GST_VIDEO_FRAME_HEIGHT (in_frame) / 2);
272 median_9 (GST_VIDEO_FRAME_PLANE_DATA (out_frame, 2),
273 GST_VIDEO_FRAME_PLANE_STRIDE (out_frame, 2),
274 GST_VIDEO_FRAME_PLANE_DATA (in_frame, 2),
275 GST_VIDEO_FRAME_PLANE_STRIDE (in_frame, 2),
276 GST_VIDEO_FRAME_WIDTH (in_frame) / 2,
277 GST_VIDEO_FRAME_HEIGHT (in_frame) / 2);
285 gst_video_median_set_property (GObject * object, guint prop_id,
286 const GValue * value, GParamSpec * pspec)
288 GstVideoMedian *median;
290 median = GST_VIDEO_MEDIAN (object);
293 case PROP_FILTERSIZE:
294 median->filtersize = g_value_get_enum (value);
297 median->lum_only = g_value_get_boolean (value);
305 gst_video_median_get_property (GObject * object, guint prop_id, GValue * value,
308 GstVideoMedian *median;
310 median = GST_VIDEO_MEDIAN (object);
313 case PROP_FILTERSIZE:
314 g_value_set_enum (value, median->filtersize);
317 g_value_set_boolean (value, median->lum_only);
320 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);