gst-indent
[platform/upstream/gst-plugins-good.git] / gst / videofilter / gstgamma.c
1 /* GStreamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3  * Copyright (C) <2003> David Schleef <ds@schleef.org>
4  * Copyright (C) 2003 Arwed v. Merkatz <v.merkatz@gmx.net>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /*
23  * This file was (probably) generated from
24  * gstvideotemplate.c,v 1.12 2004/01/07 21:07:12 ds Exp 
25  * and
26  * make_filter,v 1.6 2004/01/07 21:33:01 ds Exp 
27  */
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <gst/gst.h>
34 #include <gstvideofilter.h>
35 #include <string.h>
36 #include <math.h>
37
38 #define GST_TYPE_GAMMA \
39   (gst_gamma_get_type())
40 #define GST_GAMMA(obj) \
41   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GAMMA,GstGamma))
42 #define GST_GAMMA_CLASS(klass) \
43   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GAMMA,GstGammaClass))
44 #define GST_IS_GAMMA(obj) \
45   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GAMMA))
46 #define GST_IS_GAMMA_CLASS(obj) \
47   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GAMMA))
48
49 typedef struct _GstGamma GstGamma;
50 typedef struct _GstGammaClass GstGammaClass;
51
52 struct _GstGamma
53 {
54   GstVideofilter videofilter;
55
56   double gamma;
57   double gamma_r, gamma_g, gamma_b;
58   guint8 gamma_table[256];
59   guint8 gamma_table_r[256];
60   guint8 gamma_table_g[256];
61   guint8 gamma_table_b[256];
62 };
63
64 struct _GstGammaClass
65 {
66   GstVideofilterClass parent_class;
67 };
68
69
70 /* GstGamma signals and args */
71 enum
72 {
73   /* FILL ME */
74   LAST_SIGNAL
75 };
76
77 enum
78 {
79   ARG_0,
80   ARG_GAMMA,
81   ARG_GAMMA_R,
82   ARG_GAMMA_G,
83   ARG_GAMMA_B,
84   /* FILL ME */
85 };
86
87 static void gst_gamma_base_init (gpointer g_class);
88 static void gst_gamma_class_init (gpointer g_class, gpointer class_data);
89 static void gst_gamma_init (GTypeInstance * instance, gpointer g_class);
90
91 static void gst_gamma_set_property (GObject * object, guint prop_id,
92     const GValue * value, GParamSpec * pspec);
93 static void gst_gamma_get_property (GObject * object, guint prop_id,
94     GValue * value, GParamSpec * pspec);
95
96 static void gst_gamma_planar411 (GstVideofilter * videofilter, void *dest,
97     void *src);
98 static void gst_gamma_rgb24 (GstVideofilter * videofilter, void *dest,
99     void *src);
100 static void gst_gamma_rgb32 (GstVideofilter * videofilter, void *dest,
101     void *src);
102 static void gst_gamma_setup (GstVideofilter * videofilter);
103 static void gst_gamma_calculate_tables (GstGamma * gamma);
104
105 GType
106 gst_gamma_get_type (void)
107 {
108   static GType gamma_type = 0;
109
110   if (!gamma_type) {
111     static const GTypeInfo gamma_info = {
112       sizeof (GstGammaClass),
113       gst_gamma_base_init,
114       NULL,
115       gst_gamma_class_init,
116       NULL,
117       NULL,
118       sizeof (GstGamma),
119       0,
120       gst_gamma_init,
121     };
122     gamma_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
123         "GstGamma", &gamma_info, 0);
124   }
125   return gamma_type;
126 }
127
128 static GstVideofilterFormat gst_gamma_formats[] = {
129   {"I420", 12, gst_gamma_planar411,},
130   {"RGB ", 24, gst_gamma_rgb24, 24, G_BIG_ENDIAN, 0xff0000, 0xff00, 0xff},
131   {"RGB ", 32, gst_gamma_rgb32, 24, G_BIG_ENDIAN, 0x00ff00, 0xff0000,
132       0xff000000},
133 };
134
135
136 static void
137 gst_gamma_base_init (gpointer g_class)
138 {
139   static GstElementDetails gamma_details =
140       GST_ELEMENT_DETAILS ("Video Gamma Correction",
141       "Filter/Effect/Video",
142       "Adjusts gamma on a video stream",
143       "Arwed v. Merkatz <v.merkatz@gmx.net");
144   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
145   GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
146   int i;
147
148   gst_element_class_set_details (element_class, &gamma_details);
149
150   for (i = 0; i < G_N_ELEMENTS (gst_gamma_formats); i++) {
151     gst_videofilter_class_add_format (videofilter_class, gst_gamma_formats + i);
152   }
153
154   gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
155 }
156
157 static void
158 gst_gamma_class_init (gpointer g_class, gpointer class_data)
159 {
160   GObjectClass *gobject_class;
161   GstVideofilterClass *videofilter_class;
162
163   gobject_class = G_OBJECT_CLASS (g_class);
164   videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
165
166   g_object_class_install_property (gobject_class, ARG_GAMMA,
167       g_param_spec_double ("gamma", "Gamma", "gamma",
168           0.01, 10, 1, G_PARAM_READWRITE));
169   g_object_class_install_property (gobject_class, ARG_GAMMA_R,
170       g_param_spec_double ("redgamma", "Gamma_r",
171           "gamma value for the red channel", 0.01, 10, 1, G_PARAM_READWRITE));
172   g_object_class_install_property (gobject_class, ARG_GAMMA_G,
173       g_param_spec_double ("greengamma", "Gamma_g",
174           "gamma value for the green channel", 0.01, 10, 1, G_PARAM_READWRITE));
175   g_object_class_install_property (gobject_class, ARG_GAMMA_B,
176       g_param_spec_double ("bluegamma", "Gamma_b",
177           "gamma value for the blue channel", 0.01, 10, 1, G_PARAM_READWRITE));
178
179   gobject_class->set_property = gst_gamma_set_property;
180   gobject_class->get_property = gst_gamma_get_property;
181
182   videofilter_class->setup = gst_gamma_setup;
183 }
184
185 static void
186 gst_gamma_init (GTypeInstance * instance, gpointer g_class)
187 {
188   GstGamma *gamma = GST_GAMMA (instance);
189   GstVideofilter *videofilter;
190
191   GST_DEBUG ("gst_gamma_init");
192
193   videofilter = GST_VIDEOFILTER (gamma);
194
195   /* do stuff */
196   gamma->gamma = 1;
197   gamma->gamma_r = 1;
198   gamma->gamma_g = 1;
199   gamma->gamma_b = 1;
200   gst_gamma_calculate_tables (gamma);
201 }
202
203 static void
204 gst_gamma_set_property (GObject * object, guint prop_id, const GValue * value,
205     GParamSpec * pspec)
206 {
207   GstGamma *gamma;
208
209   /* it's not null if we got it, but it might not be ours */
210   g_return_if_fail (GST_IS_GAMMA (object));
211   gamma = GST_GAMMA (object);
212
213   GST_DEBUG ("gst_gamma_set_property");
214   switch (prop_id) {
215     case ARG_GAMMA:
216       gamma->gamma = g_value_get_double (value);
217       gst_gamma_calculate_tables (gamma);
218       break;
219     case ARG_GAMMA_R:
220       gamma->gamma_r = g_value_get_double (value);
221       gst_gamma_calculate_tables (gamma);
222       break;
223     case ARG_GAMMA_G:
224       gamma->gamma_g = g_value_get_double (value);
225       gst_gamma_calculate_tables (gamma);
226       break;
227     case ARG_GAMMA_B:
228       gamma->gamma_b = g_value_get_double (value);
229       gst_gamma_calculate_tables (gamma);
230       break;
231     default:
232       break;
233   }
234 }
235
236 static void
237 gst_gamma_get_property (GObject * object, guint prop_id, GValue * value,
238     GParamSpec * pspec)
239 {
240   GstGamma *gamma;
241
242   /* it's not null if we got it, but it might not be ours */
243   g_return_if_fail (GST_IS_GAMMA (object));
244   gamma = GST_GAMMA (object);
245
246   switch (prop_id) {
247     case ARG_GAMMA:
248       g_value_set_double (value, gamma->gamma);
249       break;
250     case ARG_GAMMA_R:
251       g_value_set_double (value, gamma->gamma_r);
252       break;
253     case ARG_GAMMA_G:
254       g_value_set_double (value, gamma->gamma_g);
255       break;
256     case ARG_GAMMA_B:
257       g_value_set_double (value, gamma->gamma_b);
258       break;
259     default:
260       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
261       break;
262   }
263 }
264
265 static gboolean
266 plugin_init (GstPlugin * plugin)
267 {
268   if (!gst_library_load ("gstvideofilter"))
269     return FALSE;
270
271   return gst_element_register (plugin, "gamma", GST_RANK_NONE, GST_TYPE_GAMMA);
272 }
273
274 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
275     GST_VERSION_MINOR,
276     "gamma",
277     "Changes gamma on video images",
278     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)
279
280
281      static void gst_gamma_setup (GstVideofilter * videofilter)
282 {
283   GstGamma *gamma;
284
285   g_return_if_fail (GST_IS_GAMMA (videofilter));
286   gamma = GST_GAMMA (videofilter);
287
288   /* if any setup needs to be done, do it here */
289
290 }
291
292 static void
293 gst_gamma_calculate_tables (GstGamma * gamma)
294 {
295   int n;
296   double val;
297   double exp;
298
299   if (gamma->gamma == 1.0 &&
300       gamma->gamma_r == 1.0 && gamma->gamma_g == 1.0 && gamma->gamma_b == 1.0) {
301     GST_VIDEOFILTER (gamma)->passthru = TRUE;
302     return;
303   }
304   GST_VIDEOFILTER (gamma)->passthru = FALSE;
305
306   exp = 1.0 / gamma->gamma;
307   for (n = 0; n < 256; n++) {
308     val = n / 255.0;
309     val = pow (val, exp);
310     val = 255.0 * val;
311     gamma->gamma_table[n] = (unsigned char) floor (val + 0.5);
312   }
313   exp = 1.0 / gamma->gamma_r;
314   for (n = 0; n < 256; n++) {
315     val = n / 255.0;
316     val = pow (val, exp);
317     val = 255.0 * val;
318     gamma->gamma_table_r[n] = (unsigned char) floor (val + 0.5);
319   }
320   exp = 1.0 / gamma->gamma_g;
321   for (n = 0; n < 256; n++) {
322     val = n / 255.0;
323     val = pow (val, exp);
324     val = 255.0 * val;
325     gamma->gamma_table_g[n] = (unsigned char) floor (val + 0.5);
326   }
327   exp = 1.0 / gamma->gamma_b;
328   for (n = 0; n < 256; n++) {
329     val = n / 255.0;
330     val = pow (val, exp);
331     val = 255.0 * val;
332     gamma->gamma_table_b[n] = (unsigned char) floor (val + 0.5);
333   }
334
335 }
336
337 static void
338 gst_gamma_planar411 (GstVideofilter * videofilter, void *dest, void *src)
339 {
340   GstGamma *gamma;
341   int width = gst_videofilter_get_input_width (videofilter);
342   int height = gst_videofilter_get_input_height (videofilter);
343
344   g_return_if_fail (GST_IS_GAMMA (videofilter));
345   gamma = GST_GAMMA (videofilter);
346
347   memcpy (dest, src, width * height + (width / 2) * (height / 2) * 2);
348
349   if (gamma->gamma != 1.0) {
350     {
351       guint8 *cdest = dest;
352       guint8 *csrc = src;
353       int x, y;
354
355       for (y = 0; y < height; y++) {
356         for (x = 0; x < width; x++) {
357           cdest[y * width + x] =
358               gamma->gamma_table[(unsigned char) csrc[y * width + x]];
359         }
360       }
361     }
362   }
363 }
364
365 static void
366 gst_gamma_rgb24 (GstVideofilter * videofilter, void *dest, void *src)
367 {
368   GstGamma *gamma;
369   int i;
370   int width, height;
371   guint8 *csrc = src;
372   guint8 *cdest = dest;
373
374   g_return_if_fail (GST_IS_GAMMA (videofilter));
375   gamma = GST_GAMMA (videofilter);
376
377   width = gst_videofilter_get_input_width (videofilter);
378   height = gst_videofilter_get_input_height (videofilter);
379   if (gamma->gamma == 1.0) {
380     i = 0;
381     while (i < width * height * 3) {
382       *cdest++ = gamma->gamma_table_r[*csrc++];
383       *cdest++ = gamma->gamma_table_g[*csrc++];
384       *cdest++ = gamma->gamma_table_b[*csrc++];
385       i = i + 3;
386     }
387   } else {
388     i = 0;
389     while (i < width * height * 3) {
390       *cdest++ = gamma->gamma_table[*csrc++];
391       i++;
392     }
393   }
394 }
395
396 static void
397 gst_gamma_rgb32 (GstVideofilter * videofilter, void *dest, void *src)
398 {
399   GstGamma *gamma;
400   int i;
401   int width, height;
402   guint8 *csrc = src;
403   guint8 *cdest = dest;
404
405   g_return_if_fail (GST_IS_GAMMA (videofilter));
406   gamma = GST_GAMMA (videofilter);
407
408   width = gst_videofilter_get_input_width (videofilter);
409   height = gst_videofilter_get_input_height (videofilter);
410   if (gamma->gamma == 1.0) {
411     i = 0;
412     while (i < width * height * 4) {
413       *cdest++ = gamma->gamma_table_b[*csrc++];
414       *cdest++ = gamma->gamma_table_g[*csrc++];
415       *cdest++ = gamma->gamma_table_r[*csrc++];
416       cdest++;
417       csrc++;
418       i = i + 4;
419     }
420   } else {
421     i = 0;
422     while (i < width * height * 4) {
423       if ((i % 4) != 3)
424         *cdest++ = gamma->gamma_table[*csrc++];
425       else {
426         cdest++;
427         csrc++;
428       }
429       i++;
430     }
431   }
432 }