From 18f3209f29a030275dc0beeba7cff2e04baff821 Mon Sep 17 00:00:00 2001 From: Mark Nauwelaerts Date: Wed, 28 Feb 2007 10:17:15 +0000 Subject: gst/videofilter/: Port gamma filter to 0.10. Fixes #412704. Original commit message from CVS: Patch by: Mark Nauwelaerts * gst/videofilter/Makefile.am: * gst/videofilter/gstgamma.c: (gst_gamma_base_init), (gst_gamma_class_init), (gst_gamma_init), (gst_gamma_set_property), (gst_gamma_get_property), (gst_gamma_calculate_tables), (oil_tablelookup_u8), (gst_gamma_set_caps), (gst_gamma_planar411_ip), (gst_gamma_transform_ip), (plugin_init): Port gamma filter to 0.10. Fixes #412704. * tests/check/Makefile.am: * tests/check/elements/videofilter.c: (setup_filter), (cleanup_filter), (check_filter), (GST_START_TEST), (videobalance_suite), (videoflip_suite), (gamma_suite), (main): Add unit tests for videofilters. --- gst/videofilter/Makefile.am | 12 +- gst/videofilter/gstgamma.c | 436 +++++++++++++++++--------------------------- 2 files changed, 170 insertions(+), 278 deletions(-) (limited to 'gst/videofilter') diff --git a/gst/videofilter/Makefile.am b/gst/videofilter/Makefile.am index f6f4e9b8..e1aee0de 100644 --- a/gst/videofilter/Makefile.am +++ b/gst/videofilter/Makefile.am @@ -1,5 +1,5 @@ # noinst_LTLIBRARIES = libgstvideoexample.la -plugin_LTLIBRARIES = libgstvideoflip.la libgstvideobalance.la +plugin_LTLIBRARIES = libgstvideoflip.la libgstvideobalance.la libgstgamma.la noinst_HEADERS = gstvideoflip.h gstvideobalance.h @@ -29,10 +29,12 @@ libgstvideobalance_la_LIBADD = \ $(LIBM) libgstvideobalance_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -# libgstgamma_la_SOURCES = gstgamma.c -# libgstgamma_la_CFLAGS = $(GST_CFLAGS) -# libgstgamma_la_LIBADD = -# libgstgamma_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -lm +libgstgamma_la_SOURCES = gstgamma.c +libgstgamma_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) \ + $(GST_PLUGINS_BASE_CFLAGS) +libgstgamma_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-@GST_MAJORMINOR@ \ + $(GST_BASE_LIBS) $(GST_LIBS) +libgstgamma_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -lm gstvideoexample.c: $(srcdir)/make_filter $(srcdir)/gstvideotemplate.c $(srcdir)/make_filter Videoexample $(srcdir)/gstvideotemplate.c diff --git a/gst/videofilter/gstgamma.c b/gst/videofilter/gstgamma.c index 7be7b8aa..b1342687 100644 --- a/gst/videofilter/gstgamma.c +++ b/gst/videofilter/gstgamma.c @@ -2,6 +2,7 @@ * 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 @@ -26,46 +27,39 @@ * 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 -#include "gstvideofilter.h" +#include "gstgamma.h" +#ifdef HAVE_LIBOIL +#include +#endif #include #include -#define GST_TYPE_GAMMA \ - (gst_gamma_get_type()) -#define GST_GAMMA(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GAMMA,GstGamma)) -#define GST_GAMMA_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GAMMA,GstGammaClass)) -#define GST_IS_GAMMA(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GAMMA)) -#define GST_IS_GAMMA_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GAMMA)) - -typedef struct _GstGamma GstGamma; -typedef struct _GstGammaClass GstGammaClass; - -struct _GstGamma -{ - GstVideofilter videofilter; - - double gamma; - double gamma_r, gamma_g, gamma_b; - guint8 gamma_table[256]; - guint8 gamma_table_r[256]; - guint8 gamma_table_g[256]; - guint8 gamma_table_b[256]; -}; +#include -struct _GstGammaClass -{ - GstVideofilterClass parent_class; -}; +GST_DEBUG_CATEGORY_STATIC (gamma_debug); +#define GST_CAT_DEFAULT gamma_debug /* GstGamma signals and args */ enum @@ -76,128 +70,89 @@ enum enum { - ARG_0, - ARG_GAMMA, - ARG_GAMMA_R, - ARG_GAMMA_G, - ARG_GAMMA_B + PROP_0, + PROP_GAMMA /* FILL ME */ }; -static void gst_gamma_base_init (gpointer g_class); -static void gst_gamma_class_init (gpointer g_class, gpointer class_data); -static void gst_gamma_init (GTypeInstance * instance, gpointer g_class); +#define DEFAULT_PROP_GAMMA 1 + +static const GstElementDetails gamma_details = +GST_ELEMENT_DETAILS ("Video gamma correction", + "Filter/Effect/Video", + "Adjusts gamma on a video stream", + "Arwed v. Merkatz set_property = gst_gamma_set_property; gobject_class->get_property = gst_gamma_get_property; - g_object_class_install_property (gobject_class, ARG_GAMMA, + g_object_class_install_property (gobject_class, PROP_GAMMA, g_param_spec_double ("gamma", "Gamma", "gamma", - 0.01, 10, 1, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_GAMMA_R, - g_param_spec_double ("redgamma", "Gamma_r", - "gamma value for the red channel", 0.01, 10, 1, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_GAMMA_G, - g_param_spec_double ("greengamma", "Gamma_g", - "gamma value for the green channel", 0.01, 10, 1, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_GAMMA_B, - g_param_spec_double ("bluegamma", "Gamma_b", - "gamma value for the blue channel", 0.01, 10, 1, G_PARAM_READWRITE)); - - videofilter_class->setup = gst_gamma_setup; + 0.01, 10, DEFAULT_PROP_GAMMA, G_PARAM_READWRITE)); + + trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_gamma_set_caps); + trans_class->transform_ip = GST_DEBUG_FUNCPTR (gst_gamma_transform_ip); } static void -gst_gamma_init (GTypeInstance * instance, gpointer g_class) +gst_gamma_init (GstGamma * gamma, GstGammaClass * g_class) { - GstGamma *gamma = GST_GAMMA (instance); - GstVideofilter *videofilter; + GST_DEBUG_OBJECT (gamma, "gst_gamma_init"); - GST_DEBUG ("gst_gamma_init"); - - videofilter = GST_VIDEOFILTER (gamma); - - /* do stuff */ - gamma->gamma = 1; - gamma->gamma_r = 1; - gamma->gamma_g = 1; - gamma->gamma_b = 1; + /* properties */ + gamma->gamma = DEFAULT_PROP_GAMMA; gst_gamma_calculate_tables (gamma); } @@ -212,22 +167,10 @@ gst_gamma_set_property (GObject * object, guint prop_id, const GValue * value, GST_DEBUG ("gst_gamma_set_property"); switch (prop_id) { - case ARG_GAMMA: + case PROP_GAMMA: gamma->gamma = g_value_get_double (value); gst_gamma_calculate_tables (gamma); break; - case ARG_GAMMA_R: - gamma->gamma_r = g_value_get_double (value); - gst_gamma_calculate_tables (gamma); - break; - case ARG_GAMMA_G: - gamma->gamma_g = g_value_get_double (value); - gst_gamma_calculate_tables (gamma); - break; - case ARG_GAMMA_B: - gamma->gamma_b = g_value_get_double (value); - gst_gamma_calculate_tables (gamma); - break; default: break; } @@ -243,52 +186,15 @@ gst_gamma_get_property (GObject * object, guint prop_id, GValue * value, gamma = GST_GAMMA (object); switch (prop_id) { - case ARG_GAMMA: + case PROP_GAMMA: g_value_set_double (value, gamma->gamma); break; - case ARG_GAMMA_R: - g_value_set_double (value, gamma->gamma_r); - break; - case ARG_GAMMA_G: - g_value_set_double (value, gamma->gamma_g); - break; - case ARG_GAMMA_B: - g_value_set_double (value, gamma->gamma_b); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_library_load ("gstvideofilter")) - return FALSE; - - return gst_element_register (plugin, "gamma", GST_RANK_NONE, GST_TYPE_GAMMA); -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "gamma", - "Changes gamma on video images", - plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); - - -static void -gst_gamma_setup (GstVideofilter * videofilter) -{ - GstGamma *gamma; - - g_return_if_fail (GST_IS_GAMMA (videofilter)); - gamma = GST_GAMMA (videofilter); - - /* if any setup needs to be done, do it here */ - -} - static void gst_gamma_calculate_tables (GstGamma * gamma) { @@ -296,12 +202,11 @@ gst_gamma_calculate_tables (GstGamma * gamma) double val; double exp; - if (gamma->gamma == 1.0 && - gamma->gamma_r == 1.0 && gamma->gamma_g == 1.0 && gamma->gamma_b == 1.0) { - GST_VIDEOFILTER (gamma)->passthru = TRUE; + if (gamma->gamma == 1.0) { + GST_BASE_TRANSFORM (gamma)->passthrough = TRUE; return; } - GST_VIDEOFILTER (gamma)->passthru = FALSE; + GST_BASE_TRANSFORM (gamma)->passthrough = FALSE; exp = 1.0 / gamma->gamma; for (n = 0; n < 256; n++) { @@ -310,123 +215,108 @@ gst_gamma_calculate_tables (GstGamma * gamma) val = 255.0 * val; gamma->gamma_table[n] = (unsigned char) floor (val + 0.5); } - exp = 1.0 / gamma->gamma_r; - for (n = 0; n < 256; n++) { - val = n / 255.0; - val = pow (val, exp); - val = 255.0 * val; - gamma->gamma_table_r[n] = (unsigned char) floor (val + 0.5); - } - exp = 1.0 / gamma->gamma_g; - for (n = 0; n < 256; n++) { - val = n / 255.0; - val = pow (val, exp); - val = 255.0 * val; - gamma->gamma_table_g[n] = (unsigned char) floor (val + 0.5); - } - exp = 1.0 / gamma->gamma_b; - for (n = 0; n < 256; n++) { - val = n / 255.0; - val = pow (val, exp); - val = 255.0 * val; - gamma->gamma_table_b[n] = (unsigned char) floor (val + 0.5); - } - } -static void -gst_gamma_planar411 (GstVideofilter * videofilter, void *dest, void *src) +#ifndef HAVE_LIBOIL +void +oil_tablelookup_u8 (guint8 * dest, int dstr, guint8 * src, int sstr, + guint8 * table, int tstr, int n) { - GstGamma *gamma; - int width = gst_videofilter_get_input_width (videofilter); - int height = gst_videofilter_get_input_height (videofilter); - - g_return_if_fail (GST_IS_GAMMA (videofilter)); - gamma = GST_GAMMA (videofilter); - - memcpy (dest, src, width * height + (width / 2) * (height / 2) * 2); - - if (gamma->gamma != 1.0) { - { - guint8 *cdest = dest; - guint8 *csrc = src; - int x, y; - - for (y = 0; y < height; y++) { - for (x = 0; x < width; x++) { - cdest[y * width + x] = - gamma->gamma_table[(unsigned char) csrc[y * width + x]]; - } - } - } + int i; + + for (i = 0; i < n; i++) { + *dest = table[*src * tstr]; + dest += dstr; + src += sstr; } } +#endif -static void -gst_gamma_rgb24 (GstVideofilter * videofilter, void *dest, void *src) +/* Useful macros */ +#define GST_VIDEO_I420_Y_ROWSTRIDE(width) (GST_ROUND_UP_4(width)) +#define GST_VIDEO_I420_U_ROWSTRIDE(width) (GST_ROUND_UP_8(width)/2) +#define GST_VIDEO_I420_V_ROWSTRIDE(width) ((GST_ROUND_UP_8(GST_VIDEO_I420_Y_ROWSTRIDE(width)))/2) + +#define GST_VIDEO_I420_Y_OFFSET(w,h) (0) +#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))) +#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)) +#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)) + +static gboolean +gst_gamma_set_caps (GstBaseTransform * base, GstCaps * incaps, + GstCaps * outcaps) { - GstGamma *gamma; - int i; - int width, height; - guint8 *csrc = src; - guint8 *cdest = dest; + GstGamma *this; + GstStructure *structure; + gboolean res; - g_return_if_fail (GST_IS_GAMMA (videofilter)); - gamma = GST_GAMMA (videofilter); + this = GST_GAMMA (base); - width = gst_videofilter_get_input_width (videofilter); - height = gst_videofilter_get_input_height (videofilter); - if (gamma->gamma == 1.0) { - i = 0; - while (i < width * height * 3) { - *cdest++ = gamma->gamma_table_r[*csrc++]; - *cdest++ = gamma->gamma_table_g[*csrc++]; - *cdest++ = gamma->gamma_table_b[*csrc++]; - i = i + 3; - } - } else { - i = 0; - while (i < width * height * 3) { - *cdest++ = gamma->gamma_table[*csrc++]; - i++; - } - } + GST_DEBUG_OBJECT (this, + "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", &this->width); + res &= gst_structure_get_int (structure, "height", &this->height); + if (!res) + goto done; + + this->size = GST_VIDEO_I420_SIZE (this->width, this->height); + +done: + return res; } static void -gst_gamma_rgb32 (GstVideofilter * videofilter, void *dest, void *src) +gst_gamma_planar411_ip (GstGamma * gamma, guint8 * data, gint size) +{ + oil_tablelookup_u8 (data, 1, data, 1, gamma->gamma_table, 1, size); +} + +static GstFlowReturn +gst_gamma_transform_ip (GstBaseTransform * base, GstBuffer * outbuf) { GstGamma *gamma; - int i; - int width, height; - guint8 *csrc = src; - guint8 *cdest = dest; + guint8 *data; + guint size; - g_return_if_fail (GST_IS_GAMMA (videofilter)); - gamma = GST_GAMMA (videofilter); + gamma = GST_GAMMA (base); - width = gst_videofilter_get_input_width (videofilter); - height = gst_videofilter_get_input_height (videofilter); - if (gamma->gamma == 1.0) { - i = 0; - while (i < width * height * 4) { - *cdest++ = gamma->gamma_table_b[*csrc++]; - *cdest++ = gamma->gamma_table_g[*csrc++]; - *cdest++ = gamma->gamma_table_r[*csrc++]; - cdest++; - csrc++; - i = i + 4; - } - } else { - i = 0; - while (i < width * height * 4) { - if ((i % 4) != 3) - *cdest++ = gamma->gamma_table[*csrc++]; - else { - cdest++; - csrc++; - } - i++; - } + if (base->passthrough) + goto done; + + data = GST_BUFFER_DATA (outbuf); + size = GST_BUFFER_SIZE (outbuf); + + if (size != gamma->size) + goto wrong_size; + + gst_gamma_planar411_ip (gamma, data, + gamma->height * GST_VIDEO_I420_Y_ROWSTRIDE (gamma->width)); + +done: + return GST_FLOW_OK; + + /* ERRORS */ +wrong_size: + { + GST_ELEMENT_ERROR (gamma, STREAM, FORMAT, + (NULL), ("Invalid buffer size %d, expected %d", size, gamma->size)); + return GST_FLOW_ERROR; } } + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (gamma_debug, "gamma", 0, "gamma"); + + return gst_element_register (plugin, "gamma", GST_RANK_NONE, GST_TYPE_GAMMA); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "gamma", + "Changes gamma on video images", + plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN); -- cgit