gst/videofilter/: Port gamma filter to 0.10. Fixes #412704.
authorMark Nauwelaerts <manauw@skynet.be>
Wed, 28 Feb 2007 10:17:15 +0000 (10:17 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Wed, 28 Feb 2007 10:17:15 +0000 (10:17 +0000)
Original commit message from CVS:
Patch by: Mark Nauwelaerts <manauw at skynet be>
* 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.

ChangeLog
gst/videofilter/Makefile.am
gst/videofilter/gstgamma.c
tests/check/Makefile.am
tests/check/elements/videofilter.c [new file with mode: 0644]

index 09b5f0a..b64151d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
 2007-02-28  Wim Taymans  <wim@fluendo.com>
 
+       Patch by: Mark Nauwelaerts <manauw at skynet be>
+
+       * 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.
+
+2007-02-28  Wim Taymans  <wim@fluendo.com>
+
        * gst/rtsp/URLS:
        Add another interesting test url.
 
index f6f4e9b..e1aee0d 100644 (file)
@@ -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
index 7be7b8a..b134268 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
  * Copyright (C) <2003> David Schleef <ds@schleef.org>
  * Copyright (C) 2003 Arwed v. Merkatz <v.merkatz@gmx.net>
+ * Copyright (C) 2006 Mark Nauwelaerts <manauw@skynet.be>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * make_filter,v 1.6 2004/01/07 21:33:01 ds Exp 
  */
 
+/**
+ * SECTION:element-gamma
+ *
+ * <refsect2>
+ * <para>
+ * Performs gamma correction on a video stream.
+ * </para>
+ * <title>Example launch line</title>
+ * <para>
+ * <programlisting>
+ * gst-launch videotestsrc ! gamma gamma=2.0 ! ffmpegcolorspace ! ximagesink
+ * </programlisting>
+ * This pipeline will make the image "brighter".
+ * </para>
+ * </refsect2>
+ */
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include <gst/gst.h>
-#include "gstvideofilter.h"
+#include "gstgamma.h"
+#ifdef HAVE_LIBOIL
+#include <liboil/liboil.h>
+#endif
 #include <string.h>
 #include <math.h>
 
-#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 <gst/video/video.h>
 
-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 <v.merkatz@gmx.net");
+
+static GstStaticPadTemplate gst_gamma_src_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
+    );
+
+static GstStaticPadTemplate gst_gamma_sink_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("{ IYUV, I420, YV12 }"))
+    );
 
 static void gst_gamma_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 static void gst_gamma_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
-static void gst_gamma_planar411 (GstVideofilter * videofilter, void *dest,
-    void *src);
-static void gst_gamma_rgb24 (GstVideofilter * videofilter, void *dest,
-    void *src);
-static void gst_gamma_rgb32 (GstVideofilter * videofilter, void *dest,
-    void *src);
-static void gst_gamma_setup (GstVideofilter * videofilter);
-static void gst_gamma_calculate_tables (GstGamma * gamma);
+static gboolean gst_gamma_set_caps (GstBaseTransform * base, GstCaps * incaps,
+    GstCaps * outcaps);
+static GstFlowReturn gst_gamma_transform_ip (GstBaseTransform * transform,
+    GstBuffer * buf);
 
-GType
-gst_gamma_get_type (void)
-{
-  static GType gamma_type = 0;
-
-  if (!gamma_type) {
-    static const GTypeInfo gamma_info = {
-      sizeof (GstGammaClass),
-      gst_gamma_base_init,
-      NULL,
-      gst_gamma_class_init,
-      NULL,
-      NULL,
-      sizeof (GstGamma),
-      0,
-      gst_gamma_init,
-    };
-
-    gamma_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
-        "GstGamma", &gamma_info, 0);
-  }
-  return gamma_type;
-}
+static void gst_gamma_planar411_ip (GstGamma * gamma, guint8 * data, gint size);
+static void gst_gamma_calculate_tables (GstGamma * gamma);
 
-static GstVideofilterFormat gst_gamma_formats[] = {
-  {"I420", 12, gst_gamma_planar411,},
-  {"RGB ", 24, gst_gamma_rgb24, 24, G_BIG_ENDIAN, 0xff0000, 0xff00, 0xff},
-  {"RGB ", 32, gst_gamma_rgb32, 24, G_BIG_ENDIAN, 0x00ff00, 0xff0000,
-      0xff000000},
-};
+GST_BOILERPLATE (GstGamma, gst_gamma, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
 
 
 static void
 gst_gamma_base_init (gpointer g_class)
 {
-  static const GstElementDetails gamma_details =
-      GST_ELEMENT_DETAILS ("Video gamma correction",
-      "Filter/Effect/Video",
-      "Adjusts gamma on a video stream",
-      "Arwed v. Merkatz <v.merkatz@gmx.net");
   GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-  GstVideofilterClass *videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
-  int i;
 
   gst_element_class_set_details (element_class, &gamma_details);
 
-  for (i = 0; i < G_N_ELEMENTS (gst_gamma_formats); i++) {
-    gst_videofilter_class_add_format (videofilter_class, gst_gamma_formats + i);
-  }
-
-  gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_gamma_sink_template));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_gamma_src_template));
 }
 
 static void
-gst_gamma_class_init (gpointer g_class, gpointer class_data)
+gst_gamma_class_init (GstGammaClass * g_class)
 {
   GObjectClass *gobject_class;
-  GstVideofilterClass *videofilter_class;
+  GstBaseTransformClass *trans_class;
 
   gobject_class = G_OBJECT_CLASS (g_class);
-  videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
+  trans_class = GST_BASE_TRANSFORM_CLASS (g_class);
 
   gobject_class->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);
index 53121d8..c03b2a5 100644 (file)
@@ -40,6 +40,7 @@ check_PROGRAMS = \
        elements/level \
        elements/matroskamux \
        elements/icydemux \
+       elements/videofilter
        $(check_taglib)
     
 TESTS = $(check_PROGRAMS)
diff --git a/tests/check/elements/videofilter.c b/tests/check/elements/videofilter.c
new file mode 100644 (file)
index 0000000..d22d75b
--- /dev/null
@@ -0,0 +1,220 @@
+/* GStreamer
+ *
+ * unit test for videofilter elements
+ *
+ * Copyright (C) <2006> Mark Nauwelaerts <manauw@skynet.be>
+ *
+ * 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.
+ */
+
+#include <unistd.h>
+#include <stdarg.h>
+
+#include <gst/check/gstcheck.h>
+
+GList *buffers = NULL;
+gboolean have_eos = FALSE;
+
+/* For ease of programming we use globals to keep refs for our floating
+ * src and sink pads we create; otherwise we always have to do get_pad,
+ * get_peer, and then remove references in every test function */
+GstPad *mysrcpad, *mysinkpad;
+
+#define VIDEO_CAPS_STRING "video/x-raw-yuv, " \
+  "format = (fourcc) I420, " \
+  "width = (int) 384, " \
+  "height = (int) 288, " \
+  "framerate = (fraction) 25/1, " \
+  "pixel-aspect-ratio = (fraction) 1/1"
+
+
+static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (VIDEO_CAPS_STRING)
+    );
+static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (VIDEO_CAPS_STRING)
+    );
+
+/* takes over reference for outcaps */
+GstElement *
+setup_filter (const gchar * name, const gchar * prop, va_list var_args)
+{
+  GstElement *element;
+
+  GST_DEBUG ("setup_element");
+  element = gst_check_setup_element (name);
+  g_object_set_valist (G_OBJECT (element), prop, var_args);
+  mysrcpad = gst_check_setup_src_pad (element, &srctemplate, NULL);
+  gst_pad_set_active (mysrcpad, TRUE);
+  mysinkpad = gst_check_setup_sink_pad (element, &sinktemplate, NULL);
+  gst_pad_set_active (mysinkpad, TRUE);
+
+  return element;
+}
+
+void
+cleanup_filter (GstElement * filter)
+{
+  GST_DEBUG ("cleanup_element");
+
+  gst_check_teardown_src_pad (filter);
+  gst_check_teardown_sink_pad (filter);
+  gst_check_teardown_element (filter);
+}
+
+
+check_filter (const gchar * name, gint num_buffers, const gchar * prop, ...)
+{
+  GstElement *filter;
+  GstBuffer *inbuffer, *outbuffer;
+  GstCaps *caps;
+  int i, size;
+  va_list varargs;
+
+  va_start (varargs, prop);
+  filter = setup_filter (name, prop, varargs);
+  va_end (varargs);
+  fail_unless (gst_element_set_state (filter,
+          GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
+      "could not set to playing");
+
+  /* corresponds to I420 buffer for the size mentioned in the caps */
+  size = 384 * 288 * 3 / 2;
+  for (i = 0; i < num_buffers; ++i) {
+    inbuffer = gst_buffer_new_and_alloc (size);
+    /* makes valgrind's memcheck happier */
+    memset (GST_BUFFER_DATA (inbuffer), 0, GST_BUFFER_SIZE (inbuffer));
+    caps = gst_caps_from_string (VIDEO_CAPS_STRING);
+    gst_buffer_set_caps (inbuffer, caps);
+    gst_caps_unref (caps);
+    GST_BUFFER_TIMESTAMP (inbuffer) = 0;
+    ASSERT_BUFFER_REFCOUNT (inbuffer, "inbuffer", 1);
+    fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK);
+  }
+
+  fail_unless (g_list_length (buffers) == num_buffers);
+
+  /* clean up buffers */
+  for (i = 0; i < num_buffers; ++i) {
+    outbuffer = GST_BUFFER (buffers->data);
+    fail_if (outbuffer == NULL);
+
+    switch (i) {
+      case 0:
+        fail_unless (GST_BUFFER_SIZE (outbuffer) == size);
+        /* no check on filter operation itself */
+        break;
+      default:
+        break;
+    }
+    buffers = g_list_remove (buffers, outbuffer);
+
+    ASSERT_BUFFER_REFCOUNT (outbuffer, "outbuffer", 1);
+    gst_buffer_unref (outbuffer);
+    outbuffer = NULL;
+  }
+
+  cleanup_filter (filter);
+  g_list_free (buffers);
+  buffers = NULL;
+}
+
+
+GST_START_TEST (test_videobalance)
+{
+  check_filter ("videobalance", 2, NULL);
+}
+
+GST_END_TEST;
+
+
+GST_START_TEST (test_videoflip)
+{
+  /* these we can handle with the caps */
+  check_filter ("videoflip", 2, "method", 2, NULL);
+  check_filter ("videoflip", 2, "method", 4, NULL);
+  check_filter ("videoflip", 2, "method", 5, NULL);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_gamma)
+{
+  check_filter ("gamma", 2, NULL);
+}
+
+GST_END_TEST;
+
+
+Suite *
+videobalance_suite ()
+{
+  Suite *s = suite_create ("videobalance");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_videobalance);
+
+  return s;
+}
+
+Suite *
+videoflip_suite ()
+{
+  Suite *s = suite_create ("videoflip");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_videoflip);
+
+  return s;
+}
+
+Suite *
+gamma_suite ()
+{
+  Suite *s = suite_create ("gamma");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_gamma);
+
+  return s;
+}
+
+int
+main (int argc, char **argv)
+{
+  int nf;
+
+  Suite *s = videobalance_suite ();
+  SRunner *sr = srunner_create (s);
+
+  srunner_add_suite (sr, videoflip_suite ());
+  srunner_add_suite (sr, gamma_suite ());
+
+  gst_check_init (&argc, &argv);
+
+  srunner_run_all (sr, CK_NORMAL);
+  nf = srunner_ntests_failed (sr);
+  srunner_free (sr);
+
+  return nf;
+}