Merge the tizen patch and fix build err based on 1.12.2
[platform/upstream/gst-plugins-good.git] / gst / videofilter / gstvideobalance.c
index 83a2afd..12fb3cf 100644 (file)
@@ -15,8 +15,8 @@
  *
  * 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.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 
 /*
  * <refsect2>
  * <title>Example launch line</title>
  * |[
- * gst-launch videotestsrc ! videobalance saturation=0.0 ! ffmpegcolorspace ! ximagesink
+ * gst-launch-1.0 videotestsrc ! videobalance saturation=0.0 ! videoconvert ! ximagesink
  * ]| This pipeline converts the image to black and white by setting the
  * saturation to 0.0.
  * </refsect2>
- *
- * Last reviewed on 2010-04-18 (0.10.22)
  */
 
 #ifdef HAVE_CONFIG_H
@@ -49,8 +47,7 @@
 #include "gstvideobalance.h"
 #include <string.h>
 
-#include <gst/controller/gstcontroller.h>
-#include <gst/interfaces/colorbalance.h>
+#include <gst/video/colorbalance.h>
 
 GST_DEBUG_CATEGORY_STATIC (videobalance_debug);
 #define GST_CAT_DEFAULT videobalance_debug
@@ -70,79 +67,40 @@ enum
   PROP_SATURATION
 };
 
+#define PROCESSING_CAPS \
+  "{ AYUV, ARGB, BGRA, ABGR, RGBA, Y444, xRGB, RGBx, " \
+  "xBGR, BGRx, RGB, BGR, Y42B, YUY2, UYVY, YVYU, " \
+  "I420, YV12, IYUV, Y41B, NV12, NV21 }"
+
 static GstStaticPadTemplate gst_video_balance_src_template =
     GST_STATIC_PAD_TEMPLATE ("src",
     GST_PAD_SRC,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
-        GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";"
-        GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_RGBA ";"
-        GST_VIDEO_CAPS_YUV ("Y444") ";"
-        GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_RGBx ";"
-        GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_BGRx ";"
-        GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";"
-        GST_VIDEO_CAPS_YUV ("Y42B") ";"
-        GST_VIDEO_CAPS_YUV ("YUY2") ";"
-        GST_VIDEO_CAPS_YUV ("UYVY") ";"
-        GST_VIDEO_CAPS_YUV ("YVYU") ";"
-        GST_VIDEO_CAPS_YUV ("I420") ";"
-        GST_VIDEO_CAPS_YUV ("YV12") ";"
-        GST_VIDEO_CAPS_YUV ("IYUV") ";" GST_VIDEO_CAPS_YUV ("Y41B")
-    )
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (PROCESSING_CAPS) ";"
+        "video/x-raw(ANY)")
     );
 
 static GstStaticPadTemplate gst_video_balance_sink_template =
     GST_STATIC_PAD_TEMPLATE ("sink",
     GST_PAD_SINK,
     GST_PAD_ALWAYS,
-    GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
-        GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";"
-        GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_RGBA ";"
-        GST_VIDEO_CAPS_YUV ("Y444") ";"
-        GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_RGBx ";"
-        GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_BGRx ";"
-        GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";"
-        GST_VIDEO_CAPS_YUV ("Y42B") ";"
-        GST_VIDEO_CAPS_YUV ("YUY2") ";"
-        GST_VIDEO_CAPS_YUV ("UYVY") ";"
-        GST_VIDEO_CAPS_YUV ("YVYU") ";"
-        GST_VIDEO_CAPS_YUV ("I420") ";"
-        GST_VIDEO_CAPS_YUV ("YV12") ";"
-        GST_VIDEO_CAPS_YUV ("IYUV") ";" GST_VIDEO_CAPS_YUV ("Y41B")
-    )
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (PROCESSING_CAPS) ";"
+        "video/x-raw(ANY)")
     );
 
-static void gst_video_balance_colorbalance_init (GstColorBalanceClass * iface);
-static void gst_video_balance_interface_init (GstImplementsInterfaceClass *
-    klass);
+static void gst_video_balance_colorbalance_init (GstColorBalanceInterface *
+    iface);
 
 static void gst_video_balance_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec);
 static void gst_video_balance_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
-static void
-_do_init (GType video_balance_type)
-{
-  static const GInterfaceInfo iface_info = {
-    (GInterfaceInitFunc) gst_video_balance_interface_init,
-    NULL,
-    NULL,
-  };
-  static const GInterfaceInfo colorbalance_info = {
-    (GInterfaceInitFunc) gst_video_balance_colorbalance_init,
-    NULL,
-    NULL,
-  };
-
-  g_type_add_interface_static (video_balance_type,
-      GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
-  g_type_add_interface_static (video_balance_type, GST_TYPE_COLOR_BALANCE,
-      &colorbalance_info);
-}
-
-GST_BOILERPLATE_FULL (GstVideoBalance, gst_video_balance, GstVideoFilter,
-    GST_TYPE_VIDEO_FILTER, _do_init);
+#define gst_video_balance_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstVideoBalance, gst_video_balance,
+    GST_TYPE_VIDEO_FILTER,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
+        gst_video_balance_colorbalance_init));
 
 /*
  * look-up tables (LUT).
@@ -197,36 +155,37 @@ gst_video_balance_is_passthrough (GstVideoBalance * videobalance)
 static void
 gst_video_balance_update_properties (GstVideoBalance * videobalance)
 {
-  gboolean passthrough = gst_video_balance_is_passthrough (videobalance);
+  gboolean passthrough;
   GstBaseTransform *base = GST_BASE_TRANSFORM (videobalance);
 
-  base->passthrough = passthrough;
-
+  GST_OBJECT_LOCK (videobalance);
+  passthrough = gst_video_balance_is_passthrough (videobalance);
   if (!passthrough)
     gst_video_balance_update_tables (videobalance);
+  GST_OBJECT_UNLOCK (videobalance);
+
+  gst_base_transform_set_passthrough (base, passthrough);
 }
 
 static void
-gst_video_balance_planar_yuv (GstVideoBalance * videobalance, guint8 * data)
+gst_video_balance_planar_yuv (GstVideoBalance * videobalance,
+    GstVideoFrame * frame)
 {
   gint x, y;
   guint8 *ydata;
   guint8 *udata, *vdata;
   gint ystride, ustride, vstride;
-  GstVideoFormat format;
   gint width, height;
   gint width2, height2;
   guint8 *tabley = videobalance->tabley;
   guint8 **tableu = videobalance->tableu;
   guint8 **tablev = videobalance->tablev;
 
-  format = videobalance->format;
-  width = videobalance->width;
-  height = videobalance->height;
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
 
-  ydata =
-      data + gst_video_format_get_component_offset (format, 0, width, height);
-  ystride = gst_video_format_get_row_stride (format, 0, width);
+  ydata = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  ystride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
 
   for (y = 0; y < height; y++) {
     guint8 *yptr;
@@ -238,15 +197,13 @@ gst_video_balance_planar_yuv (GstVideoBalance * videobalance, guint8 * data)
     }
   }
 
-  width2 = gst_video_format_get_component_width (format, 1, width);
-  height2 = gst_video_format_get_component_height (format, 1, height);
+  width2 = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1);
+  height2 = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1);
 
-  udata =
-      data + gst_video_format_get_component_offset (format, 1, width, height);
-  vdata =
-      data + gst_video_format_get_component_offset (format, 2, width, height);
-  ustride = gst_video_format_get_row_stride (format, 1, width);
-  vstride = gst_video_format_get_row_stride (format, 1, width);
+  udata = GST_VIDEO_FRAME_PLANE_DATA (frame, 1);
+  vdata = GST_VIDEO_FRAME_PLANE_DATA (frame, 2);
+  ustride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 1);
+  vstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 2);
 
   for (y = 0; y < height2; y++) {
     guint8 *uptr, *vptr;
@@ -266,28 +223,25 @@ gst_video_balance_planar_yuv (GstVideoBalance * videobalance, guint8 * data)
 }
 
 static void
-gst_video_balance_packed_yuv (GstVideoBalance * videobalance, guint8 * data)
+gst_video_balance_semiplanar_yuv (GstVideoBalance * videobalance,
+    GstVideoFrame * frame)
 {
   gint x, y;
   guint8 *ydata;
-  guint8 *udata, *vdata;
-  gint ystride, ustride, vstride;
-  gint yoff, uoff, voff;
-  GstVideoFormat format;
+  guint8 *uvdata;
+  gint ystride, uvstride;
   gint width, height;
   gint width2, height2;
   guint8 *tabley = videobalance->tabley;
   guint8 **tableu = videobalance->tableu;
   guint8 **tablev = videobalance->tablev;
+  gint upos, vpos;
 
-  format = videobalance->format;
-  width = videobalance->width;
-  height = videobalance->height;
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
 
-  ydata =
-      data + gst_video_format_get_component_offset (format, 0, width, height);
-  ystride = gst_video_format_get_row_stride (format, 0, width);
-  yoff = gst_video_format_get_pixel_stride (format, 0);
+  ydata = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  ystride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
 
   for (y = 0; y < height; y++) {
     guint8 *yptr;
@@ -295,28 +249,80 @@ gst_video_balance_packed_yuv (GstVideoBalance * videobalance, guint8 * data)
     yptr = ydata + y * ystride;
     for (x = 0; x < width; x++) {
       *yptr = tabley[*yptr];
+      yptr++;
+    }
+  }
+
+  width2 = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1);
+  height2 = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1);
+
+  uvdata = GST_VIDEO_FRAME_PLANE_DATA (frame, 1);
+  uvstride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 1);
+
+  upos = GST_VIDEO_INFO_FORMAT (&frame->info) == GST_VIDEO_FORMAT_NV12 ? 0 : 1;
+  vpos = GST_VIDEO_INFO_FORMAT (&frame->info) == GST_VIDEO_FORMAT_NV12 ? 1 : 0;
+
+  for (y = 0; y < height2; y++) {
+    guint8 *uvptr;
+    guint8 u1, v1;
+
+    uvptr = uvdata + y * uvstride;
+
+    for (x = 0; x < width2; x++) {
+      u1 = uvptr[upos];
+      v1 = uvptr[vpos];
+
+      uvptr[upos] = tableu[u1][v1];
+      uvptr[vpos] = tablev[u1][v1];
+      uvptr += 2;
+    }
+  }
+}
+
+static void
+gst_video_balance_packed_yuv (GstVideoBalance * videobalance,
+    GstVideoFrame * frame)
+{
+  gint x, y, stride;
+  guint8 *ydata, *udata, *vdata;
+  gint yoff, uoff, voff;
+  gint width, height;
+  gint width2, height2;
+  guint8 *tabley = videobalance->tabley;
+  guint8 **tableu = videobalance->tableu;
+  guint8 **tablev = videobalance->tablev;
+
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+  ydata = GST_VIDEO_FRAME_COMP_DATA (frame, 0);
+  yoff = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
+
+  for (y = 0; y < height; y++) {
+    guint8 *yptr;
+
+    yptr = ydata + y * stride;
+    for (x = 0; x < width; x++) {
+      *yptr = tabley[*yptr];
       yptr += yoff;
     }
   }
 
-  width2 = gst_video_format_get_component_width (format, 1, width);
-  height2 = gst_video_format_get_component_height (format, 1, height);
+  width2 = GST_VIDEO_FRAME_COMP_WIDTH (frame, 1);
+  height2 = GST_VIDEO_FRAME_COMP_HEIGHT (frame, 1);
 
-  udata =
-      data + gst_video_format_get_component_offset (format, 1, width, height);
-  vdata =
-      data + gst_video_format_get_component_offset (format, 2, width, height);
-  ustride = gst_video_format_get_row_stride (format, 1, width);
-  vstride = gst_video_format_get_row_stride (format, 1, width);
-  uoff = gst_video_format_get_pixel_stride (format, 1);
-  voff = gst_video_format_get_pixel_stride (format, 2);
+  udata = GST_VIDEO_FRAME_COMP_DATA (frame, 1);
+  vdata = GST_VIDEO_FRAME_COMP_DATA (frame, 2);
+  uoff = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 1);
+  voff = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 2);
 
   for (y = 0; y < height2; y++) {
     guint8 *uptr, *vptr;
     guint8 u1, v1;
 
-    uptr = udata + y * ustride;
-    vptr = vdata + y * vstride;
+    uptr = udata + y * stride;
+    vptr = vdata + y * stride;
 
     for (x = 0; x < width2; x++) {
       u1 = *uptr;
@@ -346,11 +352,13 @@ static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
 #define APPLY_MATRIX(m,o,v1,v2,v3) ((m[o*4] * v1 + m[o*4+1] * v2 + m[o*4+2] * v3 + m[o*4+3]) >> 8)
 
 static void
-gst_video_balance_packed_rgb (GstVideoBalance * videobalance, guint8 * data)
+gst_video_balance_packed_rgb (GstVideoBalance * videobalance,
+    GstVideoFrame * frame)
 {
   gint i, j, height;
-  gint width, row_stride, row_wrap;
+  gint width, stride, row_wrap;
   gint pixel_stride;
+  guint8 *data;
   gint offsets[3];
   gint r, g, b;
   gint y, u, v;
@@ -359,24 +367,18 @@ gst_video_balance_packed_rgb (GstVideoBalance * videobalance, guint8 * data)
   guint8 **tableu = videobalance->tableu;
   guint8 **tablev = videobalance->tablev;
 
-  offsets[0] = gst_video_format_get_component_offset (videobalance->format, 0,
-      videobalance->width, videobalance->height);
-  offsets[1] = gst_video_format_get_component_offset (videobalance->format, 1,
-      videobalance->width, videobalance->height);
-  offsets[2] = gst_video_format_get_component_offset (videobalance->format, 2,
-      videobalance->width, videobalance->height);
-
-  width =
-      gst_video_format_get_component_width (videobalance->format, 0,
-      videobalance->width);
-  height =
-      gst_video_format_get_component_height (videobalance->format, 0,
-      videobalance->height);
-  row_stride =
-      gst_video_format_get_row_stride (videobalance->format, 0,
-      videobalance->width);
-  pixel_stride = gst_video_format_get_pixel_stride (videobalance->format, 0);
-  row_wrap = row_stride - pixel_stride * width;
+  width = GST_VIDEO_FRAME_WIDTH (frame);
+  height = GST_VIDEO_FRAME_HEIGHT (frame);
+
+  offsets[0] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 0);
+  offsets[1] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 1);
+  offsets[2] = GST_VIDEO_FRAME_COMP_OFFSET (frame, 2);
+
+  data = GST_VIDEO_FRAME_PLANE_DATA (frame, 0);
+  stride = GST_VIDEO_FRAME_PLANE_STRIDE (frame, 0);
+
+  pixel_stride = GST_VIDEO_FRAME_COMP_PSTRIDE (frame, 0);
+  row_wrap = stride - pixel_stride * width;
 
   for (i = 0; i < height; i++) {
     for (j = 0; j < width; j++) {
@@ -411,25 +413,17 @@ gst_video_balance_packed_rgb (GstVideoBalance * videobalance, guint8 * data)
 
 /* get notified of caps and plug in the correct process function */
 static gboolean
-gst_video_balance_set_caps (GstBaseTransform * base, GstCaps * incaps,
-    GstCaps * outcaps)
+gst_video_balance_set_info (GstVideoFilter * vfilter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
 {
-  GstVideoBalance *videobalance = GST_VIDEO_BALANCE (base);
+  GstVideoBalance *videobalance = GST_VIDEO_BALANCE (vfilter);
 
   GST_DEBUG_OBJECT (videobalance,
       "in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps);
 
   videobalance->process = NULL;
 
-  if (!gst_video_format_parse_caps (incaps, &videobalance->format,
-          &videobalance->width, &videobalance->height))
-    goto invalid_caps;
-
-  videobalance->size =
-      gst_video_format_get_size (videobalance->format, videobalance->width,
-      videobalance->height);
-
-  switch (videobalance->format) {
+  switch (GST_VIDEO_INFO_FORMAT (in_info)) {
     case GST_VIDEO_FORMAT_I420:
     case GST_VIDEO_FORMAT_YV12:
     case GST_VIDEO_FORMAT_Y41B:
@@ -443,6 +437,10 @@ gst_video_balance_set_caps (GstBaseTransform * base, GstCaps * incaps,
     case GST_VIDEO_FORMAT_YVYU:
       videobalance->process = gst_video_balance_packed_yuv;
       break;
+    case GST_VIDEO_FORMAT_NV12:
+    case GST_VIDEO_FORMAT_NV21:
+      videobalance->process = gst_video_balance_semiplanar_yuv;
+      break;
     case GST_VIDEO_FORMAT_ARGB:
     case GST_VIDEO_FORMAT_ABGR:
     case GST_VIDEO_FORMAT_RGBA:
@@ -456,14 +454,19 @@ gst_video_balance_set_caps (GstBaseTransform * base, GstCaps * incaps,
       videobalance->process = gst_video_balance_packed_rgb;
       break;
     default:
+      if (!gst_video_balance_is_passthrough (videobalance))
+        goto unknown_format;
       break;
   }
 
-  return videobalance->process != NULL;
+  return TRUE;
 
-invalid_caps:
-  GST_ERROR_OBJECT (videobalance, "Invalid caps: %" GST_PTR_FORMAT, incaps);
-  return FALSE;
+  /* ERRORS */
+unknown_format:
+  {
+    GST_ERROR_OBJECT (videobalance, "unknown format %" GST_PTR_FORMAT, incaps);
+    return FALSE;
+  }
 }
 
 static void
@@ -480,63 +483,62 @@ gst_video_balance_before_transform (GstBaseTransform * base, GstBuffer * buf)
       GST_TIME_ARGS (timestamp));
 
   if (GST_CLOCK_TIME_IS_VALID (stream_time))
-    gst_object_sync_values (G_OBJECT (balance), stream_time);
+    gst_object_sync_values (GST_OBJECT (balance), stream_time);
+}
+
+static GstCaps *
+gst_video_balance_transform_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
+{
+  GstVideoBalance *balance = GST_VIDEO_BALANCE (trans);
+  GstCaps *ret;
+
+  if (!gst_video_balance_is_passthrough (balance)) {
+    static GstStaticCaps raw_caps =
+        GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (PROCESSING_CAPS));
+    GstCaps *tmp = gst_static_caps_get (&raw_caps);
+
+    caps = gst_caps_intersect (caps, tmp);
+    gst_caps_unref (tmp);
+
+    if (filter) {
+      ret = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+      gst_caps_unref (caps);
+    } else {
+      ret = caps;
+    }
+  } else {
+    if (filter) {
+      ret = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    } else {
+      ret = gst_caps_ref (caps);
+    }
+  }
+
+  return ret;
 }
 
 static GstFlowReturn
-gst_video_balance_transform_ip (GstBaseTransform * base, GstBuffer * outbuf)
+gst_video_balance_transform_frame_ip (GstVideoFilter * vfilter,
+    GstVideoFrame * frame)
 {
-  GstVideoBalance *videobalance = GST_VIDEO_BALANCE (base);
-  guint8 *data;
-  guint size;
+  GstVideoBalance *videobalance = GST_VIDEO_BALANCE (vfilter);
 
   if (!videobalance->process)
     goto not_negotiated;
 
-  /* if no change is needed, we are done */
-  if (base->passthrough)
-    goto done;
-
-  data = GST_BUFFER_DATA (outbuf);
-  size = GST_BUFFER_SIZE (outbuf);
-
-  if (size != videobalance->size)
-    goto wrong_size;
-
   GST_OBJECT_LOCK (videobalance);
-  videobalance->process (videobalance, data);
+  videobalance->process (videobalance, frame);
   GST_OBJECT_UNLOCK (videobalance);
 
-done:
   return GST_FLOW_OK;
 
   /* ERRORS */
-wrong_size:
+not_negotiated:
   {
-    GST_ELEMENT_ERROR (videobalance, STREAM, FORMAT,
-        (NULL), ("Invalid buffer size %d, expected %d", size,
-            videobalance->size));
-    return GST_FLOW_ERROR;
+    GST_ERROR_OBJECT (videobalance, "Not negotiated yet");
+    return GST_FLOW_NOT_NEGOTIATED;
   }
-not_negotiated:
-  GST_ERROR_OBJECT (videobalance, "Not negotiated yet");
-  return GST_FLOW_NOT_NEGOTIATED;
-}
-
-static void
-gst_video_balance_base_init (gpointer g_class)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
-  gst_element_class_set_details_simple (element_class, "Video balance",
-      "Filter/Effect/Video",
-      "Adjusts brightness, contrast, hue, saturation on a video stream",
-      "David Schleef <ds@schleef.org>");
-
-  gst_element_class_add_static_pad_template (element_class,
-      &gst_video_balance_sink_template);
-  gst_element_class_add_static_pad_template (element_class,
-      &gst_video_balance_src_template);
 }
 
 static void
@@ -566,7 +568,9 @@ static void
 gst_video_balance_class_init (GstVideoBalanceClass * klass)
 {
   GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
   GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstVideoFilterClass *vfilter_class = (GstVideoFilterClass *) klass;
 
   GST_DEBUG_CATEGORY_INIT (videobalance_debug, "videobalance", 0,
       "videobalance");
@@ -591,16 +595,29 @@ gst_video_balance_class_init (GstVideoBalanceClass * klass)
           DEFAULT_PROP_SATURATION,
           GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
-  trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_video_balance_set_caps);
-  trans_class->transform_ip =
-      GST_DEBUG_FUNCPTR (gst_video_balance_transform_ip);
+  gst_element_class_set_static_metadata (gstelement_class, "Video balance",
+      "Filter/Effect/Video",
+      "Adjusts brightness, contrast, hue, saturation on a video stream",
+      "David Schleef <ds@schleef.org>");
+
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_video_balance_sink_template);
+  gst_element_class_add_static_pad_template (gstelement_class,
+      &gst_video_balance_src_template);
+
   trans_class->before_transform =
       GST_DEBUG_FUNCPTR (gst_video_balance_before_transform);
+  trans_class->transform_ip_on_passthrough = FALSE;
+  trans_class->transform_caps =
+      GST_DEBUG_FUNCPTR (gst_video_balance_transform_caps);
+
+  vfilter_class->set_info = GST_DEBUG_FUNCPTR (gst_video_balance_set_info);
+  vfilter_class->transform_frame_ip =
+      GST_DEBUG_FUNCPTR (gst_video_balance_transform_frame_ip);
 }
 
 static void
-gst_video_balance_init (GstVideoBalance * videobalance,
-    GstVideoBalanceClass * klass)
+gst_video_balance_init (GstVideoBalance * videobalance)
 {
   const gchar *channels[4] = { "HUE", "SATURATION",
     "BRIGHTNESS", "CONTRAST"
@@ -637,20 +654,6 @@ gst_video_balance_init (GstVideoBalance * videobalance,
   }
 }
 
-static gboolean
-gst_video_balance_interface_supported (GstImplementsInterface * iface,
-    GType type)
-{
-  g_assert (type == GST_TYPE_COLOR_BALANCE);
-  return TRUE;
-}
-
-static void
-gst_video_balance_interface_init (GstImplementsInterfaceClass * klass)
-{
-  klass->supported = gst_video_balance_interface_supported;
-}
-
 static const GList *
 gst_video_balance_colorbalance_list_channels (GstColorBalance * balance)
 {
@@ -675,7 +678,6 @@ gst_video_balance_colorbalance_set_value (GstColorBalance * balance,
   g_return_if_fail (GST_IS_VIDEO_FILTER (vb));
   g_return_if_fail (channel->label != NULL);
 
-  GST_BASE_TRANSFORM_LOCK (vb);
   GST_OBJECT_LOCK (vb);
   if (!g_ascii_strcasecmp (channel->label, "HUE")) {
     new_val = (value + 1000.0) * 2.0 / 2000.0 - 1.0;
@@ -694,11 +696,10 @@ gst_video_balance_colorbalance_set_value (GstColorBalance * balance,
     changed = new_val != vb->contrast;
     vb->contrast = new_val;
   }
+  GST_OBJECT_UNLOCK (vb);
 
   if (changed)
     gst_video_balance_update_properties (vb);
-  GST_OBJECT_UNLOCK (vb);
-  GST_BASE_TRANSFORM_UNLOCK (vb);
 
   if (changed) {
     gst_color_balance_value_changed (balance, channel,
@@ -730,13 +731,19 @@ gst_video_balance_colorbalance_get_value (GstColorBalance * balance,
   return value;
 }
 
+static GstColorBalanceType
+gst_video_balance_colorbalance_get_balance_type (GstColorBalance * balance)
+{
+  return GST_COLOR_BALANCE_SOFTWARE;
+}
+
 static void
-gst_video_balance_colorbalance_init (GstColorBalanceClass * iface)
+gst_video_balance_colorbalance_init (GstColorBalanceInterface * iface)
 {
-  GST_COLOR_BALANCE_TYPE (iface) = GST_COLOR_BALANCE_SOFTWARE;
   iface->list_channels = gst_video_balance_colorbalance_list_channels;
   iface->set_value = gst_video_balance_colorbalance_set_value;
   iface->get_value = gst_video_balance_colorbalance_get_value;
+  iface->get_balance_type = gst_video_balance_colorbalance_get_balance_type;
 }
 
 static GstColorBalanceChannel *
@@ -761,7 +768,6 @@ gst_video_balance_set_property (GObject * object, guint prop_id,
   gdouble d;
   const gchar *label = NULL;
 
-  GST_BASE_TRANSFORM_LOCK (balance);
   GST_OBJECT_LOCK (balance);
   switch (prop_id) {
     case PROP_CONTRAST:
@@ -801,9 +807,8 @@ gst_video_balance_set_property (GObject * object, guint prop_id,
       break;
   }
 
-  gst_video_balance_update_properties (balance);
   GST_OBJECT_UNLOCK (balance);
-  GST_BASE_TRANSFORM_UNLOCK (balance);
+  gst_video_balance_update_properties (balance);
 
   if (label) {
     GstColorBalanceChannel *channel =