Fix build against core CVS.
[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
28 #include <gst/video/gstvideofilter.h>
29
30 #include <string.h>
31
32 #include <gst/video/video.h>
33
34 #define GST_TYPE_EDGETV \
35   (gst_edgetv_get_type())
36 #define GST_EDGETV(obj) \
37   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_EDGETV,GstEdgeTV))
38 #define GST_EDGETV_CLASS(klass) \
39   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_EDGETV,GstEdgeTVClass))
40 #define GST_IS_EDGETV(obj) \
41   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_EDGETV))
42 #define GST_IS_EDGETV_CLASS(klass) \
43   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_EDGETV))
44
45 typedef struct _GstEdgeTV GstEdgeTV;
46 typedef struct _GstEdgeTVClass GstEdgeTVClass;
47
48 struct _GstEdgeTV
49 {
50   GstVideoFilter videofilter;
51
52   gint width, height;
53   gint map_width, map_height;
54   guint32 *map;
55   gint video_width_margin;
56 };
57
58 struct _GstEdgeTVClass
59 {
60   GstVideoFilterClass parent_class;
61 };
62
63 GType gst_edgetv_get_type (void);
64
65 static const GstElementDetails gst_edgetv_details =
66 GST_ELEMENT_DETAILS ("EdgeTV effect",
67     "Filter/Effect/Video",
68     "Apply edge detect on video",
69     "Wim Taymans <wim.taymans@chello.be>");
70
71 static GstStaticPadTemplate gst_edgetv_src_template =
72 GST_STATIC_PAD_TEMPLATE ("src",
73     GST_PAD_SRC,
74     GST_PAD_ALWAYS,
75     GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx)
76     );
77
78 static GstStaticPadTemplate gst_edgetv_sink_template =
79 GST_STATIC_PAD_TEMPLATE ("sink",
80     GST_PAD_SINK,
81     GST_PAD_ALWAYS,
82     GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx)
83     );
84
85 static GstVideoFilterClass *parent_class = NULL;
86
87 static gboolean
88 gst_edgetv_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
89     GstCaps * outcaps)
90 {
91   GstEdgeTV *edgetv = GST_EDGETV (btrans);
92   GstStructure *structure;
93   gboolean ret = FALSE;
94
95   structure = gst_caps_get_structure (incaps, 0);
96
97   if (gst_structure_get_int (structure, "width", &edgetv->width) &&
98       gst_structure_get_int (structure, "height", &edgetv->height)) {
99     edgetv->map_width = edgetv->width / 4;
100     edgetv->map_height = edgetv->height / 4;
101     edgetv->video_width_margin = edgetv->width % 4;
102
103     g_free (edgetv->map);
104     edgetv->map =
105         (guint32 *) g_malloc (edgetv->map_width * edgetv->map_height *
106         sizeof (guint32) * 2);
107     memset (edgetv->map, 0,
108         edgetv->map_width * edgetv->map_height * sizeof (guint32) * 2);
109     ret = TRUE;
110   }
111
112   return ret;
113 }
114
115 static gboolean
116 gst_edgetv_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
117     guint * size)
118 {
119   GstEdgeTV *filter;
120   GstStructure *structure;
121   gboolean ret = FALSE;
122   gint width, height;
123
124   filter = GST_EDGETV (btrans);
125
126   structure = gst_caps_get_structure (caps, 0);
127
128   if (gst_structure_get_int (structure, "width", &width) &&
129       gst_structure_get_int (structure, "height", &height)) {
130     *size = width * height * 32 / 8;
131     ret = TRUE;
132     GST_DEBUG_OBJECT (filter, "our frame size is %d bytes (%dx%d)", *size,
133         width, height);
134   }
135
136   return ret;
137 }
138
139 static GstFlowReturn
140 gst_edgetv_transform (GstBaseTransform * trans, GstBuffer * in, GstBuffer * out)
141 {
142   GstEdgeTV *filter;
143   gint x, y, r, g, b;
144   guint32 *src, *dest;
145   guint32 p, q;
146   guint32 v0, v1, v2, v3;
147   GstFlowReturn ret = GST_FLOW_OK;
148
149   filter = GST_EDGETV (trans);
150
151   gst_buffer_copy_metadata (out, in, GST_BUFFER_COPY_TIMESTAMPS);
152
153   src = (guint32 *) GST_BUFFER_DATA (in);
154   dest = (guint32 *) GST_BUFFER_DATA (out);
155
156   src += filter->width * 4 + 4;
157   dest += filter->width * 4 + 4;
158
159   for (y = 1; y < filter->map_height - 1; y++) {
160     for (x = 1; x < filter->map_width - 1; x++) {
161
162       p = *src;
163       q = *(src - 4);
164
165       /* difference between the current pixel and right neighbor. */
166       r = ((p & 0xff0000) - (q & 0xff0000)) >> 16;
167       g = ((p & 0xff00) - (q & 0xff00)) >> 8;
168       b = (p & 0xff) - (q & 0xff);
169       r *= r;
170       g *= g;
171       b *= b;
172       r = r >> 5;               /* To lack the lower bit for saturated addition,  */
173       g = g >> 5;               /* devide the value with 32, instead of 16. It is */
174       b = b >> 4;               /* same as `v2 &= 0xfefeff' */
175       if (r > 127)
176         r = 127;
177       if (g > 127)
178         g = 127;
179       if (b > 255)
180         b = 255;
181       v2 = (r << 17) | (g << 9) | b;
182
183       /* difference between the current pixel and upper neighbor. */
184       q = *(src - filter->width * 4);
185       r = ((p & 0xff0000) - (q & 0xff0000)) >> 16;
186       g = ((p & 0xff00) - (q & 0xff00)) >> 8;
187       b = (p & 0xff) - (q & 0xff);
188       r *= r;
189       g *= g;
190       b *= b;
191       r = r >> 5;
192       g = g >> 5;
193       b = b >> 4;
194       if (r > 127)
195         r = 127;
196       if (g > 127)
197         g = 127;
198       if (b > 255)
199         b = 255;
200       v3 = (r << 17) | (g << 9) | b;
201
202       v0 = filter->map[(y - 1) * filter->map_width * 2 + x * 2];
203       v1 = filter->map[y * filter->map_width * 2 + (x - 1) * 2 + 1];
204       filter->map[y * filter->map_width * 2 + x * 2] = v2;
205       filter->map[y * filter->map_width * 2 + x * 2 + 1] = v3;
206       r = v0 + v1;
207       g = r & 0x01010100;
208       dest[0] = r | (g - (g >> 8));
209       r = v0 + v3;
210       g = r & 0x01010100;
211       dest[1] = r | (g - (g >> 8));
212       dest[2] = v3;
213       dest[3] = v3;
214       r = v2 + v1;
215       g = r & 0x01010100;
216       dest[filter->width] = r | (g - (g >> 8));
217       r = v2 + v3;
218       g = r & 0x01010100;
219       dest[filter->width + 1] = r | (g - (g >> 8));
220       dest[filter->width + 2] = v3;
221       dest[filter->width + 3] = v3;
222       dest[filter->width * 2] = v2;
223       dest[filter->width * 2 + 1] = v2;
224       dest[filter->width * 3] = v2;
225       dest[filter->width * 3 + 1] = v2;
226
227       src += 4;
228       dest += 4;
229     }
230     src += filter->width * 3 + 8 + filter->video_width_margin;
231     dest += filter->width * 3 + 8 + filter->video_width_margin;
232   }
233
234   return ret;
235 }
236
237 static void
238 gst_edgetv_base_init (gpointer g_class)
239 {
240   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
241
242   gst_element_class_set_details (element_class, &gst_edgetv_details);
243
244   gst_element_class_add_pad_template (element_class,
245       gst_static_pad_template_get (&gst_edgetv_sink_template));
246   gst_element_class_add_pad_template (element_class,
247       gst_static_pad_template_get (&gst_edgetv_src_template));
248 }
249
250 static void
251 gst_edgetv_class_init (gpointer klass, gpointer class_data)
252 {
253   GObjectClass *gobject_class;
254   GstElementClass *element_class;
255   GstBaseTransformClass *trans_class;
256
257   gobject_class = (GObjectClass *) klass;
258   element_class = (GstElementClass *) klass;
259   trans_class = (GstBaseTransformClass *) klass;
260
261   parent_class = g_type_class_peek_parent (klass);
262
263   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_edgetv_set_caps);
264   trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_edgetv_get_unit_size);
265   trans_class->transform = GST_DEBUG_FUNCPTR (gst_edgetv_transform);
266 }
267
268 static void
269 gst_edgetv_init (GTypeInstance * instance, gpointer g_class)
270 {
271   GstEdgeTV *edgetv = GST_EDGETV (instance);
272
273   edgetv->map = NULL;
274 }
275
276 GType
277 gst_edgetv_get_type (void)
278 {
279   static GType edgetv_type = 0;
280
281   if (!edgetv_type) {
282     static const GTypeInfo edgetv_info = {
283       sizeof (GstEdgeTVClass),
284       gst_edgetv_base_init,
285       NULL,
286       (GClassInitFunc) gst_edgetv_class_init,
287       NULL,
288       NULL,
289       sizeof (GstEdgeTV),
290       0,
291       (GInstanceInitFunc) gst_edgetv_init,
292     };
293
294     edgetv_type =
295         g_type_register_static (GST_TYPE_VIDEO_FILTER, "GstEdgeTV",
296         &edgetv_info, 0);
297   }
298   return edgetv_type;
299 }