#include "config.h"
#endif
-/*#define DEBUG_ENABLED */
#include "gstvideoflip.h"
-#include <string.h>
-/* GstVideoflip signals and args */
-enum
-{
- /* FILL ME */
- LAST_SIGNAL
-};
+#include <gst/video/video.h>
+/* GstVideoflip signals and args */
enum
{
ARG_0,
/* FILL ME */
};
-static void gst_videoflip_base_init (gpointer g_class);
-static void gst_videoflip_class_init (gpointer g_class, gpointer class_data);
-static void gst_videoflip_init (GTypeInstance * instance, gpointer g_class);
+GST_DEBUG_CATEGORY (videoflip_debug);
+#define GST_CAT_DEFAULT videoflip_debug
-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 GstElementDetails videoflip_details =
+GST_ELEMENT_DETAILS ("Video Flipper",
+ "Filter/Effect/Video",
+ "Flips and rotates video",
+ "David Schleef <ds@schleef.org>");
+
+static GstStaticPadTemplate gst_videoflip_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_videoflip_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_videoflip_planar411 (GstVideofilter * videofilter, void *dest,
- void *src);
-static void gst_videoflip_setup (GstVideofilter * videofilter);
+static GstVideofilterClass *parent_class = NULL;
#define GST_TYPE_VIDEOFLIP_METHOD (gst_videoflip_method_get_type())
{
static GType videoflip_method_type = 0;
static GEnumValue videoflip_methods[] = {
- {GST_VIDEOFLIP_METHOD_IDENTITY, "0", "Identity (no rotation)"},
- {GST_VIDEOFLIP_METHOD_90R, "1", "Rotate clockwise 90 degrees"},
- {GST_VIDEOFLIP_METHOD_180, "2", "Rotate 180 degrees"},
- {GST_VIDEOFLIP_METHOD_90L, "3", "Rotate counter-clockwise 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"},
+ {GST_VIDEOFLIP_METHOD_IDENTITY, "Identity (no rotation)", "none"},
+ {GST_VIDEOFLIP_METHOD_90R, "Rotate clockwise 90 degrees", "clockwise"},
+ {GST_VIDEOFLIP_METHOD_180, "Rotate 180 degrees", "rotate-180"},
+ {GST_VIDEOFLIP_METHOD_90L, "Rotate counter-clockwise 90 degrees",
+ "counterclockwise"},
+ {GST_VIDEOFLIP_METHOD_HORIZ, "Flip horizontally", "horizontal-flip"},
+ {GST_VIDEOFLIP_METHOD_VERT, "Flip vertically", "vertical-flip"},
+ {GST_VIDEOFLIP_METHOD_TRANS,
+ "Flip across upper left/lower right diagonal", "upper-left-diagonal"},
+ {GST_VIDEOFLIP_METHOD_OTHER,
+ "Flip across upper right/lower left diagonal", "upper-right-diagonal"},
{0, NULL, NULL},
};
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),
- gst_videoflip_base_init,
- NULL,
- gst_videoflip_class_init,
- NULL,
- NULL,
- sizeof (GstVideoflip),
- 0,
- gst_videoflip_init,
- };
-
- videoflip_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
- "GstVideoflip", &videoflip_info, 0);
- }
- return videoflip_type;
-}
-
-static GstVideofilterFormat gst_videoflip_formats[] = {
- /* planar */
- {"YV12", 12, gst_videoflip_planar411,},
- {"I420", 12, gst_videoflip_planar411,},
- {"IYUV", 12, gst_videoflip_planar411,},
-};
-
-static void
-gst_videoflip_base_init (gpointer g_class)
+static gboolean
+gst_videoflip_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
+ GstCaps * outcaps)
{
- static GstElementDetails videoflip_details =
- GST_ELEMENT_DETAILS ("Video Flipper",
- "Filter/Effect/Video",
- "Flips and rotates video",
- "David Schleef <ds@schleef.org>");
- 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, &videoflip_details);
-
- for (i = 0; i < G_N_ELEMENTS (gst_videoflip_formats); i++) {
- gst_videofilter_class_add_format (videofilter_class,
- gst_videoflip_formats + i);
+ GstVideoflip *vf;
+ GstStructure *in_s, *out_s;
+ gboolean ret = FALSE;
+
+ vf = GST_VIDEOFLIP (btrans);
+
+ in_s = gst_caps_get_structure (incaps, 0);
+ out_s = gst_caps_get_structure (outcaps, 0);
+
+ if (gst_structure_get_int (in_s, "width", &vf->from_width) &&
+ gst_structure_get_int (in_s, "height", &vf->from_height) &&
+ gst_structure_get_int (out_s, "width", &vf->to_width) &&
+ gst_structure_get_int (out_s, "height", &vf->to_height)) {
+ /* Check that they are correct */
+ switch (vf->method) {
+ case GST_VIDEOFLIP_METHOD_90R:
+ case GST_VIDEOFLIP_METHOD_90L:
+ case GST_VIDEOFLIP_METHOD_TRANS:
+ case GST_VIDEOFLIP_METHOD_OTHER:
+ if ((vf->from_width != vf->to_height) ||
+ (vf->from_height != vf->to_width)) {
+ GST_DEBUG_OBJECT (vf, "we are inverting width and height but caps "
+ "are not correct : %dx%d to %dx%d", vf->from_width,
+ vf->from_height, vf->to_width, vf->to_height);
+ goto beach;
+ }
+ break;
+ case GST_VIDEOFLIP_METHOD_IDENTITY:
+
+ break;
+ case GST_VIDEOFLIP_METHOD_180:
+ case GST_VIDEOFLIP_METHOD_HORIZ:
+ case GST_VIDEOFLIP_METHOD_VERT:
+ if ((vf->from_width != vf->to_width) ||
+ (vf->from_height != vf->to_height)) {
+ GST_DEBUG_OBJECT (vf, "we are keeping width and height but caps "
+ "are not correct : %dx%d to %dx%d", vf->from_width,
+ vf->from_height, vf->to_width, vf->to_height);
+ goto beach;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
}
- gst_videofilter_class_add_pad_templates (GST_VIDEOFILTER_CLASS (g_class));
-}
+ ret = TRUE;
-static void
-gst_videoflip_class_init (gpointer g_class, gpointer class_data)
-{
- GObjectClass *gobject_class;
- GstVideofilterClass *videofilter_class;
-
- gobject_class = G_OBJECT_CLASS (g_class);
- videofilter_class = GST_VIDEOFILTER_CLASS (g_class);
-
- gobject_class->set_property = gst_videoflip_set_property;
- gobject_class->get_property = gst_videoflip_get_property;
-
- g_object_class_install_property (gobject_class, ARG_METHOD,
- g_param_spec_enum ("method", "method", "method",
- GST_TYPE_VIDEOFLIP_METHOD, GST_VIDEOFLIP_METHOD_90R,
- G_PARAM_READWRITE));
-
- videofilter_class->setup = gst_videoflip_setup;
-}
-
-static void
-gst_videoflip_init (GTypeInstance * instance, gpointer g_class)
-{
- GstVideoflip *videoflip = GST_VIDEOFLIP (instance);
- GstVideofilter *videofilter;
-
- GST_DEBUG ("gst_videoflip_init");
-
- videofilter = GST_VIDEOFILTER (videoflip);
-
- /* do stuff */
+beach:
+ return ret;
}
-static void
-gst_videoflip_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
+static GstCaps *
+gst_videoflip_transform_caps (GstBaseTransform * trans,
+ GstPadDirection direction, GstCaps * caps)
{
- 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 ("gst_videoflip_set_property");
- switch (prop_id) {
- case ARG_METHOD:
- src->method = g_value_get_enum (value);
- /* FIXME is this ok? (threading issues) */
- gst_videoflip_setup (GST_VIDEOFILTER (src));
- 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;
+ GstVideoflip *videoflip;
+ GstCaps *ret;
+ gint width, height, i;
+
+ videoflip = GST_VIDEOFLIP (trans);
+
+ ret = gst_caps_copy (caps);
+
+ for (i = 0; i < gst_caps_get_size (ret); i++) {
+ GstStructure *structure = gst_caps_get_structure (ret, i);
+
+ if (gst_structure_get_int (structure, "width", &width) &&
+ gst_structure_get_int (structure, "height", &height)) {
+
+ switch (videoflip->method) {
+ case GST_VIDEOFLIP_METHOD_90R:
+ case GST_VIDEOFLIP_METHOD_90L:
+ case GST_VIDEOFLIP_METHOD_TRANS:
+ case GST_VIDEOFLIP_METHOD_OTHER:
+ gst_structure_set (structure, "width", G_TYPE_INT, height,
+ "height", G_TYPE_INT, width, NULL);
+ break;
+ case GST_VIDEOFLIP_METHOD_IDENTITY:
+ case GST_VIDEOFLIP_METHOD_180:
+ case GST_VIDEOFLIP_METHOD_HORIZ:
+ case GST_VIDEOFLIP_METHOD_VERT:
+ gst_structure_set (structure, "width", G_TYPE_INT, width,
+ "height", G_TYPE_INT, height, NULL);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
}
-}
-static gboolean
-plugin_init (GstPlugin * plugin)
-{
- if (!gst_library_load ("gstvideofilter"))
- return FALSE;
+ GST_DEBUG_OBJECT (videoflip, "transformed %" GST_PTR_FORMAT " to %"
+ GST_PTR_FORMAT, caps, ret);
- return gst_element_register (plugin, "videoflip", GST_RANK_NONE,
- GST_TYPE_VIDEOFLIP);
+ return ret;
}
-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
- GST_VERSION_MINOR,
- "videoflip",
- "Flips and rotates video",
- plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)
+/* 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)
- static void gst_videoflip_flip (GstVideoflip * videoflip,
- unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh);
+#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 void gst_videoflip_setup (GstVideofilter * videofilter)
+static gboolean
+gst_videoflip_get_unit_size (GstBaseTransform * btrans, GstCaps * caps,
+ guint * size)
{
- int from_width, from_height;
GstVideoflip *videoflip;
+ GstStructure *structure;
+ gboolean ret = FALSE;
+ gint width, height;
- GST_DEBUG ("gst_videoflip_setup");
+ videoflip = GST_VIDEOFLIP (btrans);
- videoflip = GST_VIDEOFLIP (videofilter);
+ structure = gst_caps_get_structure (caps, 0);
- from_width = gst_videofilter_get_input_width (videofilter);
- from_height = gst_videofilter_get_input_height (videofilter);
-
- if (from_width == 0 || from_height == 0) {
- return;
+ if (gst_structure_get_int (structure, "width", &width) &&
+ gst_structure_get_int (structure, "height", &height)) {
+ *size = GST_VIDEO_I420_SIZE (width, height);
+ ret = TRUE;
+ GST_DEBUG_OBJECT (videoflip, "our frame size is %d bytes (%dx%d)", *size,
+ width, height);
}
- switch (videoflip->method) {
- case GST_VIDEOFLIP_METHOD_90R:
- case GST_VIDEOFLIP_METHOD_90L:
- case GST_VIDEOFLIP_METHOD_TRANS:
- case GST_VIDEOFLIP_METHOD_OTHER:
- gst_videofilter_set_output_size (videofilter, from_height, from_width);
- break;
- case GST_VIDEOFLIP_METHOD_IDENTITY:
- case GST_VIDEOFLIP_METHOD_180:
- case GST_VIDEOFLIP_METHOD_HORIZ:
- case GST_VIDEOFLIP_METHOD_VERT:
- gst_videofilter_set_output_size (videofilter, from_width, from_height);
- break;
- default:
- g_assert_not_reached ();
- break;
- }
-
- GST_DEBUG ("format=%p \"%s\" from %dx%d to %dx%d",
- videofilter->format, videofilter->format->fourcc,
- from_width, from_height, videofilter->to_width, videofilter->to_height);
-
- if (videoflip->method == GST_VIDEOFLIP_METHOD_IDENTITY) {
- GST_DEBUG ("videoflip: using passthru");
- videofilter->passthru = TRUE;
- } else {
- videofilter->passthru = FALSE;
- }
-
- videofilter->from_buf_size =
- (videofilter->from_width * videofilter->from_height *
- videofilter->format->depth) / 8;
- videofilter->to_buf_size =
- (videofilter->to_width * videofilter->to_height *
- videofilter->format->depth) / 8;
-
- videofilter->inited = TRUE;
+ return ret;
}
-static void
-gst_videoflip_planar411 (GstVideofilter * videofilter, void *dest, void *src)
-{
- GstVideoflip *videoflip;
- int sw;
- int sh;
- int dw;
- int dh;
-
- g_return_if_fail (GST_IS_VIDEOFLIP (videofilter));
- videoflip = GST_VIDEOFLIP (videofilter);
-
- sw = videofilter->from_width;
- sh = videofilter->from_height;
- dw = videofilter->to_width;
- dh = videofilter->to_height;
-
- GST_DEBUG ("videoflip: scaling planar 4:1:1 %dx%d to %dx%d", sw, sh, dw, dh);
-
- gst_videoflip_flip (videoflip, 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 (videoflip, dest, src, sw, sh, dw, dh);
-
- src += sw * sh;
- dest += dw * dh;
-
- gst_videoflip_flip (videoflip, dest, src, sw, sh, dw, dh);
-}
-
-static void
+static GstFlowReturn
gst_videoflip_flip (GstVideoflip * videoflip, unsigned char *dest,
unsigned char *src, int sw, int sh, int dw, int dh)
{
+ GstFlowReturn ret = GST_FLOW_OK;
int x, y;
switch (videoflip->method) {
}
break;
default:
- /* FIXME */
+ ret = GST_FLOW_ERROR;
+ break;
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_videoflip_transform (GstBaseTransform * trans, GstBuffer * in,
+ GstBuffer * out)
+{
+ GstVideoflip *videoflip;
+ gpointer dest, src;
+ int sw, sh, dw, dh;
+ GstFlowReturn ret = GST_FLOW_OK;
+
+ videoflip = GST_VIDEOFLIP (trans);
+
+ gst_buffer_stamp (out, in);
+
+ src = GST_BUFFER_DATA (in);
+ dest = GST_BUFFER_DATA (out);
+ sw = videoflip->from_width;
+ sh = videoflip->from_height;
+ dw = videoflip->to_width;
+ dh = videoflip->to_height;
+
+ GST_LOG_OBJECT (videoflip, "videoflip: scaling planar 4:1:1 %dx%d to %dx%d",
+ sw, sh, dw, dh);
+
+ ret = gst_videoflip_flip (videoflip, dest, src, sw, sh, dw, dh);
+ if (ret != GST_FLOW_OK)
+ goto beach;
+
+ src += sw * sh;
+ dest += dw * dh;
+
+ dh = dh >> 1;
+ dw = dw >> 1;
+ sh = sh >> 1;
+ sw = sw >> 1;
+
+ ret = gst_videoflip_flip (videoflip, dest, src, sw, sh, dw, dh);
+ if (ret != GST_FLOW_OK)
+ goto beach;
+
+ src += sw * sh;
+ dest += dw * dh;
+
+ ret = gst_videoflip_flip (videoflip, dest, src, sw, sh, dw, dh);
+
+beach:
+ return ret;
+}
+
+static gboolean
+gst_videoflip_handle_src_event (GstPad * pad, GstEvent * event)
+{
+ GstVideoflip *vf;
+ gboolean ret;
+ gdouble x, y;
+ GstStructure *structure;
+
+ vf = GST_VIDEOFLIP (gst_pad_get_parent (pad));
+
+ GST_DEBUG_OBJECT (vf, "handling %s event", GST_EVENT_TYPE_NAME (event));
+
+ switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_NAVIGATION:
+ event =
+ GST_EVENT (gst_mini_object_make_writable (GST_MINI_OBJECT (event)));
+
+ structure = (GstStructure *) gst_event_get_structure (event);
+ if (gst_structure_get_double (structure, "pointer_x", &x) &&
+ gst_structure_get_double (structure, "pointer_y", &y)) {
+ switch (vf->method) {
+ case GST_VIDEOFLIP_METHOD_90R:
+ case GST_VIDEOFLIP_METHOD_OTHER:
+ x = y;
+ y = vf->to_width - x;
+ break;
+ case GST_VIDEOFLIP_METHOD_90L:
+ case GST_VIDEOFLIP_METHOD_TRANS:
+ x = vf->to_height - y;
+ y = x;
+ break;
+ case GST_VIDEOFLIP_METHOD_180:
+ x = vf->to_width - x;
+ y = vf->to_height - y;
+ break;
+ case GST_VIDEOFLIP_METHOD_HORIZ:
+ x = vf->to_width - x;
+ y = y;
+ break;
+ case GST_VIDEOFLIP_METHOD_VERT:
+ x = x;
+ y = vf->to_height - y;
+ break;
+ default:
+ x = x;
+ y = y;
+ break;
+ }
+ gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, x,
+ "pointer_y", G_TYPE_DOUBLE, y, NULL);
+ }
+ break;
+ default:
+ break;
+ }
+
+ ret = gst_pad_event_default (pad, event);
+
+ gst_object_unref (vf);
+
+ return ret;
+}
+
+static void
+gst_videoflip_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstVideoflip *videoflip;
+ GstVideofilter *videofilter;
+
+ g_return_if_fail (GST_IS_VIDEOFLIP (object));
+ videoflip = GST_VIDEOFLIP (object);
+ videofilter = GST_VIDEOFILTER (object);
+
+ switch (prop_id) {
+ case ARG_METHOD:
+ {
+ GstVideoflipMethod method;
+
+ method = g_value_get_enum (value);
+ if (method != videoflip->method) {
+ GstBaseTransform *btrans = GST_BASE_TRANSFORM (videoflip);
+
+ g_mutex_lock (btrans->transform_lock);
+ gst_pad_set_caps (btrans->sinkpad, NULL);
+ gst_pad_set_caps (btrans->srcpad, NULL);
+ g_mutex_unlock (btrans->transform_lock);
+ videoflip->method = method;
+ }
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_videoflip_get_property (GObject * object, guint prop_id, GValue * value,
+ GParamSpec * pspec)
+{
+ GstVideoflip *videoflip;
+
+ g_return_if_fail (GST_IS_VIDEOFLIP (object));
+ videoflip = GST_VIDEOFLIP (object);
+
+ switch (prop_id) {
+ case ARG_METHOD:
+ g_value_set_enum (value, videoflip->method);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
+
+static void
+gst_videoflip_base_init (gpointer g_class)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+
+ gst_element_class_set_details (element_class, &videoflip_details);
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_videoflip_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_videoflip_src_template));
+}
+
+static void
+gst_videoflip_class_init (gpointer klass, gpointer class_data)
+{
+ GObjectClass *gobject_class;
+ GstBaseTransformClass *trans_class;
+
+ gobject_class = (GObjectClass *) klass;
+ trans_class = (GstBaseTransformClass *) klass;
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ gobject_class->set_property = gst_videoflip_set_property;
+ gobject_class->get_property = gst_videoflip_get_property;
+
+ g_object_class_install_property (gobject_class, ARG_METHOD,
+ g_param_spec_enum ("method", "method", "method",
+ GST_TYPE_VIDEOFLIP_METHOD, GST_VIDEOFLIP_METHOD_90R,
+ G_PARAM_READWRITE));
+
+ trans_class->transform_caps =
+ GST_DEBUG_FUNCPTR (gst_videoflip_transform_caps);
+ trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_videoflip_set_caps);
+ trans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_videoflip_get_unit_size);
+ trans_class->transform = GST_DEBUG_FUNCPTR (gst_videoflip_transform);
+}
+
+static void
+gst_videoflip_init (GTypeInstance * instance, gpointer g_class)
+{
+ GstVideoflip *videoflip = GST_VIDEOFLIP (instance);
+ GstBaseTransform *btrans = GST_BASE_TRANSFORM (instance);
+
+ GST_DEBUG_OBJECT (videoflip, "gst_videoflip_init");
+
+ videoflip->method = GST_VIDEOFLIP_METHOD_90R;
+
+ gst_pad_set_event_function (btrans->srcpad,
+ GST_DEBUG_FUNCPTR (gst_videoflip_handle_src_event));
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (videoflip_debug, "videoflip", 0, "videoflip");
+
+ return gst_element_register (plugin, "videoflip", GST_RANK_NONE,
+ GST_TYPE_VIDEOFLIP);
+}
+
+GType
+gst_videoflip_get_type (void)
+{
+ static GType videoflip_type = 0;
+
+ if (!videoflip_type) {
+ static const GTypeInfo videoflip_info = {
+ sizeof (GstVideoflipClass),
+ gst_videoflip_base_init,
+ NULL,
+ gst_videoflip_class_init,
+ NULL,
+ NULL,
+ sizeof (GstVideoflip),
+ 0,
+ gst_videoflip_init,
+ };
+
+ videoflip_type = g_type_register_static (GST_TYPE_VIDEOFILTER,
+ "GstVideoflip", &videoflip_info, 0);
+ }
+ return videoflip_type;
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "videoflip",
+ "Flips and rotates video",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN);