From 38bf83dbe9fa94cc02dff22963c0bba4696e9bc3 Mon Sep 17 00:00:00 2001 From: "Joshua M. Doe" Date: Tue, 13 Apr 2010 10:07:55 -0400 Subject: [PATCH] videolevels: add support for signed 16-bit input video --- gst/gstvideolevels.c | 869 +++++++++++++++++++++++++++++-------------- gst/gstvideolevels.h | 2 + 2 files changed, 583 insertions(+), 288 deletions(-) diff --git a/gst/gstvideolevels.c b/gst/gstvideolevels.c index c8f0c2c..c0fcd77 100644 --- a/gst/gstvideolevels.c +++ b/gst/gstvideolevels.c @@ -3,6 +3,7 @@ * Copyright (C) <2003> David Schleef * Copyright (C) 2003 Arwed v. Merkatz * Copyright (C) 2006 Mark Nauwelaerts + * Copyright (C) 2010 United States Government, Joshua M. Doe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -20,43 +21,30 @@ * 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". - * - */ +* SECTION:element-videolevels +* +* Convert grayscale video from one bpp/depth combination to another. +* +* +* Example launch line +* |[ +* gst-launch videotestsrc ! videolevels ! ffmpegcolorspace ! autovideosink +* ]| +* +*/ #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 { @@ -74,88 +62,106 @@ enum /* FILL ME */ }; -#define DEFAULT_PROP_LOWIN 0 -#define DEFAULT_PROP_HIGHIN 65535 -#define DEFAULT_PROP_LOWOUT 0 -#define DEFAULT_PROP_HIGHOUT 255 +#define DEFAULT_PROP_LOWIN 0.0 +#define DEFAULT_PROP_HIGHIN 1.0 +#define DEFAULT_PROP_LOWOUT 0.0 +#define DEFAULT_PROP_HIGHOUT 1.0 static const GstElementDetails videolevels_details = GST_ELEMENT_DETAILS ("Video videolevels adjustment", "Filter/Effect/Video", "Adjusts videolevels on a video stream", - "Josh Doe levels_table); + gst_videolevels_reset (videolevels); - if(G_OBJECT_CLASS(parent_class)->finalize) { - G_OBJECT_CLASS(parent_class)->finalize(object); - } + /* chain up to the parent class */ + G_OBJECT_CLASS (parent_class)->finalize (object); } +/** + * gst_videolevels_class_init: + * @object: #GstVideoLevelsClass. + * + */ static void -gst_videolevels_class_init (GstVideoLevelsClass * g_class) +gst_videolevels_class_init (GstVideoLevelsClass * object) { - GObjectClass *gobject_class; - GstBaseTransformClass *trans_class; + GObjectClass *obj_class = G_OBJECT_CLASS (object); + GstBaseTransformClass *trans_class = GST_BASE_TRANSFORM_CLASS (object); - GST_DEBUG_CATEGORY_INIT (videolevels_debug, "videolevels", 0, - "Video Levels Filter"); - - GST_CAT_INFO (GST_CAT_DEFAULT, "gst_videolevels_class_init"); + GST_DEBUG ("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); + /* Register GObject vmethods */ + obj_class->finalize = GST_DEBUG_FUNCPTR (gst_videolevels_finalize); + obj_class->set_property = GST_DEBUG_FUNCPTR (gst_videolevels_set_property); + obj_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)); + /* Install GObject properties */ + g_object_class_install_property (obj_class, PROP_LOWIN, + g_param_spec_double ("low_in", "Lower Input Level", "Lower Input Level", + 0.0, 1.0, DEFAULT_PROP_LOWIN, G_PARAM_READWRITE)); + g_object_class_install_property (obj_class, PROP_HIGHIN, + g_param_spec_double ("upper_in", "Upper Input Level", "Upper Input Level", + 0.0, 1.0, DEFAULT_PROP_HIGHIN, G_PARAM_READWRITE)); + g_object_class_install_property (obj_class, PROP_LOWOUT, + g_param_spec_double ("low_out", "Lower Output Level", "Lower Output Level", + 0.0, 1.0, DEFAULT_PROP_LOWOUT, G_PARAM_READWRITE)); + g_object_class_install_property (obj_class, PROP_HIGHOUT, + g_param_spec_double ("upper_out", "Upper Output Level", "Upper Output Level", + 0.0, 1.0, DEFAULT_PROP_HIGHOUT, G_PARAM_READWRITE)); - // Register GstBaseTransform virtual functions + /* Register GstBaseTransform vmethods */ + trans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_videolevels_transform_caps); 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->transform_ip = GST_DEBUG_FUNCPTR (gst_videolevels_transform_ip); trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_videolevels_get_unit_size); + + /* simply pass the data through if in/out caps are the same */ + trans_class->passthrough_on_same_caps = TRUE; } +/** +* gst_videolevels_init: +* @videolevels: GstVideoLevels +* @g_class: GstVideoLevelsClass +* +* Initialize the new element +*/ static void -gst_videolevels_init (GstVideoLevels * videolevels, GstVideoLevelsClass * g_class) +gst_videolevels_init (GstVideoLevels * videolevels, + GstVideoLevelsClass * g_class) { - GST_DEBUG_OBJECT (videolevels, "gst_videolevels_init"); + GST_DEBUG_OBJECT (videolevels, "init class instance"); + + gst_videolevels_reset (videolevels); - videolevels->width=0; - videolevels->height=0; - videolevels->bpp=16; - videolevels->depth=16; - videolevels->levels_table = g_malloc(65536); - reset(videolevels); - calculate_tables (videolevels); } +/** + * gst_videolevels_set_property: + * @object: #GObject + * @prop_id: guint + * @value: #GValue + * @pspec: #GParamSpec + * + */ static void -gst_videolevels_set_property (GObject * object, guint prop_id, const GValue * value, - GParamSpec * pspec) +gst_videolevels_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) { - GstVideoLevels *videolevels; + GstVideoLevels *videolevels = GST_VIDEOLEVELS (object); - g_return_if_fail (GST_IS_VIDEOLEVELS (object)); - videolevels = GST_VIDEOLEVELS (object); + GST_DEBUG ("setting property %s", pspec->name); - GST_DEBUG ("gst_videolevels_set_property"); switch (prop_id) { case PROP_LOWIN: - videolevels->lower_input = g_value_get_int (value); - calculate_tables (videolevels); + videolevels->lower_input = g_value_get_double (value); + gst_videolevels_calculate_tables (videolevels); + break; + case PROP_HIGHIN: + videolevels->upper_input = g_value_get_double (value); + gst_videolevels_calculate_tables (videolevels); + break; + case PROP_LOWOUT: + videolevels->lower_output = g_value_get_double (value); + gst_videolevels_calculate_tables (videolevels); + break; + case PROP_HIGHOUT: + videolevels->upper_output = g_value_get_double (value); + gst_videolevels_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; } } +/** + * gst_videolevels_get_property: + * @object: #GObject + * @prop_id: guint + * @value: #GValue + * @pspec: #GParamSpec + * + */ static void gst_videolevels_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstVideoLevels *videolevels; + GstVideoLevels *videolevels = GST_VIDEOLEVELS (object); - g_return_if_fail (GST_IS_VIDEOLEVELS (object)); - videolevels = GST_VIDEOLEVELS (object); + GST_DEBUG ("getting property %s", pspec->name); - GST_INFO_OBJECT (videolevels, "gst_videolevels_get_property"); switch (prop_id) { case PROP_LOWIN: - g_value_set_int (value, videolevels->lower_input); + g_value_set_double (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: + case PROP_HIGHIN: + g_value_set_double (value, videolevels->upper_input); + break; + case PROP_LOWOUT: + g_value_set_double (value, videolevels->lower_output); + break; + case PROP_HIGHOUT: + g_value_set_double (value, videolevels->upper_output); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } +/************************************************************************/ +/* GstBaseTransform vmethod implementations */ +/************************************************************************/ + +/** + * gst_videolevels_transform_caps: + * @base: #GstBaseTransform + * @direction: #GstPadDirection + * @caps: #GstCaps + * + * Given caps on one side, what caps are allowed on the other + * + * Returns: #GstCaps allowed on other pad + */ +static GstCaps * +gst_videolevels_transform_caps (GstBaseTransform * base, + GstPadDirection direction, GstCaps * caps) +{ + GstVideoLevels *videolevels; + GstCaps *static_caps; + GstCaps *newcaps; + GstStructure *structure; + const GValue * width; + const GValue * height; + + videolevels = GST_VIDEOLEVELS (base); + + GST_DEBUG_OBJECT (caps, "transforming caps (from)"); + + /* copy static pad caps to get bpp/depth/endianess */ + //if (direction == GST_PAD_SINK) { + // static_caps = gst_static_pad_template_get_caps (&gst_videolevels_sink_template); + //} + //else { + // static_caps = gst_static_pad_template_get_caps (&gst_videolevels_src_template); + //} + //structure = gst_caps_get_structure (static_caps, 0); + //gst_structure_get_value() + //newcaps = gst_caps_copy (caps); + //gst_caps_unref (static_caps); + + ///* get width and height from proposed caps */ + //structure = gst_caps_get_structure (caps, 0); + //width = gst_structure_get_value (structure, "width"); + //height = gst_structure_get_value (structure, "height"); + // + ///* set width and height to new caps */ + //structure = gst_caps_get_structure (newcaps, 0); + //gst_structure_set_value (structure, "width", width); + //gst_structure_set_value (structure, "height", height); + + newcaps = gst_caps_copy (caps); + + /* finish settings caps of the opposite pad */ + if (direction == GST_PAD_SINK) { + GST_DEBUG ("Pad direction is sink"); + gst_caps_set_simple (newcaps, + "bpp", G_TYPE_INT, 8, + "depth", G_TYPE_INT, 8, + NULL); + structure = gst_caps_get_structure (newcaps, 0); + gst_structure_remove_field (structure, "endianness"); + } + else { + GValue endianness = {0}; + GValue signed_list = {0}; + GValue ival = {0}; + + GST_DEBUG ("Pad direction is src"); + + gst_caps_set_simple (newcaps, + "bpp", G_TYPE_INT, 16, + "depth", G_TYPE_INT, 16, + NULL); + structure = gst_caps_get_structure (newcaps, 0); + + /* add BIG/LITTLE endianness to caps */ + g_value_init (&ival, G_TYPE_INT); + g_value_init (&endianness, GST_TYPE_LIST); + g_value_set_int (&ival, G_LITTLE_ENDIAN); + gst_value_list_append_value (&endianness, &ival); + g_value_set_int (&ival, G_BIG_ENDIAN); + gst_value_list_append_value (&endianness, &ival); + gst_structure_set_value (structure, "endianness", &endianness); + + /* add signed/unsigned to caps */ + g_value_init (&signed_list, GST_TYPE_LIST); + g_value_set_int (&ival, TRUE); + gst_value_list_append_value (&signed_list, &ival); + g_value_set_int (&ival, FALSE); + gst_value_list_append_value (&signed_list, &ival); + gst_structure_set_value (structure, "signed", &signed_list); + } + GST_DEBUG_OBJECT (newcaps, "allowed caps are"); + + return newcaps; +} + +/** + * gst_videolevels_set_caps: + * base: #GstBaseTransform + * incaps: #GstCaps + * outcaps: #GstCaps + * + * Notification of the actual caps set. + * + * Returns: TRUE on success + */ static gboolean gst_videolevels_set_caps (GstBaseTransform * base, GstCaps * incaps, GstCaps * outcaps) @@ -310,164 +445,322 @@ gst_videolevels_set_caps (GstBaseTransform * base, GstCaps * incaps, GST_DEBUG_OBJECT (levels, "set_caps: in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps); + GST_DEBUG_OBJECT (incaps, "incaps"); + GST_DEBUG_OBJECT (outcaps, "outcaps"); + + /* retrieve input caps info */ 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); + res = gst_structure_get (structure, + "width", G_TYPE_INT, &levels->width, + "height", G_TYPE_INT, &levels->height, + "bpp", G_TYPE_INT, &levels->bpp_in, + "depth", G_TYPE_INT, &levels->depth_in, + "endianness", G_TYPE_INT, &levels->endianness_in, + NULL); if (!res) - goto done; + return FALSE; - levels->size = levels->width * levels->height; - calculate_tables(levels); + if (!gst_structure_get (structure, + "signed", G_TYPE_BOOLEAN, &levels->is_signed_in)) + levels->is_signed_in = FALSE; + + /* retrieve src caps bpp/depth/endianness */ + structure = gst_caps_get_structure (incaps, 0); + res = gst_structure_get (structure, + "width", G_TYPE_INT, &levels->width, + "height", G_TYPE_INT, &levels->height, + "bpp", G_TYPE_INT, &levels->bpp_in, + "depth", G_TYPE_INT, &levels->depth_in, + "endianness", G_TYPE_INT, &levels->endianness_in, + NULL); + if (!res) + return FALSE; + + levels->stride_in = GST_ROUND_UP_4 (levels->width * levels->depth_in/8); + levels->stride_out = GST_ROUND_UP_4 (levels->width * levels->depth_out/8); + + gst_videolevels_calculate_tables (levels); -done: return res; } -static GstCaps * -gst_videolevels_transform_caps (GstBaseTransform * trans, - GstPadDirection direction, GstCaps * caps) +/** + * gst_videolevels_get_unit_size: + * @base: #GstBaseTransform + * @caps: #GstCaps + * @size: guint size of unit (one frame for video) + * + * Tells GstBaseTransform the size in bytes of an output frame from the given + * caps. + * + * Returns: TRUE on success + */ +static gboolean +gst_videolevels_get_unit_size (GstBaseTransform * base, GstCaps * caps, + guint * size) { - GstVideoLevels *videolevels; - GstCaps *newcaps; GstStructure *structure; - GstStructure *newstruct; - int bpp; - - videolevels = GST_VIDEOLEVELS (trans); - - GST_DEBUG_OBJECT (caps, "transforming caps (from)"); + gint width; + gint height; + gint depth; 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; + /* get proposed caps width, height, and depth to determine frame size */ + if (gst_structure_get_int (structure, "width", &width) && + gst_structure_get_int (structure, "height", &height) && + gst_structure_get_int (structure, "depth", &depth)) { + guint stride = GST_ROUND_UP_4 (width*depth/8); /* need 4-byte alignment */ + *size = stride * height; + GST_DEBUG ("Get unit size %dx%d, stride %u, %u bytes", width, height, + stride, *size); + return TRUE; } - 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; + GST_ELEMENT_ERROR (base, CORE, NEGOTIATION, (NULL), + ("Incomplete caps, some required field missing")); + return FALSE; } +/** + * gst_videolevels_transform: + * @base: #GstBaseTransform + * @inbuf: #GstBuffer + * @outbuf: #GstBuffer + * + * Transforms input buffer to output buffer. + * + * Returns: GST_FLOW_OK on success + */ static GstFlowReturn gst_videolevels_transform (GstBaseTransform * base, GstBuffer * inbuf, - GstBuffer * outbuf) + GstBuffer * outbuf) { - GstVideoLevels *filter = GST_VIDEOLEVELS (base); - guint16 *input; - guint8 *output; + GstVideoLevels *filter = GST_VIDEOLEVELS (base); + gpointer input; + gpointer output; + gboolean ret; - /* - * 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); + /* + * 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); + input = GST_BUFFER_DATA (inbuf); + output = GST_BUFFER_DATA (outbuf); - do_levels (filter, input, output, - filter->height * filter->width); + ret = gst_videolevels_do_levels (filter, input, output); - GST_OBJECT_UNLOCK (filter); - return GST_FLOW_OK; + GST_OBJECT_UNLOCK (filter); + + if (ret) + return GST_FLOW_OK; + else + return GST_FLOW_ERROR; } -static void -calculate_tables (GstVideoLevels * videolevels) +GstFlowReturn gst_videolevels_transform_ip( GstBaseTransform * base, GstBuffer * buf ) { - 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; + return GST_FLOW_OK; } -static void -do_levels (GstVideoLevels * videolevels, guint16 * indata, guint8* outdata, gint size) +/************************************************************************/ +/* GstVideoLevels method implementations */ +/************************************************************************/ + +/** + * gst_videolevels_reset: + * @videolevels: #GstVideoLevels + * + * Reset instance variables and free memory + */ +static void gst_videolevels_reset(GstVideoLevels* videolevels) { - int i; - guint8* dst = outdata; - guint16* src = indata; - for (i = 0; i < size; i++) { - *dst++ = videolevels->levels_table[*src++]; + videolevels->width = 0; + videolevels->height = 0; + + videolevels->stride_in = 0; + videolevels->bpp_in = 0; + videolevels->depth_in = 0; + videolevels->endianness_in = 0; + videolevels->is_signed_in = FALSE; + + videolevels->stride_out = 0; + videolevels->bpp_out = 0; + videolevels->depth_out = 0; + videolevels->endianness_out = 0; + + videolevels->lower_input = DEFAULT_PROP_LOWIN; + videolevels->upper_input = DEFAULT_PROP_HIGHIN; + videolevels->lower_output = DEFAULT_PROP_LOWOUT; + videolevels->upper_output = DEFAULT_PROP_HIGHOUT; + + g_free (videolevels->lookup_table); + videolevels->lookup_table = NULL; +} + +/** + * gst_videolevels_calculate_tables + * @videolevels: #GstVideoLevels + * + * Calculate lookup tables based on input and output levels + */ +static void +gst_videolevels_calculate_tables (GstVideoLevels * videolevels) +{ + gint i; + guint8 loIn, hiIn; + guint8 loOut, hiOut; + gdouble slope; + guint8 * lut; + + GST_DEBUG ("calculating lookup table"); + + if (!videolevels->lookup_table) { + videolevels->lookup_table = g_malloc (256); } -} \ No newline at end of file + lut = (guint8*) videolevels->lookup_table; + + loIn = (guint8) videolevels->lower_input * 255; + hiIn = (guint8) videolevels->upper_input * 255; + loOut = (guint8) videolevels->lower_output * 255; + hiOut = (guint8) videolevels->upper_output * 255; + + if (hiIn == loIn) + slope = 0; + else + slope = (videolevels->upper_output - videolevels->lower_output) / + (videolevels->upper_input - videolevels->lower_input); + + for (i=0; ilookup_table; + + GST_DEBUG ("Converting frame using LUT"); + + if (!videolevels->is_signed_in) { + if (videolevels->endianness_in == G_BYTE_ORDER) { + for (r = 0; r < videolevels->height; r++) { + for (c = 0; c < videolevels->width; c++) { + dst[c+r*videolevels->stride_out] = + lut[src[c+r*videolevels->stride_in] >> 8]; + } + GST_DEBUG ("Row %d", r); + } + } + else { + for (r = 0; r < videolevels->height; r++) { + for (c = 0; c < videolevels->width; c++) { + dst[c+r*videolevels->stride_out] = + lut[GUINT16_FROM_BE(src[c+r*videolevels->stride_in]) >> 8]; + } + } + } + } + else { + if (videolevels->endianness_in == G_BYTE_ORDER) { + for (r = 0; r < videolevels->height; r++) { + for (c = 0; c < videolevels->width; c++) { + dst[c+r*videolevels->stride_out] = + lut[(src[c+r*videolevels->stride_in]+32767) >> 8]; + } + GST_DEBUG ("Row %d", r); + } + } + else { + for (r = 0; r < videolevels->height; r++) { + for (c = 0; c < videolevels->width; c++) { + dst[c+r*videolevels->stride_out] = + lut[(GUINT16_FROM_BE(src[c+r*videolevels->stride_in])+32767) >> 8]; + } + } + } + } + + GST_DEBUG ("DONE converting frame using LUT"); + + return TRUE; + + //gdouble loIn = videolevels->lower_input; + //gdouble hiIn = videolevels->upper_input; + //gdouble loOut = videolevels->lower_output; + //gdouble hiOut = videolevels->upper_output; + //gdouble slope; + //gdouble yintercept; + //guint32 dst_max; + //guint32 src_max; + // + ///* y=mx+b */ + ///* check for division by zero */ + //if (hiIn == loIn) + // slope=0; + //else + // slope = (hiOut-loOut)/(hiIn-loIn); + //yintercept = loOut - slope*loIn; + + //src_max = (1 << videolevels->bpp_in) - 1; + //dst_max = (1 << videolevels->bpp_out) - 1; + + /* TODO doesn't handle byte ordering */ + //if (videolevels->depth_in == 32 && videolevels->depth_out == 32) { + // guint32 * src = indata; + // guint32 * dst = outdata; + // gint r; + // gint c; + // guint32 b = dst_max * yintercept; + // gdouble m = slope*dst_max/src_max; + + + // for (r = 0; r < videolevels->height; r++) { + // for (c = 0; c < videolevels->width; c++) { + // dst[c+r*videolevels->stride_out] = m*src[c+r*videolevels->stride_in] + b; + // } + // } + //} + //else if (videolevels->depth_in == 16 && videolevels->depth_out == 8) { + // guint16 * src = indata; + // guint8 * dst = outdata; + // gint r; + // gint c; + // guint8 b = dst_max * yintercept; + // gdouble m = slope*dst_max/src_max; + + + // for (r = 0; r < videolevels->height; r++) { + // for (c = 0; c < videolevels->width; c++) { + // dst[c+r*videolevels->stride_out] = m*src[c+r*videolevels->stride_in] + b; + // } + // } + //} + //else { + // return FALSE; + //} + return TRUE; +} diff --git a/gst/gstvideolevels.h b/gst/gstvideolevels.h index 56339b5..e66bfcc 100644 --- a/gst/gstvideolevels.h +++ b/gst/gstvideolevels.h @@ -3,6 +3,7 @@ * Copyright (C) <2003> David Schleef * Copyright (C) 2003 Arwed v. Merkatz * Copyright (C) 2006 Mark Nauwelaerts + * Copyright (C) 2010 United States Government, Joshua M. Doe * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -57,6 +58,7 @@ struct _GstVideoLevels gint bpp; gint depth; gint size; + gboolean is_signed_in; /* properties */ guint16 lower_input;