diff options
-rw-r--r-- | ChangeLog | 22 | ||||
-rw-r--r-- | gst/smpte/Makefile.am | 10 | ||||
-rw-r--r-- | gst/smpte/gstsmpte.c | 10 | ||||
-rw-r--r-- | gst/smpte/gstsmpte.h | 2 | ||||
-rw-r--r-- | gst/smpte/gstsmptealpha.c | 656 | ||||
-rw-r--r-- | gst/smpte/gstsmptealpha.h | 73 | ||||
-rw-r--r-- | gst/smpte/plugin.c | 43 |
7 files changed, 804 insertions, 12 deletions
@@ -1,3 +1,25 @@ +2008-05-20 Wim Taymans <wim.taymans@collabora.co.uk> + + * gst/smpte/Makefile.am: + * gst/smpte/gstsmpte.c: (gst_smpte_plugin_init): + * gst/smpte/gstsmpte.h: + * gst/smpte/gstsmptealpha.c: + (gst_smpte_alpha_transition_type_get_type), + (gst_smpte_alpha_get_type), (gst_smpte_alpha_base_init), + (gst_smpte_alpha_class_init), (gst_smpte_alpha_update_mask), + (gst_smpte_alpha_setcaps), (gst_smpte_alpha_get_unit_size), + (gst_smpte_alpha_init), (gst_smpte_alpha_finalize), + (gst_smpte_alpha_do_ayuv), (gst_smpte_alpha_do_i420), + (gst_smpte_alpha_transform), (gst_smpte_alpha_set_property), + (gst_smpte_alpha_get_property), (gst_smpte_alpha_plugin_init): + * gst/smpte/gstsmptealpha.h: + * gst/smpte/plugin.c: (plugin_init): + Add new plugin that adds the SMPTE transition in the alpha channel of + I420 and AYUV frames so that they can be blended with videomixer later + on. Uses all niceties such as using base transform for efficient alloc + and negotiation. It currently requires GstController to control the + position in the transition effect. + 2008-05-19 Stefan Kost <ensonic@users.sf.net> * docs/plugins/gst-plugins-good-plugins-docs.sgml: diff --git a/gst/smpte/Makefile.am b/gst/smpte/Makefile.am index 3ecc9152f..cce8f5c4f 100644 --- a/gst/smpte/Makefile.am +++ b/gst/smpte/Makefile.am @@ -1,9 +1,11 @@ plugin_LTLIBRARIES = libgstsmpte.la -libgstsmpte_la_SOURCES = gstsmpte.c gstmask.c barboxwipes.c paint.c +libgstsmpte_la_SOURCES = gstsmpte.c gstmask.c barboxwipes.c paint.c gstsmptealpha.c plugin.c -noinst_HEADERS = gstsmpte.h gstmask.h paint.h +noinst_HEADERS = gstsmpte.h gstmask.h paint.h gstsmptealpha.h -libgstsmpte_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) -libgstsmpte_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(LIBM) +libgstsmpte_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS) $(GST_CONTROLLER_CFLAGS) +libgstsmpte_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(LIBM) \ + -lgstvideo-$(GST_MAJORMINOR) \ + $(GST_CONTROLLER_LIBS) libgstsmpte_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) diff --git a/gst/smpte/gstsmpte.c b/gst/smpte/gstsmpte.c index 5d3101cc0..91f6c2f8e 100644 --- a/gst/smpte/gstsmpte.c +++ b/gst/smpte/gstsmpte.c @@ -640,17 +640,11 @@ gst_smpte_change_state (GstElement * element, GstStateChange transition) return ret; } -static gboolean -plugin_init (GstPlugin * plugin) +gboolean +gst_smpte_plugin_init (GstPlugin * plugin) { GST_DEBUG_CATEGORY_INIT (gst_smpte_debug, "smpte", 0, "SMPTE transition effect"); return gst_element_register (plugin, "smpte", GST_RANK_NONE, GST_TYPE_SMPTE); } - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "smpte", - "Apply the standard SMPTE transitions on video images", - plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/gst/smpte/gstsmpte.h b/gst/smpte/gstsmpte.h index 611d7d63a..44a88c2c3 100644 --- a/gst/smpte/gstsmpte.h +++ b/gst/smpte/gstsmpte.h @@ -75,5 +75,7 @@ struct _GstSMPTEClass { GstElementClass parent_class; }; +gboolean gst_smpte_plugin_init (GstPlugin * plugin); + G_END_DECLS #endif /* __GST_SMPTE_H__ */ diff --git a/gst/smpte/gstsmptealpha.c b/gst/smpte/gstsmptealpha.c new file mode 100644 index 000000000..5da53f327 --- /dev/null +++ b/gst/smpte/gstsmptealpha.c @@ -0,0 +1,656 @@ +/* GStreamer + * Copyright (C) <2008> Wim Taymans <wim.taymans@gmail.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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:element-smptealpha + * @short_description: Takes a video frames and applies an SMPTE transition + * effect on it in the alpha channel. + * + * <refsect2> + * <para> + * smptealpha can accept an I420 or AYUV video stream. An alpha channel is added + * using an effect specific SMPTE mask in the I420 input case. In the AYUV case, the + * alpha channel is modified using the effect specific SMPTE mask. + * </para> + * <para> + * The "position" property is a controllabe double between 0.0 and 1.0 that + * specifies the position in the transition. 0.0 is the start of the transition + * with the alpha channel to complete opaque where 1.0 has the alpha channel set + * to completely transparent. + * </para> + * <para> + * The depth property defines the precision in bits of the mask. A higher + * presision will create a mask with smoother gradients in order to avoid + * banding. + * </para> + * <title>Sample pipelines</title> + * <para> + * Here is a pipeline to demonstrate the smpte transition : + * <programlisting> + * gst-launch -v videotestsrc ! smptealpha border=20000 type=44 + * position=0.5 ! videomixer ! ffmpegcolorspace ! ximagesink + * </programlisting> + * This shows a midway bowtie-h transition a from a videotestsrc to a + * transparent image. The edges of the transition are smoothed with a + * 20000 big border. + * </para> + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <string.h> + +#include <gst/controller/gstcontroller.h> + +#include "gstsmptealpha.h" +#include "paint.h" + +GST_DEBUG_CATEGORY_STATIC (gst_smpte_alpha_debug); +#define GST_CAT_DEFAULT gst_smpte_alpha_debug + +/* elementfactory information */ +static const GstElementDetails smpte_details = +GST_ELEMENT_DETAILS ("SMPTE transitions", + "Filter/Editor/Video", + "Apply the standard SMPTE transitions as alpha on video images", + "Wim Taymans <wim.taymans@gmail.com>"); + +static GstStaticPadTemplate gst_smpte_alpha_src_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") + ) + ); + +static GstStaticPadTemplate gst_smpte_alpha_sink_template = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420") ";" GST_VIDEO_CAPS_YUV ("AYUV") + ) + ); + +/* SMPTE signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +#define DEFAULT_PROP_TYPE 1 +#define DEFAULT_PROP_BORDER 0 +#define DEFAULT_PROP_DEPTH 16 +#define DEFAULT_PROP_POSITION 0.0 + +enum +{ + PROP_0, + PROP_TYPE, + PROP_BORDER, + PROP_DEPTH, + PROP_POSITION, + PROP_LAST, +}; + +#define AYUV_SIZE(w,h) ((w) * (h) * 4) + +#define GST_TYPE_SMPTE_TRANSITION_TYPE (gst_smpte_alpha_transition_type_get_type()) +static GType +gst_smpte_alpha_transition_type_get_type (void) +{ + static GType smpte_transition_type = 0; + GEnumValue *smpte_transitions; + + if (!smpte_transition_type) { + const GList *definitions; + gint i = 0; + + definitions = gst_mask_get_definitions (); + smpte_transitions = + g_new0 (GEnumValue, g_list_length ((GList *) definitions) + 1); + + while (definitions) { + GstMaskDefinition *definition = (GstMaskDefinition *) definitions->data; + + definitions = g_list_next (definitions); + + smpte_transitions[i].value = definition->type; + /* older GLib versions have the two fields as non-const, hence the cast */ + smpte_transitions[i].value_nick = (gchar *) definition->short_name; + smpte_transitions[i].value_name = (gchar *) definition->long_name; + + i++; + } + + smpte_transition_type = + g_enum_register_static ("GstSMPTEAlphaTransitionType", + smpte_transitions); + } + return smpte_transition_type; +} + + +static void gst_smpte_alpha_class_init (GstSMPTEAlphaClass * klass); +static void gst_smpte_alpha_base_init (GstSMPTEAlphaClass * klass); +static void gst_smpte_alpha_init (GstSMPTEAlpha * smpte); +static void gst_smpte_alpha_finalize (GstSMPTEAlpha * smpte); + +static void gst_smpte_alpha_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_smpte_alpha_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static gboolean gst_smpte_alpha_setcaps (GstBaseTransform * btrans, + GstCaps * incaps, GstCaps * outcaps); +static gboolean gst_smpte_alpha_get_unit_size (GstBaseTransform * btrans, + GstCaps * caps, guint * size); +static GstFlowReturn gst_smpte_alpha_transform (GstBaseTransform * trans, + GstBuffer * in, GstBuffer * out); + +static GstElementClass *parent_class = NULL; + +/*static guint gst_smpte_alpha_signals[LAST_SIGNAL] = { 0 }; */ + +static GType +gst_smpte_alpha_get_type (void) +{ + static GType smpte_type = 0; + + if (!smpte_type) { + static const GTypeInfo smpte_info = { + sizeof (GstSMPTEAlphaClass), + (GBaseInitFunc) gst_smpte_alpha_base_init, + NULL, + (GClassInitFunc) gst_smpte_alpha_class_init, + NULL, + NULL, + sizeof (GstSMPTEAlpha), + 0, + (GInstanceInitFunc) gst_smpte_alpha_init, + }; + + smpte_type = + g_type_register_static (GST_TYPE_VIDEO_FILTER, "GstSMPTEAlpha", + &smpte_info, 0); + } + return smpte_type; +} + +static void +gst_smpte_alpha_base_init (GstSMPTEAlphaClass * klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_smpte_alpha_sink_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_smpte_alpha_src_template)); + gst_element_class_set_details (element_class, &smpte_details); +} + +static void +gst_smpte_alpha_class_init (GstSMPTEAlphaClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseTransformClass *trans_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + trans_class = (GstBaseTransformClass *) klass; + + parent_class = g_type_class_peek_parent (klass); + + gobject_class->set_property = gst_smpte_alpha_set_property; + gobject_class->get_property = gst_smpte_alpha_get_property; + + gobject_class->finalize = (GObjectFinalizeFunc) gst_smpte_alpha_finalize; + + _gst_mask_init (); + + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TYPE, + g_param_spec_enum ("type", "Type", "The type of transition to use", + GST_TYPE_SMPTE_TRANSITION_TYPE, DEFAULT_PROP_TYPE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BORDER, + g_param_spec_int ("border", "Border", + "The border width of the transition", 0, G_MAXINT, + DEFAULT_PROP_BORDER, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEPTH, + g_param_spec_int ("depth", "Depth", "Depth of the mask in bits", 1, 24, + DEFAULT_PROP_DEPTH, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_POSITION, + g_param_spec_double ("position", "Position", + "Position of the transition effect", 0.0, 1.0, DEFAULT_PROP_POSITION, + GST_PARAM_CONTROLLABLE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_smpte_alpha_setcaps); + trans_class->get_unit_size = + GST_DEBUG_FUNCPTR (gst_smpte_alpha_get_unit_size); + trans_class->transform = GST_DEBUG_FUNCPTR (gst_smpte_alpha_transform); +} + +static gboolean +gst_smpte_alpha_update_mask (GstSMPTEAlpha * smpte, gint type, gint depth, + gint width, gint height) +{ + GstMask *newmask; + + /* try to avoid regenerating the mask if we already have one that is + * correct */ + if (smpte->mask) { + if (smpte->type == type && + smpte->depth == depth && + smpte->width == width && smpte->height == height) + return TRUE; + } + + newmask = gst_mask_factory_new (type, depth, width, height); + if (!newmask) + goto mask_failed; + + if (smpte->mask) + gst_mask_destroy (smpte->mask); + + smpte->mask = newmask; + smpte->type = type; + smpte->depth = depth; + smpte->width = width; + smpte->height = height; + + return TRUE; + + /* ERRORS */ +mask_failed: + { + GST_ERROR_OBJECT (smpte, "failed to create a mask"); + return FALSE; + } +} + +static gboolean +gst_smpte_alpha_setcaps (GstBaseTransform * btrans, GstCaps * incaps, + GstCaps * outcaps) +{ + GstSMPTEAlpha *smpte; + GstStructure *structure; + gboolean ret; + gint width, height; + guint32 fourcc; + + smpte = GST_SMPTE_ALPHA (btrans); + + structure = gst_caps_get_structure (incaps, 0); + + /* see if we can get essential info */ + ret = gst_structure_get_int (structure, "width", &width); + ret &= gst_structure_get_int (structure, "height", &height); + ret &= gst_structure_get_fourcc (structure, "format", &fourcc); + if (!ret) + goto no_dimensions; + + /* try to update the mask now, this will also adjust the width/height on + * success */ + GST_OBJECT_LOCK (smpte); + ret = gst_smpte_alpha_update_mask (smpte, smpte->type, smpte->depth, + width, height); + GST_OBJECT_UNLOCK (smpte); + if (!ret) + goto mask_failed; + + switch (fourcc) { + case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'): + smpte->format = GST_VIDEO_FORMAT_AYUV; + break; + case GST_MAKE_FOURCC ('I', '4', '2', '0'): + smpte->format = GST_VIDEO_FORMAT_I420; + break; + default: + goto unsupported_fourcc; + } + + return ret; + + /* ERRORS */ +no_dimensions: + { + GST_ERROR_OBJECT (smpte, "no width, height and fourcc given"); + return FALSE; + } +mask_failed: + { + GST_ERROR_OBJECT (smpte, "failed creating the mask"); + return FALSE; + } +unsupported_fourcc: + { + GST_ERROR_OBJECT (smpte, "unsupported fourcc %" GST_FOURCC_FORMAT, fourcc); + return FALSE; + } +} + +static gboolean +gst_smpte_alpha_get_unit_size (GstBaseTransform * btrans, GstCaps * caps, + guint * size) +{ + GstSMPTEAlpha *smpte; + GstStructure *structure; + gboolean ret; + gint width, height; + guint32 fourcc; + + smpte = GST_SMPTE_ALPHA (btrans); + + structure = gst_caps_get_structure (caps, 0); + + ret = gst_structure_get_int (structure, "width", &width); + ret &= gst_structure_get_int (structure, "height", &height); + ret &= gst_structure_get_fourcc (structure, "format", &fourcc); + if (ret) { + switch (fourcc) { + case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'): + *size = + gst_video_format_get_size (GST_VIDEO_FORMAT_AYUV, width, height); + break; + case GST_MAKE_FOURCC ('I', '4', '2', '0'): + *size = + gst_video_format_get_size (GST_VIDEO_FORMAT_I420, width, height); + break; + default: + ret = FALSE; + break; + } + } + return ret; +} + +static void +gst_smpte_alpha_init (GstSMPTEAlpha * smpte) +{ + smpte->type = DEFAULT_PROP_TYPE; + smpte->border = DEFAULT_PROP_BORDER; + smpte->depth = DEFAULT_PROP_DEPTH; +} + +static void +gst_smpte_alpha_finalize (GstSMPTEAlpha * smpte) +{ + if (smpte->mask) + gst_mask_destroy (smpte->mask); + + G_OBJECT_CLASS (parent_class)->finalize ((GObject *) smpte); +} + +static void +gst_smpte_alpha_do_ayuv (GstSMPTEAlpha * smpte, guint8 * in, guint8 * out, + GstMask * mask, gint width, gint height, gint border, gint pos) +{ + gint i, j; + guint32 *maskp; + gint value; + gint min, max; + + if (border == 0) + border++; + + min = pos - border; + max = pos; + GST_DEBUG_OBJECT (smpte, "pos %d, min %d, max %d, border %d", pos, min, max, + border); + + maskp = mask->data; + + /* we basically copy the source to dest but we scale the alpha channel with + * the mask */ + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + value = *maskp++; + *out++ = (*in++ * ((CLAMP (value, min, max) - min) << 8) / border) >> 8; + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + } + } +} +static void +gst_smpte_alpha_do_i420 (GstSMPTEAlpha * smpte, guint8 * in, guint8 * out, + GstMask * mask, gint width, gint height, gint border, gint pos) +{ + guint8 *srcY; + guint8 *srcU; + guint8 *srcV; + gint i, j; + gint src_wrap, src_uv_wrap; + gint y_stride, uv_stride; + gboolean odd_width; + guint32 *maskp; + gint value; + gint min, max; + + if (border == 0) + border++; + + min = pos - border; + max = pos; + GST_DEBUG_OBJECT (smpte, "pos %d, min %d, max %d, border %d", pos, min, max, + border); + + maskp = mask->data; + + y_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, width); + uv_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, width); + + src_wrap = y_stride - width; + src_uv_wrap = uv_stride - (width / 2); + + srcY = in; + srcU = in + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, + 1, width, height); + srcV = in + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, + 2, width, height); + + odd_width = (width % 2 != 0); + + for (i = 0; i < height; i++) { + for (j = 0; j < width / 2; j++) { + value = *maskp++; + *out++ = (0xff * ((CLAMP (value, min, max) - min) << 8) / border) >> 8; + *out++ = *srcY++; + *out++ = *srcU; + *out++ = *srcV; + value = *maskp++; + *out++ = (0xff * ((CLAMP (value, min, max) - min) << 8) / border) >> 8; + *out++ = *srcY++; + *out++ = *srcU++; + *out++ = *srcV++; + } + /* Might have one odd column left to do */ + if (odd_width) { + value = *maskp++; + *out++ = (0xff * ((CLAMP (value, min, max) - min) << 8) / border) >> 8; + *out++ = *srcY++; + *out++ = *srcU; + *out++ = *srcV; + } + if (i % 2 == 0) { + srcU -= width / 2; + srcV -= width / 2; + } else { + srcU += src_uv_wrap; + srcV += src_uv_wrap; + } + srcY += src_wrap; + } +} + +static GstFlowReturn +gst_smpte_alpha_transform (GstBaseTransform * trans, GstBuffer * in, + GstBuffer * out) +{ + GstSMPTEAlpha *smpte; + GstClockTime timestamp, stream_time; + gdouble position; + gint border; + + smpte = GST_SMPTE_ALPHA (trans); + + /* first sync the controller to the current stream_time of the buffer */ + timestamp = GST_BUFFER_TIMESTAMP (in); + stream_time = + gst_segment_to_stream_time (&trans->segment, GST_FORMAT_TIME, timestamp); + + GST_DEBUG_OBJECT (smpte, "sync to %" GST_TIME_FORMAT, + GST_TIME_ARGS (timestamp)); + + if (GST_CLOCK_TIME_IS_VALID (stream_time)) + gst_object_sync_values (G_OBJECT (smpte), stream_time); + + /* these are the propertis we update with only the object lock, others are + * only updated with the TRANSFORM_LOCK. */ + GST_OBJECT_LOCK (smpte); + position = smpte->position; + border = smpte->border; + GST_OBJECT_UNLOCK (smpte); + + /* run the type specific filter code */ + switch (smpte->format) { + case GST_VIDEO_FORMAT_I420: + gst_smpte_alpha_do_i420 (smpte, GST_BUFFER_DATA (in), + GST_BUFFER_DATA (out), + smpte->mask, smpte->width, smpte->height, + border, ((1 << smpte->depth) + border) * position); + break; + case GST_VIDEO_FORMAT_AYUV: + gst_smpte_alpha_do_ayuv (smpte, GST_BUFFER_DATA (in), + GST_BUFFER_DATA (out), + smpte->mask, smpte->width, smpte->height, + border, ((1 << smpte->depth) + border) * position); + break; + default: + goto not_negotiated; + } + + return GST_FLOW_OK; + + /* ERRORS */ +not_negotiated: + { + GST_ELEMENT_ERROR (smpte, CORE, NEGOTIATION, (NULL), + ("No input format negotiated")); + return GST_FLOW_NOT_NEGOTIATED; + } +} + +static void +gst_smpte_alpha_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstSMPTEAlpha *smpte; + + smpte = GST_SMPTE_ALPHA (object); + + switch (prop_id) { + case PROP_TYPE: + GST_BASE_TRANSFORM_LOCK (smpte); + /* also lock with the object lock so that reading the property doesn't + * have to wait for the transform lock */ + GST_OBJECT_LOCK (smpte); + smpte->type = g_value_get_enum (value); + GST_OBJECT_UNLOCK (smpte); + gst_smpte_alpha_update_mask (smpte, smpte->type, smpte->depth, + smpte->width, smpte->height); + GST_BASE_TRANSFORM_UNLOCK (smpte); + break; + case PROP_BORDER: + GST_OBJECT_LOCK (smpte); + smpte->border = g_value_get_int (value); + GST_OBJECT_UNLOCK (smpte); + break; + case PROP_DEPTH: + GST_BASE_TRANSFORM_LOCK (smpte); + /* also lock with the object lock so that reading the property doesn't + * have to wait for the transform lock */ + GST_OBJECT_LOCK (smpte); + smpte->depth = g_value_get_int (value); + GST_OBJECT_UNLOCK (smpte); + gst_smpte_alpha_update_mask (smpte, smpte->type, smpte->depth, + smpte->width, smpte->height); + GST_BASE_TRANSFORM_UNLOCK (smpte); + break; + case PROP_POSITION: + GST_OBJECT_LOCK (smpte); + smpte->position = g_value_get_double (value); + GST_OBJECT_UNLOCK (smpte); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_smpte_alpha_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstSMPTEAlpha *smpte; + + smpte = GST_SMPTE_ALPHA (object); + + switch (prop_id) { + case PROP_TYPE: + GST_OBJECT_LOCK (smpte); + g_value_set_enum (value, smpte->type); + GST_OBJECT_UNLOCK (smpte); + break; + case PROP_BORDER: + GST_OBJECT_LOCK (smpte); + g_value_set_int (value, smpte->border); + GST_OBJECT_UNLOCK (smpte); + break; + case PROP_DEPTH: + GST_OBJECT_LOCK (smpte); + g_value_set_int (value, smpte->depth); + GST_OBJECT_UNLOCK (smpte); + break; + case PROP_POSITION: + GST_OBJECT_LOCK (smpte); + g_value_set_double (value, smpte->position); + GST_OBJECT_UNLOCK (smpte); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +gboolean +gst_smpte_alpha_plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (gst_smpte_alpha_debug, "smptealpha", 0, + "SMPTE alpha effect"); + + /* initialize gst controller library */ + gst_controller_init (NULL, NULL); + + return gst_element_register (plugin, "smptealpha", GST_RANK_NONE, + GST_TYPE_SMPTE_ALPHA); +} diff --git a/gst/smpte/gstsmptealpha.h b/gst/smpte/gstsmptealpha.h new file mode 100644 index 000000000..5e8f6fc82 --- /dev/null +++ b/gst/smpte/gstsmptealpha.h @@ -0,0 +1,73 @@ +/* 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_SMPTE_ALPHA_H__ +#define __GST_SMPTE_ALPHA_H__ + +#include <gst/gst.h> +#include <gst/video/video.h> +#include <gst/video/gstvideofilter.h> + + +G_BEGIN_DECLS + +#include "gstmask.h" + +#define GST_TYPE_SMPTE_ALPHA \ + (gst_smpte_alpha_get_type()) +#define GST_SMPTE_ALPHA(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SMPTE_ALPHA,GstSMPTEAlpha)) +#define GST_SMPTE_ALPHA_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SMPTE_ALPHA,GstSMPTEAlphaClass)) +#define GST_IS_SMPTE_ALPHA(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SMPTE_ALPHA)) +#define GST_IS_SMPTE_ALPHA_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SMPTE_ALPHA)) + +typedef struct _GstSMPTEAlpha GstSMPTEAlpha; +typedef struct _GstSMPTEAlphaClass GstSMPTEAlphaClass; + +struct _GstSMPTEAlpha { + GstVideoFilter element; + + /* properties */ + gint type; + gint border; + gint depth; + gdouble position; + + /* negotiated format */ + GstVideoFormat format; + gint width; + gint height; + + /* state of the effect */ + GstMask *mask; +}; + +struct _GstSMPTEAlphaClass { + GstVideoFilterClass parent_class; +}; + +gboolean gst_smpte_alpha_plugin_init (GstPlugin * plugin); + +G_END_DECLS + +#endif /* __GST_SMPTE_ALPHA_H__ */ diff --git a/gst/smpte/plugin.c b/gst/smpte/plugin.c new file mode 100644 index 000000000..cacc80c42 --- /dev/null +++ b/gst/smpte/plugin.c @@ -0,0 +1,43 @@ +/* GStreamer + * Copyright (C) <2008> Wim Taymans <wim.taymans@google.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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstsmpte.h" +#include "gstsmptealpha.h" + +static gboolean +plugin_init (GstPlugin * plugin) +{ + if (!gst_smpte_plugin_init (plugin)) + return FALSE; + + if (!gst_smpte_alpha_plugin_init (plugin)) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "smpte", + "Apply the standard SMPTE transitions on video images", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) |