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
35 * Performs gamma correction on a video stream.
37 * <title>Example launch line</title>
40 * gst-launch videotestsrc ! gamma gamma=2.0 ! ffmpegcolorspace ! ximagesink
42 * This pipeline will make the image "brighter".
53 #include <liboil/liboil.h>
58 #include <gst/video/video.h>
61 GST_DEBUG_CATEGORY_STATIC (gamma_debug);
62 #define GST_CAT_DEFAULT gamma_debug
64 /* GstGamma signals and args */
78 #define DEFAULT_PROP_GAMMA 1
80 static const GstElementDetails gamma_details =
81 GST_ELEMENT_DETAILS ("Video gamma correction",
82 "Filter/Effect/Video",
83 "Adjusts gamma on a video stream",
84 "Arwed v. Merkatz <v.merkatz@gmx.net");
86 static GstStaticPadTemplate gst_gamma_src_template =
87 GST_STATIC_PAD_TEMPLATE ("src",
90 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
93 static GstStaticPadTemplate gst_gamma_sink_template =
94 GST_STATIC_PAD_TEMPLATE ("sink",
97 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
100 static void gst_gamma_set_property (GObject * object, guint prop_id,
101 const GValue * value, GParamSpec * pspec);
102 static void gst_gamma_get_property (GObject * object, guint prop_id,
103 GValue * value, GParamSpec * pspec);
105 static gboolean gst_gamma_set_caps (GstBaseTransform * base, GstCaps * incaps,
107 static GstFlowReturn gst_gamma_transform_ip (GstBaseTransform * transform,
110 static void gst_gamma_planar411_ip (GstGamma * gamma, guint8 * data, gint size);
111 static void gst_gamma_calculate_tables (GstGamma * gamma);
113 GST_BOILERPLATE (GstGamma, gst_gamma, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
117 gst_gamma_base_init (gpointer g_class)
119 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
121 gst_element_class_set_details (element_class, &gamma_details);
123 gst_element_class_add_pad_template (element_class,
124 gst_static_pad_template_get (&gst_gamma_sink_template));
125 gst_element_class_add_pad_template (element_class,
126 gst_static_pad_template_get (&gst_gamma_src_template));
130 gst_gamma_class_init (GstGammaClass * g_class)
132 GObjectClass *gobject_class;
133 GstBaseTransformClass *trans_class;
135 gobject_class = G_OBJECT_CLASS (g_class);
136 trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
138 gobject_class->set_property = gst_gamma_set_property;
139 gobject_class->get_property = gst_gamma_get_property;
141 g_object_class_install_property (gobject_class, PROP_GAMMA,
142 g_param_spec_double ("gamma", "Gamma", "gamma",
143 0.01, 10, DEFAULT_PROP_GAMMA, G_PARAM_READWRITE));
145 trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_gamma_set_caps);
146 trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_gamma_transform_ip);
150 gst_gamma_init (GstGamma * gamma, GstGammaClass * g_class)
152 GST_DEBUG_OBJECT (gamma, "gst_gamma_init");
155 gamma->gamma = DEFAULT_PROP_GAMMA;
156 gst_gamma_calculate_tables (gamma);
160 gst_gamma_set_property (GObject * object, guint prop_id, const GValue * value,
165 g_return_if_fail (GST_IS_GAMMA (object));
166 gamma = GST_GAMMA (object);
168 GST_DEBUG ("gst_gamma_set_property");
171 gamma->gamma = g_value_get_double (value);
172 gst_gamma_calculate_tables (gamma);
180 gst_gamma_get_property (GObject * object, guint prop_id, GValue * value,
185 g_return_if_fail (GST_IS_GAMMA (object));
186 gamma = GST_GAMMA (object);
190 g_value_set_double (value, gamma->gamma);
193 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
199 gst_gamma_calculate_tables (GstGamma * gamma)
205 if (gamma->gamma == 1.0) {
206 GST_BASE_TRANSFORM (gamma)->passthrough = TRUE;
209 GST_BASE_TRANSFORM (gamma)->passthrough = FALSE;
211 exp = 1.0 / gamma->gamma;
212 for (n = 0; n < 256; n++) {
214 val = pow (val, exp);
216 gamma->gamma_table[n] = (unsigned char) floor (val + 0.5);
222 oil_tablelookup_u8 (guint8 * dest, int dstr, guint8 * src, int sstr,
223 guint8 * table, int tstr, int n)
227 for (i = 0; i < n; i++) {
228 *dest = table[*src * tstr];
236 #define GST_VIDEO_I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width))
237 #define GST_VIDEO_I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2)
238 #define GST_VIDEO_I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2)
240 #define GST_VIDEO_I420_Y_OFFSET(w,h) (0)
241 #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)))
242 #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))
243 #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))
246 gst_gamma_set_caps (GstBaseTransform * base, GstCaps * incaps,
250 GstStructure *structure;
253 this = GST_GAMMA (base);
255 GST_DEBUG_OBJECT (this,
256 "set_caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps);
258 structure = gst_caps_get_structure (incaps, 0);
260 res = gst_structure_get_int (structure, "width", &this->width);
261 res &= gst_structure_get_int (structure, "height", &this->height);
265 this->size = GST_VIDEO_I420_SIZE (this->width, this->height);
272 gst_gamma_planar411_ip (GstGamma * gamma, guint8 * data, gint size)
274 oil_tablelookup_u8 (data, 1, data, 1, gamma->gamma_table, 1, size);
278 gst_gamma_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
284 gamma = GST_GAMMA (base);
286 if (base->passthrough)
289 data = GST_BUFFER_DATA (outbuf);
290 size = GST_BUFFER_SIZE (outbuf);
292 if (size != gamma->size)
295 gst_gamma_planar411_ip (gamma, data,
296 gamma->height * GST_VIDEO_I420_Y_ROWSTRIDE (gamma->width));
304 GST_ELEMENT_ERROR (gamma, STREAM, FORMAT,
305 (NULL), ("Invalid buffer size %d, expected %d", size, gamma->size));
306 return GST_FLOW_ERROR;
311 plugin_init (GstPlugin * plugin)
313 GST_DEBUG_CATEGORY_INIT (gamma_debug, "gamma", 0, "gamma");
315 return gst_element_register (plugin, "gamma", GST_RANK_NONE, GST_TYPE_GAMMA);
318 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
321 "Changes gamma on video images",
322 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);