VideoFilter inherits from
[platform/upstream/gstreamer.git] / gst / effectv / gstquark.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 <gstvideofilter.h>
29
30 #include <math.h>
31 #include <string.h>
32
33 #include <gst/video/video.h>
34
35 #define GST_TYPE_QUARKTV \
36   (gst_quarktv_get_type())
37 #define GST_QUARKTV(obj) \
38   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_QUARKTV,GstQuarkTV))
39 #define GST_QUARKTV_CLASS(klass) \
40   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_QUARKTV,GstQuarkTVClass))
41 #define GST_IS_QUARKTV(obj) \
42   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_QUARKTV))
43 #define GST_IS_QUARKTV_CLASS(obj) \
44   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_QUARKTV))
45
46 /* number of frames of time-buffer. It should be as a configurable paramater */
47 /* This number also must be 2^n just for the speed. */
48 #define PLANES 16
49
50 typedef struct _GstQuarkTV GstQuarkTV;
51 typedef struct _GstQuarkTVClass GstQuarkTVClass;
52
53 struct _GstQuarkTV
54 {
55   GstVideofilter element;
56
57   gint width, height;
58   gint area;
59   gint planes;
60   gint current_plane;
61   GstBuffer **planetable;
62 };
63
64 struct _GstQuarkTVClass
65 {
66   GstVideofilterClass parent_class;
67 };
68
69 enum
70 {
71   ARG_0,
72   ARG_PLANES
73 };
74
75 GType gst_quarktv_get_type (void);
76
77 static GstElementDetails quarktv_details = GST_ELEMENT_DETAILS ("QuarkTV",
78     "Filter/Effect/Video",
79     "Motion dissolver",
80     "FUKUCHI, Kentarou <fukuchi@users.sourceforge.net>");
81
82 static GstStaticPadTemplate gst_quarktv_src_template =
83     GST_STATIC_PAD_TEMPLATE ("src",
84     GST_PAD_SRC,
85     GST_PAD_ALWAYS,
86     GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx "; " GST_VIDEO_CAPS_RGBx)
87     );
88
89 static GstStaticPadTemplate gst_quarktv_sink_template =
90     GST_STATIC_PAD_TEMPLATE ("sink",
91     GST_PAD_SINK,
92     GST_PAD_ALWAYS,
93     GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx "; " GST_VIDEO_CAPS_RGBx)
94     );
95
96 static GstVideofilterClass *parent_class = NULL;
97
98 static gboolean
99 gst_quarktv_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
100     GstCaps * outcaps)
101 {
102   GstQuarkTV *filter = GST_QUARKTV (btrans);
103   GstStructure *structure;
104   gboolean ret = FALSE;
105
106   structure = gst_caps_get_structure (incaps, 0);
107
108   if (gst_structure_get_int (structure, "width", &filter->width) &&
109       gst_structure_get_int (structure, "height", &filter->height)) {
110     filter->area = filter->width * filter->height;
111     ret = TRUE;
112   }
113
114   return ret;
115 }
116
117 static gboolean
118 gst_quarktv_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
119     guint * size)
120 {
121   GstQuarkTV *filter;
122   GstStructure *structure;
123   gboolean ret = FALSE;
124   gint width, height;
125
126   filter = GST_QUARKTV (btrans);
127
128   structure = gst_caps_get_structure (caps, 0);
129
130   if (gst_structure_get_int (structure, "width", &width) &&
131       gst_structure_get_int (structure, "height", &height)) {
132     *size = width * height * 32 / 8;
133     ret = TRUE;
134     GST_DEBUG_OBJECT (filter, "our frame size is %d bytes (%dx%d)", *size,
135         width, height);
136   }
137
138   return ret;
139 }
140
141 static inline guint32
142 fastrand (void)
143 {
144   static unsigned int fastrand_val;
145
146   return (fastrand_val = fastrand_val * 1103515245 + 12345);
147 }
148
149 static GstFlowReturn
150 gst_quarktv_transform (GstBaseTransform * trans, GstBuffer * in,
151     GstBuffer * out)
152 {
153   GstQuarkTV *filter;
154   gint area;
155   guint32 *src, *dest;
156   GstFlowReturn ret = GST_FLOW_OK;
157
158   filter = GST_QUARKTV (trans);
159
160   gst_buffer_stamp (out, in);
161
162   area = filter->area;
163   src = (guint32 *) GST_BUFFER_DATA (in);
164   dest = (guint32 *) GST_BUFFER_DATA (out);
165
166   if (filter->planetable[filter->current_plane])
167     gst_buffer_unref (filter->planetable[filter->current_plane]);
168
169   filter->planetable[filter->current_plane] = gst_buffer_ref (in);
170
171   /* For each pixel */
172   while (--area) {
173     GstBuffer *rand;
174
175     /* pick a random buffer */
176     rand =
177         filter->planetable[(filter->current_plane +
178             (fastrand () >> 24)) & (filter->planes - 1)];
179
180     /* Copy the pixel from the random buffer to dest */
181     dest[area] = (rand ? ((guint32 *) GST_BUFFER_DATA (rand))[area] : 0);
182   }
183
184   filter->current_plane--;
185   if (filter->current_plane < 0)
186     filter->current_plane = filter->planes - 1;
187
188   return ret;
189 }
190
191 static GstStateChangeReturn
192 gst_quarktv_change_state (GstElement * element, GstStateChange transition)
193 {
194   GstQuarkTV *filter = GST_QUARKTV (element);
195   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
196
197   switch (transition) {
198     case GST_STATE_CHANGE_READY_TO_PAUSED:
199     {
200       filter->planetable =
201           (GstBuffer **) g_malloc (filter->planes * sizeof (GstBuffer *));
202       memset (filter->planetable, 0, filter->planes * sizeof (GstBuffer *));
203       break;
204     }
205     default:
206       break;
207   }
208
209   if (GST_ELEMENT_CLASS (parent_class)->change_state)
210     ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
211
212   switch (transition) {
213     case GST_STATE_CHANGE_PAUSED_TO_READY:
214     {
215       gint i;
216
217       for (i = 0; i < filter->planes; i++) {
218         if (filter->planetable[i])
219           gst_buffer_unref (filter->planetable[i]);
220         filter->planetable[i] = NULL;
221       }
222       g_free (filter->planetable);
223       filter->planetable = NULL;
224       break;
225     }
226     default:
227       break;
228   }
229
230   return ret;
231 }
232
233
234 static void
235 gst_quarktv_set_property (GObject * object, guint prop_id, const GValue * value,
236     GParamSpec * pspec)
237 {
238   GstQuarkTV *filter;
239
240   g_return_if_fail (GST_IS_QUARKTV (object));
241
242   filter = GST_QUARKTV (object);
243
244   switch (prop_id) {
245     case ARG_PLANES:
246     {
247       gint new_n_planes = g_value_get_int (value);
248       GstBuffer **new_planetable;
249       gint i;
250
251       /* If the number of planes changed, copy across any existing planes */
252       if (new_n_planes != filter->planes) {
253         new_planetable =
254             (GstBuffer **) g_malloc (new_n_planes * sizeof (GstBuffer *));
255
256         for (i = 0; (i < new_n_planes) && (i < filter->planes); i++) {
257           new_planetable[i] = filter->planetable[i];
258         }
259         for (; i < filter->planes; i++) {
260           if (filter->planetable[i])
261             gst_buffer_unref (filter->planetable[i]);
262         }
263         g_free (filter->planetable);
264         filter->planetable = new_planetable;
265         filter->current_plane = filter->planes - 1;
266         filter->planes = new_n_planes;
267       }
268     }
269       break;
270     default:
271       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
272       break;
273   }
274 }
275
276 static void
277 gst_quarktv_get_property (GObject * object, guint prop_id, GValue * value,
278     GParamSpec * pspec)
279 {
280   GstQuarkTV *filter;
281
282   g_return_if_fail (GST_IS_QUARKTV (object));
283
284   filter = GST_QUARKTV (object);
285
286   switch (prop_id) {
287     case ARG_PLANES:
288       g_value_set_int (value, filter->planes);
289       break;
290     default:
291       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
292       break;
293   }
294 }
295
296 static void
297 gst_quarktv_base_init (gpointer g_class)
298 {
299   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
300
301   gst_element_class_set_details (element_class, &quarktv_details);
302
303   gst_element_class_add_pad_template (element_class,
304       gst_static_pad_template_get (&gst_quarktv_sink_template));
305   gst_element_class_add_pad_template (element_class,
306       gst_static_pad_template_get (&gst_quarktv_src_template));
307 }
308
309 static void
310 gst_quarktv_class_init (gpointer klass, gpointer class_data)
311 {
312   GObjectClass *gobject_class;
313   GstElementClass *element_class;
314   GstBaseTransformClass *trans_class;
315
316   gobject_class = (GObjectClass *) klass;
317   element_class = (GstElementClass *) klass;
318   trans_class = (GstBaseTransformClass *) klass;
319
320   parent_class = g_type_class_peek_parent (klass);
321
322   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_quarktv_set_property);
323   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_quarktv_get_property);
324
325   element_class->change_state = GST_DEBUG_FUNCPTR (gst_quarktv_change_state);
326
327   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_quarktv_set_caps);
328   trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_quarktv_get_unit_size);
329   trans_class->transform = GST_DEBUG_FUNCPTR (gst_quarktv_transform);
330 }
331
332 static void
333 gst_quarktv_init (GTypeInstance * instance, gpointer g_class)
334 {
335   GstQuarkTV *filter = GST_QUARKTV (instance);
336
337   filter->planes = PLANES;
338   filter->current_plane = filter->planes - 1;
339 }
340
341 GType
342 gst_quarktv_get_type (void)
343 {
344   static GType quarktv_type = 0;
345
346   if (!quarktv_type) {
347     static const GTypeInfo quarktv_info = {
348       sizeof (GstQuarkTVClass),
349       gst_quarktv_base_init,
350       NULL,
351       gst_quarktv_class_init,
352       NULL,
353       NULL,
354       sizeof (GstQuarkTV),
355       0,
356       gst_quarktv_init,
357     };
358
359     quarktv_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
360         "GstQuarkTV", &quarktv_info, 0);
361   }
362   return quarktv_type;
363 }