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>
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.
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.
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.
24 * This file was (probably) generated from
25 * gstvideotemplate.c,v 1.12 2004/01/07 21:07:12 ds Exp
27 * make_filter,v 1.6 2004/01/07 21:33:01 ds Exp
31 * SECTION:element-gamma
33 * Performs gamma correction on a video stream.
36 * <title>Example launch line</title>
38 * gst-launch videotestsrc ! gamma gamma=2.0 ! ffmpegcolorspace ! ximagesink
39 * ]| This pipeline will make the image "brighter".
49 #include <liboil/liboil.h>
54 #include <gst/video/video.h>
57 GST_DEBUG_CATEGORY_STATIC (gamma_debug);
58 #define GST_CAT_DEFAULT gamma_debug
60 /* GstGamma signals and args */
74 #define DEFAULT_PROP_GAMMA 1
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");
82 static GstStaticPadTemplate gst_gamma_src_template =
83 GST_STATIC_PAD_TEMPLATE ("src",
86 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
89 static GstStaticPadTemplate gst_gamma_sink_template =
90 GST_STATIC_PAD_TEMPLATE ("sink",
93 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
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);
101 static gboolean gst_gamma_set_caps (GstBaseTransform * base, GstCaps * incaps,
103 static GstFlowReturn gst_gamma_transform_ip (GstBaseTransform * transform,
106 static void gst_gamma_planar411_ip (GstGamma * gamma, guint8 * data, gint size);
107 static void gst_gamma_calculate_tables (GstGamma * gamma);
109 GST_BOILERPLATE (GstGamma, gst_gamma, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
113 gst_gamma_base_init (gpointer g_class)
115 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
117 gst_element_class_set_details (element_class, &gamma_details);
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));
126 gst_gamma_class_init (GstGammaClass * g_class)
128 GObjectClass *gobject_class;
129 GstBaseTransformClass *trans_class;
131 gobject_class = G_OBJECT_CLASS (g_class);
132 trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
134 gobject_class->set_property = gst_gamma_set_property;
135 gobject_class->get_property = gst_gamma_get_property;
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));
141 trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_gamma_set_caps);
142 trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_gamma_transform_ip);
146 gst_gamma_init (GstGamma * gamma, GstGammaClass * g_class)
148 GST_DEBUG_OBJECT (gamma, "gst_gamma_init");
151 gamma->gamma = DEFAULT_PROP_GAMMA;
152 gst_gamma_calculate_tables (gamma);
156 gst_gamma_set_property (GObject * object, guint prop_id, const GValue * value,
161 g_return_if_fail (GST_IS_GAMMA (object));
162 gamma = GST_GAMMA (object);
164 GST_DEBUG ("gst_gamma_set_property");
167 gamma->gamma = g_value_get_double (value);
168 gst_gamma_calculate_tables (gamma);
176 gst_gamma_get_property (GObject * object, guint prop_id, GValue * value,
181 g_return_if_fail (GST_IS_GAMMA (object));
182 gamma = GST_GAMMA (object);
186 g_value_set_double (value, gamma->gamma);
189 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
195 gst_gamma_calculate_tables (GstGamma * gamma)
201 if (gamma->gamma == 1.0) {
202 GST_BASE_TRANSFORM (gamma)->passthrough = TRUE;
205 GST_BASE_TRANSFORM (gamma)->passthrough = FALSE;
207 exp = 1.0 / gamma->gamma;
208 for (n = 0; n < 256; n++) {
210 val = pow (val, exp);
212 gamma->gamma_table[n] = (unsigned char) floor (val + 0.5);
218 oil_tablelookup_u8 (guint8 * dest, int dstr, guint8 * src, int sstr,
219 guint8 * table, int tstr, int n)
223 for (i = 0; i < n; i++) {
224 *dest = table[*src * tstr];
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)
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))
242 gst_gamma_set_caps (GstBaseTransform * base, GstCaps * incaps,
246 GstStructure *structure;
249 this = GST_GAMMA (base);
251 GST_DEBUG_OBJECT (this,
252 "set_caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps);
254 structure = gst_caps_get_structure (incaps, 0);
256 res = gst_structure_get_int (structure, "width", &this->width);
257 res &= gst_structure_get_int (structure, "height", &this->height);
261 this->size = GST_VIDEO_I420_SIZE (this->width, this->height);
268 gst_gamma_planar411_ip (GstGamma * gamma, guint8 * data, gint size)
270 oil_tablelookup_u8 (data, 1, data, 1, gamma->gamma_table, 1, size);
274 gst_gamma_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
280 gamma = GST_GAMMA (base);
282 if (base->passthrough)
285 data = GST_BUFFER_DATA (outbuf);
286 size = GST_BUFFER_SIZE (outbuf);
288 if (size != gamma->size)
291 gst_gamma_planar411_ip (gamma, data,
292 gamma->height * GST_VIDEO_I420_Y_ROWSTRIDE (gamma->width));
300 GST_ELEMENT_ERROR (gamma, STREAM, FORMAT,
301 (NULL), ("Invalid buffer size %d, expected %d", size, gamma->size));
302 return GST_FLOW_ERROR;
307 plugin_init (GstPlugin * plugin)
309 GST_DEBUG_CATEGORY_INIT (gamma_debug, "gamma", 0, "gamma");
311 return gst_element_register (plugin, "gamma", GST_RANK_NONE, GST_TYPE_GAMMA);
314 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
317 "Changes gamma on video images",
318 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);