summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Schleef <ds@schleef.org>2003-06-13 05:37:19 +0000
committerDavid Schleef <ds@schleef.org>2003-06-13 05:37:19 +0000
commit176e9f83f383570682c67392e90a32ebae61c567 (patch)
tree8f3ca4504108e009ce89f1bf3be08155749fd5e2
parent195e19b6ada8f9c215fd3b7d2b6522bcf378887b (diff)
Rotate/flip video by increments of 90 degrees.
Original commit message from CVS: Rotate/flip video by increments of 90 degrees.
-rw-r--r--gst/videoflip/Makefile.am12
-rw-r--r--gst/videoflip/gstvideoflip.c455
-rw-r--r--gst/videoflip/gstvideoflip.h94
-rw-r--r--gst/videoflip/videoflip.c233
-rw-r--r--gst/videoflip/videoflip.h46
5 files changed, 840 insertions, 0 deletions
diff --git a/gst/videoflip/Makefile.am b/gst/videoflip/Makefile.am
new file mode 100644
index 00000000..ad9b7a9e
--- /dev/null
+++ b/gst/videoflip/Makefile.am
@@ -0,0 +1,12 @@
+plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
+
+plugin_LTLIBRARIES = libgstvideoflip.la
+
+libgstvideoflip_la_SOURCES = \
+ gstvideoflip.c \
+ videoflip.c
+libgstvideoflip_la_CFLAGS = $(GST_CFLAGS)
+libgstvideoflip_la_LIBADD =
+libgstvideoflip_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstvideoflip.h videoflip.h
diff --git a/gst/videoflip/gstvideoflip.c b/gst/videoflip/gstvideoflip.c
new file mode 100644
index 00000000..6f51d705
--- /dev/null
+++ b/gst/videoflip/gstvideoflip.c
@@ -0,0 +1,455 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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.
+ */
+
+
+/*#define DEBUG_ENABLED */
+#include <gstvideoflip.h>
+#include <videoflip.h>
+
+
+
+/* elementfactory information */
+static GstElementDetails videoflip_details = {
+ "Video scaler",
+ "Filter/Video",
+ "LGPL",
+ "Resizes video",
+ VERSION,
+ "Wim Taymans <wim.taymans@chello.be>",
+ "(C) 2000",
+};
+
+/* GstVideoflip signals and args */
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_METHOD,
+ /* FILL ME */
+};
+
+static void gst_videoflip_class_init (GstVideoflipClass *klass);
+static void gst_videoflip_init (GstVideoflip *videoflip);
+
+static void gst_videoflip_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void gst_videoflip_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
+
+static void gst_videoflip_chain (GstPad *pad, GstBuffer *buf);
+static GstCaps * gst_videoflip_get_capslist(void);
+
+static GstElementClass *parent_class = NULL;
+
+#define GST_TYPE_VIDEOFLIP_METHOD (gst_videoflip_method_get_type())
+
+static GType
+gst_videoflip_method_get_type(void)
+{
+ static GType videoflip_method_type = 0;
+ static GEnumValue videoflip_methods[] = {
+ { GST_VIDEOFLIP_METHOD_IDENTITY, "0", "Identity (no rotation)" },
+ { GST_VIDEOFLIP_METHOD_90R, "1", "Rotate right 90 degrees" },
+ { GST_VIDEOFLIP_METHOD_180, "2", "Rotate 180 degrees" },
+ { GST_VIDEOFLIP_METHOD_90L, "3", "Rotate left 90 degrees" },
+ { GST_VIDEOFLIP_METHOD_HORIZ, "4", "Flip horizontally" },
+ { GST_VIDEOFLIP_METHOD_VERT, "5", "Flip vertically" },
+ { GST_VIDEOFLIP_METHOD_TRANS, "6", "Flip across upper left/lower right diagonal" },
+ { GST_VIDEOFLIP_METHOD_OTHER, "7", "Flip across upper right/lower left diagonal" },
+ { 0, NULL, NULL },
+ };
+ if(!videoflip_method_type){
+ videoflip_method_type = g_enum_register_static("GstVideoflipMethod",
+ videoflip_methods);
+ }
+ return videoflip_method_type;
+}
+
+GType
+gst_videoflip_get_type (void)
+{
+ static GType videoflip_type = 0;
+
+ if (!videoflip_type) {
+ static const GTypeInfo videoflip_info = {
+ sizeof(GstVideoflipClass), NULL,
+ NULL,
+ (GClassInitFunc)gst_videoflip_class_init,
+ NULL,
+ NULL,
+ sizeof(GstVideoflip),
+ 0,
+ (GInstanceInitFunc)gst_videoflip_init,
+ };
+ videoflip_type = g_type_register_static(GST_TYPE_ELEMENT, "GstVideoflip", &videoflip_info, 0);
+ }
+ return videoflip_type;
+}
+
+static void
+gst_videoflip_class_init (GstVideoflipClass *klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass*)klass;
+ gstelement_class = (GstElementClass*)klass;
+
+ g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_METHOD,
+ g_param_spec_enum("method","method","method",
+ GST_TYPE_VIDEOFLIP_METHOD, GST_VIDEOFLIP_METHOD_90R,
+ G_PARAM_READWRITE));
+
+ parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
+
+ gobject_class->set_property = gst_videoflip_set_property;
+ gobject_class->get_property = gst_videoflip_get_property;
+
+}
+
+static GstPadTemplate *
+gst_videoflip_src_template_factory(void)
+{
+ static GstPadTemplate *templ = NULL;
+
+ if(!templ){
+ GstCaps *caps = GST_CAPS_NEW("src","video/raw",
+ "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
+ "height", GST_PROPS_INT_RANGE (0, G_MAXINT));
+
+ caps = gst_caps_intersect(caps, gst_videoflip_get_capslist ());
+
+ templ = GST_PAD_TEMPLATE_NEW("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
+ }
+ return templ;
+}
+
+static GstPadTemplate *
+gst_videoflip_sink_template_factory(void)
+{
+ static GstPadTemplate *templ = NULL;
+
+ if(!templ){
+ GstCaps *caps = GST_CAPS_NEW("sink","video/raw",
+ "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
+ "height", GST_PROPS_INT_RANGE (0, G_MAXINT));
+
+ caps = gst_caps_intersect(caps, gst_videoflip_get_capslist ());
+
+ templ = GST_PAD_TEMPLATE_NEW("src", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
+ }
+ return templ;
+}
+
+static GstCaps *
+gst_videoflip_get_capslist(void)
+{
+ static GstCaps *capslist = NULL;
+ GstCaps *caps;
+ int i;
+
+ if (capslist){
+ gst_caps_ref(capslist);
+ return capslist;
+ }
+
+ for(i=0;i<videoflip_n_formats;i++){
+ caps = videoflip_get_caps(videoflip_formats + i);
+ capslist = gst_caps_append(capslist, caps);
+ }
+
+ gst_caps_ref(capslist);
+ return capslist;
+}
+
+static GstCaps *
+gst_videoflip_sink_getcaps (GstPad *pad, GstCaps *caps)
+{
+ GstVideoflip *videoflip;
+ GstCaps *capslist = NULL;
+ GstCaps *peercaps;
+ GstCaps *sizecaps;
+ int i;
+
+ GST_DEBUG(0,"gst_videoflip_src_link");
+ videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
+
+ /* get list of peer's caps */
+ if(pad == videoflip->srcpad){
+ peercaps = gst_pad_get_allowed_caps (videoflip->sinkpad);
+ }else{
+ peercaps = gst_pad_get_allowed_caps (videoflip->srcpad);
+ }
+
+ /* FIXME videoflip doesn't allow passthru of video formats it
+ * doesn't understand. */
+ /* Look through our list of caps and find those that match with
+ * the peer's formats. Create a list of them. */
+ for(i=0;i<videoflip_n_formats;i++){
+ GstCaps *fromcaps = videoflip_get_caps(videoflip_formats + i);
+ if(gst_caps_is_always_compatible(fromcaps, peercaps)){
+ capslist = gst_caps_append(capslist, fromcaps);
+ }
+ gst_caps_unref (fromcaps);
+ }
+ gst_caps_unref (peercaps);
+
+ sizecaps = GST_CAPS_NEW("videoflip_size","video/raw",
+ "width", GST_PROPS_INT_RANGE (0, G_MAXINT),
+ "height", GST_PROPS_INT_RANGE (0, G_MAXINT));
+
+ caps = gst_caps_intersect(caps, gst_videoflip_get_capslist ());
+ gst_caps_unref (sizecaps);
+
+ return caps;
+}
+
+
+static GstPadLinkReturn
+gst_videoflip_src_link (GstPad *pad, GstCaps *caps)
+{
+ GstVideoflip *videoflip;
+ GstPadLinkReturn ret;
+ GstCaps *peercaps;
+
+ GST_DEBUG(0,"gst_videoflip_src_link");
+ videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
+
+ if (!GST_CAPS_IS_FIXED (caps)) {
+ return GST_PAD_LINK_DELAYED;
+ }
+
+ gst_caps_debug(caps,"ack");
+
+ videoflip->format = videoflip_find_by_caps (caps);
+ g_return_val_if_fail(videoflip->format, GST_PAD_LINK_REFUSED);
+
+ gst_caps_get_int (caps, "width", &videoflip->to_width);
+ gst_caps_get_int (caps, "height", &videoflip->to_height);
+
+ GST_DEBUG(0,"width %d height %d",videoflip->to_width,videoflip->to_height);
+
+ peercaps = gst_caps_copy(caps);
+
+ gst_caps_set(peercaps, "width", GST_PROPS_INT_RANGE (0, G_MAXINT));
+ gst_caps_set(peercaps, "height", GST_PROPS_INT_RANGE (0, G_MAXINT));
+
+ ret = gst_pad_try_set_caps (videoflip->srcpad, peercaps);
+
+ gst_caps_unref(peercaps);
+
+ if(ret==GST_PAD_LINK_OK){
+ caps = gst_pad_get_caps (videoflip->srcpad);
+
+ gst_caps_get_int (caps, "width", &videoflip->from_width);
+ gst_caps_get_int (caps, "height", &videoflip->from_height);
+ gst_videoflip_setup(videoflip);
+ }
+
+ return ret;
+}
+
+static GstPadLinkReturn
+gst_videoflip_sink_link (GstPad *pad, GstCaps *caps)
+{
+ GstVideoflip *videoflip;
+ GstPadLinkReturn ret;
+ GstCaps *peercaps;
+
+ GST_DEBUG(0,"gst_videoflip_src_link");
+ videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
+
+ if (!GST_CAPS_IS_FIXED (caps)) {
+ return GST_PAD_LINK_DELAYED;
+ }
+
+ videoflip->format = videoflip_find_by_caps (caps);
+ gst_caps_debug(caps,"ack");
+ g_return_val_if_fail(videoflip->format, GST_PAD_LINK_REFUSED);
+
+ gst_caps_get_int (caps, "width", &videoflip->from_width);
+ gst_caps_get_int (caps, "height", &videoflip->from_height);
+
+ gst_videoflip_setup(videoflip);
+
+ peercaps = gst_caps_copy(caps);
+
+ gst_caps_set(peercaps, "width", GST_PROPS_INT (videoflip->to_width));
+ gst_caps_set(peercaps, "height", GST_PROPS_INT (videoflip->to_height));
+
+ ret = gst_pad_try_set_caps (videoflip->srcpad, peercaps);
+
+ gst_caps_unref(peercaps);
+
+ if(ret==GST_PAD_LINK_OK){
+ caps = gst_pad_get_caps (videoflip->srcpad);
+
+ gst_caps_get_int (caps, "width", &videoflip->to_width);
+ gst_caps_get_int (caps, "height", &videoflip->to_height);
+ gst_videoflip_setup(videoflip);
+ }
+
+ return ret;
+}
+
+static void
+gst_videoflip_init (GstVideoflip *videoflip)
+{
+ GST_DEBUG(0,"gst_videoflip_init");
+ videoflip->sinkpad = gst_pad_new_from_template (
+ GST_PAD_TEMPLATE_GET (gst_videoflip_sink_template_factory),
+ "sink");
+ gst_element_add_pad(GST_ELEMENT(videoflip),videoflip->sinkpad);
+ gst_pad_set_chain_function(videoflip->sinkpad,gst_videoflip_chain);
+ gst_pad_set_link_function(videoflip->sinkpad,gst_videoflip_sink_link);
+ gst_pad_set_getcaps_function(videoflip->sinkpad,gst_videoflip_sink_getcaps);
+
+ videoflip->srcpad = gst_pad_new_from_template (
+ GST_PAD_TEMPLATE_GET (gst_videoflip_src_template_factory),
+ "src");
+ gst_element_add_pad(GST_ELEMENT(videoflip),videoflip->srcpad);
+ gst_pad_set_link_function(videoflip->srcpad,gst_videoflip_src_link);
+ //gst_pad_set_getcaps_function(videoflip->srcpad,gst_videoflip_getcaps);
+
+ videoflip->inited = FALSE;
+ videoflip->force_size = FALSE;
+}
+
+
+static void
+gst_videoflip_chain (GstPad *pad, GstBuffer *buf)
+{
+ GstVideoflip *videoflip;
+ guchar *data;
+ gulong size;
+ GstBuffer *outbuf;
+
+ GST_DEBUG (0,"gst_videoflip_chain");
+
+ g_return_if_fail (pad != NULL);
+ g_return_if_fail (GST_IS_PAD (pad));
+ g_return_if_fail (buf != NULL);
+
+ videoflip = GST_VIDEOFLIP (gst_pad_get_parent (pad));
+ g_return_if_fail (videoflip->inited);
+
+ data = GST_BUFFER_DATA(buf);
+ size = GST_BUFFER_SIZE(buf);
+
+ if(videoflip->passthru){
+ gst_pad_push(videoflip->srcpad, buf);
+ return;
+ }
+
+ GST_DEBUG (0,"gst_videoflip_chain: got buffer of %ld bytes in '%s'",size,
+ GST_OBJECT_NAME (videoflip));
+
+ GST_DEBUG(0,"size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d",
+ size,
+ videoflip->from_width, videoflip->from_height,
+ videoflip->to_width, videoflip->to_height,
+ size, videoflip->from_buf_size,
+ videoflip->to_buf_size);
+
+ g_return_if_fail (size == videoflip->from_buf_size);
+
+ outbuf = gst_buffer_new();
+ /* FIXME: handle bufferpools */
+ GST_BUFFER_SIZE(outbuf) = videoflip->to_buf_size;
+ GST_BUFFER_DATA(outbuf) = g_malloc (videoflip->to_buf_size);
+ GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf);
+
+ g_return_if_fail(videoflip->format);
+ GST_DEBUG (0,"format %s",videoflip->format->fourcc);
+ g_return_if_fail(videoflip->format->scale);
+
+ videoflip->format->scale(videoflip, GST_BUFFER_DATA(outbuf), data);
+
+ GST_DEBUG (0,"gst_videoflip_chain: pushing buffer of %d bytes in '%s'",GST_BUFFER_SIZE(outbuf),
+ GST_OBJECT_NAME (videoflip));
+
+ gst_pad_push(videoflip->srcpad, outbuf);
+
+ gst_buffer_unref(buf);
+}
+
+static void
+gst_videoflip_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+ GstVideoflip *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_VIDEOFLIP(object));
+ src = GST_VIDEOFLIP(object);
+
+ GST_DEBUG(0,"gst_videoflip_set_property");
+ switch (prop_id) {
+ case ARG_METHOD:
+ src->method = g_value_get_enum (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_videoflip_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+ GstVideoflip *src;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail(GST_IS_VIDEOFLIP(object));
+ src = GST_VIDEOFLIP(object);
+
+ switch (prop_id) {
+ case ARG_METHOD:
+ g_value_set_enum (value, src->method);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+static gboolean
+plugin_init (GModule *module, GstPlugin *plugin)
+{
+ GstElementFactory *factory;
+
+ /* create an elementfactory for the videoflip element */
+ factory = gst_element_factory_new("videoflip",GST_TYPE_VIDEOFLIP,
+ &videoflip_details);
+ g_return_val_if_fail(factory != NULL, FALSE);
+
+ gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (gst_videoflip_sink_template_factory));
+ gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (gst_videoflip_src_template_factory));
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "videoflip",
+ plugin_init
+};
diff --git a/gst/videoflip/gstvideoflip.h b/gst/videoflip/gstvideoflip.h
new file mode 100644
index 00000000..e3463e5e
--- /dev/null
+++ b/gst/videoflip/gstvideoflip.h
@@ -0,0 +1,94 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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_VIDEOFLIP_H__
+#define __GST_VIDEOFLIP_H__
+
+
+#include <config.h>
+#include <gst/gst.h>
+
+
+G_BEGIN_DECLS
+
+typedef enum {
+ GST_VIDEOFLIP_METHOD_IDENTITY,
+ GST_VIDEOFLIP_METHOD_90R,
+ GST_VIDEOFLIP_METHOD_180,
+ GST_VIDEOFLIP_METHOD_90L,
+ GST_VIDEOFLIP_METHOD_HORIZ,
+ GST_VIDEOFLIP_METHOD_VERT,
+ GST_VIDEOFLIP_METHOD_TRANS,
+ GST_VIDEOFLIP_METHOD_OTHER,
+} GstVideoflipMethod;
+
+
+#define GST_TYPE_VIDEOFLIP \
+ (gst_videoflip_get_type())
+#define GST_VIDEOFLIP(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEOFLIP,GstVideoflip))
+#define GST_VIDEOFLIP_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEOFLIP,GstVideoflip))
+#define GST_IS_VIDEOFLIP(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEOFLIP))
+#define GST_IS_VIDEOFLIP_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEOFLIP))
+
+typedef struct _GstVideoflip GstVideoflip;
+typedef struct _GstVideoflipClass GstVideoflipClass;
+
+struct _GstVideoflip {
+ GstElement element;
+
+ GstPad *sinkpad,*srcpad;
+
+ gboolean force_size;
+ gint forced_width;
+ gint forced_height;
+
+ /* video state */
+ gboolean inited;
+ struct videoflip_format_struct *format;
+ gint to_width;
+ gint to_height;
+ gint from_width;
+ gint from_height;
+ gboolean passthru;
+
+ GstVideoflipMethod method;
+
+ /* private */
+ gint from_buf_size;
+ gint to_buf_size;
+};
+
+struct _GstVideoflipClass {
+ GstElementClass parent_class;
+};
+
+GType gst_videoflip_get_type(void);
+
+void gst_videoflip_setup(GstVideoflip *);
+#define gst_videoflip_scale(scale, src, dest) (scale)->scale_cc((scale), (src), (dest))
+
+G_END_DECLS
+
+#endif /* __GST_VIDEOFLIP_H__ */
+
diff --git a/gst/videoflip/videoflip.c b/gst/videoflip/videoflip.c
new file mode 100644
index 00000000..ea93a7c6
--- /dev/null
+++ b/gst/videoflip/videoflip.c
@@ -0,0 +1,233 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * 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.
+ */
+
+#define DEBUG_ENABLED
+#include <gst/gst.h>
+#include <stdlib.h>
+#include <math.h>
+#include <videoflip.h>
+#include <string.h>
+
+#include "config.h"
+#include "gstvideoflip.h"
+
+static void gst_videoflip_planar411 (GstVideoflip *scale, unsigned char *dest, unsigned char *src);
+
+static void gst_videoflip_flip(GstVideoflip *videoflip, unsigned char *dest,
+ unsigned char *src, int sw, int sh, int dw, int dh);
+
+struct videoflip_format_struct videoflip_formats[] = {
+ /* planar */
+ { "YV12", 12, gst_videoflip_planar411, },
+ { "I420", 12, gst_videoflip_planar411, },
+ { "IYUV", 12, gst_videoflip_planar411, },
+};
+
+int videoflip_n_formats = sizeof(videoflip_formats)/sizeof(videoflip_formats[0]);
+
+GstCaps *
+videoflip_get_caps(struct videoflip_format_struct *format)
+{
+ unsigned int fourcc;
+ GstCaps *caps;
+
+ if(format->scale==NULL)
+ return NULL;
+
+ fourcc = GST_MAKE_FOURCC(format->fourcc[0],format->fourcc[1],format->fourcc[2],format->fourcc[3]);
+
+ if(format->bpp){
+ caps = GST_CAPS_NEW ("videoflip", "video/raw",
+ "format", GST_PROPS_FOURCC (fourcc),
+ "depth", GST_PROPS_INT(format->bpp),
+ "bpp", GST_PROPS_INT(format->depth),
+ "endianness", GST_PROPS_INT(format->endianness),
+ "red_mask", GST_PROPS_INT(format->red_mask),
+ "green_mask", GST_PROPS_INT(format->green_mask),
+ "blue_mask", GST_PROPS_INT(format->blue_mask));
+ }else{
+ caps = GST_CAPS_NEW ("videoflip", "video/raw",
+ "format", GST_PROPS_FOURCC (fourcc));
+ }
+
+ return caps;
+}
+
+struct videoflip_format_struct *
+videoflip_find_by_caps(GstCaps *caps)
+{
+ int i;
+
+ GST_DEBUG (0,"finding %p",caps);
+
+ g_return_val_if_fail(caps != NULL, NULL);
+
+ for (i = 0; i < videoflip_n_formats; i++){
+ GstCaps *c;
+
+ c = videoflip_get_caps(videoflip_formats + i);
+ if(c){
+ if(gst_caps_is_always_compatible(caps, c)){
+ gst_caps_unref(c);
+ return videoflip_formats + i;
+ }
+ gst_caps_unref(c);
+ }
+ }
+
+ return NULL;
+}
+
+void
+gst_videoflip_setup (GstVideoflip *videoflip)
+{
+ if(videoflip->from_width==0 || videoflip->from_height==0){
+ return;
+ }
+
+ switch(videoflip->method){
+ case GST_VIDEOFLIP_METHOD_90R:
+ case GST_VIDEOFLIP_METHOD_90L:
+ case GST_VIDEOFLIP_METHOD_TRANS:
+ case GST_VIDEOFLIP_METHOD_OTHER:
+ videoflip->to_height = videoflip->from_width;
+ videoflip->to_width = videoflip->from_height;
+ break;
+ case GST_VIDEOFLIP_METHOD_IDENTITY:
+ case GST_VIDEOFLIP_METHOD_180:
+ case GST_VIDEOFLIP_METHOD_HORIZ:
+ case GST_VIDEOFLIP_METHOD_VERT:
+ videoflip->to_height = videoflip->from_height;
+ videoflip->to_width = videoflip->from_width;
+ break;
+ default:
+ /* FIXME */
+ break;
+ }
+
+ GST_DEBUG (0,"format=%p \"%s\" from %dx%d to %dx%d",
+ videoflip->format, videoflip->format->fourcc,
+ videoflip->from_width, videoflip->from_height,
+ videoflip->to_width, videoflip->to_height);
+
+ if(videoflip->method == GST_VIDEOFLIP_METHOD_IDENTITY){
+ GST_DEBUG (0,"videoflip: using passthru");
+ videoflip->passthru = TRUE;
+ videoflip->inited = TRUE;
+ return;
+ }
+
+ videoflip->from_buf_size = (videoflip->from_width * videoflip->from_height
+ * videoflip->format->depth) / 8;
+ videoflip->to_buf_size = (videoflip->to_width * videoflip->to_height
+ * videoflip->format->depth) / 8;
+
+ videoflip->inited = TRUE;
+}
+
+static void
+gst_videoflip_planar411 (GstVideoflip *scale, unsigned char *dest, unsigned char *src)
+{
+ int sw = scale->from_width;
+ int sh = scale->from_height;
+ int dw = scale->to_width;
+ int dh = scale->to_height;
+
+ GST_DEBUG (0,"videoflip: scaling planar 4:1:1 %dx%d to %dx%d", sw, sh, dw, dh);
+
+ gst_videoflip_flip(scale, dest, src, sw, sh, dw, dh);
+
+ src += sw*sh;
+ dest += dw*dh;
+
+ dh = dh>>1;
+ dw = dw>>1;
+ sh = sh>>1;
+ sw = sw>>1;
+
+ gst_videoflip_flip(scale, dest, src, sw, sh, dw, dh);
+
+ src += sw*sh;
+ dest += dw*dh;
+
+ gst_videoflip_flip(scale, dest, src, sw, sh, dw, dh);
+}
+
+static void
+gst_videoflip_flip(GstVideoflip *videoflip, unsigned char *dest,
+ unsigned char *src, int sw, int sh, int dw, int dh)
+{
+ int x,y;
+
+ switch(videoflip->method){
+ case GST_VIDEOFLIP_METHOD_90R:
+ for(y=0;y<dh;y++){
+ for(x=0;x<dw;x++){
+ dest[y*dw + x] = src[(sh - 1 - x)*sw + y];
+ }
+ }
+ break;
+ case GST_VIDEOFLIP_METHOD_90L:
+ for(y=0;y<dh;y++){
+ for(x=0;x<dw;x++){
+ dest[y*dw + x] = src[x*sw + (sw - 1 - y)];
+ }
+ }
+ break;
+ case GST_VIDEOFLIP_METHOD_180:
+ for(y=0;y<dh;y++){
+ for(x=0;x<dw;x++){
+ dest[y*dw + x] = src[(sh - 1 - y)*sw + (sw - 1 - x)];
+ }
+ }
+ break;
+ case GST_VIDEOFLIP_METHOD_HORIZ:
+ for(y=0;y<dh;y++){
+ for(x=0;x<dw;x++){
+ dest[y*dw + x] = src[y*sw + (sw - 1 - x)];
+ }
+ }
+ break;
+ case GST_VIDEOFLIP_METHOD_VERT:
+ for(y=0;y<dh;y++){
+ for(x=0;x<dw;x++){
+ dest[y*dw + x] = src[(sh - 1 - y)*sw + x];
+ }
+ }
+ break;
+ case GST_VIDEOFLIP_METHOD_TRANS:
+ for(y=0;y<dh;y++){
+ for(x=0;x<dw;x++){
+ dest[y*dw + x] = src[x*sw + y];
+ }
+ }
+ break;
+ case GST_VIDEOFLIP_METHOD_OTHER:
+ for(y=0;y<dh;y++){
+ for(x=0;x<dw;x++){
+ dest[y*dw + x] = src[(sh - 1 - x)*sw + (sw - 1 - y)];
+ }
+ }
+ break;
+ default:
+ /* FIXME */
+ break;
+ }
+}
+
diff --git a/gst/videoflip/videoflip.h b/gst/videoflip/videoflip.h
new file mode 100644
index 00000000..e61cbffe
--- /dev/null
+++ b/gst/videoflip/videoflip.h
@@ -0,0 +1,46 @@
+/* GStreamer
+ * Copyright (C) <2003> David A. Schleef <ds@schleef.org>
+ *
+ * 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 __VIDEOFLIP_H__
+#define __VIDEOFLIP_H__
+
+#include "gstvideoflip.h"
+
+struct videoflip_format_struct {
+ char *fourcc;
+ int depth;
+ void (*scale)(GstVideoflip *,unsigned char *dest, unsigned char *src);
+ int bpp;
+ unsigned int endianness;
+ unsigned int red_mask;
+ unsigned int green_mask;
+ unsigned int blue_mask;
+};
+
+extern struct videoflip_format_struct videoflip_formats[];
+extern int videoflip_n_formats;
+
+GstCaps *videoflip_get_caps(struct videoflip_format_struct *format);
+
+struct videoflip_format_struct *videoflip_find_by_caps(GstCaps *caps);
+
+
+#endif
+