dicetv: Clean up dicetv element and fix some smaller issues
[platform/upstream/gstreamer.git] / gst / effectv / gstdice.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
4  *
5  * dice.c: a 'dicing' effect
6  *  copyright (c) 2001 Sam Mertens.  This code is subject to the provisions of
7  *  the GNU Library Public License.
8  *
9  * I suppose this looks similar to PuzzleTV, but it's not. The screen is
10  * divided into small squares, each of which is rotated either 0, 90, 180 or
11  * 270 degrees.  The amount of rotation for each square is chosen at random.
12  */
13
14 #ifdef HAVE_CONFIG_H
15 #include "config.h"
16 #endif
17
18 #include <string.h>
19 #include <gst/gst.h>
20
21 #include <gst/video/video.h>
22 #include <gst/video/gstvideofilter.h>
23
24 #include <gst/controller/gstcontroller.h>
25
26 #define GST_TYPE_DICETV \
27   (gst_dicetv_get_type())
28 #define GST_DICETV(obj) \
29   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DICETV,GstDiceTV))
30 #define GST_DICETV_CLASS(klass) \
31   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DICETV,GstDiceTVClass))
32 #define GST_IS_DICETV(obj) \
33   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DICETV))
34 #define GST_IS_DICETV_CLASS(klass) \
35   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DICETV))
36
37 typedef struct _GstDiceTV GstDiceTV;
38 typedef struct _GstDiceTVClass GstDiceTVClass;
39
40 #define DEFAULT_CUBE_BITS   4
41 #define MAX_CUBE_BITS       5
42 #define MIN_CUBE_BITS       0
43
44 typedef enum _dice_dir
45 {
46   DICE_UP = 0,
47   DICE_RIGHT = 1,
48   DICE_DOWN = 2,
49   DICE_LEFT = 3
50 }
51 DiceDir;
52
53 struct _GstDiceTV
54 {
55   GstVideoFilter videofilter;
56
57   gint width, height;
58   gchar *dicemap;
59
60   gint g_cube_bits;
61   gint g_cube_size;
62   gint g_map_height;
63   gint g_map_width;
64 };
65
66 struct _GstDiceTVClass
67 {
68   GstVideoFilterClass parent_class;
69 };
70
71 GST_BOILERPLATE (GstDiceTV, gst_dicetv, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
72
73 static void gst_dicetv_create_map (GstDiceTV * filter);
74
75 static GstStaticPadTemplate gst_dicetv_src_template =
76     GST_STATIC_PAD_TEMPLATE ("src",
77     GST_PAD_SRC,
78     GST_PAD_ALWAYS,
79     GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_xRGB ";"
80         GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_xBGR)
81     );
82
83 static GstStaticPadTemplate gst_dicetv_sink_template =
84     GST_STATIC_PAD_TEMPLATE ("sink",
85     GST_PAD_SINK,
86     GST_PAD_ALWAYS,
87     GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_xRGB ";"
88         GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_xBGR)
89     );
90
91 enum
92 {
93   ARG_0,
94   ARG_CUBE_BITS
95 };
96
97 static gboolean
98 gst_dicetv_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
99     GstCaps * outcaps)
100 {
101   GstDiceTV *filter = GST_DICETV (btrans);
102   GstStructure *structure;
103   gboolean ret = FALSE;
104
105   structure = gst_caps_get_structure (incaps, 0);
106
107   if (gst_structure_get_int (structure, "width", &filter->width) &&
108       gst_structure_get_int (structure, "height", &filter->height)) {
109     g_free (filter->dicemap);
110     filter->dicemap =
111         (gchar *) g_malloc (filter->height * filter->width * sizeof (gchar));
112     gst_dicetv_create_map (filter);
113     ret = TRUE;
114   }
115
116   return ret;
117 }
118
119 static gboolean
120 gst_dicetv_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
121     guint * size)
122 {
123   GstDiceTV *filter = GST_DICETV (btrans);
124   GstStructure *structure;
125   gboolean ret = FALSE;
126   gint width, height;
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 guint
142 fastrand (void)
143 {
144   static guint fastrand_val;
145
146   return (fastrand_val = fastrand_val * 1103515245 + 12345);
147 }
148
149 static GstFlowReturn
150 gst_dicetv_transform (GstBaseTransform * trans, GstBuffer * in, GstBuffer * out)
151 {
152   GstDiceTV *filter = GST_DICETV (trans);
153   guint32 *src, *dest;
154   gint i, map_x, map_y, map_i, base, dx, dy, di;
155   gint video_width, g_cube_bits, g_cube_size;
156   GstFlowReturn ret = GST_FLOW_OK;
157   GstClockTime timestamp, stream_time;
158
159   src = (guint32 *) GST_BUFFER_DATA (in);
160   dest = (guint32 *) GST_BUFFER_DATA (out);
161
162   timestamp = GST_BUFFER_TIMESTAMP (in);
163   stream_time =
164       gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp);
165
166   GST_DEBUG_OBJECT (filter, "sync to %" GST_TIME_FORMAT,
167       GST_TIME_ARGS (timestamp));
168
169   if (GST_CLOCK_TIME_IS_VALID (stream_time))
170     gst_object_sync_values (G_OBJECT (filter), stream_time);
171
172   video_width = filter->width;
173   g_cube_bits = filter->g_cube_bits;
174   g_cube_size = filter->g_cube_size;
175
176   map_i = 0;
177   for (map_y = 0; map_y < filter->g_map_height; map_y++) {
178     for (map_x = 0; map_x < filter->g_map_width; map_x++) {
179       base = (map_y << g_cube_bits) * video_width + (map_x << g_cube_bits);
180
181       switch (filter->dicemap[map_i]) {
182         case DICE_UP:
183           for (dy = 0; dy < g_cube_size; dy++) {
184             i = base + dy * video_width;
185             for (dx = 0; dx < g_cube_size; dx++) {
186               dest[i] = src[i];
187               i++;
188             }
189           }
190           break;
191         case DICE_LEFT:
192           for (dy = 0; dy < g_cube_size; dy++) {
193             i = base + dy * video_width;
194
195             for (dx = 0; dx < g_cube_size; dx++) {
196               di = base + (dx * video_width) + (g_cube_size - dy - 1);
197               dest[di] = src[i];
198               i++;
199             }
200           }
201           break;
202         case DICE_DOWN:
203           for (dy = 0; dy < g_cube_size; dy++) {
204             di = base + dy * video_width;
205             i = base + (g_cube_size - dy - 1) * video_width + g_cube_size;
206             for (dx = 0; dx < g_cube_size; dx++) {
207               i--;
208               dest[di] = src[i];
209               di++;
210             }
211           }
212           break;
213         case DICE_RIGHT:
214           for (dy = 0; dy < g_cube_size; dy++) {
215             i = base + (dy * video_width);
216             for (dx = 0; dx < g_cube_size; dx++) {
217               di = base + dy + (g_cube_size - dx - 1) * video_width;
218               dest[di] = src[i];
219               i++;
220             }
221           }
222           break;
223         default:
224           g_assert_not_reached ();
225           break;
226       }
227       map_i++;
228     }
229   }
230
231   return ret;
232 }
233
234 static void
235 gst_dicetv_create_map (GstDiceTV * filter)
236 {
237   gint x, y, i;
238
239   if (filter->height <= 0 || filter->width <= 0)
240     return;
241
242   filter->g_map_height = filter->height >> filter->g_cube_bits;
243   filter->g_map_width = filter->width >> filter->g_cube_bits;
244   filter->g_cube_size = 1 << filter->g_cube_bits;
245
246   i = 0;
247
248   for (y = 0; y < filter->g_map_height; y++) {
249     for (x = 0; x < filter->g_map_width; x++) {
250       // dicemap[i] = ((i + y) & 0x3); /* Up, Down, Left or Right */
251       filter->dicemap[i] = (fastrand () >> 24) & 0x03;
252       i++;
253     }
254   }
255 }
256
257 static void
258 gst_dicetv_set_property (GObject * object, guint prop_id, const GValue * value,
259     GParamSpec * pspec)
260 {
261   GstDiceTV *filter = GST_DICETV (object);
262
263   switch (prop_id) {
264     case ARG_CUBE_BITS:
265       filter->g_cube_bits = g_value_get_int (value);
266       gst_dicetv_create_map (filter);
267       break;
268     default:
269       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
270       break;
271   }
272 }
273
274 static void
275 gst_dicetv_get_property (GObject * object, guint prop_id, GValue * value,
276     GParamSpec * pspec)
277 {
278   GstDiceTV *filter = GST_DICETV (object);
279
280   switch (prop_id) {
281     case ARG_CUBE_BITS:
282       g_value_set_int (value, filter->g_cube_bits);
283       break;
284     default:
285       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
286       break;
287   }
288 }
289
290 static void
291 gst_dicetv_finalize (GObject * object)
292 {
293   GstDiceTV *filter = GST_DICETV (object);
294
295   g_free (filter->dicemap);
296   filter->dicemap = NULL;
297
298   G_OBJECT_CLASS (parent_class)->finalize (object);
299 }
300
301 static void
302 gst_dicetv_base_init (gpointer g_class)
303 {
304   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
305
306   gst_element_class_set_details_simple (element_class, "DiceTV effect",
307       "Filter/Effect/Video",
308       "'Dices' the screen up into many small squares",
309       "Wim Taymans <wim.taymans@chello.be>");
310
311   gst_element_class_add_pad_template (element_class,
312       gst_static_pad_template_get (&gst_dicetv_sink_template));
313   gst_element_class_add_pad_template (element_class,
314       gst_static_pad_template_get (&gst_dicetv_src_template));
315 }
316
317 static void
318 gst_dicetv_class_init (GstDiceTVClass * klass)
319 {
320   GObjectClass *gobject_class = (GObjectClass *) klass;
321   GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
322
323   gobject_class->set_property = gst_dicetv_set_property;
324   gobject_class->get_property = gst_dicetv_get_property;
325   gobject_class->finalize = gst_dicetv_finalize;
326
327   g_object_class_install_property (gobject_class, ARG_CUBE_BITS,
328       g_param_spec_int ("square-bits", "Square Bits", "The size of the Squares",
329           MIN_CUBE_BITS, MAX_CUBE_BITS, DEFAULT_CUBE_BITS,
330           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | GST_PARAM_CONTROLLABLE));
331
332   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_dicetv_set_caps);
333   trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_dicetv_get_unit_size);
334   trans_class->transform = GST_DEBUG_FUNCPTR (gst_dicetv_transform);
335 }
336
337 static void
338 gst_dicetv_init (GstDiceTV * filter, GstDiceTVClass * klass)
339 {
340   filter->dicemap = NULL;
341   filter->g_cube_bits = DEFAULT_CUBE_BITS;
342   filter->g_cube_size = 0;
343   filter->g_map_height = 0;
344   filter->g_map_width = 0;
345 }