2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
5 * Copyright (C) 2001 FUKUCHI Kentarou
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
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.
18 #include "gsteffectv.h"
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))
31 typedef struct _GstEdgeTV GstEdgeTV;
32 typedef struct _GstEdgeTVClass GstEdgeTVClass;
38 GstPad *sinkpad, *srcpad;
41 gint map_width, map_height;
43 gint video_width_margin;
46 struct _GstEdgeTVClass
48 GstElementClass parent_class;
51 GstElementDetails gst_edgetv_details = {
54 "Aply edge detect on video",
56 "Wim Taymans <wim.taymans@chello.be>",
57 "(C) 2001 FUKUCHI Kentarou",
61 /* Filter signals and args */
73 static void gst_edgetv_class_init (GstEdgeTVClass * klass);
74 static void gst_edgetv_init (GstEdgeTV * filter);
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);
81 static void gst_edgetv_chain (GstPad * pad, GstBuffer * buf);
83 static GstElementClass *parent_class = NULL;
84 /*static guint gst_edgetv_signals[LAST_SIGNAL] = { 0 }; */
86 GType gst_edgetv_get_type (void)
88 static GType edgetv_type = 0;
91 static const GTypeInfo edgetv_info = {
92 sizeof (GstEdgeTVClass), NULL,
94 (GClassInitFunc) gst_edgetv_class_init,
99 (GInstanceInitFunc) gst_edgetv_init,
102 edgetv_type = g_type_register_static (GST_TYPE_ELEMENT, "GstEdgeTV", &edgetv_info, 0);
108 gst_edgetv_class_init (GstEdgeTVClass * klass)
110 GObjectClass *gobject_class;
111 GstElementClass *gstelement_class;
113 gobject_class = (GObjectClass *) klass;
114 gstelement_class = (GstElementClass *) klass;
116 parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
118 gobject_class->set_property = gst_edgetv_set_property;
119 gobject_class->get_property = gst_edgetv_get_property;
122 static GstPadConnectReturn
123 gst_edgetv_sinkconnect (GstPad * pad, GstCaps * caps)
127 filter = GST_EDGETV (gst_pad_get_parent (pad));
129 if (!GST_CAPS_IS_FIXED (caps))
130 return GST_PAD_CONNECT_DELAYED;
132 gst_caps_get_int (caps, "width", &filter->width);
133 gst_caps_get_int (caps, "height", &filter->height);
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;
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);
143 if (gst_pad_try_set_caps (filter->srcpad, caps)) {
144 return GST_PAD_CONNECT_OK;
147 return GST_PAD_CONNECT_REFUSED;
151 gst_edgetv_init (GstEdgeTV * filter)
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);
158 filter->srcpad = gst_pad_new_from_template (gst_effectv_src_factory (), "src");
159 gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
165 gst_edgetv_chain (GstPad * pad, GstBuffer * buf)
172 guint32 v0, v1, v2, v3;
175 filter = GST_EDGETV (gst_pad_get_parent (pad));
177 src = (guint32 *) GST_BUFFER_DATA (buf);
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);
184 src += filter->width * 4 + 4;
185 dest += filter->width * 4 + 4;
187 for (y = 1; y < filter->map_height - 1; y++) {
188 for (x = 1; x < filter->map_width - 1; x++) {
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);
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' */
209 v2 = (r << 17) | (g << 9) | b;
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);
228 v3 = (r << 17) | (g << 9) | b;
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;
236 dest[0] = r | (g - (g >> 8));
239 dest[1] = r | (g - (g >> 8));
244 dest[filter->width] = r | (g - (g >> 8));
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;
258 src += filter->width * 3 + 8 + filter->video_width_margin;
259 dest += filter->width * 3 + 8 + filter->video_width_margin;
261 gst_buffer_unref (buf);
263 gst_pad_push (filter->srcpad, outbuf);
267 gst_edgetv_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
271 /* it's not null if we got it, but it might not be ours */
272 g_return_if_fail (GST_IS_EDGETV (object));
274 filter = GST_EDGETV (object);
283 gst_edgetv_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
287 /* it's not null if we got it, but it might not be ours */
288 g_return_if_fail (GST_IS_EDGETV (object));
290 filter = GST_EDGETV (object);
294 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);