733dc862be15f44efda21e79de60d7f73ec13972
[platform/upstream/gstreamer.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. We release this product under the terms of the
8  * GNU General Public License version 2. The license is included in the file
9  * COPYING.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
12  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13  * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14  */
15
16 #include <string.h>
17 #include <gst/gst.h>
18 #include "gsteffectv.h"
19
20 #define GST_TYPE_EDGETV \
21   (gst_edgetv_get_type())
22 #define GST_EDGETV(obj) \
23   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_EDGETV,GstEdgeTV))
24 #define GST_EDGETV_CLASS(klass) \
25   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstEdgeTV))
26 #define GST_IS_EDGETV(obj) \
27   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_EDGETV))
28 #define GST_IS_EDGETV_CLASS(obj) \
29   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EDGETV))
30
31 typedef struct _GstEdgeTV GstEdgeTV;
32 typedef struct _GstEdgeTVClass GstEdgeTVClass;
33
34 struct _GstEdgeTV
35 {
36   GstElement element;
37
38   GstPad *sinkpad, *srcpad;
39
40   gint width, height;
41   gint map_width, map_height;
42   guint32 *map;
43   gint video_width_margin;
44 };
45
46 struct _GstEdgeTVClass
47 {
48   GstElementClass parent_class;
49 };
50
51 GstElementDetails gst_edgetv_details = {
52   "EdgeTV",
53   "Filter/Effect",
54   "Aply edge detect on video",
55   VERSION,
56   "Wim Taymans <wim.taymans@chello.be>",
57   "(C) 2001 FUKUCHI Kentarou",
58 };
59
60
61 /* Filter signals and args */
62 enum
63 {
64   /* FILL ME */
65   LAST_SIGNAL
66 };
67
68 enum
69 {
70   ARG_0,
71 };
72
73 static void     gst_edgetv_class_init           (GstEdgeTVClass * klass);
74 static void     gst_edgetv_init                 (GstEdgeTV * filter);
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_chain                (GstPad * pad, GstBuffer * buf);
82
83 static GstElementClass *parent_class = NULL;
84 /*static guint gst_edgetv_signals[LAST_SIGNAL] = { 0 }; */
85
86 GType gst_edgetv_get_type (void)
87 {
88   static GType edgetv_type = 0;
89
90   if (!edgetv_type) {
91     static const GTypeInfo edgetv_info = {
92       sizeof (GstEdgeTVClass), NULL,
93       NULL,
94       (GClassInitFunc) gst_edgetv_class_init,
95       NULL,
96       NULL,
97       sizeof (GstEdgeTV),
98       0,
99       (GInstanceInitFunc) gst_edgetv_init,
100     };
101
102     edgetv_type = g_type_register_static (GST_TYPE_ELEMENT, "GstEdgeTV", &edgetv_info, 0);
103   }
104   return edgetv_type;
105 }
106
107 static void
108 gst_edgetv_class_init (GstEdgeTVClass * klass)
109 {
110   GObjectClass *gobject_class;
111   GstElementClass *gstelement_class;
112
113   gobject_class = (GObjectClass *) klass;
114   gstelement_class = (GstElementClass *) klass;
115
116   parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
117
118   gobject_class->set_property = gst_edgetv_set_property;
119   gobject_class->get_property = gst_edgetv_get_property;
120 }
121
122 static GstPadConnectReturn
123 gst_edgetv_sinkconnect (GstPad * pad, GstCaps * caps)
124 {
125   GstEdgeTV *filter;
126
127   filter = GST_EDGETV (gst_pad_get_parent (pad));
128
129   if (!GST_CAPS_IS_FIXED (caps))
130     return GST_PAD_CONNECT_DELAYED;
131
132   gst_caps_get_int (caps, "width", &filter->width);
133   gst_caps_get_int (caps, "height", &filter->height);
134
135   filter->map_width = filter->width / 4;
136   filter->map_height = filter->height / 4;
137   filter->video_width_margin = filter->width - filter->map_width * 4;
138
139   g_free (filter->map);
140   filter->map = (guint32 *)g_malloc (filter->map_width * filter->map_height * sizeof(guint32) * 2);
141   bzero(filter->map, filter->map_width * filter->map_height * sizeof(guint32) * 2);
142
143   if (gst_pad_try_set_caps (filter->srcpad, caps)) {
144     return GST_PAD_CONNECT_OK;
145   }
146
147   return GST_PAD_CONNECT_REFUSED;
148 }
149
150 static void
151 gst_edgetv_init (GstEdgeTV * filter)
152 {
153   filter->sinkpad = gst_pad_new_from_template (gst_effectv_sink_factory (), "sink");
154   gst_pad_set_chain_function (filter->sinkpad, gst_edgetv_chain);
155   gst_pad_set_connect_function (filter->sinkpad, gst_edgetv_sinkconnect);
156   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
157
158   filter->srcpad = gst_pad_new_from_template (gst_effectv_src_factory (), "src");
159   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
160
161   filter->map = NULL;
162 }
163
164 static void
165 gst_edgetv_chain (GstPad * pad, GstBuffer * buf)
166 {
167   GstEdgeTV *filter;
168   int x, y;
169   int r, g, b;
170   guint32 *src, *dest;
171   guint32 p, q;
172   guint32 v0, v1, v2, v3;
173   GstBuffer *outbuf;
174
175   filter = GST_EDGETV (gst_pad_get_parent (pad));
176
177   src = (guint32 *) GST_BUFFER_DATA (buf);
178
179   outbuf = gst_buffer_new ();
180   GST_BUFFER_SIZE (outbuf) = (filter->width * filter->height * 4);
181   dest = (guint32 *) GST_BUFFER_DATA (outbuf) = g_malloc (GST_BUFFER_SIZE (outbuf));
182   GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buf);
183   
184   src += filter->width * 4 + 4;
185   dest += filter->width * 4 + 4;
186   
187   for (y = 1; y < filter->map_height - 1; y++) {
188     for (x = 1; x < filter->map_width - 1; x++) {
189
190       p = *src;
191       q = *(src - 4);
192
193 /* difference between the current pixel and right neighbor. */
194       r = ((p & 0xff0000) - (q & 0xff0000)) >> 16;
195       g = ((p & 0xff00) - (q & 0xff00)) >> 8;
196       b = (p & 0xff) - (q & 0xff);
197       r *= r;
198       g *= g;
199       b *= b;
200       r = r >> 5;               /* To lack the lower bit for saturated addition,  */
201       g = g >> 5;               /* devide the value with 32, instead of 16. It is */
202       b = b >> 4;               /* same as `v2 &= 0xfefeff' */
203       if (r > 127)
204         r = 127;
205       if (g > 127)
206         g = 127;
207       if (b > 255)
208         b = 255;
209       v2 = (r << 17) | (g << 9) | b;
210
211 /* difference between the current pixel and upper neighbor. */
212       q = *(src - filter->width * 4);
213       r = ((p & 0xff0000) - (q & 0xff0000)) >> 16;
214       g = ((p & 0xff00) - (q & 0xff00)) >> 8;
215       b = (p & 0xff) - (q & 0xff);
216       r *= r;
217       g *= g;
218       b *= b;
219       r = r >> 5;
220       g = g >> 5;
221       b = b >> 4;
222       if (r > 127)
223         r = 127;
224       if (g > 127)
225         g = 127;
226       if (b > 255)
227         b = 255;
228       v3 = (r << 17) | (g << 9) | b;
229
230       v0 = filter->map[(y - 1) * filter->map_width * 2 + x * 2];
231       v1 = filter->map[y * filter->map_width * 2 + (x - 1) * 2 + 1];
232       filter->map[y * filter->map_width * 2 + x * 2] = v2;
233       filter->map[y * filter->map_width * 2 + x * 2 + 1] = v3;
234       r = v0 + v1;
235       g = r & 0x01010100;
236       dest[0] = r | (g - (g >> 8));
237       r = v0 + v3;
238       g = r & 0x01010100;
239       dest[1] = r | (g - (g >> 8));
240       dest[2] = v3;
241       dest[3] = v3;
242       r = v2 + v1;
243       g = r & 0x01010100;
244       dest[filter->width] = r | (g - (g >> 8));
245       r = v2 + v3;
246       g = r & 0x01010100;
247       dest[filter->width + 1] = r | (g - (g >> 8));
248       dest[filter->width + 2] = v3;
249       dest[filter->width + 3] = v3;
250       dest[filter->width * 2] = v2;
251       dest[filter->width * 2 + 1] = v2;
252       dest[filter->width * 3] = v2;
253       dest[filter->width * 3 + 1] = v2;
254
255       src += 4;
256       dest += 4;
257     }
258     src += filter->width * 3 + 8 + filter->video_width_margin;
259     dest += filter->width * 3 + 8 + filter->video_width_margin;
260   }
261   gst_buffer_unref (buf);
262
263   gst_pad_push (filter->srcpad, outbuf);
264 }
265
266 static void
267 gst_edgetv_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
268 {
269   GstEdgeTV *filter;
270
271   /* it's not null if we got it, but it might not be ours */
272   g_return_if_fail (GST_IS_EDGETV (object));
273
274   filter = GST_EDGETV (object);
275
276   switch (prop_id) {
277     default:
278       break;
279   }
280 }
281
282 static void
283 gst_edgetv_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
284 {
285   GstEdgeTV *filter;
286
287   /* it's not null if we got it, but it might not be ours */
288   g_return_if_fail (GST_IS_EDGETV (object));
289
290   filter = GST_EDGETV (object);
291
292   switch (prop_id) {
293     default:
294       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
295       break;
296   }
297 }