effectv: Add rippletv element

This produces a water ripple effect on the video input,
based on motion or a rain drop algorithm.

Kindly relicensed to LGPL2+ by Kentaro Fukuchi <fukuchi@megaui.net>.

Fixes bug #588695.
diff --git a/gst/effectv/Makefile.am b/gst/effectv/Makefile.am
index 0aed796..e0c2803 100644
--- a/gst/effectv/Makefile.am
+++ b/gst/effectv/Makefile.am
@@ -3,7 +3,7 @@
 libgsteffectv_la_SOURCES = \
 	gsteffectv.c gstedge.c gstaging.c gstdice.c gstwarp.c \
 	gstshagadelic.c gstvertigo.c gstrev.c gstquark.c gstop.c \
-	gstradioac.c gststreak.c
+	gstradioac.c gststreak.c gstripple.c
 libgsteffectv_la_CFLAGS = \
 	$(GST_PLUGINS_BASE_CFLAGS) \
 	$(GST_CONTROLLER_CFLAGS) \
@@ -21,4 +21,4 @@
 
 noinst_HEADERS = gsteffectv.h gstaging.h gstdice.h gstedge.h \
         gstquark.h gstrev.h gstshagadelic.h gstvertigo.h gstwarp.h gstop.h \
-	gstradioac.h gststreak.h
+	gstradioac.h gststreak.h gstripple.h
diff --git a/gst/effectv/gsteffectv.c b/gst/effectv/gsteffectv.c
index 57cbbca..1615fd7 100644
--- a/gst/effectv/gsteffectv.c
+++ b/gst/effectv/gsteffectv.c
@@ -37,6 +37,7 @@
 #include "gstop.h"
 #include "gstradioac.h"
 #include "gststreak.h"
+#include "gstripple.h"
 
 struct _elements_entry
 {
@@ -56,6 +57,7 @@
   {"optv", gst_optv_get_type},
   {"radioactv", gst_radioactv_get_type},
   {"streaktv", gst_streaktv_get_type},
+  {"rippletv", gst_rippletv_get_type},
   {NULL, 0},
 };
 
diff --git a/gst/effectv/gstripple.c b/gst/effectv/gstripple.c
new file mode 100644
index 0000000..ce4a58c
--- /dev/null
+++ b/gst/effectv/gstripple.c
@@ -0,0 +1,610 @@
+/* GStreamer
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001-2006 FUKUCHI Kentaro
+ *
+ * RippleTV - Water ripple effect.
+ * Copyright (C) 2001-2002 FUKUCHI Kentaro
+ *
+ * This combines the RippleTV and BaltanTV effects, which are
+ * very similar. BaltanTV is used if the feedback property is set
+ * to TRUE, otherwise RippleTV is used.
+ *
+ * EffecTV is free software. 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.
+ */
+
+/**
+ * SECTION:element-rippletv
+ *
+ * RippleTV does ripple mark effect on the video input. The ripple is caused
+ * by motion or random rain drops.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch -v videotestsrc ! rippletv ! ffmpegcolorspace ! autovideosink
+ * ]| This pipeline shows the effect of rippletv on a test stream.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <string.h>
+
+#include "gstripple.h"
+#include "gsteffectv.h"
+
+#include <gst/video/video.h>
+
+#define DEFAULT_MODE 0
+
+enum
+{
+  PROP_0,
+  PROP_RESET,
+  PROP_MODE
+};
+
+static gint sqrtable[256];
+
+#define GST_TYPE_RIPPLETV_MODE (gst_rippletv_mode_get_type())
+static GType
+gst_rippletv_mode_get_type (void)
+{
+  static GType type = 0;
+
+  static const GEnumValue enumvalue[] = {
+    {0, "Motion Detection", "motion-detection"},
+    {1, "Rain", "rain"},
+    {0, NULL, NULL},
+  };
+
+  if (!type) {
+    type = g_enum_register_static ("GstRippleTVMode", enumvalue);
+  }
+  return type;
+}
+
+
+GST_BOILERPLATE (GstRippleTV, gst_rippletv, GstVideoFilter,
+    GST_TYPE_VIDEO_FILTER);
+
+static GstStaticPadTemplate gst_rippletv_src_template =
+    GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx "; " GST_VIDEO_CAPS_RGBx ";"
+        GST_VIDEO_CAPS_xBGR "; " GST_VIDEO_CAPS_xRGB)
+    );
+
+static GstStaticPadTemplate gst_rippletv_sink_template =
+    GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx "; " GST_VIDEO_CAPS_RGBx ";"
+        GST_VIDEO_CAPS_xBGR "; " GST_VIDEO_CAPS_xRGB)
+    );
+
+static const gint point = 16;
+static const gint impact = 2;
+static const gint decay = 8;
+static const gint loopnum = 2;
+
+static void
+setTable (void)
+{
+  gint i;
+
+  for (i = 0; i < 128; i++) {
+    sqrtable[i] = i * i;
+  }
+  for (i = 1; i <= 128; i++) {
+    sqrtable[256 - i] = -i * i;
+  }
+}
+
+static void
+image_bgset_y (guint32 * src, gint16 * background, gint video_area)
+{
+  gint i;
+  gint R, G, B;
+  guint32 *p;
+  gint16 *q;
+
+  p = src;
+  q = background;
+  for (i = 0; i < video_area; i++) {
+    R = ((*p) & 0xff0000) >> (16 - 1);
+    G = ((*p) & 0xff00) >> (8 - 2);
+    B = (*p) & 0xff;
+    *q = (gint16) (R + G + B);
+    p++;
+    q++;
+  }
+}
+
+static gint
+setBackground (GstRippleTV * filter, guint32 * src)
+{
+  image_bgset_y (src, filter->background, filter->width * filter->height);
+  filter->bg_is_set = TRUE;
+
+  return 0;
+}
+
+static void
+image_bgsubtract_update_y (guint32 * src, gint16 * background, guint8 * diff,
+    gint video_area)
+{
+  gint i;
+  gint R, G, B;
+  guint32 *p;
+  gint16 *q;
+  guint8 *r;
+  gint v;
+
+  p = src;
+  q = background;
+  r = diff;
+  for (i = 0; i < video_area; i++) {
+    R = ((*p) & 0xff0000) >> (16 - 1);
+    G = ((*p) & 0xff00) >> (8 - 2);
+    B = (*p) & 0xff;
+    v = (R + G + B) - (gint) (*q);
+    *q = (gint16) (R + G + B);
+    *r = ((v + 70 * 7) >> 24) | ((70 * 7 - v) >> 24);
+
+    p++;
+    q++;
+    r++;
+  }
+}
+
+static void
+motiondetect (GstRippleTV * filter, guint32 * src)
+{
+  guint8 *diff = filter->diff;
+  gint width = filter->width;
+  gint *p, *q;
+  gint x, y, h;
+
+  if (!filter->bg_is_set)
+    setBackground (filter, src);
+
+  image_bgsubtract_update_y (src, filter->background, filter->diff,
+      filter->width * filter->height);
+  p = filter->map1 + filter->map_w + 1;
+  q = filter->map2 + filter->map_w + 1;
+  diff += filter->width + 2;
+
+  for (y = filter->map_h - 2; y > 0; y--) {
+    for (x = filter->map_w - 2; x > 0; x--) {
+      h = (gint) * diff + (gint) * (diff + 1) + (gint) * (diff + width) +
+          (gint) * (diff + width + 1);
+      if (h > 0) {
+        *p = h << (point + impact - 8);
+        *q = *p;
+      }
+      p++;
+      q++;
+      diff += 2;
+    }
+    diff += width + 2;
+    p += 2;
+    q += 2;
+  }
+}
+
+static inline void
+drop (gint power, gint * map1, gint * map2, gint map_w, gint map_h)
+{
+  gint x, y;
+  gint *p, *q;
+
+  x = fastrand () % (map_w - 4) + 2;
+  y = fastrand () % (map_h - 4) + 2;
+  p = map1 + y * map_w + x;
+  q = map2 + y * map_w + x;
+  *p = power;
+  *q = power;
+  *(p - map_w) = *(p - 1) = *(p + 1) = *(p + map_w) = power / 2;
+  *(p - map_w - 1) = *(p - map_w + 1) = *(p + map_w - 1) = *(p + map_w + 1) =
+      power / 4;
+  *(q - map_w) = *(q - 1) = *(q + 1) = *(q + map_w) = power / 2;
+  *(q - map_w - 1) = *(q - map_w + 1) = *(q + map_w - 1) = *(p + map_w + 1) =
+      power / 4;
+}
+
+static void
+raindrop (GstRippleTV * filter)
+{
+  gint i;
+
+  if (filter->period == 0) {
+    switch (filter->rain_stat) {
+      case 0:
+        filter->period = (fastrand () >> 23) + 100;
+        filter->drop_prob = 0;
+        filter->drop_prob_increment = 0x00ffffff / filter->period;
+        filter->drop_power = (-(fastrand () >> 28) - 2) << point;
+        filter->drops_per_frame_max = 2 << (fastrand () >> 30); // 2,4,8 or 16
+        filter->rain_stat = 1;
+        break;
+      case 1:
+        filter->drop_prob = 0x00ffffff;
+        filter->drops_per_frame = 1;
+        filter->drop_prob_increment = 1;
+        filter->period = (filter->drops_per_frame_max - 1) * 16;
+        filter->rain_stat = 2;
+        break;
+      case 2:
+        filter->period = (fastrand () >> 22) + 1000;
+        filter->drop_prob_increment = 0;
+        filter->rain_stat = 3;
+        break;
+      case 3:
+        filter->period = (filter->drops_per_frame_max - 1) * 16;
+        filter->drop_prob_increment = -1;
+        filter->rain_stat = 4;
+        break;
+      case 4:
+        filter->period = (fastrand () >> 24) + 60;
+        filter->drop_prob_increment = -(filter->drop_prob / filter->period);
+        filter->rain_stat = 5;
+        break;
+      case 5:
+      default:
+        filter->period = (fastrand () >> 23) + 500;
+        filter->drop_prob = 0;
+        filter->rain_stat = 0;
+        break;
+    }
+  }
+  switch (filter->rain_stat) {
+    default:
+    case 0:
+      break;
+    case 1:
+    case 5:
+      if ((fastrand () >> 8) < filter->drop_prob) {
+        drop (filter->drop_power, filter->map1, filter->map2, filter->map_w,
+            filter->map_h);
+      }
+      filter->drop_prob += filter->drop_prob_increment;
+      break;
+    case 2:
+    case 3:
+    case 4:
+      for (i = filter->drops_per_frame / 16; i > 0; i--) {
+        drop (filter->drop_power, filter->map1, filter->map2, filter->map_w,
+            filter->map_h);
+      }
+      filter->drops_per_frame += filter->drop_prob_increment;
+      break;
+  }
+  filter->period--;
+}
+
+static GstFlowReturn
+gst_rippletv_transform (GstBaseTransform * trans, GstBuffer * in,
+    GstBuffer * out)
+{
+  GstRippleTV *filter = GST_RIPPLETV (trans);
+  guint32 *src, *dest;
+  GstFlowReturn ret = GST_FLOW_OK;
+  gint x, y, i;
+  gint dx, dy;
+  gint h, v;
+  gint width, height;
+  gint *p, *q, *r;
+  gint8 *vp;
+
+  src = (guint32 *) GST_BUFFER_DATA (in);
+  dest = (guint32 *) GST_BUFFER_DATA (out);
+
+  /* impact from the motion or rain drop */
+  if (filter->mode)
+    raindrop (filter);
+  else
+    motiondetect (filter, src);
+
+  /* simulate surface wave */
+  width = filter->map_w;
+  height = filter->map_h;
+
+  /* This function is called only 30 times per second. To increase a speed
+   * of wave, iterates this loop several times. */
+  for (i = loopnum; i > 0; i--) {
+    /* wave simulation */
+    p = filter->map1 + width + 1;
+    q = filter->map2 + width + 1;
+    r = filter->map3 + width + 1;
+    for (y = height - 2; y > 0; y--) {
+      for (x = width - 2; x > 0; x--) {
+        h = *(p - width - 1) + *(p - width + 1) + *(p + width - 1) + *(p +
+            width + 1)
+            + *(p - width) + *(p - 1) + *(p + 1) + *(p + width) - (*p) * 9;
+        h = h >> 3;
+        v = *p - *q;
+        v += h - (v >> decay);
+        *r = v + *p;
+        p++;
+        q++;
+        r++;
+      }
+      p += 2;
+      q += 2;
+      r += 2;
+    }
+
+    /* low pass filter */
+    p = filter->map3 + width + 1;
+    q = filter->map2 + width + 1;
+    for (y = height - 2; y > 0; y--) {
+      for (x = width - 2; x > 0; x--) {
+        h = *(p - width) + *(p - 1) + *(p + 1) + *(p + width) + (*p) * 60;
+        *q = h >> 6;
+        p++;
+        q++;
+      }
+      p += 2;
+      q += 2;
+    }
+
+    p = filter->map1;
+    filter->map1 = filter->map2;
+    filter->map2 = p;
+  }
+
+  vp = filter->vtable;
+  p = filter->map1;
+  for (y = height - 1; y > 0; y--) {
+    for (x = width - 1; x > 0; x--) {
+      /* difference of the height between two voxel. They are twiced to
+       * emphasise the wave. */
+      vp[0] = sqrtable[((p[0] - p[1]) >> (point - 1)) & 0xff];
+      vp[1] = sqrtable[((p[0] - p[width]) >> (point - 1)) & 0xff];
+      p++;
+      vp += 2;
+    }
+    p++;
+    vp += 2;
+  }
+
+  height = filter->height;
+  width = filter->width;
+  vp = filter->vtable;
+
+  /* draw refracted image. The vector table is stretched. */
+  for (y = 0; y < height; y += 2) {
+    for (x = 0; x < width; x += 2) {
+      h = (gint) vp[0];
+      v = (gint) vp[1];
+      dx = x + h;
+      dy = y + v;
+      if (dx < 0)
+        dx = 0;
+      if (dy < 0)
+        dy = 0;
+      if (dx >= width)
+        dx = width - 1;
+      if (dy >= height)
+        dy = height - 1;
+      dest[0] = src[dy * width + dx];
+
+      i = dx;
+
+      dx = x + 1 + (h + (gint) vp[2]) / 2;
+      if (dx < 0)
+        dx = 0;
+      if (dx >= width)
+        dx = width - 1;
+      dest[1] = src[dy * width + dx];
+
+      dy = y + 1 + (v + (gint) vp[filter->map_w * 2 + 1]) / 2;
+      if (dy < 0)
+        dy = 0;
+      if (dy >= height)
+        dy = height - 1;
+      dest[width] = src[dy * width + i];
+
+      dest[width + 1] = src[dy * width + dx];
+      dest += 2;
+      vp += 2;
+    }
+    dest += filter->width;
+    vp += 2;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_rippletv_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
+    GstCaps * outcaps)
+{
+  GstRippleTV *filter = GST_RIPPLETV (btrans);
+  GstStructure *structure;
+  gboolean ret = FALSE;
+
+  structure = gst_caps_get_structure (incaps, 0);
+
+  if (gst_structure_get_int (structure, "width", &filter->width) &&
+      gst_structure_get_int (structure, "height", &filter->height)) {
+
+    filter->map_h = filter->height / 2 + 1;
+    filter->map_w = filter->width / 2 + 1;
+
+    if (filter->map)
+      g_free (filter->map);
+    filter->map = g_new0 (gint, filter->map_h * filter->map_w * 3);
+
+    filter->map1 = filter->map;
+    filter->map2 = filter->map + filter->map_w * filter->map_h;
+    filter->map3 = filter->map + filter->map_w * filter->map_h * 2;
+
+    if (filter->vtable)
+      g_free (filter->vtable);
+    filter->vtable = g_new0 (gint8, filter->map_h * filter->map_w * 2);
+
+    if (filter->background)
+      g_free (filter->background);
+    filter->background = g_new0 (gint16, filter->width * filter->height);
+
+    if (filter->diff)
+      g_free (filter->diff);
+    filter->diff = g_new0 (guint8, filter->width * filter->height);
+
+    ret = TRUE;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_rippletv_start (GstBaseTransform * trans)
+{
+  GstRippleTV *filter = GST_RIPPLETV (trans);
+
+  filter->bg_is_set = FALSE;
+
+  filter->period = 0;
+  filter->rain_stat = 0;
+  filter->drop_prob = 0;
+  filter->drop_prob_increment = 0;
+  filter->drops_per_frame_max = 0;
+  filter->drops_per_frame = 0;
+  filter->drop_power = 0;
+
+  return TRUE;
+}
+
+static void
+gst_rippletv_finalize (GObject * object)
+{
+  GstRippleTV *filter = GST_RIPPLETV (object);
+
+  if (filter->map)
+    g_free (filter->map);
+  filter->map = NULL;
+
+  if (filter->vtable)
+    g_free (filter->vtable);
+  filter->vtable = NULL;
+
+  if (filter->background)
+    g_free (filter->background);
+  filter->background = NULL;
+
+  if (filter->diff)
+    g_free (filter->diff);
+  filter->diff = NULL;
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rippletv_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRippleTV *filter = GST_RIPPLETV (object);
+
+  switch (prop_id) {
+    case PROP_RESET:{
+      memset (filter->map, 0,
+          filter->map_h * filter->map_w * 2 * sizeof (gint));
+      break;
+    }
+    case PROP_MODE:
+      filter->mode = g_value_get_enum (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rippletv_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstRippleTV *filter = GST_RIPPLETV (object);
+
+  switch (prop_id) {
+    case PROP_MODE:
+      g_value_set_enum (value, filter->mode);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rippletv_base_init (gpointer g_class)
+{
+  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+  gst_element_class_set_details_simple (element_class, "RippleTV effect",
+      "Filter/Effect/Video",
+      "RippleTV does ripple mark effect on the video input",
+      "FUKUCHI, Kentarou <fukuchi@users.sourceforge.net>, "
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_rippletv_sink_template));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_rippletv_src_template));
+}
+
+static void
+gst_rippletv_class_init (GstRippleTVClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+
+  gobject_class->set_property = gst_rippletv_set_property;
+  gobject_class->get_property = gst_rippletv_get_property;
+
+  gobject_class->finalize = gst_rippletv_finalize;
+
+  g_object_class_install_property (gobject_class, PROP_RESET,
+      g_param_spec_boolean ("reset", "Reset",
+          "Reset all current ripples", FALSE,
+          G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_MODE,
+      g_param_spec_enum ("mode", "Mode",
+          "Mode", GST_TYPE_RIPPLETV_MODE, DEFAULT_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_rippletv_set_caps);
+  trans_class->transform = GST_DEBUG_FUNCPTR (gst_rippletv_transform);
+  trans_class->start = GST_DEBUG_FUNCPTR (gst_rippletv_start);
+
+  setTable ();
+}
+
+static void
+gst_rippletv_init (GstRippleTV * filter, GstRippleTVClass * klass)
+{
+  filter->mode = DEFAULT_MODE;
+}
diff --git a/gst/effectv/gstripple.h b/gst/effectv/gstripple.h
new file mode 100644
index 0000000..388ba56
--- /dev/null
+++ b/gst/effectv/gstripple.h
@@ -0,0 +1,87 @@
+/* GStreamer
+ * Copyright (C) <2009> Sebastian Dröge <sebastian.droege@collabora.co.uk>
+ *
+ * EffecTV - Realtime Digital Video Effector
+ * Copyright (C) 2001-2006 FUKUCHI Kentaro
+ *
+ * RippleTV - Water ripple effect.
+ * Copyright (C) 2001-2002 FUKUCHI Kentaro
+ *
+ * EffecTV is free software. 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.
+ */
+
+#ifndef __GST_RIPPLE_H__
+#define __GST_RIPPLE_H__
+
+#include <gst/gst.h>
+
+#include <gst/video/gstvideofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RIPPLETV \
+  (gst_rippletv_get_type())
+#define GST_RIPPLETV(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RIPPLETV,GstRippleTV))
+#define GST_RIPPLETV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RIPPLETV,GstRippleTVClass))
+#define GST_IS_RIPPLETV(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RIPPLETV))
+#define GST_IS_RIPPLETV_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RIPPLETV))
+
+typedef struct _GstRippleTV GstRippleTV;
+typedef struct _GstRippleTVClass GstRippleTVClass;
+
+struct _GstRippleTV
+{
+  GstVideoFilter element;
+
+  /* < private > */
+  gint width, height;
+
+  gint mode;
+
+  gint16 *background;
+  guint8 *diff;
+
+  gint *map, *map1, *map2, *map3;
+  gint map_h, map_w;
+
+  gint8 *vtable;
+
+  gboolean bg_is_set;
+
+  gint period;
+  gint rain_stat;
+  guint drop_prob;
+  gint drop_prob_increment;
+  gint drops_per_frame_max;
+  gint drops_per_frame;
+  gint drop_power;
+};
+
+struct _GstRippleTVClass
+{
+  GstVideoFilterClass parent_class;
+};
+
+GType gst_rippletv_get_type (void);
+
+G_END_DECLS
+
+#endif /* __GST_RIPPLE_H__ */