/* GStreamer * Copyright (C) <1999> Erik Walthinsen * Copyright (C) <2003> David Schleef * Copyright (C) 2003 Arwed v. Merkatz * Copyright (C) 2006 Mark Nauwelaerts * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ /* * This file was (probably) generated from * gstvideotemplate.c,v 1.12 2004/01/07 21:07:12 ds Exp * and * make_filter,v 1.6 2004/01/07 21:33:01 ds Exp */ /** * SECTION:element-gamma * * Performs gamma correction on a video stream. * * * Example launch line * |[ * gst-launch videotestsrc ! gamma gamma=2.0 ! ffmpegcolorspace ! ximagesink * ]| This pipeline will make the image "brighter". * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "gstvideolevels.h" #ifdef HAVE_LIBOIL #include #endif #include #include #include GST_DEBUG_CATEGORY_STATIC (videolevels_debug); #define GST_CAT_DEFAULT videolevels_debug /* GstVideoLevels signals and args */ enum { /* FILL ME */ LAST_SIGNAL }; enum { PROP_0, PROP_LOWIN, PROP_HIGHIN, PROP_LOWOUT, PROP_HIGHOUT /* FILL ME */ }; #define DEFAULT_PROP_LOWIN 0 #define DEFAULT_PROP_HIGHIN 65535 #define DEFAULT_PROP_LOWOUT 0 #define DEFAULT_PROP_HIGHOUT 255 static const GstElementDetails videolevels_details = GST_ELEMENT_DETAILS ("Video videolevels adjustment", "Filter/Effect/Video", "Adjusts videolevels on a video stream", "Josh Doe levels_table); if(G_OBJECT_CLASS(parent_class)->finalize) { G_OBJECT_CLASS(parent_class)->finalize(object); } } static void gst_videolevels_class_init (GstVideoLevelsClass * g_class) { GObjectClass *gobject_class; GstBaseTransformClass *trans_class; GST_DEBUG_CATEGORY_INIT (videolevels_debug, "videolevels", 0, "Video Levels Filter"); GST_CAT_INFO (GST_CAT_DEFAULT, "gst_videolevels_class_init"); gobject_class = G_OBJECT_CLASS (g_class); trans_class = GST_BASE_TRANSFORM_CLASS (g_class); // Register GObject virtual functions gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_videolevels_finalize); gobject_class->set_property = GST_DEBUG_FUNCPTR(gst_videolevels_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR(gst_videolevels_get_property); // Install GObject properties g_object_class_install_property (gobject_class, PROP_LOWIN, g_param_spec_int ("low_in", "Lower Input Level", "Lower Input Level", 0, 65535, DEFAULT_PROP_LOWIN, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_HIGHIN, g_param_spec_int ("upper_in", "Upper Input Level", "Upper Input Level", 0, 65535, DEFAULT_PROP_HIGHIN, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_LOWOUT, g_param_spec_int ("low_out", "Lower Output Level", "Lower Output Level", 0, 255, DEFAULT_PROP_LOWOUT, G_PARAM_READWRITE)); g_object_class_install_property (gobject_class, PROP_HIGHOUT, g_param_spec_int ("upper_out", "Upper Output Level", "Upper Output Level", 0, 255, DEFAULT_PROP_HIGHOUT, G_PARAM_READWRITE)); // Register GstBaseTransform virtual functions trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_videolevels_set_caps); trans_class->transform = GST_DEBUG_FUNCPTR (gst_videolevels_transform); trans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_videolevels_transform_caps); trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_videolevels_get_unit_size); } static void gst_videolevels_init (GstVideoLevels * videolevels, GstVideoLevelsClass * g_class) { GST_DEBUG_OBJECT (videolevels, "gst_videolevels_init"); videolevels->width=0; videolevels->height=0; videolevels->bpp=16; videolevels->depth=16; videolevels->levels_table = g_malloc(65536); reset(videolevels); calculate_tables (videolevels); } static void gst_videolevels_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstVideoLevels *videolevels; g_return_if_fail (GST_IS_VIDEOLEVELS (object)); videolevels = GST_VIDEOLEVELS (object); GST_DEBUG ("gst_videolevels_set_property"); switch (prop_id) { case PROP_LOWIN: videolevels->lower_input = g_value_get_int (value); calculate_tables (videolevels); break; case PROP_HIGHIN: videolevels->upper_input = g_value_get_int (value); calculate_tables (videolevels); break; case PROP_LOWOUT: videolevels->lower_output = g_value_get_int (value); calculate_tables (videolevels); break; case PROP_HIGHOUT: videolevels->upper_output = g_value_get_int (value); calculate_tables (videolevels); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gst_videolevels_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstVideoLevels *videolevels; g_return_if_fail (GST_IS_VIDEOLEVELS (object)); videolevels = GST_VIDEOLEVELS (object); GST_INFO_OBJECT (videolevels, "gst_videolevels_get_property"); switch (prop_id) { case PROP_LOWIN: g_value_set_int (value, videolevels->lower_input); break; case PROP_HIGHIN: g_value_set_int (value, videolevels->upper_input); break; case PROP_LOWOUT: g_value_set_int (value, videolevels->lower_output); break; case PROP_HIGHOUT: g_value_set_int (value, videolevels->upper_output); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static gboolean gst_videolevels_set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps) { GstVideoLevels *levels; GstStructure *structure; gboolean res; levels = GST_VIDEOLEVELS (base); GST_DEBUG_OBJECT (levels, "set_caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps); structure = gst_caps_get_structure (incaps, 0); res = gst_structure_get_int (structure, "width", &levels->width); res &= gst_structure_get_int (structure, "height", &levels->height); res &= gst_structure_get_int (structure, "bpp", &levels->bpp); res &= gst_structure_get_int (structure, "depth", &levels->depth); if (!res) goto done; levels->size = levels->width * levels->height; calculate_tables(levels); done: return res; } static GstCaps * gst_videolevels_transform_caps (GstBaseTransform * trans, GstPadDirection direction, GstCaps * caps) { GstVideoLevels *videolevels; GstCaps *newcaps; GstStructure *structure; GstStructure *newstruct; int bpp; videolevels = GST_VIDEOLEVELS (trans); GST_DEBUG_OBJECT (caps, "transforming caps (from)"); structure = gst_caps_get_structure (caps, 0); newcaps = gst_caps_new_simple ("video/x-raw-gray", NULL); newstruct = gst_caps_get_structure (newcaps, 0); gst_structure_set_value (newstruct, "width", gst_structure_get_value (structure, "width")); gst_structure_set_value (newstruct, "height", gst_structure_get_value (structure, "height")); gst_structure_set_value (newstruct, "framerate", gst_structure_get_value (structure, "framerate")); if (direction == GST_PAD_SRC) { GST_CAT_INFO(GST_CAT_DEFAULT, "direction=SRC"); bpp = 16; } else { GST_CAT_INFO(GST_CAT_DEFAULT, "direction=SINK"); bpp = 8; } gst_structure_set (newstruct, "bpp", G_TYPE_INT, bpp, "depth", G_TYPE_INT, bpp, NULL ); GST_DEBUG_OBJECT (newcaps, "transforming caps (into)"); return newcaps; } static gboolean gst_videolevels_get_unit_size (GstBaseTransform * base, GstCaps * caps, guint * size) { GstStructure *structure; int width; int height; int pixsize; structure = gst_caps_get_structure (caps, 0); if (gst_structure_get_int (structure, "width", &width) && gst_structure_get_int (structure, "height", &height) && gst_structure_get_int (structure, "bpp", &pixsize)) { *size = width * height * (pixsize/8); GST_CAT_DEBUG(GST_CAT_DEFAULT, "Get unit size width=%d,height=%d,size=%d",width,height,*size); return TRUE; } GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL), ("Incomplete caps, some required field missing")); return FALSE; } static void reset(GstVideoLevels* filter) { filter->width = 0; filter->height = 0; filter->lower_input = DEFAULT_PROP_LOWIN; filter->upper_input = DEFAULT_PROP_HIGHIN; filter->lower_output = DEFAULT_PROP_LOWOUT; filter->upper_output = DEFAULT_PROP_HIGHOUT; } static GstFlowReturn gst_videolevels_transform (GstBaseTransform * base, GstBuffer * inbuf, GstBuffer * outbuf) { GstVideoLevels *filter = GST_VIDEOLEVELS (base); guint16 *input; guint8 *output; /* * We need to lock our filter params to prevent changing * caps in the middle of a transformation (nice way to get * segfaults) */ GST_OBJECT_LOCK (filter); input = (guint16 *) GST_BUFFER_DATA (inbuf); output = (guint8 *) GST_BUFFER_DATA (outbuf); do_levels (filter, input, output, filter->height * filter->width); GST_OBJECT_UNLOCK (filter); return GST_FLOW_OK; } static void calculate_tables (GstVideoLevels * videolevels) { int i; guint16 loIn, hiIn; guint8 loOut, hiOut; double slope; GST_INFO_OBJECT (videolevels, "gst_videolevels_get_property"); GST_BASE_TRANSFORM (videolevels)->passthrough = FALSE; loIn = videolevels->lower_input; hiIn = videolevels->upper_input; loOut = videolevels->lower_output; hiOut = videolevels->upper_output; if(hiIn==loIn) slope=0; else slope = (double)(hiOut-loOut)/(hiIn-loIn); for(i=0;ilevels_table[i] = loOut; for(i=loIn;ilevels_table[i] = loOut+(guint8)((i-loIn)*slope); } for(i=hiIn;i<65536;i++) videolevels->levels_table[i] = hiOut; } static void do_levels (GstVideoLevels * videolevels, guint16 * indata, guint8* outdata, gint size) { int i; guint8* dst = outdata; guint16* src = indata; for (i = 0; i < size; i++) { *dst++ = videolevels->levels_table[*src++]; } }