videofilters: Add videodiff element
authorDavid Schleef <ds@schleef.org>
Sat, 11 May 2013 00:30:48 +0000 (17:30 -0700)
committerDavid Schleef <ds@schleef.org>
Sat, 11 May 2013 00:40:17 +0000 (17:40 -0700)
gst/videofilters/Makefile.am
gst/videofilters/gstvideodiff.c [new file with mode: 0644]
gst/videofilters/gstvideodiff.h [new file with mode: 0644]
gst/videofilters/gstvideofiltersbad.c

index f261186..276f853 100644 (file)
@@ -5,7 +5,10 @@ plugin_LTLIBRARIES = libgstvideofiltersbad.la
 
 libgstvideofiltersbad_la_SOURCES = \
        gstzebrastripe.c \
+       gstzebrastripe.h \
        gstscenechange.c \
+       gstvideodiff.c \
+       gstvideodiff.h \
        gstvideofiltersbad.c
 #nodist_libgstvideofiltersbad_la_SOURCES = $(ORC_NODIST_SOURCES)
 libgstvideofiltersbad_la_CFLAGS = \
diff --git a/gst/videofilters/gstvideodiff.c b/gst/videofilters/gstvideodiff.c
new file mode 100644 (file)
index 0000000..364fa1c
--- /dev/null
@@ -0,0 +1,292 @@
+/* GStreamer
+ * Copyright (C) 2013 FIXME <fixme@example.com>
+ *
+ * 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., 51 Franklin Street, Suite 500,
+ * Boston, MA 02110-1335, USA.
+ */
+/**
+ * SECTION:element-gstvideodiff
+ *
+ * The videodiff element does FIXME stuff.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch -v fakesrc ! videodiff ! FIXME ! fakesink
+ * ]|
+ * FIXME Describe what the pipeline does.
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+#include "gstvideodiff.h"
+
+GST_DEBUG_CATEGORY_STATIC (gst_video_diff_debug_category);
+#define GST_CAT_DEFAULT gst_video_diff_debug_category
+
+/* prototypes */
+
+
+static void gst_video_diff_set_property (GObject * object,
+    guint property_id, const GValue * value, GParamSpec * pspec);
+static void gst_video_diff_get_property (GObject * object,
+    guint property_id, GValue * value, GParamSpec * pspec);
+static void gst_video_diff_dispose (GObject * object);
+static void gst_video_diff_finalize (GObject * object);
+
+static gboolean gst_video_diff_start (GstBaseTransform * trans);
+static gboolean gst_video_diff_stop (GstBaseTransform * trans);
+static gboolean gst_video_diff_set_info (GstVideoFilter * filter,
+    GstCaps * incaps, GstVideoInfo * in_info, GstCaps * outcaps,
+    GstVideoInfo * out_info);
+static GstFlowReturn gst_video_diff_transform_frame (GstVideoFilter * filter,
+    GstVideoFrame * inframe, GstVideoFrame * outframe);
+
+enum
+{
+  PROP_0
+};
+
+/* pad templates */
+
+/* FIXME: add/remove formats you can handle */
+#define VIDEO_SRC_CAPS \
+    GST_VIDEO_CAPS_MAKE("{ I420, Y444, Y42B, UYVY, RGBA }")
+
+/* FIXME: add/remove formats you can handle */
+#define VIDEO_SINK_CAPS \
+    GST_VIDEO_CAPS_MAKE("{ I420, Y444, Y42B, UYVY, RGBA }")
+
+
+/* class initialization */
+
+G_DEFINE_TYPE_WITH_CODE (GstVideoDiff, gst_video_diff, GST_TYPE_VIDEO_FILTER,
+    GST_DEBUG_CATEGORY_INIT (gst_video_diff_debug_category, "videodiff", 0,
+        "debug category for videodiff element"));
+
+static void
+gst_video_diff_class_init (GstVideoDiffClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GstBaseTransformClass *base_transform_class =
+      GST_BASE_TRANSFORM_CLASS (klass);
+  GstVideoFilterClass *video_filter_class = GST_VIDEO_FILTER_CLASS (klass);
+
+  /* Setting up pads and setting metadata should be moved to
+     base_class_init if you intend to subclass this class. */
+  gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass),
+      gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+          gst_caps_from_string (VIDEO_SRC_CAPS)));
+  gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass),
+      gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+          gst_caps_from_string (VIDEO_SINK_CAPS)));
+
+  gst_element_class_set_static_metadata (GST_ELEMENT_CLASS (klass),
+      "FIXME Long name", "Generic", "FIXME Description",
+      "FIXME <fixme@example.com>");
+
+  gobject_class->set_property = gst_video_diff_set_property;
+  gobject_class->get_property = gst_video_diff_get_property;
+  gobject_class->dispose = gst_video_diff_dispose;
+  gobject_class->finalize = gst_video_diff_finalize;
+  base_transform_class->start = GST_DEBUG_FUNCPTR (gst_video_diff_start);
+  base_transform_class->stop = GST_DEBUG_FUNCPTR (gst_video_diff_stop);
+  video_filter_class->set_info = GST_DEBUG_FUNCPTR (gst_video_diff_set_info);
+  video_filter_class->transform_frame =
+      GST_DEBUG_FUNCPTR (gst_video_diff_transform_frame);
+
+}
+
+static void
+gst_video_diff_init (GstVideoDiff * videodiff)
+{
+  videodiff->threshold = 10;
+}
+
+void
+gst_video_diff_set_property (GObject * object, guint property_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVideoDiff *videodiff = GST_VIDEO_DIFF (object);
+
+  GST_DEBUG_OBJECT (videodiff, "set_property");
+
+  switch (property_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+void
+gst_video_diff_get_property (GObject * object, guint property_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVideoDiff *videodiff = GST_VIDEO_DIFF (object);
+
+  GST_DEBUG_OBJECT (videodiff, "get_property");
+
+  switch (property_id) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+void
+gst_video_diff_dispose (GObject * object)
+{
+  GstVideoDiff *videodiff = GST_VIDEO_DIFF (object);
+
+  GST_DEBUG_OBJECT (videodiff, "dispose");
+
+  /* clean up as possible.  may be called multiple times */
+
+  G_OBJECT_CLASS (gst_video_diff_parent_class)->dispose (object);
+}
+
+void
+gst_video_diff_finalize (GObject * object)
+{
+  GstVideoDiff *videodiff = GST_VIDEO_DIFF (object);
+
+  GST_DEBUG_OBJECT (videodiff, "finalize");
+
+  /* clean up object here */
+
+  G_OBJECT_CLASS (gst_video_diff_parent_class)->finalize (object);
+}
+
+static gboolean
+gst_video_diff_start (GstBaseTransform * trans)
+{
+  GstVideoDiff *videodiff = GST_VIDEO_DIFF (trans);
+
+  GST_DEBUG_OBJECT (videodiff, "start");
+
+  return TRUE;
+}
+
+static gboolean
+gst_video_diff_stop (GstBaseTransform * trans)
+{
+  GstVideoDiff *videodiff = GST_VIDEO_DIFF (trans);
+
+  GST_DEBUG_OBJECT (videodiff, "stop");
+
+  return TRUE;
+}
+
+static gboolean
+gst_video_diff_set_info (GstVideoFilter * filter, GstCaps * incaps,
+    GstVideoInfo * in_info, GstCaps * outcaps, GstVideoInfo * out_info)
+{
+  GstVideoDiff *videodiff = GST_VIDEO_DIFF (filter);
+
+  GST_DEBUG_OBJECT (videodiff, "set_info");
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_video_diff_transform_frame_ip_planarY (GstVideoDiff * videodiff,
+    GstVideoFrame * outframe, GstVideoFrame * inframe, GstVideoFrame * oldframe)
+{
+  int width = inframe->info.width;
+  int height = inframe->info.height;
+  int i, j;
+  int threshold = videodiff->threshold;
+  int t = videodiff->t;
+
+  for (j = 0; j < height; j++) {
+    guint8 *d = (guint8 *) outframe->data[0] + outframe->info.stride[0] * j;
+    guint8 *s1 = (guint8 *) oldframe->data[0] + oldframe->info.stride[0] * j;
+    guint8 *s2 = (guint8 *) inframe->data[0] + inframe->info.stride[0] * j;
+    for (i = 0; i < width; i++) {
+      if ((s2[i] < s1[i] - threshold) || (s2[i] > s1[i] + threshold)) {
+        if ((i + j + t) & 0x4) {
+          d[i] = 16;
+        } else {
+          d[i] = 240;
+        }
+      } else {
+        d[i] = s2[i];
+      }
+    }
+  }
+  for (j = 0; j < GST_VIDEO_FRAME_COMP_HEIGHT (inframe, 1); j++) {
+    guint8 *d = (guint8 *) outframe->data[1] + outframe->info.stride[1] * j;
+    guint8 *s = (guint8 *) inframe->data[1] + inframe->info.stride[1] * j;
+    memcpy (d, s, GST_VIDEO_FRAME_COMP_WIDTH (inframe, 1));
+  }
+  for (j = 0; j < GST_VIDEO_FRAME_COMP_HEIGHT (inframe, 2); j++) {
+    guint8 *d = (guint8 *) outframe->data[2] + outframe->info.stride[2] * j;
+    guint8 *s = (guint8 *) inframe->data[2] + inframe->info.stride[2] * j;
+    memcpy (d, s, GST_VIDEO_FRAME_COMP_WIDTH (inframe, 2));
+  }
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_video_diff_transform_frame (GstVideoFilter * filter,
+    GstVideoFrame * inframe, GstVideoFrame * outframe)
+{
+  GstVideoDiff *videodiff = GST_VIDEO_DIFF (filter);
+
+  GST_DEBUG_OBJECT (videodiff, "transform_frame_ip");
+
+  if (videodiff->previous_buffer) {
+    GstVideoFrame oldframe;
+
+    gst_video_frame_map (&oldframe, &videodiff->oldinfo,
+        videodiff->previous_buffer, GST_MAP_READ);
+
+    switch (inframe->info.finfo->format) {
+      case GST_VIDEO_FORMAT_I420:
+      case GST_VIDEO_FORMAT_Y41B:
+      case GST_VIDEO_FORMAT_Y444:
+      case GST_VIDEO_FORMAT_Y42B:
+        gst_video_diff_transform_frame_ip_planarY (videodiff, outframe,
+            inframe, &oldframe);
+        break;
+      default:
+        g_assert_not_reached ();
+    }
+
+    gst_video_frame_unmap (&oldframe);
+    gst_buffer_unref (videodiff->previous_buffer);
+  } else {
+    int k;
+    int j;
+    for (k = 0; k < 3; k++) {
+      for (j = 0; j < GST_VIDEO_FRAME_COMP_HEIGHT (inframe, k); j++) {
+        guint8 *d = (guint8 *) outframe->data[k] + outframe->info.stride[k] * j;
+        guint8 *s = (guint8 *) inframe->data[k] + inframe->info.stride[k] * j;
+        memcpy (d, s, GST_VIDEO_FRAME_COMP_WIDTH (inframe, k));
+      }
+    }
+  }
+
+  videodiff->previous_buffer = gst_buffer_ref (inframe->buffer);
+  memcpy (&videodiff->oldinfo, &inframe->info, sizeof (GstVideoInfo));
+
+  return GST_FLOW_OK;
+}
diff --git a/gst/videofilters/gstvideodiff.h b/gst/videofilters/gstvideodiff.h
new file mode 100644 (file)
index 0000000..c91844a
--- /dev/null
@@ -0,0 +1,58 @@
+/* GStreamer
+ * Copyright (C) 2013 FIXME <fixme@example.com>
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _GST_VIDEO_DIFF_H_
+#define _GST_VIDEO_DIFF_H_
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideofilter.h>
+#include <string.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VIDEO_DIFF   (gst_video_diff_get_type())
+#define GST_VIDEO_DIFF(obj)   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO_DIFF,GstVideoDiff))
+#define GST_VIDEO_DIFF_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO_DIFF,GstVideoDiffClass))
+#define GST_IS_VIDEO_DIFF(obj)   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO_DIFF))
+#define GST_IS_VIDEO_DIFF_CLASS(obj)   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO_DIFF))
+
+typedef struct _GstVideoDiff GstVideoDiff;
+typedef struct _GstVideoDiffClass GstVideoDiffClass;
+
+struct _GstVideoDiff
+{
+  GstVideoFilter base_videodiff;
+
+  GstBuffer *previous_buffer;
+  GstVideoInfo oldinfo;
+
+  int threshold;
+  int t;
+};
+
+struct _GstVideoDiffClass
+{
+  GstVideoFilterClass base_videodiff_class;
+};
+
+GType gst_video_diff_get_type (void);
+
+G_END_DECLS
+
+#endif
index b65b4d5..1f361e4 100644 (file)
@@ -25,6 +25,7 @@
 #include <gst/base/gstbasetransform.h>
 #include "gstscenechange.h"
 #include "gstzebrastripe.h"
+#include "gstvideodiff.h"
 
 
 static gboolean
@@ -35,6 +36,8 @@ plugin_init (GstPlugin * plugin)
       gst_scene_change_get_type ());
   gst_element_register (plugin, "zebrastripe", GST_RANK_NONE,
       gst_zebra_stripe_get_type ());
+  return gst_element_register (plugin, "videodiff", GST_RANK_NONE,
+      GST_TYPE_VIDEO_DIFF);
 
   return TRUE;
 }