Update and add documentation for plugins with no deps (gst).
[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       break;
172   }
173 }
174
175 static void
176 gst_gamma_get_property (GObject * object, guint prop_id, GValue * value,
177     GParamSpec * pspec)
178 {
179   GstGamma *gamma;
180
181   g_return_if_fail (GST_IS_GAMMA (object));
182   gamma = GST_GAMMA (object);
183
184   switch (prop_id) {
185     case PROP_GAMMA:
186       g_value_set_double (value, gamma->gamma);
187       break;
188     default:
189       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
190       break;
191   }
192 }
193
194 static void
195 gst_gamma_calculate_tables (GstGamma * gamma)
196 {
197   int n;
198   double val;
199   double exp;
200
201   if (gamma->gamma == 1.0) {
202     GST_BASE_TRANSFORM (gamma)->passthrough = TRUE;
203     return;
204   }
205   GST_BASE_TRANSFORM (gamma)->passthrough = FALSE;
206
207   exp = 1.0 / gamma->gamma;
208   for (n = 0; n < 256; n++) {
209     val = n / 255.0;
210     val = pow (val, exp);
211     val = 255.0 * val;
212     gamma->gamma_table[n] = (unsigned char) floor (val + 0.5);
213   }
214 }
215
216 #ifndef HAVE_LIBOIL
217 void
218 oil_tablelookup_u8 (guint8 * dest, int dstr, guint8 * src, int sstr,
219     guint8 * table, int tstr, int n)
220 {
221   int i;
222
223   for (i = 0; i < n; i++) {
224     *dest = table[*src * tstr];
225     dest += dstr;
226     src += sstr;
227   }
228 }
229 #endif
230
231 /* Useful macros */
232 #define GST_VIDEO_I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
233 #define GST_VIDEO_I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
234 #define GST_VIDEO_I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
235
236 #define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
237 #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)))
238 #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))
239 #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))
240
241 static gboolean
242 gst_gamma_set_caps (GstBaseTransform * base, GstCaps * incaps,
243     GstCaps * outcaps)
244 {
245   GstGamma *this;
246   GstStructure *structure;
247   gboolean res;
248
249   this = GST_GAMMA (base);
250
251   GST_DEBUG_OBJECT (this,
252       "set_caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps);
253
254   structure = gst_caps_get_structure (incaps, 0);
255
256   res = gst_structure_get_int (structure, "width", &this->width);
257   res &= gst_structure_get_int (structure, "height", &this->height);
258   if (!res)
259     goto done;
260
261   this->size = GST_VIDEO_I420_SIZE (this->width, this->height);
262
263 done:
264   return res;
265 }
266
267 static void
268 gst_gamma_planar411_ip (GstGamma * gamma, guint8 * data, gint size)
269 {
270   oil_tablelookup_u8 (data, 1, data, 1, gamma->gamma_table, 1, size);
271 }
272
273 static GstFlowReturn
274 gst_gamma_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
275 {
276   GstGamma *gamma;
277   guint8 *data;
278   guint size;
279
280   gamma = GST_GAMMA (base);
281
282   if (base->passthrough)
283     goto done;
284
285   data = GST_BUFFER_DATA (outbuf);
286   size = GST_BUFFER_SIZE (outbuf);
287
288   if (size != gamma->size)
289     goto wrong_size;
290
291   gst_gamma_planar411_ip (gamma, data,
292       gamma->height * GST_VIDEO_I420_Y_ROWSTRIDE (gamma->width));
293
294 done:
295   return GST_FLOW_OK;
296
297   /* ERRORS */
298 wrong_size:
299   {
300     GST_ELEMENT_ERROR (gamma, STREAM, FORMAT,
301         (NULL), ("Invalid buffer size %d, expected %d", size, gamma->size));
302     return GST_FLOW_ERROR;
303   }
304 }
305
306 static gboolean
307 plugin_init (GstPlugin * plugin)
308 {
309   GST_DEBUG_CATEGORY_INIT (gamma_debug, "gamma", 0, "gamma");
310
311   return gst_element_register (plugin, "gamma", GST_RANK_NONE, GST_TYPE_GAMMA);
312 }
313
314 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
315     GST_VERSION_MINOR,
316     "gamma",
317     "Changes gamma on video images",
318     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);