Way, way, way too many files: Remove crack comment from the 2000 era.
[platform/upstream/gst-plugins-good.git] / gst / effectv / gstedge.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  *
4  * EffecTV:
5  * Copyright (C) 2001 FUKUCHI Kentarou
6  *
7  * EffecTV is free software. * This library is free software;
8  * you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  * 
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  * 
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 #include <string.h>
28 #include <gst/gst.h>
29 #include <gstvideofilter.h>
30
31 #define GST_TYPE_EDGETV \
32   (gst_edgetv_get_type())
33 #define GST_EDGETV(obj) \
34   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_EDGETV,GstEdgeTV))
35 #define GST_EDGETV_CLASS(klass) \
36   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EDGETV,GstEdgeTVClass))
37 #define GST_IS_EDGETV(obj) \
38   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_EDGETV))
39 #define GST_IS_EDGETV_CLASS(obj) \
40   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EDGETV))
41
42 typedef struct _GstEdgeTV GstEdgeTV;
43 typedef struct _GstEdgeTVClass GstEdgeTVClass;
44
45 struct _GstEdgeTV
46 {
47   GstVideofilter videofilter;
48
49   gint width, height;
50   gint map_width, map_height;
51   guint32 *map;
52   gint video_width_margin;
53 };
54
55 struct _GstEdgeTVClass
56 {
57   GstVideofilterClass parent_class;
58 };
59
60 /* Filter signals and args */
61 enum
62 {
63   /* FILL ME */
64   LAST_SIGNAL
65 };
66
67 enum
68 {
69   ARG_0
70 };
71
72 static void gst_edgetv_base_init (gpointer g_class);
73 static void gst_edgetv_class_init (gpointer g_class, gpointer class_data);
74 static void gst_edgetv_init (GTypeInstance * instance, gpointer g_class);
75
76 static void gst_edgetv_set_property (GObject * object, guint prop_id,
77     const GValue * value, GParamSpec * pspec);
78 static void gst_edgetv_get_property (GObject * object, guint prop_id,
79     GValue * value, GParamSpec * pspec);
80
81 static void gst_edgetv_setup (GstVideofilter * videofilter);
82 static void gst_edgetv_rgb32 (GstVideofilter * videofilter, void *d, void *s);
83
84 /*static guint gst_edgetv_signals[LAST_SIGNAL] = { 0 }; */
85
86 GType
87 gst_edgetv_get_type (void)
88 {
89   static GType edgetv_type = 0;
90
91   if (!edgetv_type) {
92     static const GTypeInfo edgetv_info = {
93       sizeof (GstEdgeTVClass),
94       gst_edgetv_base_init,
95       NULL,
96       (GClassInitFunc) gst_edgetv_class_init,
97       NULL,
98       NULL,
99       sizeof (GstEdgeTV),
100       0,
101       (GInstanceInitFunc) gst_edgetv_init,
102     };
103
104     edgetv_type =
105         g_type_register_static (GST_TYPE_VIDEOFILTER, "GstEdgeTV", &edgetv_info,
106         0);
107   }
108   return edgetv_type;
109 }
110
111 static GstVideofilterFormat gst_edgetv_formats[] = {
112   {"RGB ", 32, gst_edgetv_rgb32, 24, G_BIG_ENDIAN, 0x0000ff00, 0x00ff0000,
113       0xff000000}
114 };
115
116 static void
117 gst_edgetv_base_init (gpointer g_class)
118 {
119   /* elementfactory information */
120   static GstElementDetails gst_edgetv_details = GST_ELEMENT_DETAILS ("EdgeTV",
121       "Filter/Effect/Video",
122       "Apply edge detect on video",
123       "Wim Taymans <wim.taymans@chello.be>");
124
125   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
126   GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
127   int i;
128
129   gst_element_class_set_details (element_class, &gst_edgetv_details);
130
131   for (i = 0; i < G_N_ELEMENTS (gst_edgetv_formats); i++) {
132     gst_videofilter_class_add_format (videofilter_class,
133         gst_edgetv_formats + i);
134   }
135
136   gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
137 }
138
139 static void
140 gst_edgetv_class_init (gpointer g_class, gpointer class_data)
141 {
142   GObjectClass *gobject_class;
143   GstVideofilterClass *videofilter_class;
144
145   gobject_class = G_OBJECT_CLASS (g_class);
146   videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
147
148   gobject_class->set_property = gst_edgetv_set_property;
149   gobject_class->get_property = gst_edgetv_get_property;
150
151   videofilter_class->setup = gst_edgetv_setup;
152 }
153
154 static void
155 gst_edgetv_init (GTypeInstance * instance, gpointer g_class)
156 {
157   GstEdgeTV *edgetv = GST_EDGETV (instance);
158
159   edgetv->map = NULL;
160 }
161
162 static void
163 gst_edgetv_setup (GstVideofilter * videofilter)
164 {
165   GstEdgeTV *edgetv;
166   int width = gst_videofilter_get_input_width (videofilter);
167   int height = gst_videofilter_get_input_height (videofilter);
168
169   g_return_if_fail (GST_IS_EDGETV (videofilter));
170   edgetv = GST_EDGETV (videofilter);
171
172   edgetv->width = width;
173   edgetv->height = height;
174   edgetv->map_width = width / 4;
175   edgetv->map_height = height / 4;
176   edgetv->video_width_margin = width % 4;
177
178   g_free (edgetv->map);
179   edgetv->map =
180       (guint32 *) g_malloc (edgetv->map_width * edgetv->map_height *
181       sizeof (guint32) * 2);
182   memset (edgetv->map, 0,
183       edgetv->map_width * edgetv->map_height * sizeof (guint32) * 2);
184 }
185
186 static void
187 gst_edgetv_rgb32 (GstVideofilter * videofilter, void *d, void *s)
188 {
189   GstEdgeTV *filter;
190   int x, y;
191   int r, g, b;
192   guint32 *src, *dest;
193   guint32 p, q;
194   guint32 v0, v1, v2, v3;
195
196   filter = GST_EDGETV (videofilter);
197
198   src = (guint32 *) s;
199   dest = (guint32 *) d;
200
201   src += filter->width * 4 + 4;
202   dest += filter->width * 4 + 4;
203
204   for (y = 1; y < filter->map_height - 1; y++) {
205     for (x = 1; x < filter->map_width - 1; x++) {
206
207       p = *src;
208       q = *(src - 4);
209
210 /* difference between the current pixel and right neighbor. */
211       r = ((p & 0xff0000) - (q & 0xff0000)) >> 16;
212       g = ((p & 0xff00) - (q & 0xff00)) >> 8;
213       b = (p & 0xff) - (q & 0xff);
214       r *= r;
215       g *= g;
216       b *= b;
217       r = r >> 5;               /* To lack the lower bit for saturated addition,  */
218       g = g >> 5;               /* devide the value with 32, instead of 16. It is */
219       b = b >> 4;               /* same as `v2 &= 0xfefeff' */
220       if (r > 127)
221         r = 127;
222       if (g > 127)
223         g = 127;
224       if (b > 255)
225         b = 255;
226       v2 = (r << 17) | (g << 9) | b;
227
228 /* difference between the current pixel and upper neighbor. */
229       q = *(src - filter->width * 4);
230       r = ((p & 0xff0000) - (q & 0xff0000)) >> 16;
231       g = ((p & 0xff00) - (q & 0xff00)) >> 8;
232       b = (p & 0xff) - (q & 0xff);
233       r *= r;
234       g *= g;
235       b *= b;
236       r = r >> 5;
237       g = g >> 5;
238       b = b >> 4;
239       if (r > 127)
240         r = 127;
241       if (g > 127)
242         g = 127;
243       if (b > 255)
244         b = 255;
245       v3 = (r << 17) | (g << 9) | b;
246
247       v0 = filter->map[(y - 1) * filter->map_width * 2 + x * 2];
248       v1 = filter->map[y * filter->map_width * 2 + (x - 1) * 2 + 1];
249       filter->map[y * filter->map_width * 2 + x * 2] = v2;
250       filter->map[y * filter->map_width * 2 + x * 2 + 1] = v3;
251       r = v0 + v1;
252       g = r & 0x01010100;
253       dest[0] = r | (g - (g >> 8));
254       r = v0 + v3;
255       g = r & 0x01010100;
256       dest[1] = r | (g - (g >> 8));
257       dest[2] = v3;
258       dest[3] = v3;
259       r = v2 + v1;
260       g = r & 0x01010100;
261       dest[filter->width] = r | (g - (g >> 8));
262       r = v2 + v3;
263       g = r & 0x01010100;
264       dest[filter->width + 1] = r | (g - (g >> 8));
265       dest[filter->width + 2] = v3;
266       dest[filter->width + 3] = v3;
267       dest[filter->width * 2] = v2;
268       dest[filter->width * 2 + 1] = v2;
269       dest[filter->width * 3] = v2;
270       dest[filter->width * 3 + 1] = v2;
271
272       src += 4;
273       dest += 4;
274     }
275     src += filter->width * 3 + 8 + filter->video_width_margin;
276     dest += filter->width * 3 + 8 + filter->video_width_margin;
277   }
278 }
279
280 static void
281 gst_edgetv_set_property (GObject * object, guint prop_id, const GValue * value,
282     GParamSpec * pspec)
283 {
284   GstEdgeTV *filter;
285
286   g_return_if_fail (GST_IS_EDGETV (object));
287
288   filter = GST_EDGETV (object);
289
290   switch (prop_id) {
291     default:
292       break;
293   }
294 }
295
296 static void
297 gst_edgetv_get_property (GObject * object, guint prop_id, GValue * value,
298     GParamSpec * pspec)
299 {
300   GstEdgeTV *filter;
301
302   g_return_if_fail (GST_IS_EDGETV (object));
303
304   filter = GST_EDGETV (object);
305
306   switch (prop_id) {
307     default:
308       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
309       break;
310   }
311 }