From e315541000ece43370fd884d19660d9ae7fecfb3 Mon Sep 17 00:00:00 2001 From: Jan Schmidt Date: Thu, 31 Jan 2008 00:00:23 +0000 Subject: gst/alpha/: Re-write the 'alpha' plugin to be BaseTransform based, simplifying some stuff, and making buffer-alloc an... Original commit message from CVS: * gst/alpha/Makefile.am: * gst/alpha/gstalpha.c: Re-write the 'alpha' plugin to be BaseTransform based, simplifying some stuff, and making buffer-alloc and resizing work automatically. No longer crashes on odd frame widths and heights, although there seems to be a disagreement with ffmpegcolorspace about what size an AYUV frame with odd height should be. --- gst/alpha/Makefile.am | 3 +- gst/alpha/gstalpha.c | 674 ++++++++++++++++++++++---------------------------- 2 files changed, 292 insertions(+), 385 deletions(-) (limited to 'gst/alpha') diff --git a/gst/alpha/Makefile.am b/gst/alpha/Makefile.am index 1ae03a41..98f81167 100644 --- a/gst/alpha/Makefile.am +++ b/gst/alpha/Makefile.am @@ -3,7 +3,8 @@ plugin_LTLIBRARIES = libgstalpha.la libgstalphacolor.la libgstalpha_la_SOURCES = gstalpha.c libgstalpha_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \ $(GST_BASE_CFLAGS) $(GST_CFLAGS) $(GST_CONTROLLER_CFLAGS) -libgstalpha_la_LIBADD = $(GST_LIBS) $(LIBM) $(GST_CONTROLLER_LIBS) +libgstalpha_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \ + $(GST_LIBS) $(LIBM) $(GST_CONTROLLER_LIBS) libgstalpha_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstalphacolor_la_SOURCES = gstalphacolor.c diff --git a/gst/alpha/gstalpha.c b/gst/alpha/gstalpha.c index 9daf29b1..1a5b954e 100644 --- a/gst/alpha/gstalpha.c +++ b/gst/alpha/gstalpha.c @@ -1,5 +1,8 @@ /* GStreamer * Copyright (C) <1999> Erik Walthinsen + * Copyright (C) <2007> Wim Taymans + * Copyright (C) <2007> Edward Hervey + * Copyright (C) <2007> Jan Schmidt * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -21,6 +24,7 @@ #include "config.h" #endif #include +#include #include #include @@ -55,24 +59,16 @@ typedef enum } GstAlphaMethod; -#define ROUND_UP_2(x) (((x) + 1) & ~1) -#define ROUND_UP_4(x) (((x) + 3) & ~3) -#define ROUND_UP_8(x) (((x) + 7) & ~7) - +GST_DEBUG_CATEGORY_STATIC (gst_alpha_debug); #define GST_CAT_DEFAULT gst_alpha_debug -GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); struct _GstAlpha { - GstElement element; - - /* pads */ - GstPad *sinkpad; - GstPad *srcpad; + GstBaseTransform parent; /* caps */ - gint in_width, in_height; - gint out_width, out_height; + GstVideoFormat format; + gint width, height; gboolean ayuv; gdouble alpha; @@ -95,22 +91,21 @@ struct _GstAlpha guint8 accept_angle_ctg; guint8 one_over_kc; guint8 kfgy_scale; - - GstSegment segment; }; struct _GstAlphaClass { - GstElementClass parent_class; + GstBaseTransformClass parent_class; }; /* elementfactory information */ static const GstElementDetails gst_alpha_details = GST_ELEMENT_DETAILS ("Alpha filter", "Filter/Effect/Video", - "Adds an alpha channel to video", - "Wim Taymans "); - + "Adds an alpha channel to video - uniform or via chroma-keying", + "Wim Taymans \n" + "Edward Hervey \n" + "Jan Schmidt "); /* Alpha signals and args */ enum @@ -151,15 +146,20 @@ static GstStaticPadTemplate gst_alpha_sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") - ";" GST_VIDEO_CAPS_YUV ("I420") + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";" GST_VIDEO_CAPS_YUV ("I420") ) ); +static gboolean gst_alpha_start (GstBaseTransform * trans); +static gboolean gst_alpha_get_unit_size (GstBaseTransform * btrans, + GstCaps * caps, guint * size); +static GstCaps *gst_alpha_transform_caps (GstBaseTransform * btrans, + GstPadDirection direction, GstCaps * caps); +static gboolean gst_alpha_set_caps (GstBaseTransform * btrans, + GstCaps * incaps, GstCaps * outcaps); +static GstFlowReturn gst_alpha_transform (GstBaseTransform * btrans, + GstBuffer * in, GstBuffer * out); -static void gst_alpha_base_init (gpointer g_class); -static void gst_alpha_class_init (GstAlphaClass * klass); -static void gst_alpha_init (GstAlpha * alpha); static void gst_alpha_init_params (GstAlpha * alpha); static void gst_alpha_set_property (GObject * object, guint prop_id, @@ -167,15 +167,8 @@ static void gst_alpha_set_property (GObject * object, guint prop_id, static void gst_alpha_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static gboolean gst_alpha_sink_setcaps (GstPad * pad, GstCaps * caps); -static GstFlowReturn gst_alpha_chain (GstPad * pad, GstBuffer * buffer); -static gboolean gst_alpha_sink_event (GstPad * pad, GstEvent * event); - -static GstStateChangeReturn gst_alpha_change_state (GstElement * element, - GstStateChange transition); - - -static GstElementClass *parent_class = NULL; +GST_BOILERPLATE (GstAlpha, gst_alpha, GstBaseTransform, + GST_TYPE_BASE_TRANSFORM); #define GST_TYPE_ALPHA_METHOD (gst_alpha_method_get_type()) static GType @@ -196,32 +189,6 @@ gst_alpha_method_get_type (void) return alpha_method_type; } -/* static guint gst_alpha_signals[LAST_SIGNAL] = { 0 }; */ - -GType -gst_alpha_get_type (void) -{ - static GType alpha_type = 0; - - if (!alpha_type) { - static const GTypeInfo alpha_info = { - sizeof (GstAlphaClass), - gst_alpha_base_init, - NULL, - (GClassInitFunc) gst_alpha_class_init, - NULL, - NULL, - sizeof (GstAlpha), - 0, - (GInstanceInitFunc) gst_alpha_init, - }; - - alpha_type = - g_type_register_static (GST_TYPE_ELEMENT, "GstAlpha", &alpha_info, 0); - } - return alpha_type; -} - static void gst_alpha_base_init (gpointer g_class) { @@ -233,17 +200,18 @@ gst_alpha_base_init (gpointer g_class) gst_static_pad_template_get (&gst_alpha_sink_template)); gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&gst_alpha_src_template)); + + GST_DEBUG_CATEGORY_INIT (gst_alpha_debug, "alpha", 0, + "alpha - Element for adding alpha channel to streams"); } static void gst_alpha_class_init (GstAlphaClass * klass) { GObjectClass *gobject_class; - GstElementClass *gstelement_class; + GstBaseTransformClass *btrans_class; gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - parent_class = g_type_class_peek_parent (klass); + btrans_class = (GstBaseTransformClass *) klass; gobject_class->set_property = gst_alpha_set_property; gobject_class->get_property = gst_alpha_get_property; @@ -277,24 +245,16 @@ gst_alpha_class_init (GstAlphaClass * klass) 0.0, 64.0, DEFAULT_NOISE_LEVEL, (GParamFlags) G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); - gstelement_class->change_state = gst_alpha_change_state; + btrans_class->start = GST_DEBUG_FUNCPTR (gst_alpha_start); + btrans_class->transform = GST_DEBUG_FUNCPTR (gst_alpha_transform); + btrans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_alpha_get_unit_size); + btrans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_alpha_transform_caps); + btrans_class->set_caps = GST_DEBUG_FUNCPTR (gst_alpha_set_caps); } static void -gst_alpha_init (GstAlpha * alpha) +gst_alpha_init (GstAlpha * alpha, GstAlphaClass * klass) { - /* create the sink and src pads */ - alpha->sinkpad = - gst_pad_new_from_static_template (&gst_alpha_sink_template, "sink"); - gst_element_add_pad (GST_ELEMENT (alpha), alpha->sinkpad); - gst_pad_set_chain_function (alpha->sinkpad, gst_alpha_chain); - gst_pad_set_setcaps_function (alpha->sinkpad, gst_alpha_sink_setcaps); - gst_pad_set_event_function (alpha->sinkpad, gst_alpha_sink_event); - - alpha->srcpad = - gst_pad_new_from_static_template (&gst_alpha_src_template, "src"); - gst_element_add_pad (GST_ELEMENT (alpha), alpha->srcpad); - alpha->alpha = DEFAULT_ALPHA; alpha->method = DEFAULT_METHOD; alpha->target_r = DEFAULT_TARGET_R; @@ -302,8 +262,6 @@ gst_alpha_init (GstAlpha * alpha) alpha->target_b = DEFAULT_TARGET_B; alpha->angle = DEFAULT_ANGLE; alpha->noise_level = DEFAULT_NOISE_LEVEL; - - GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "alpha", 0, "Alpha adding element"); } /* do we need this function? */ @@ -403,33 +361,77 @@ gst_alpha_get_property (GObject * object, guint prop_id, GValue * value, } static gboolean -gst_alpha_sink_setcaps (GstPad * pad, GstCaps * caps) +gst_alpha_get_unit_size (GstBaseTransform * btrans, + GstCaps * caps, guint * size) { - GstAlpha *alpha; + GstAlpha *alpha = GST_ALPHA (btrans); + GstVideoFormat format; + gint width, height; + + if (!gst_video_format_parse_caps (caps, &format, &width, &height)) + return FALSE; + + *size = gst_video_format_get_size (format, width, height); + + GST_DEBUG_OBJECT (alpha, "unit size = %d for format %d w %d height %d", + *size, format, width, height); + + return TRUE; +} + +static GstCaps * +gst_alpha_transform_caps (GstBaseTransform * btrans, + GstPadDirection direction, GstCaps * caps) +{ + GstCaps *ret; GstStructure *structure; - gboolean ret; - guint32 fourcc; - - alpha = GST_ALPHA (GST_PAD_PARENT (pad)); - structure = gst_caps_get_structure (caps, 0); - - if (gst_structure_get_fourcc (structure, "format", &fourcc)) { - switch (fourcc) { - case GST_MAKE_FOURCC ('I', '4', '2', '0'): - alpha->ayuv = FALSE; - break; - case GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'): - alpha->ayuv = TRUE; - break; - default: - return FALSE; + gint i; + + ret = gst_caps_copy (caps); + + /* When going from the SINK pad to the src, we just need to make sure the + * format is AYUV */ + if (direction == GST_PAD_SINK) { + for (i = 0; i < gst_caps_get_size (ret); i++) { + structure = gst_caps_get_structure (ret, i); + gst_structure_set (structure, "format", + GST_TYPE_FOURCC, GST_MAKE_FOURCC ('A', 'Y', 'U', 'V'), NULL); } } else { - return FALSE; + GstCaps *ayuv_caps; + + /* In the other direction, prepend a copy of the caps with format AYUV, + * and set the first to I420 */ + ayuv_caps = gst_caps_copy (ret); + + for (i = 0; i < gst_caps_get_size (ret); i++) { + structure = gst_caps_get_structure (ret, i); + gst_structure_set (structure, "format", + GST_TYPE_FOURCC, GST_MAKE_FOURCC ('I', '4', '2', '0'), NULL); + } + + gst_caps_append (ret, ayuv_caps); } - ret = gst_structure_get_int (structure, "width", &alpha->in_width); - ret &= gst_structure_get_int (structure, "height", &alpha->in_height); + gst_caps_do_simplify (ret); + + return ret; +} + +static gboolean +gst_alpha_set_caps (GstBaseTransform * btrans, + GstCaps * incaps, GstCaps * outcaps) +{ + GstAlpha *alpha = GST_ALPHA (btrans); + + if (!gst_video_format_parse_caps (incaps, &alpha->format, + &alpha->width, &alpha->height)) + return FALSE; + + if (alpha->format == GST_VIDEO_FORMAT_AYUV) + alpha->ayuv = TRUE; + else + alpha->ayuv = FALSE; return TRUE; } @@ -439,28 +441,20 @@ gst_alpha_set_ayuv (guint8 * src, guint8 * dest, gint width, gint height, gdouble alpha) { gint b_alpha = (gint) (alpha * 255); - gint i, j; + gint y, x; gint size; gint stride; - gint wrap; - width = ROUND_UP_2 (width); - height = ROUND_UP_2 (height); + stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_AYUV, 0, width); + size = gst_video_format_get_size (GST_VIDEO_FORMAT_AYUV, width, height); - stride = ROUND_UP_4 (width); - size = stride * height; - - wrap = stride - width; - - for (i = 0; i < height; i++) { - for (j = 0; j < width; j++) { + for (y = 0; y < height; y++) { + for (x = 0; x < width; x++) { *dest++ = (*src++ * b_alpha) >> 8; *dest++ = *src++; *dest++ = *src++; *dest++ = *src++; } - src += wrap; - dest += wrap; } } @@ -473,24 +467,23 @@ gst_alpha_set_i420 (guint8 * src, guint8 * dest, gint width, gint height, guint8 *srcU; guint8 *srcV; gint i, j; - gint size, size2; - gint stride, stride2; - gint wrap, wrap2; - - width = ROUND_UP_2 (width); - height = ROUND_UP_2 (height); + gint src_wrap, src_uv_wrap; + gint y_stride, uv_stride; + gboolean odd_width; - stride = ROUND_UP_4 (width); - size = stride * height; - stride2 = ROUND_UP_8 (width) / 2; - size2 = stride2 * height / 2; + 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); - wrap = stride - 2 * (width / 2); - wrap2 = stride2 - width / 2; + src_wrap = y_stride - width; + src_uv_wrap = uv_stride - (width / 2); srcY = src; - srcU = srcY + size; - srcV = srcU + size2; + srcU = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, + 1, width, height); + srcV = src + 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++) { @@ -503,14 +496,21 @@ gst_alpha_set_i420 (guint8 * src, guint8 * dest, gint width, gint height, *dest++ = *srcU++; *dest++ = *srcV++; } + /* Might have one odd column left to do */ + if (odd_width) { + *dest++ = b_alpha; + *dest++ = *srcY++; + *dest++ = *srcU; + *dest++ = *srcV; + } if (i % 2 == 0) { srcU -= width / 2; srcV -= width / 2; } else { - srcU += wrap2; - srcV += wrap2; + srcU += src_uv_wrap; + srcV += src_uv_wrap; } - srcY += wrap; + srcY += src_wrap; } } @@ -523,23 +523,12 @@ gst_alpha_chroma_key_ayuv (guint8 * src, guint8 * dest, gint width, gint height, guint8 *dest1; gint i, j; gint x, z, u, v, y, a; - gint size; - gint stride; - gint wrap; gint tmp, tmp1; gint x1, y1; - width = ROUND_UP_2 (width); - height = ROUND_UP_2 (height); - - stride = ROUND_UP_4 (width); - size = stride * height; - src1 = src; dest1 = dest; - wrap = stride - width; - for (i = 0; i < height; i++) { for (j = 0; j < width; j++) { a = *src1++ * (alpha->alpha); @@ -618,155 +607,166 @@ gst_alpha_chroma_key_ayuv (guint8 * src, guint8 * dest, gint width, gint height, *dest1++ = u; *dest1++ = v; } - dest1 += wrap; - src1 += wrap; } } -/* based on http://www.cs.utah.edu/~michael/chroma/ - */ static void -gst_alpha_chroma_key_i420 (guint8 * src, guint8 * dest, gint width, gint height, - GstAlpha * alpha) +gst_alpha_chromakey_row_i420 (GstAlpha * alpha, guint8 * dest1, guint8 * dest2, + guint8 * srcY1, guint8 * srcY2, guint8 * srcU, guint8 * srcV, gint width) { + gint xpos; gint b_alpha; - guint8 *srcY1, *srcY2, *srcU, *srcV; - guint8 *dest1, *dest2; - gint i, j; gint x, z, u, v, y11, y12, y21, y22, a; - gint size, size2; - gint stride, stride2; - gint wrap, wrap2, wrap3; gint tmp, tmp1; gint x1, y1; - width = ROUND_UP_2 (width); - height = ROUND_UP_2 (height); - - stride = ROUND_UP_4 (width); - size = stride * height; - stride2 = ROUND_UP_8 (width) / 2; - size2 = stride2 * height / 2; - - srcY1 = src; - srcY2 = src + stride; - srcU = srcY1 + size; - srcV = srcU + size2; - - dest1 = dest; - dest2 = dest + width * 4; - - wrap = 2 * stride - 2 * (width / 2); - wrap2 = stride2 - width / 2; - wrap3 = 8 * width - 8 * (width / 2); - a = 255 * alpha->alpha; - for (i = 0; i < height / 2; i++) { - for (j = 0; j < width / 2; j++) { - y11 = *srcY1++; - y12 = *srcY1++; - y21 = *srcY2++; - y22 = *srcY2++; - u = *srcU++ - 128; - v = *srcV++ - 128; - - /* Convert foreground to XZ coords where X direction is defined by - the key color */ - tmp = ((short) u * alpha->cb + (short) v * alpha->cr) >> 7; - x = CLAMP (tmp, -128, 127); - tmp = ((short) v * alpha->cb - (short) u * alpha->cr) >> 7; - z = CLAMP (tmp, -128, 127); - - /* WARNING: accept angle should never be set greater than "somewhat less - than 90 degrees" to avoid dealing with negative/infinite tg. In reality, - 80 degrees should be enough if foreground is reasonable. If this seems - to be a problem, go to alternative ways of checking point position - (scalar product or line equations). This angle should not be too small - either to avoid infinite ctg (used to suppress foreground without use of - division) */ - - tmp = ((short) (x) * alpha->accept_angle_tg) >> 4; - tmp = MIN (tmp, 127); + for (xpos = 0; xpos < width / 2; xpos++) { + y11 = *srcY1++; + y12 = *srcY1++; + y21 = *srcY2++; + y22 = *srcY2++; + u = *srcU++ - 128; + v = *srcV++ - 128; + + /* Convert foreground to XZ coords where X direction is defined by + the key color */ + tmp = ((short) u * alpha->cb + (short) v * alpha->cr) >> 7; + x = CLAMP (tmp, -128, 127); + tmp = ((short) v * alpha->cb - (short) u * alpha->cr) >> 7; + z = CLAMP (tmp, -128, 127); + + /* WARNING: accept angle should never be set greater than "somewhat less + than 90 degrees" to avoid dealing with negative/infinite tg. In reality, + 80 degrees should be enough if foreground is reasonable. If this seems + to be a problem, go to alternative ways of checking point position + (scalar product or line equations). This angle should not be too small + either to avoid infinite ctg (used to suppress foreground without use of + division) */ + + tmp = ((short) (x) * alpha->accept_angle_tg) >> 4; + tmp = MIN (tmp, 127); + + if (abs (z) > tmp) { + /* keep foreground Kfg = 0 */ + b_alpha = 255; + } else { + /* Compute Kfg (implicitly) and Kbg, suppress foreground in XZ coord + according to Kfg */ + tmp = ((short) (z) * alpha->accept_angle_ctg) >> 4; + tmp = CLAMP (tmp, -128, 127); + x1 = abs (tmp); + y1 = z; + + tmp1 = x - x1; + tmp1 = MAX (tmp1, 0); + b_alpha = (((unsigned char) (tmp1) * + (unsigned short) (alpha->one_over_kc)) / 2); + b_alpha = 255 - CLAMP (b_alpha, 0, 255); + b_alpha = (a * b_alpha) >> 8; + + tmp = ((unsigned short) (tmp1) * alpha->kfgy_scale) >> 4; + tmp1 = MIN (tmp, 255); + + tmp = y11 - tmp1; + y11 = MAX (tmp, 0); + tmp = y12 - tmp1; + y12 = MAX (tmp, 0); + tmp = y21 - tmp1; + y21 = MAX (tmp, 0); + tmp = y22 - tmp1; + y22 = MAX (tmp, 0); + + /* Convert suppressed foreground back to CbCr */ + tmp = ((char) (x1) * (short) (alpha->cb) - + (char) (y1) * (short) (alpha->cr)) >> 7; + u = CLAMP (tmp, -128, 127); + + tmp = ((char) (x1) * (short) (alpha->cr) + + (char) (y1) * (short) (alpha->cb)) >> 7; + v = CLAMP (tmp, -128, 127); + + /* Deal with noise. For now, a circle around the key color with + radius of noise_level treated as exact key color. Introduces + sharp transitions. + */ + tmp = z * (short) (z) + (x - alpha->kg) * (short) (x - alpha->kg); + tmp = MIN (tmp, 0xffff); + + if (tmp < alpha->noise_level * alpha->noise_level) { + /* Uncomment this if you want total suppression within the noise circle */ + b_alpha = 0; + } + } - if (abs (z) > tmp) { - /* keep foreground Kfg = 0 */ - b_alpha = 255; - } else { - /* Compute Kfg (implicitly) and Kbg, suppress foreground in XZ coord - according to Kfg */ - tmp = ((short) (z) * alpha->accept_angle_ctg) >> 4; - tmp = CLAMP (tmp, -128, 127); - x1 = abs (tmp); - y1 = z; + u += 128; + v += 128; + + *dest1++ = b_alpha; + *dest1++ = y11; + *dest1++ = u; + *dest1++ = v; + *dest1++ = b_alpha; + *dest1++ = y12; + *dest1++ = u; + *dest1++ = v; + + *dest2++ = b_alpha; + *dest2++ = y21; + *dest2++ = u; + *dest2++ = v; + *dest2++ = b_alpha; + *dest2++ = y22; + *dest2++ = u; + *dest2++ = v; + } +} - tmp1 = x - x1; - tmp1 = MAX (tmp1, 0); - b_alpha = (((unsigned char) (tmp1) * - (unsigned short) (alpha->one_over_kc)) / 2); - b_alpha = 255 - CLAMP (b_alpha, 0, 255); - b_alpha = (a * b_alpha) >> 8; +/* based on http://www.cs.utah.edu/~michael/chroma/ + */ +static void +gst_alpha_chroma_key_i420 (guint8 * src, guint8 * dest, gint width, gint height, + GstAlpha * alpha) +{ + guint8 *srcY1, *srcY2, *srcU, *srcV; + guint8 *dest1, *dest2; + gint ypos; + gint dest_stride, src_y_stride, src_uv_stride; - tmp = ((unsigned short) (tmp1) * alpha->kfgy_scale) >> 4; - tmp1 = MIN (tmp, 255); + dest_stride = + gst_video_format_get_row_stride (GST_VIDEO_FORMAT_AYUV, 0, width); + src_y_stride = + gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, width); + src_uv_stride = + gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, width); - tmp = y11 - tmp1; - y11 = MAX (tmp, 0); - tmp = y12 - tmp1; - y12 = MAX (tmp, 0); - tmp = y21 - tmp1; - y21 = MAX (tmp, 0); - tmp = y22 - tmp1; - y22 = MAX (tmp, 0); + srcY1 = src; + srcY2 = src + src_y_stride; - /* Convert suppressed foreground back to CbCr */ - tmp = ((char) (x1) * (short) (alpha->cb) - - (char) (y1) * (short) (alpha->cr)) >> 7; - u = CLAMP (tmp, -128, 127); + srcU = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, + 1, width, height); + srcV = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, + 2, width, height); - tmp = ((char) (x1) * (short) (alpha->cr) + - (char) (y1) * (short) (alpha->cb)) >> 7; - v = CLAMP (tmp, -128, 127); + dest1 = dest; + dest2 = dest + dest_stride; - /* Deal with noise. For now, a circle around the key color with - radius of noise_level treated as exact key color. Introduces - sharp transitions. - */ - tmp = z * (short) (z) + (x - alpha->kg) * (short) (x - alpha->kg); - tmp = MIN (tmp, 0xffff); + /* Redefine Y strides to skip 2 lines at a time ... */ + dest_stride *= 2; + src_y_stride *= 2; - if (tmp < alpha->noise_level * alpha->noise_level) { - /* Uncomment this if you want total suppression within the noise circle */ - b_alpha = 0; - } - } + for (ypos = 0; ypos < height / 2; ypos++) { - u += 128; - v += 128; + gst_alpha_chromakey_row_i420 (alpha, dest1, dest2, + srcY1, srcY2, srcU, srcV, width); - *dest1++ = b_alpha; - *dest1++ = y11; - *dest1++ = u; - *dest1++ = v; - *dest1++ = b_alpha; - *dest1++ = y12; - *dest1++ = u; - *dest1++ = v; - *dest2++ = b_alpha; - *dest2++ = y21; - *dest2++ = u; - *dest2++ = v; - *dest2++ = b_alpha; - *dest2++ = y22; - *dest2++ = u; - *dest2++ = v; - } - dest1 += wrap3; - dest2 += wrap3; - srcY1 += wrap; - srcY2 += wrap; - srcU += wrap2; - srcV += wrap2; + dest1 += dest_stride; + dest2 += dest_stride; + srcY1 += src_y_stride; + srcY2 += src_y_stride; + srcU += src_uv_stride; + srcV += src_uv_stride; } } @@ -807,76 +807,29 @@ gst_alpha_init_params (GstAlpha * alpha) } static gboolean -gst_alpha_sink_event (GstPad * pad, GstEvent * event) +gst_alpha_start (GstBaseTransform * btrans) { - GstAlpha *alpha; - gboolean ret; - - alpha = GST_ALPHA (GST_PAD_PARENT (pad)); - - switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_FLUSH_STOP: - gst_segment_init (&alpha->segment, GST_FORMAT_UNDEFINED); - break; - case GST_EVENT_NEWSEGMENT:{ - GstFormat format; - gdouble rate, arate; - gint64 start, stop, time; - gboolean update; - - gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format, - &start, &stop, &time); - - gst_segment_set_newsegment_full (&alpha->segment, update, rate, arate, - format, start, stop, time); - break; - } - default: - break; - } + GstAlpha *alpha = GST_ALPHA (btrans); - ret = gst_pad_push_event (alpha->srcpad, event); + gst_alpha_init_params (alpha); - return ret; + return TRUE; } static GstFlowReturn -gst_alpha_chain (GstPad * pad, GstBuffer * buffer) +gst_alpha_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out) { - GstAlpha *alpha; - GstBuffer *outbuf; - gint new_width, new_height; - GstFlowReturn ret; + GstAlpha *alpha = GST_ALPHA (btrans); + gint width, height; GstClockTime timestamp; - alpha = GST_ALPHA (GST_PAD_PARENT (pad)); - - new_width = alpha->in_width; - new_height = alpha->in_height; + width = alpha->width; + height = alpha->height; - if (new_width != alpha->out_width || - new_height != alpha->out_height || !GST_PAD_CAPS (alpha->srcpad)) { - GstCaps *newcaps; - - newcaps = gst_caps_copy (gst_pad_get_negotiated_caps (alpha->sinkpad)); - gst_caps_set_simple (newcaps, - "format", GST_TYPE_FOURCC, GST_STR_FOURCC ("AYUV"), - "width", G_TYPE_INT, new_width, "height", G_TYPE_INT, new_height, NULL); - - gst_pad_set_caps (alpha->srcpad, newcaps); - - alpha->out_width = new_width; - alpha->out_height = new_height; - } - - outbuf = - gst_buffer_new_and_alloc (ROUND_UP_2 (new_width) * - ROUND_UP_2 (new_height) * 4); - gst_buffer_set_caps (outbuf, GST_PAD_CAPS (alpha->srcpad)); - GST_BUFFER_TIMESTAMP (outbuf) = GST_BUFFER_TIMESTAMP (buffer); - GST_BUFFER_DURATION (outbuf) = GST_BUFFER_DURATION (buffer); - timestamp = gst_segment_to_stream_time (&alpha->segment, GST_FORMAT_TIME, - GST_BUFFER_TIMESTAMP (buffer)); + GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_TIMESTAMP (in); + GST_BUFFER_DURATION (out) = GST_BUFFER_DURATION (in); + timestamp = gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME, + GST_BUFFER_TIMESTAMP (in)); GST_LOG ("Got stream time of %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp)); if (GST_CLOCK_TIME_IS_VALID (timestamp)) gst_object_sync_values (G_OBJECT (alpha), timestamp); @@ -884,76 +837,29 @@ gst_alpha_chain (GstPad * pad, GstBuffer * buffer) switch (alpha->method) { case ALPHA_METHOD_SET: if (alpha->ayuv) { - gst_alpha_set_ayuv (GST_BUFFER_DATA (buffer), - GST_BUFFER_DATA (outbuf), new_width, new_height, alpha->alpha); + gst_alpha_set_ayuv (GST_BUFFER_DATA (in), + GST_BUFFER_DATA (out), width, height, alpha->alpha); } else { - gst_alpha_set_i420 (GST_BUFFER_DATA (buffer), - GST_BUFFER_DATA (outbuf), new_width, new_height, alpha->alpha); + gst_alpha_set_i420 (GST_BUFFER_DATA (in), + GST_BUFFER_DATA (out), width, height, alpha->alpha); } break; case ALPHA_METHOD_GREEN: case ALPHA_METHOD_BLUE: case ALPHA_METHOD_CUSTOM: if (alpha->ayuv) { - gst_alpha_chroma_key_ayuv (GST_BUFFER_DATA (buffer), - GST_BUFFER_DATA (outbuf), new_width, new_height, alpha); + gst_alpha_chroma_key_ayuv (GST_BUFFER_DATA (in), + GST_BUFFER_DATA (out), width, height, alpha); } else { - gst_alpha_chroma_key_i420 (GST_BUFFER_DATA (buffer), - GST_BUFFER_DATA (outbuf), new_width, new_height, alpha); + gst_alpha_chroma_key_i420 (GST_BUFFER_DATA (in), + GST_BUFFER_DATA (out), width, height, alpha); } break; default: break; } - gst_buffer_unref (buffer); - - /* Update last stop position in segment */ - if (GST_BUFFER_TIMESTAMP (outbuf) != GST_CLOCK_TIME_NONE) { - GstClockTime last_stop = GST_BUFFER_TIMESTAMP (outbuf); - - if (GST_BUFFER_DURATION (outbuf) != GST_CLOCK_TIME_NONE) - last_stop += GST_BUFFER_DURATION (outbuf); - - gst_segment_set_last_stop (&alpha->segment, GST_FORMAT_TIME, last_stop); - } - - ret = gst_pad_push (alpha->srcpad, outbuf); - - return ret; -} - -static GstStateChangeReturn -gst_alpha_change_state (GstElement * element, GstStateChange transition) -{ - GstStateChangeReturn res; - GstAlpha *alpha; - - alpha = GST_ALPHA (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - gst_segment_init (&alpha->segment, GST_FORMAT_UNDEFINED); - gst_alpha_init_params (alpha); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - default: - break; - } - - res = parent_class->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - case GST_STATE_CHANGE_PAUSED_TO_READY: - case GST_STATE_CHANGE_READY_TO_NULL: - default: - break; - } - - return res; + return GST_FLOW_OK; } static gboolean @@ -967,5 +873,5 @@ plugin_init (GstPlugin * plugin) GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "alpha", - "adds an alpha channel to video", + "adds an alpha channel to video - constant or via chroma-keying", plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) -- cgit