videofilter: add G_OBJECT_WARN_INVALID_PROPERTY_ID to property setter
[platform/upstream/gstreamer.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  * Copyright (C) 2006 Mark Nauwelaerts <manauw@skynet.be>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /*
24  * This file was (probably) generated from
25  * gstvideotemplate.c,v 1.12 2004/01/07 21:07:12 ds Exp 
26  * and
27  * make_filter,v 1.6 2004/01/07 21:33:01 ds Exp 
28  */
29
30 /**
31  * SECTION:element-gamma
32  *
33  * Performs gamma correction on a video stream.
34  *
35  * <refsect2>
36  * <title>Example launch line</title>
37  * |[
38  * gst-launch videotestsrc ! gamma gamma=2.0 ! ffmpegcolorspace ! ximagesink
39  * ]| This pipeline will make the image "brighter".
40  * </refsect2>
41  */
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46
47 #include "gstgamma.h"
48 #ifdef HAVE_LIBOIL
49 #include <liboil/liboil.h>
50 #endif
51 #include <string.h>
52 #include <math.h>
53
54 #include <gst/video/video.h>
55
56
57 GST_DEBUG_CATEGORY_STATIC (gamma_debug);
58 #define GST_CAT_DEFAULT gamma_debug
59
60 /* GstGamma signals and args */
61 enum
62 {
63   /* FILL ME */
64   LAST_SIGNAL
65 };
66
67 enum
68 {
69   PROP_0,
70   PROP_GAMMA
71       /* FILL ME */
72 };
73
74 #define DEFAULT_PROP_GAMMA  1
75
76 static const GstElementDetails gamma_details =
77 GST_ELEMENT_DETAILS ("Video gamma correction",
78     "Filter/Effect/Video",
79     "Adjusts gamma on a video stream",
80     "Arwed v. Merkatz <v.merkatz@gmx.net");
81
82 static GstStaticPadTemplate gst_gamma_src_template =
83 GST_STATIC_PAD_TEMPLATE ("src",
84     GST_PAD_SRC,
85     GST_PAD_ALWAYS,
86     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
87     );
88
89 static GstStaticPadTemplate gst_gamma_sink_template =
90 GST_STATIC_PAD_TEMPLATE ("sink",
91     GST_PAD_SINK,
92     GST_PAD_ALWAYS,
93     GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
94     );
95
96 static void gst_gamma_set_property (GObject * object, guint prop_id,
97     const GValue * value, GParamSpec * pspec);
98 static void gst_gamma_get_property (GObject * object, guint prop_id,
99     GValue * value, GParamSpec * pspec);
100
101 static gboolean gst_gamma_set_caps (GstBaseTransform * base, GstCaps * incaps,
102     GstCaps * outcaps);
103 static GstFlowReturn gst_gamma_transform_ip (GstBaseTransform * transform,
104     GstBuffer * buf);
105
106 static void gst_gamma_planar411_ip (GstGamma * gamma, guint8 * data, gint size);
107 static void gst_gamma_calculate_tables (GstGamma * gamma);
108
109 GST_BOILERPLATE (GstGamma, gst_gamma, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
110
111
112 static void
113 gst_gamma_base_init (gpointer g_class)
114 {
115   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
116
117   gst_element_class_set_details (element_class, &gamma_details);
118
119   gst_element_class_add_pad_template (element_class,
120       gst_static_pad_template_get (&gst_gamma_sink_template));
121   gst_element_class_add_pad_template (element_class,
122       gst_static_pad_template_get (&gst_gamma_src_template));
123 }
124
125 static void
126 gst_gamma_class_init (GstGammaClass * g_class)
127 {
128   GObjectClass *gobject_class;
129   GstBaseTransformClass *trans_class;
130
131   gobject_class = G_OBJECT_CLASS (g_class);
132   trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
133
134   gobject_class->set_property = gst_gamma_set_property;
135   gobject_class->get_property = gst_gamma_get_property;
136
137   g_object_class_install_property (gobject_class, PROP_GAMMA,
138       g_param_spec_double ("gamma", "Gamma", "gamma",
139           0.01, 10, DEFAULT_PROP_GAMMA, G_PARAM_READWRITE));
140
141   trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_gamma_set_caps);
142   trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_gamma_transform_ip);
143 }
144
145 static void
146 gst_gamma_init (GstGamma * gamma, GstGammaClass * g_class)
147 {
148   GST_DEBUG_OBJECT (gamma, "gst_gamma_init");
149
150   /* properties */
151   gamma->gamma = DEFAULT_PROP_GAMMA;
152   gst_gamma_calculate_tables (gamma);
153 }
154
155 static void
156 gst_gamma_set_property (GObject * object, guint prop_id, const GValue * value,
157     GParamSpec * pspec)
158 {
159   GstGamma *gamma;
160
161   g_return_if_fail (GST_IS_GAMMA (object));
162   gamma = GST_GAMMA (object);
163
164   GST_DEBUG ("gst_gamma_set_property");
165   switch (prop_id) {
166     case PROP_GAMMA:
167       gamma->gamma = g_value_get_double (value);
168       gst_gamma_calculate_tables (gamma);
169       break;
170     default:
171       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
172       break;
173   }
174 }
175
176 static void
177 gst_gamma_get_property (GObject * object, guint prop_id, GValue * value,
178     GParamSpec * pspec)
179 {
180   GstGamma *gamma;
181
182   g_return_if_fail (GST_IS_GAMMA (object));
183   gamma = GST_GAMMA (object);
184
185   switch (prop_id) {
186     case PROP_GAMMA:
187       g_value_set_double (value, gamma->gamma);
188       break;
189     default:
190       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
191       break;
192   }
193 }
194
195 static void
196 gst_gamma_calculate_tables (GstGamma * gamma)
197 {
198   int n;
199   double val;
200   double exp;
201
202   if (gamma->gamma == 1.0) {
203     GST_BASE_TRANSFORM (gamma)->passthrough = TRUE;
204     return;
205   }
206   GST_BASE_TRANSFORM (gamma)->passthrough = FALSE;
207
208   exp = 1.0 / gamma->gamma;
209   for (n = 0; n < 256; n++) {
210     val = n / 255.0;
211     val = pow (val, exp);
212     val = 255.0 * val;
213     gamma->gamma_table[n] = (unsigned char) floor (val + 0.5);
214   }
215 }
216
217 #ifndef HAVE_LIBOIL
218 void
219 oil_tablelookup_u8 (guint8 * dest, int dstr, guint8 * src, int sstr,
220     guint8 * table, int tstr, int n)
221 {
222   int i;
223
224   for (i = 0; i < n; i++) {
225     *dest = table[*src * tstr];
226     dest += dstr;
227     src += sstr;
228   }
229 }
230 #endif
231
232 /* Useful macros */
233 #define GST_VIDEO_I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
234 #define GST_VIDEO_I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
235 #define GST_VIDEO_I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
236
237 #define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
238 #define GST_VIDEO_I420_U_OFFSET(w,h) (GST_VIDEO_I420_Y_OFFSET(w,h)+(GST_VIDEO_I420_Y_ROWSTRIDE(w)*GST_ROUND_UP_2(h)))
239 #define GST_VIDEO_I420_V_OFFSET(w,h) (GST_VIDEO_I420_U_OFFSET(w,h)+(GST_VIDEO_I420_U_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
240 #define GST_VIDEO_I420_SIZE(w,h)     (GST_VIDEO_I420_V_OFFSET(w,h)+(GST_VIDEO_I420_V_ROWSTRIDE(w)*GST_ROUND_UP_2(h)/2))
241
242 static gboolean
243 gst_gamma_set_caps (GstBaseTransform * base, GstCaps * incaps,
244     GstCaps * outcaps)
245 {
246   GstGamma *this;
247   GstStructure *structure;
248   gboolean res;
249
250   this = GST_GAMMA (base);
251
252   GST_DEBUG_OBJECT (this,
253       "set_caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps);
254
255   structure = gst_caps_get_structure (incaps, 0);
256
257   res = gst_structure_get_int (structure, "width", &this->width);
258   res &= gst_structure_get_int (structure, "height", &this->height);
259   if (!res)
260     goto done;
261
262   this->size = GST_VIDEO_I420_SIZE (this->width, this->height);
263
264 done:
265   return res;
266 }
267
268 static void
269 gst_gamma_planar411_ip (GstGamma * gamma, guint8 * data, gint size)
270 {
271   oil_tablelookup_u8 (data, 1, data, 1, gamma->gamma_table, 1, size);
272 }
273
274 static GstFlowReturn
275 gst_gamma_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
276 {
277   GstGamma *gamma;
278   guint8 *data;
279   guint size;
280
281   gamma = GST_GAMMA (base);
282
283   if (base->passthrough)
284     goto done;
285
286   data = GST_BUFFER_DATA (outbuf);
287   size = GST_BUFFER_SIZE (outbuf);
288
289   if (size != gamma->size)
290     goto wrong_size;
291
292   gst_gamma_planar411_ip (gamma, data,
293       gamma->height * GST_VIDEO_I420_Y_ROWSTRIDE (gamma->width));
294
295 done:
296   return GST_FLOW_OK;
297
298   /* ERRORS */
299 wrong_size:
300   {
301     GST_ELEMENT_ERROR (gamma, STREAM, FORMAT,
302         (NULL), ("Invalid buffer size %d, expected %d", size, gamma->size));
303     return GST_FLOW_ERROR;
304   }
305 }
306
307 static gboolean
308 plugin_init (GstPlugin * plugin)
309 {
310   GST_DEBUG_CATEGORY_INIT (gamma_debug, "gamma", 0, "gamma");
311
312   return gst_element_register (plugin, "gamma", GST_RANK_NONE, GST_TYPE_GAMMA);
313 }
314
315 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
316     GST_VERSION_MINOR,
317     "gamma",
318     "Changes gamma on video images",
319     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);