diff options
Diffstat (limited to 'gst/overlay/gstoverlay.c')
-rw-r--r-- | gst/overlay/gstoverlay.c | 399 |
1 files changed, 399 insertions, 0 deletions
diff --git a/gst/overlay/gstoverlay.c b/gst/overlay/gstoverlay.c new file mode 100644 index 00000000..79c061fa --- /dev/null +++ b/gst/overlay/gstoverlay.c @@ -0,0 +1,399 @@ +/* GStreamer + * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> + * Copyright (C) <2003> David 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "gstoverlay.h" + +/* elementfactory information */ +static GstElementDetails overlay_details = { + "Video Overlay", + "Filter/Video", + "LGPL", + "Overlay multiple video streams", + VERSION, + "David Schleef <ds@schleef.org>", + "(C) 2002, 2003", +}; + +GST_PAD_TEMPLATE_FACTORY (overlay_src_factory, + "src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "overlay_src", + "video/x-raw-yuv", + "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')), + "width", GST_PROPS_INT_RANGE (1, G_MAXINT), + "height", GST_PROPS_INT_RANGE (1, G_MAXINT), + "framerate",GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT) + ) +) + +GST_PAD_TEMPLATE_FACTORY (overlay_sink1_factory, + "sink1", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "overlay_sink1", + "video/x-raw-yuv", + "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')), + "width", GST_PROPS_INT_RANGE (1, G_MAXINT), + "height", GST_PROPS_INT_RANGE (1, G_MAXINT), + "framerate",GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT) + ) +) + +GST_PAD_TEMPLATE_FACTORY (overlay_sink2_factory, + "sink2", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "overlay_sink2", + "video/x-raw-yuv", + "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')), + "width", GST_PROPS_INT_RANGE (1, G_MAXINT), + "height", GST_PROPS_INT_RANGE (1, G_MAXINT), + "framerate",GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT) + ) +) + +GST_PAD_TEMPLATE_FACTORY (overlay_sink3_factory, + "sink3", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_CAPS_NEW ( + "overlay_sink2", + "video/x-raw-yuv", + "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')), + "width", GST_PROPS_INT_RANGE (1, G_MAXINT), + "height", GST_PROPS_INT_RANGE (1, G_MAXINT), + "framerate",GST_PROPS_FLOAT_RANGE (0, G_MAXFLOAT) + ) +) + +/* OVERLAY signals and args */ +enum { + /* FILL ME */ + LAST_SIGNAL +}; + +enum { + ARG_0, +}; + + +static void gst_overlay_class_init (GstOverlayClass *klass); +static void gst_overlay_init (GstOverlay *overlay); + +static void gst_overlay_loop (GstElement *element); + +static void gst_overlay_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec); +static void gst_overlay_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec); + +static GstElementClass *parent_class = NULL; +/*static guint gst_overlay_signals[LAST_SIGNAL] = { 0 }; */ + +static GType +gst_overlay_get_type (void) +{ + static GType overlay_type = 0; + + if (!overlay_type) { + static const GTypeInfo overlay_info = { + sizeof(GstOverlayClass), + NULL, + NULL, + (GClassInitFunc)gst_overlay_class_init, + NULL, + NULL, + sizeof(GstOverlay), + 0, + (GInstanceInitFunc)gst_overlay_init, + }; + overlay_type = g_type_register_static(GST_TYPE_ELEMENT, "GstOverlay", &overlay_info, 0); + } + return overlay_type; +} + +static void +gst_overlay_class_init (GstOverlayClass *klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass*)klass; + gstelement_class = (GstElementClass*)klass; + + parent_class = g_type_class_ref(GST_TYPE_ELEMENT); + + gobject_class->set_property = gst_overlay_set_property; + gobject_class->get_property = gst_overlay_get_property; + +} + +#if 0 +static GstCaps *gst_overlay_getcaps(GstPad *pad) +{ + GstCaps *caps; + GstOverlay *overlay; + + overlay = GST_OVERLAY (gst_pad_get_parent (pad)); + + if(overlay->width && overlay->height){ + caps = GST_CAPS_NEW ( + "overlay_sink2", + "video/raw", + "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')), + "width", GST_PROPS_INT (overlay->width), + "height", GST_PROPS_INT (overlay->height) + ); + }else{ + caps = GST_CAPS_NEW ( + "overlay_sink2", + "video/raw", + "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')), + "width", GST_PROPS_INT_RANGE (0, 4096), + "height", GST_PROPS_INT_RANGE (0, 4096) + ); + } + + return caps; +} +#endif + +static gboolean +gst_overlay_sinkconnect (GstPad *pad, GstCaps *caps) +{ + GstOverlay *overlay; + + overlay = GST_OVERLAY (gst_pad_get_parent (pad)); + + if (!GST_CAPS_IS_FIXED (caps)) + return GST_PAD_LINK_DELAYED; + + gst_caps_get_int (caps, "width", &overlay->width); + gst_caps_get_int (caps, "height", &overlay->height); + gst_caps_get_float (caps, "framerate", &overlay->framerate); + + /* forward to the next plugin */ + return gst_pad_try_set_caps(overlay->srcpad, gst_caps_copy_1(caps)); +} + +static void +gst_overlay_init (GstOverlay *overlay) +{ + overlay->sinkpad1 = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (overlay_sink1_factory), "sink1"); + gst_pad_set_link_function (overlay->sinkpad1, gst_overlay_sinkconnect); + gst_element_add_pad (GST_ELEMENT (overlay), overlay->sinkpad1); + + overlay->sinkpad2 = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (overlay_sink2_factory), "sink2"); + gst_pad_set_link_function (overlay->sinkpad2, gst_overlay_sinkconnect); + gst_element_add_pad (GST_ELEMENT (overlay), overlay->sinkpad2); + + overlay->sinkpad3 = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (overlay_sink3_factory), "sink3"); + gst_pad_set_link_function (overlay->sinkpad3, gst_overlay_sinkconnect); + gst_element_add_pad (GST_ELEMENT (overlay), overlay->sinkpad3); + + overlay->srcpad = gst_pad_new_from_template ( + GST_PAD_TEMPLATE_GET (overlay_src_factory), "src"); + gst_element_add_pad (GST_ELEMENT (overlay), overlay->srcpad); + + gst_element_set_loop_function (GST_ELEMENT (overlay), gst_overlay_loop); +} + +static void +gst_overlay_blend_i420 (guint8 *out, guint8 *in1, guint8 *in2, guint8 *in3, + gint width, gint height) +{ + int mask; + int i, j; + guint8 *in1u, *in1v, *in2u, *in2v, *outu, *outv; + int lumsize; + int chromsize; + int width2 = width/2; + int height2 = height/2; + + lumsize = width * height; + chromsize = width2 * height2; + + in1u = in1 + lumsize; in1v = in1u + chromsize; + in2u = in2 + lumsize; in2v = in2u + chromsize; + outu = out + lumsize; outv = outu + chromsize; + + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + mask = in3[i*width + j]; + out[i*width+j] = ((in1[i*width+j] * mask) + + (in2[i*width+j] * (255 - mask))) >> 8; + } + } + + for (i = 0; i < height/2; i++) { + for (j = 0; j < width/2; j++) { + mask = (in3[(i*2)*width + (j*2)] + in3[(i*2 + 1)*width + (j*2)] + + in3[(i*2)*width + (j*2 + 1)] + in3[(i*2 + 1)*width + (j*2 + 1)]) / 4; + outu[i*width2 + j] = ((in1u[i*width2+j] * mask) + + (in2u[i*width2 + j] * (255 - mask))) >> 8; + outv[i*width2 + j] = ((in1v[i*width2+j] * mask) + + (in2v[i*width2 + j] * (255 - mask))) >> 8; + } + } +} + +static void +gst_overlay_loop (GstElement *element) +{ + GstOverlay *overlay; + GstBuffer *out; + GstBuffer *in1 = NULL, *in2 = NULL, *in3 = NULL; + int size; + + overlay = GST_OVERLAY (element); + + in1 = gst_pad_pull (overlay->sinkpad1); + if (GST_IS_EVENT (in1)) { + gst_pad_push (overlay->srcpad, in1); + /* FIXME */ + return; + } + in2 = gst_pad_pull (overlay->sinkpad2); + if (GST_IS_EVENT (in2)) { + gst_pad_push (overlay->srcpad, in2); + /* FIXME */ + return; + } + in3 = gst_pad_pull (overlay->sinkpad3); + if (GST_IS_EVENT (in3)) { + gst_pad_push (overlay->srcpad, in3); + /* FIXME */ + return; + } + + g_return_if_fail(in1 != NULL); + g_return_if_fail(in2 != NULL); + g_return_if_fail(in3 != NULL); + + size = (overlay->width * overlay->height * 3)/2; + g_return_if_fail(GST_BUFFER_SIZE(in1) != size); + g_return_if_fail(GST_BUFFER_SIZE(in2) != size); + g_return_if_fail(GST_BUFFER_SIZE(in3) != size); + + out = gst_buffer_new_and_alloc (size); + + if (!GST_PAD_CAPS (overlay->srcpad)) { + if (!gst_pad_try_set_caps (overlay->srcpad, + GST_CAPS_NEW ( + "overlay_srccaps", + "video/x-raw-yuv", + "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')), + "width", GST_PROPS_INT (overlay->width), + "height", GST_PROPS_INT (overlay->height), + "framerate",GST_PROPS_FLOAT (overlay->framerate) + ))) + { + gst_element_error (element, "cannot set caps"); + return; + } + } + + gst_overlay_blend_i420 (GST_BUFFER_DATA (out), + GST_BUFFER_DATA (in1), + GST_BUFFER_DATA (in2), + GST_BUFFER_DATA (in3), + overlay->width, overlay->height); + + GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_TIMESTAMP (in1); + GST_BUFFER_DURATION (out) = GST_BUFFER_DURATION (in1); + + gst_buffer_unref (in1); + gst_buffer_unref (in2); + gst_buffer_unref (in3); + + gst_pad_push (overlay->srcpad, out); +} + +static void +gst_overlay_set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + GstOverlay *overlay; + + overlay = GST_OVERLAY(object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_overlay_get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + GstOverlay *overlay; + + overlay = GST_OVERLAY(object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + + +static gboolean +plugin_init (GModule *module, GstPlugin *plugin) +{ + GstElementFactory *factory; + + factory = gst_element_factory_new("overlay",GST_TYPE_OVERLAY, + &overlay_details); + g_return_val_if_fail(factory != NULL, FALSE); + + gst_element_factory_add_pad_template (factory, + GST_PAD_TEMPLATE_GET (overlay_sink1_factory)); + gst_element_factory_add_pad_template (factory, + GST_PAD_TEMPLATE_GET (overlay_sink2_factory)); + gst_element_factory_add_pad_template (factory, + GST_PAD_TEMPLATE_GET (overlay_sink3_factory)); + gst_element_factory_add_pad_template (factory, + GST_PAD_TEMPLATE_GET (overlay_src_factory)); + + gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); + + return TRUE; +} + +GstPluginDesc plugin_desc = { + GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "overlay", + plugin_init +}; + |