2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
3 * Copyright (C) <2007> Wim Taymans <wim.taymans@collabora.co.uk>
4 * Copyright (C) <2007> Edward Hervey <edward.hervey@collabora.co.uk>
5 * Copyright (C) <2007> Jan Schmidt <thaytan@noraisin.net>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
24 * SECTION:element-alpha
26 * The alpha element adds an alpha channel to a video stream. The values
27 * of the alpha channel can be either be set to a constant or can be
28 * dynamically calculated via chroma keying, e.g. blue can be set as
29 * the transparent color.
33 * gst-launch videotestsrc pattern=smpte75 ! alpha method=green ! \
34 * videomixer name=mixer ! ffmpegcolorspace ! autovideosink \
35 * videotestsrc pattern=snow ! mixer.
36 * ]| This pipeline adds a alpha channel to the SMPTE color bars
37 * with green as the transparent color and mixes the output with
38 * a snow video stream.
53 #define M_PI 3.14159265358979323846
56 /* Generated by -bad/ext/cog/generate_tables */
57 static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
59 298, -55, -136, 19681,
63 static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
65 298, -100, -208, 34707,
69 static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
72 112, -102, -10, 32768,
75 static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
81 static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
87 static const gint cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = {
93 /* Alpha signals and args */
100 #define DEFAULT_METHOD ALPHA_METHOD_SET
101 #define DEFAULT_ALPHA 1.0
102 #define DEFAULT_TARGET_R 0
103 #define DEFAULT_TARGET_G 255
104 #define DEFAULT_TARGET_B 0
105 #define DEFAULT_ANGLE 20.0
106 #define DEFAULT_NOISE_LEVEL 2.0
107 #define DEFAULT_BLACK_SENSITIVITY 100
108 #define DEFAULT_WHITE_SENSITIVITY 100
109 #define DEFAULT_PREFER_PASSTHROUGH FALSE
121 PROP_BLACK_SENSITIVITY,
122 PROP_WHITE_SENSITIVITY,
123 PROP_PREFER_PASSTHROUGH,
127 static GstStaticPadTemplate gst_alpha_src_template =
128 GST_STATIC_PAD_TEMPLATE ("src",
131 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
132 GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";"
133 GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_RGBA
134 ";" GST_VIDEO_CAPS_YUV ("Y444")
135 ";" GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_xBGR
136 ";" GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR
137 ";" GST_VIDEO_CAPS_YUV ("Y42B") ";" GST_VIDEO_CAPS_YUV ("YUY2")
138 ";" GST_VIDEO_CAPS_YUV ("YVYU") ";" GST_VIDEO_CAPS_YUV ("UYVY")
139 ";" GST_VIDEO_CAPS_YUV ("I420") ";" GST_VIDEO_CAPS_YUV ("YV12")
140 ";" GST_VIDEO_CAPS_YUV ("Y41B"))
143 static GstStaticPadTemplate gst_alpha_sink_template =
144 GST_STATIC_PAD_TEMPLATE ("sink",
147 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV")
148 ";" GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";" GST_VIDEO_CAPS_ABGR
149 ";" GST_VIDEO_CAPS_RGBA ";" GST_VIDEO_CAPS_YUV ("Y444")
150 ";" GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_xBGR
151 ";" GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR
152 ";" GST_VIDEO_CAPS_YUV ("Y42B") ";" GST_VIDEO_CAPS_YUV ("YUY2")
153 ";" GST_VIDEO_CAPS_YUV ("YVYU") ";" GST_VIDEO_CAPS_YUV ("UYVY")
154 ";" GST_VIDEO_CAPS_YUV ("I420") ";" GST_VIDEO_CAPS_YUV ("YV12")
155 ";" GST_VIDEO_CAPS_YUV ("Y41B")
159 static GstStaticCaps gst_alpha_alpha_caps =
160 GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV")
161 ";" GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";" GST_VIDEO_CAPS_ABGR ";"
162 GST_VIDEO_CAPS_RGBA);
164 /* FIXME: why do we need our own lock for this? */
165 #if !GLIB_CHECK_VERSION (2, 31, 0)
166 #define GST_ALPHA_LOCK(alpha) G_STMT_START { \
167 GST_LOG_OBJECT (alpha, "Locking alpha from thread %p", g_thread_self ()); \
168 g_static_mutex_lock (&alpha->lock); \
169 GST_LOG_OBJECT (alpha, "Locked alpha from thread %p", g_thread_self ()); \
172 #define GST_ALPHA_UNLOCK(alpha) G_STMT_START { \
173 GST_LOG_OBJECT (alpha, "Unlocking alpha from thread %p", g_thread_self ()); \
174 g_static_mutex_unlock (&alpha->lock); \
177 #define GST_ALPHA_LOCK(alpha) G_STMT_START { \
178 GST_LOG_OBJECT (alpha, "Locking alpha from thread %p", g_thread_self ()); \
179 g_mutex_lock (&alpha->lock); \
180 GST_LOG_OBJECT (alpha, "Locked alpha from thread %p", g_thread_self ()); \
183 #define GST_ALPHA_UNLOCK(alpha) G_STMT_START { \
184 GST_LOG_OBJECT (alpha, "Unlocking alpha from thread %p", g_thread_self ()); \
185 g_mutex_unlock (&alpha->lock); \
189 static gboolean gst_alpha_start (GstBaseTransform * trans);
190 static gboolean gst_alpha_get_unit_size (GstBaseTransform * btrans,
191 GstCaps * caps, guint * size);
192 static GstCaps *gst_alpha_transform_caps (GstBaseTransform * btrans,
193 GstPadDirection direction, GstCaps * caps);
194 static gboolean gst_alpha_set_caps (GstBaseTransform * btrans,
195 GstCaps * incaps, GstCaps * outcaps);
196 static GstFlowReturn gst_alpha_transform (GstBaseTransform * btrans,
197 GstBuffer * in, GstBuffer * out);
198 static void gst_alpha_before_transform (GstBaseTransform * btrans,
201 static void gst_alpha_init_params (GstAlpha * alpha);
202 static gboolean gst_alpha_set_process_function (GstAlpha * alpha);
204 static void gst_alpha_set_property (GObject * object, guint prop_id,
205 const GValue * value, GParamSpec * pspec);
206 static void gst_alpha_get_property (GObject * object, guint prop_id,
207 GValue * value, GParamSpec * pspec);
208 static void gst_alpha_finalize (GObject * object);
210 GST_BOILERPLATE (GstAlpha, gst_alpha, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
212 #define GST_TYPE_ALPHA_METHOD (gst_alpha_method_get_type())
214 gst_alpha_method_get_type (void)
216 static GType alpha_method_type = 0;
217 static const GEnumValue alpha_method[] = {
218 {ALPHA_METHOD_SET, "Set/adjust alpha channel", "set"},
219 {ALPHA_METHOD_GREEN, "Chroma Key green", "green"},
220 {ALPHA_METHOD_BLUE, "Chroma Key blue", "blue"},
221 {ALPHA_METHOD_CUSTOM, "Chroma Key on target_r/g/b", "custom"},
225 if (!alpha_method_type) {
226 alpha_method_type = g_enum_register_static ("GstAlphaMethod", alpha_method);
228 return alpha_method_type;
232 gst_alpha_base_init (gpointer g_class)
234 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
236 gst_element_class_set_details_simple (element_class, "Alpha filter",
237 "Filter/Effect/Video",
238 "Adds an alpha channel to video - uniform or via chroma-keying",
239 "Wim Taymans <wim@fluendo.com>\n"
240 "Edward Hervey <edward.hervey@collabora.co.uk>\n"
241 "Jan Schmidt <thaytan@noraisin.net>");
243 gst_element_class_add_static_pad_template (element_class,
244 &gst_alpha_sink_template);
245 gst_element_class_add_static_pad_template (element_class,
246 &gst_alpha_src_template);
248 GST_DEBUG_CATEGORY_INIT (gst_alpha_debug, "alpha", 0,
249 "alpha - Element for adding alpha channel to streams");
253 gst_alpha_class_init (GstAlphaClass * klass)
255 GObjectClass *gobject_class = (GObjectClass *) klass;
256 GstBaseTransformClass *btrans_class = (GstBaseTransformClass *) klass;
258 gobject_class->set_property = gst_alpha_set_property;
259 gobject_class->get_property = gst_alpha_get_property;
260 gobject_class->finalize = gst_alpha_finalize;
262 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_METHOD,
263 g_param_spec_enum ("method", "Method",
264 "How the alpha channels should be created", GST_TYPE_ALPHA_METHOD,
265 DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
266 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA,
267 g_param_spec_double ("alpha", "Alpha", "The value for the alpha channel",
268 0.0, 1.0, DEFAULT_ALPHA,
269 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
270 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_R,
271 g_param_spec_uint ("target-r", "Target Red", "The Red target", 0, 255,
273 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
274 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_G,
275 g_param_spec_uint ("target-g", "Target Green", "The Green target", 0, 255,
277 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
278 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_B,
279 g_param_spec_uint ("target-b", "Target Blue", "The Blue target", 0, 255,
281 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
282 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ANGLE,
283 g_param_spec_float ("angle", "Angle", "Size of the colorcube to change",
284 0.0, 90.0, DEFAULT_ANGLE,
285 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
286 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NOISE_LEVEL,
287 g_param_spec_float ("noise-level", "Noise Level", "Size of noise radius",
288 0.0, 64.0, DEFAULT_NOISE_LEVEL,
289 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
290 g_object_class_install_property (G_OBJECT_CLASS (klass),
291 PROP_BLACK_SENSITIVITY, g_param_spec_uint ("black-sensitivity",
292 "Black Sensitivity", "Sensitivity to dark colors", 0, 128,
293 DEFAULT_BLACK_SENSITIVITY,
294 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
295 g_object_class_install_property (G_OBJECT_CLASS (klass),
296 PROP_WHITE_SENSITIVITY, g_param_spec_uint ("white-sensitivity",
297 "Sensitivity", "Sensitivity to bright colors", 0, 128,
298 DEFAULT_WHITE_SENSITIVITY,
299 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
300 g_object_class_install_property (G_OBJECT_CLASS (klass),
301 PROP_PREFER_PASSTHROUGH, g_param_spec_boolean ("prefer-passthrough",
302 "Prefer Passthrough",
303 "Don't do any processing for alpha=1.0 if possible",
304 DEFAULT_PREFER_PASSTHROUGH,
305 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
307 btrans_class->start = GST_DEBUG_FUNCPTR (gst_alpha_start);
308 btrans_class->transform = GST_DEBUG_FUNCPTR (gst_alpha_transform);
309 btrans_class->before_transform =
310 GST_DEBUG_FUNCPTR (gst_alpha_before_transform);
311 btrans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_alpha_get_unit_size);
312 btrans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_alpha_transform_caps);
313 btrans_class->set_caps = GST_DEBUG_FUNCPTR (gst_alpha_set_caps);
317 gst_alpha_init (GstAlpha * alpha, GstAlphaClass * klass)
319 alpha->alpha = DEFAULT_ALPHA;
320 alpha->method = DEFAULT_METHOD;
321 alpha->target_r = DEFAULT_TARGET_R;
322 alpha->target_g = DEFAULT_TARGET_G;
323 alpha->target_b = DEFAULT_TARGET_B;
324 alpha->angle = DEFAULT_ANGLE;
325 alpha->noise_level = DEFAULT_NOISE_LEVEL;
326 alpha->black_sensitivity = DEFAULT_BLACK_SENSITIVITY;
327 alpha->white_sensitivity = DEFAULT_WHITE_SENSITIVITY;
329 #if !GLIB_CHECK_VERSION (2, 31, 0)
330 g_static_mutex_init (&alpha->lock);
332 g_mutex_init (&alpha->lock);
337 gst_alpha_finalize (GObject * object)
339 GstAlpha *alpha = GST_ALPHA (object);
341 #if !GLIB_CHECK_VERSION (2, 31, 0)
342 g_static_mutex_free (&alpha->lock);
344 g_mutex_clear (&alpha->lock);
347 G_OBJECT_CLASS (parent_class)->finalize (object);
351 gst_alpha_set_property (GObject * object, guint prop_id,
352 const GValue * value, GParamSpec * pspec)
354 GstAlpha *alpha = GST_ALPHA (object);
355 gboolean reconfigure = FALSE;
357 GST_ALPHA_LOCK (alpha);
360 gint method = g_value_get_enum (value);
362 reconfigure = (method != alpha->method) && (method == ALPHA_METHOD_SET
363 || alpha->method == ALPHA_METHOD_SET) && (alpha->alpha == 1.0)
364 && (alpha->prefer_passthrough);
365 alpha->method = method;
367 switch (alpha->method) {
368 case ALPHA_METHOD_GREEN:
370 alpha->target_g = 255;
373 case ALPHA_METHOD_BLUE:
376 alpha->target_b = 255;
381 gst_alpha_set_process_function (alpha);
382 gst_alpha_init_params (alpha);
386 gdouble a = g_value_get_double (value);
388 reconfigure = (a != alpha->alpha) && (a == 1.0 || alpha->alpha == 1.0)
389 && (alpha->method == ALPHA_METHOD_SET) && (alpha->prefer_passthrough);
394 alpha->target_r = g_value_get_uint (value);
395 gst_alpha_init_params (alpha);
398 alpha->target_g = g_value_get_uint (value);
399 gst_alpha_init_params (alpha);
402 alpha->target_b = g_value_get_uint (value);
403 gst_alpha_init_params (alpha);
406 alpha->angle = g_value_get_float (value);
407 gst_alpha_init_params (alpha);
409 case PROP_NOISE_LEVEL:
410 alpha->noise_level = g_value_get_float (value);
411 gst_alpha_init_params (alpha);
413 case PROP_BLACK_SENSITIVITY:
414 alpha->black_sensitivity = g_value_get_uint (value);
416 case PROP_WHITE_SENSITIVITY:
417 alpha->white_sensitivity = g_value_get_uint (value);
419 case PROP_PREFER_PASSTHROUGH:{
420 gboolean prefer_passthrough = g_value_get_boolean (value);
422 reconfigure = ((! !prefer_passthrough) != (! !alpha->prefer_passthrough))
423 && (alpha->method == ALPHA_METHOD_SET) && (alpha->alpha == 1.0);
424 alpha->prefer_passthrough = prefer_passthrough;
428 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
433 gst_base_transform_reconfigure (GST_BASE_TRANSFORM_CAST (alpha));
435 GST_ALPHA_UNLOCK (alpha);
439 gst_alpha_get_property (GObject * object, guint prop_id, GValue * value,
442 GstAlpha *alpha = GST_ALPHA (object);
446 g_value_set_enum (value, alpha->method);
449 g_value_set_double (value, alpha->alpha);
452 g_value_set_uint (value, alpha->target_r);
455 g_value_set_uint (value, alpha->target_g);
458 g_value_set_uint (value, alpha->target_b);
461 g_value_set_float (value, alpha->angle);
463 case PROP_NOISE_LEVEL:
464 g_value_set_float (value, alpha->noise_level);
466 case PROP_BLACK_SENSITIVITY:
467 g_value_set_uint (value, alpha->black_sensitivity);
469 case PROP_WHITE_SENSITIVITY:
470 g_value_set_uint (value, alpha->white_sensitivity);
472 case PROP_PREFER_PASSTHROUGH:
473 g_value_set_boolean (value, alpha->prefer_passthrough);
476 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
482 gst_alpha_get_unit_size (GstBaseTransform * btrans,
483 GstCaps * caps, guint * size)
485 GstVideoFormat format;
488 if (!gst_video_format_parse_caps (caps, &format, &width, &height))
491 *size = gst_video_format_get_size (format, width, height);
493 GST_DEBUG_OBJECT (btrans, "unit size = %d for format %d w %d height %d",
494 *size, format, width, height);
500 gst_alpha_transform_caps (GstBaseTransform * btrans,
501 GstPadDirection direction, GstCaps * caps)
503 GstAlpha *alpha = GST_ALPHA (btrans);
504 GstCaps *ret, *tmp, *tmp2;
505 GstStructure *structure;
508 tmp = gst_caps_new_empty ();
510 GST_ALPHA_LOCK (alpha);
511 for (i = 0; i < gst_caps_get_size (caps); i++) {
512 structure = gst_structure_copy (gst_caps_get_structure (caps, i));
514 gst_structure_remove_field (structure, "format");
515 gst_structure_remove_field (structure, "endianness");
516 gst_structure_remove_field (structure, "depth");
517 gst_structure_remove_field (structure, "bpp");
518 gst_structure_remove_field (structure, "red_mask");
519 gst_structure_remove_field (structure, "green_mask");
520 gst_structure_remove_field (structure, "blue_mask");
521 gst_structure_remove_field (structure, "alpha_mask");
522 gst_structure_remove_field (structure, "color-matrix");
523 gst_structure_remove_field (structure, "chroma-site");
525 gst_structure_set_name (structure, "video/x-raw-yuv");
526 gst_caps_append_structure (tmp, gst_structure_copy (structure));
527 gst_structure_set_name (structure, "video/x-raw-rgb");
528 gst_caps_append_structure (tmp, structure);
531 if (direction == GST_PAD_SINK) {
532 tmp2 = gst_static_caps_get (&gst_alpha_alpha_caps);
533 ret = gst_caps_intersect (tmp, tmp2);
534 gst_caps_unref (tmp);
535 gst_caps_unref (tmp2);
539 if (alpha->prefer_passthrough && alpha->method == ALPHA_METHOD_SET
540 && alpha->alpha == 1.0) {
541 ret = gst_caps_copy (caps);
542 gst_caps_append (ret, tmp);
553 GST_DEBUG_OBJECT (alpha,
554 "Transformed %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT, caps, ret);
556 GST_ALPHA_UNLOCK (alpha);
562 gst_alpha_set_caps (GstBaseTransform * btrans,
563 GstCaps * incaps, GstCaps * outcaps)
565 GstAlpha *alpha = GST_ALPHA (btrans);
567 gboolean passthrough;
569 GST_ALPHA_LOCK (alpha);
571 if (!gst_video_format_parse_caps (incaps, &alpha->in_format,
572 &alpha->width, &alpha->height) ||
573 !gst_video_format_parse_caps (outcaps, &alpha->out_format,
574 &alpha->width, &alpha->height)) {
575 GST_WARNING_OBJECT (alpha,
576 "Failed to parse caps %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT, incaps,
578 GST_ALPHA_UNLOCK (alpha);
582 matrix = gst_video_parse_caps_color_matrix (incaps);
583 alpha->in_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
585 matrix = gst_video_parse_caps_color_matrix (outcaps);
586 alpha->out_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
588 passthrough = alpha->prefer_passthrough &&
589 alpha->in_format == alpha->out_format && alpha->in_sdtv == alpha->out_sdtv
590 && alpha->method == ALPHA_METHOD_SET && alpha->alpha == 1.0;
592 GST_DEBUG_OBJECT (alpha,
593 "Setting caps %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT
594 " (passthrough: %d)", incaps, outcaps, passthrough);
595 gst_base_transform_set_passthrough (btrans, passthrough);
597 if (!gst_alpha_set_process_function (alpha) && !passthrough) {
598 GST_WARNING_OBJECT (alpha,
599 "No processing function for this caps and no passthrough mode");
600 GST_ALPHA_UNLOCK (alpha);
604 gst_alpha_init_params (alpha);
606 GST_ALPHA_UNLOCK (alpha);
611 /* based on http://www.cs.utah.edu/~michael/chroma/
614 chroma_keying_yuv (gint a, gint * y, gint * u,
615 gint * v, gint cr, gint cb, gint smin, gint smax, guint8 accept_angle_tg,
616 guint8 accept_angle_ctg, guint8 one_over_kc, guint8 kfgy_scale, gint8 kg,
624 /* too dark or too bright, keep alpha */
625 if (*y < smin || *y > smax)
628 /* Convert foreground to XZ coords where X direction is defined by
630 tmp = ((*u) * cb + (*v) * cr) >> 7;
631 x = CLAMP (tmp, -128, 127);
632 tmp = ((*v) * cb - (*u) * cr) >> 7;
633 z = CLAMP (tmp, -128, 127);
635 /* WARNING: accept angle should never be set greater than "somewhat less
636 than 90 degrees" to avoid dealing with negative/infinite tg. In reality,
637 80 degrees should be enough if foreground is reasonable. If this seems
638 to be a problem, go to alternative ways of checking point position
639 (scalar product or line equations). This angle should not be too small
640 either to avoid infinite ctg (used to suppress foreground without use of
643 tmp = (x * accept_angle_tg) >> 4;
644 tmp = MIN (tmp, 127);
647 /* keep foreground Kfg = 0 */
650 /* Compute Kfg (implicitly) and Kbg, suppress foreground in XZ coord
652 tmp = (z * accept_angle_ctg) >> 4;
653 tmp = CLAMP (tmp, -128, 127);
658 tmp1 = MAX (tmp1, 0);
659 b_alpha = (tmp1 * one_over_kc) / 2;
660 b_alpha = 255 - CLAMP (b_alpha, 0, 255);
661 b_alpha = (a * b_alpha) >> 8;
663 tmp = (tmp1 * kfgy_scale) >> 4;
664 tmp1 = MIN (tmp, 255);
666 *y = (*y < tmp1) ? 0 : *y - tmp1;
668 /* Convert suppressed foreground back to CbCr */
669 tmp = (x1 * cb - y1 * cr) >> 7;
670 *u = CLAMP (tmp, -128, 127);
672 tmp = (x1 * cr + y1 * cb) >> 7;
673 *v = CLAMP (tmp, -128, 127);
675 /* Deal with noise. For now, a circle around the key color with
676 radius of noise_level treated as exact key color. Introduces
679 tmp = z * z + (x - kg) * (x - kg);
680 tmp = MIN (tmp, 0xffff);
682 if (tmp < noise_level2)
688 #define APPLY_MATRIX(m,o,v1,v2,v3) ((m[o*4] * v1 + m[o*4+1] * v2 + m[o*4+2] * v3 + m[o*4+3]) >> 8)
691 gst_alpha_set_argb_ayuv (const guint8 * src, guint8 * dest, gint width,
692 gint height, GstAlpha * alpha)
694 gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
701 gst_video_format_get_component_offset (alpha->in_format, 3, width,
704 gst_video_format_get_component_offset (alpha->in_format, 0, width,
707 gst_video_format_get_component_offset (alpha->in_format, 1, width,
710 gst_video_format_get_component_offset (alpha->in_format, 2, width,
714 alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
715 cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
717 for (i = 0; i < height; i++) {
718 for (j = 0; j < width; j++) {
719 dest[0] = (src[o[0]] * s_alpha) >> 8;
721 y = APPLY_MATRIX (matrix, 0, src[o[1]], src[o[2]], src[o[3]]);
722 u = APPLY_MATRIX (matrix, 1, src[o[1]], src[o[2]], src[o[3]]);
723 v = APPLY_MATRIX (matrix, 2, src[o[1]], src[o[2]], src[o[3]]);
736 gst_alpha_chroma_key_argb_ayuv (const guint8 * src, guint8 * dest, gint width,
737 gint height, GstAlpha * alpha)
743 gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
744 gint8 cb = alpha->cb, cr = alpha->cr;
745 gint8 kg = alpha->kg;
746 guint8 accept_angle_tg = alpha->accept_angle_tg;
747 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
748 guint8 one_over_kc = alpha->one_over_kc;
749 guint8 kfgy_scale = alpha->kfgy_scale;
750 guint noise_level2 = alpha->noise_level2;
755 gst_video_format_get_component_offset (alpha->in_format, 3, width,
758 gst_video_format_get_component_offset (alpha->in_format, 0, width,
761 gst_video_format_get_component_offset (alpha->in_format, 1, width,
764 gst_video_format_get_component_offset (alpha->in_format, 2, width,
767 smin = 128 - alpha->black_sensitivity;
768 smax = 128 + alpha->white_sensitivity;
771 alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
772 cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
774 for (i = 0; i < height; i++) {
775 for (j = 0; j < width; j++) {
776 a = (src[o[0]] * pa) >> 8;
781 y = APPLY_MATRIX (matrix, 0, r, g, b);
782 u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
783 v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
785 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
786 smin, smax, accept_angle_tg, accept_angle_ctg,
787 one_over_kc, kfgy_scale, kg, noise_level2);
804 gst_alpha_set_argb_argb (const guint8 * src, guint8 * dest, gint width,
805 gint height, GstAlpha * alpha)
807 gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
812 gst_video_format_get_component_offset (alpha->out_format, 3, width,
815 gst_video_format_get_component_offset (alpha->out_format, 0, width,
818 gst_video_format_get_component_offset (alpha->out_format, 1, width,
821 gst_video_format_get_component_offset (alpha->out_format, 2, width,
825 gst_video_format_get_component_offset (alpha->in_format, 3, width,
828 gst_video_format_get_component_offset (alpha->in_format, 0, width,
831 gst_video_format_get_component_offset (alpha->in_format, 1, width,
834 gst_video_format_get_component_offset (alpha->in_format, 2, width,
837 for (i = 0; i < height; i++) {
838 for (j = 0; j < width; j++) {
839 dest[p[0]] = (src[o[0]] * s_alpha) >> 8;
841 dest[p[1]] = src[o[1]];
842 dest[p[2]] = src[o[2]];
843 dest[p[3]] = src[o[3]];
852 gst_alpha_chroma_key_argb_argb (const guint8 * src, guint8 * dest, gint width,
853 gint height, GstAlpha * alpha)
859 gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
860 gint8 cb = alpha->cb, cr = alpha->cr;
861 gint8 kg = alpha->kg;
862 guint8 accept_angle_tg = alpha->accept_angle_tg;
863 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
864 guint8 one_over_kc = alpha->one_over_kc;
865 guint8 kfgy_scale = alpha->kfgy_scale;
866 guint noise_level2 = alpha->noise_level2;
867 gint matrix[12], matrix2[12];
871 gst_video_format_get_component_offset (alpha->out_format, 3, width,
874 gst_video_format_get_component_offset (alpha->out_format, 0, width,
877 gst_video_format_get_component_offset (alpha->out_format, 1, width,
880 gst_video_format_get_component_offset (alpha->out_format, 2, width,
884 gst_video_format_get_component_offset (alpha->in_format, 3, width,
887 gst_video_format_get_component_offset (alpha->in_format, 0, width,
890 gst_video_format_get_component_offset (alpha->in_format, 1, width,
893 gst_video_format_get_component_offset (alpha->in_format, 2, width,
896 smin = 128 - alpha->black_sensitivity;
897 smax = 128 + alpha->white_sensitivity;
899 memcpy (matrix, cog_rgb_to_ycbcr_matrix_8bit_sdtv, 12 * sizeof (gint));
900 memcpy (matrix2, cog_ycbcr_to_rgb_matrix_8bit_sdtv, 12 * sizeof (gint));
902 for (i = 0; i < height; i++) {
903 for (j = 0; j < width; j++) {
904 a = (src[o[0]] * pa) >> 8;
909 y = APPLY_MATRIX (matrix, 0, r, g, b);
910 u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
911 v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
913 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
914 smin, smax, accept_angle_tg, accept_angle_ctg,
915 one_over_kc, kfgy_scale, kg, noise_level2);
920 r = APPLY_MATRIX (matrix2, 0, y, u, v);
921 g = APPLY_MATRIX (matrix2, 1, y, u, v);
922 b = APPLY_MATRIX (matrix2, 2, y, u, v);
925 dest[p[1]] = CLAMP (r, 0, 255);
926 dest[p[2]] = CLAMP (g, 0, 255);
927 dest[p[3]] = CLAMP (b, 0, 255);
936 gst_alpha_set_ayuv_argb (const guint8 * src, guint8 * dest, gint width,
937 gint height, GstAlpha * alpha)
939 gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
946 gst_video_format_get_component_offset (alpha->out_format, 3, width,
949 gst_video_format_get_component_offset (alpha->out_format, 0, width,
952 gst_video_format_get_component_offset (alpha->out_format, 1, width,
955 gst_video_format_get_component_offset (alpha->out_format, 2, width,
959 alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
960 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
962 for (y = 0; y < height; y++) {
963 for (x = 0; x < width; x++) {
964 dest[p[0]] = (src[0] * s_alpha) >> 8;
966 r = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
967 g = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]);
968 b = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]);
970 dest[p[1]] = CLAMP (r, 0, 255);
971 dest[p[2]] = CLAMP (g, 0, 255);
972 dest[p[3]] = CLAMP (b, 0, 255);
981 gst_alpha_chroma_key_ayuv_argb (const guint8 * src, guint8 * dest, gint width,
982 gint height, GstAlpha * alpha)
988 gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
989 gint8 cb = alpha->cb, cr = alpha->cr;
990 gint8 kg = alpha->kg;
991 guint8 accept_angle_tg = alpha->accept_angle_tg;
992 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
993 guint8 one_over_kc = alpha->one_over_kc;
994 guint8 kfgy_scale = alpha->kfgy_scale;
995 guint noise_level2 = alpha->noise_level2;
1000 gst_video_format_get_component_offset (alpha->out_format, 3, width,
1003 gst_video_format_get_component_offset (alpha->out_format, 0, width,
1006 gst_video_format_get_component_offset (alpha->out_format, 1, width,
1009 gst_video_format_get_component_offset (alpha->out_format, 2, width,
1012 smin = 128 - alpha->black_sensitivity;
1013 smax = 128 + alpha->white_sensitivity;
1016 alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
1017 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
1019 for (i = 0; i < height; i++) {
1020 for (j = 0; j < width; j++) {
1021 a = (src[0] * pa) >> 8;
1026 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1027 smin, smax, accept_angle_tg, accept_angle_ctg,
1028 one_over_kc, kfgy_scale, kg, noise_level2);
1033 r = APPLY_MATRIX (matrix, 0, y, u, v);
1034 g = APPLY_MATRIX (matrix, 1, y, u, v);
1035 b = APPLY_MATRIX (matrix, 2, y, u, v);
1038 dest[p[1]] = CLAMP (r, 0, 255);
1039 dest[p[2]] = CLAMP (g, 0, 255);
1040 dest[p[3]] = CLAMP (b, 0, 255);
1049 gst_alpha_set_ayuv_ayuv (const guint8 * src, guint8 * dest, gint width,
1050 gint height, GstAlpha * alpha)
1052 gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
1055 if (alpha->in_sdtv == alpha->out_sdtv) {
1056 for (y = 0; y < height; y++) {
1057 for (x = 0; x < width; x++) {
1058 dest[0] = (src[0] * s_alpha) >> 8;
1071 alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1072 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1074 for (y = 0; y < height; y++) {
1075 for (x = 0; x < width; x++) {
1076 dest[0] = (src[0] * s_alpha) >> 8;
1077 dest[1] = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
1078 dest[2] = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]);
1079 dest[3] = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]);
1089 gst_alpha_chroma_key_ayuv_ayuv (const guint8 * src, guint8 * dest,
1090 gint width, gint height, GstAlpha * alpha)
1095 gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
1096 gint8 cb = alpha->cb, cr = alpha->cr;
1097 gint8 kg = alpha->kg;
1098 guint8 accept_angle_tg = alpha->accept_angle_tg;
1099 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1100 guint8 one_over_kc = alpha->one_over_kc;
1101 guint8 kfgy_scale = alpha->kfgy_scale;
1102 guint noise_level2 = alpha->noise_level2;
1104 smin = 128 - alpha->black_sensitivity;
1105 smax = 128 + alpha->white_sensitivity;
1107 if (alpha->in_sdtv == alpha->out_sdtv) {
1108 for (i = 0; i < height; i++) {
1109 for (j = 0; j < width; j++) {
1110 a = (src[0] * pa) >> 8;
1115 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1116 smin, smax, accept_angle_tg, accept_angle_ctg,
1117 one_over_kc, kfgy_scale, kg, noise_level2);
1135 alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1136 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1138 for (i = 0; i < height; i++) {
1139 for (j = 0; j < width; j++) {
1140 a = (src[0] * pa) >> 8;
1141 y = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
1142 u = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]) - 128;
1143 v = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]) - 128;
1145 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1146 smin, smax, accept_angle_tg, accept_angle_ctg,
1147 one_over_kc, kfgy_scale, kg, noise_level2);
1165 gst_alpha_set_rgb_ayuv (const guint8 * src, guint8 * dest, gint width,
1166 gint height, GstAlpha * alpha)
1168 gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1175 bpp = gst_video_format_get_pixel_stride (alpha->in_format, 0);
1178 gst_video_format_get_component_offset (alpha->in_format, 0, width,
1181 gst_video_format_get_component_offset (alpha->in_format, 1, width,
1184 gst_video_format_get_component_offset (alpha->in_format, 2, width,
1188 alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
1189 cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
1191 for (i = 0; i < height; i++) {
1192 for (j = 0; j < width; j++) {
1195 y = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[2]]);
1196 u = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[2]]);
1197 v = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[2]]);
1210 gst_alpha_chroma_key_rgb_ayuv (const guint8 * src, guint8 * dest, gint width,
1211 gint height, GstAlpha * alpha)
1217 gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1218 gint8 cb = alpha->cb, cr = alpha->cr;
1219 gint8 kg = alpha->kg;
1220 guint8 accept_angle_tg = alpha->accept_angle_tg;
1221 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1222 guint8 one_over_kc = alpha->one_over_kc;
1223 guint8 kfgy_scale = alpha->kfgy_scale;
1224 guint noise_level2 = alpha->noise_level2;
1229 bpp = gst_video_format_get_pixel_stride (alpha->in_format, 0);
1232 gst_video_format_get_component_offset (alpha->in_format, 0, width,
1235 gst_video_format_get_component_offset (alpha->in_format, 1, width,
1238 gst_video_format_get_component_offset (alpha->in_format, 2, width,
1241 smin = 128 - alpha->black_sensitivity;
1242 smax = 128 + alpha->white_sensitivity;
1245 alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
1246 cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
1248 for (i = 0; i < height; i++) {
1249 for (j = 0; j < width; j++) {
1255 y = APPLY_MATRIX (matrix, 0, r, g, b);
1256 u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
1257 v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
1259 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1260 smin, smax, accept_angle_tg, accept_angle_ctg,
1261 one_over_kc, kfgy_scale, kg, noise_level2);
1278 gst_alpha_set_rgb_argb (const guint8 * src, guint8 * dest, gint width,
1279 gint height, GstAlpha * alpha)
1281 gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1286 bpp = gst_video_format_get_pixel_stride (alpha->in_format, 0);
1289 gst_video_format_get_component_offset (alpha->in_format, 0, width,
1292 gst_video_format_get_component_offset (alpha->in_format, 1, width,
1295 gst_video_format_get_component_offset (alpha->in_format, 2, width,
1299 gst_video_format_get_component_offset (alpha->out_format, 3, width,
1302 gst_video_format_get_component_offset (alpha->out_format, 0, width,
1305 gst_video_format_get_component_offset (alpha->out_format, 1, width,
1308 gst_video_format_get_component_offset (alpha->out_format, 2, width,
1311 for (i = 0; i < height; i++) {
1312 for (j = 0; j < width; j++) {
1313 dest[p[0]] = s_alpha;
1315 dest[p[1]] = src[o[0]];
1316 dest[p[2]] = src[o[1]];
1317 dest[p[3]] = src[o[2]];
1326 gst_alpha_chroma_key_rgb_argb (const guint8 * src, guint8 * dest, gint width,
1327 gint height, GstAlpha * alpha)
1333 gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1334 gint8 cb = alpha->cb, cr = alpha->cr;
1335 gint8 kg = alpha->kg;
1336 guint8 accept_angle_tg = alpha->accept_angle_tg;
1337 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1338 guint8 one_over_kc = alpha->one_over_kc;
1339 guint8 kfgy_scale = alpha->kfgy_scale;
1340 guint noise_level2 = alpha->noise_level2;
1341 gint matrix[12], matrix2[12];
1345 bpp = gst_video_format_get_pixel_stride (alpha->in_format, 0);
1348 gst_video_format_get_component_offset (alpha->in_format, 0, width,
1351 gst_video_format_get_component_offset (alpha->in_format, 1, width,
1354 gst_video_format_get_component_offset (alpha->in_format, 2, width,
1358 gst_video_format_get_component_offset (alpha->out_format, 3, width,
1361 gst_video_format_get_component_offset (alpha->out_format, 0, width,
1364 gst_video_format_get_component_offset (alpha->out_format, 1, width,
1367 gst_video_format_get_component_offset (alpha->out_format, 2, width,
1370 smin = 128 - alpha->black_sensitivity;
1371 smax = 128 + alpha->white_sensitivity;
1373 memcpy (matrix, cog_rgb_to_ycbcr_matrix_8bit_sdtv, 12 * sizeof (gint));
1374 memcpy (matrix2, cog_ycbcr_to_rgb_matrix_8bit_sdtv, 12 * sizeof (gint));
1376 for (i = 0; i < height; i++) {
1377 for (j = 0; j < width; j++) {
1383 y = APPLY_MATRIX (matrix, 0, r, g, b);
1384 u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
1385 v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
1387 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1388 smin, smax, accept_angle_tg, accept_angle_ctg,
1389 one_over_kc, kfgy_scale, kg, noise_level2);
1394 r = APPLY_MATRIX (matrix2, 0, y, u, v);
1395 g = APPLY_MATRIX (matrix2, 1, y, u, v);
1396 b = APPLY_MATRIX (matrix2, 2, y, u, v);
1399 dest[p[1]] = CLAMP (r, 0, 255);
1400 dest[p[2]] = CLAMP (g, 0, 255);
1401 dest[p[3]] = CLAMP (b, 0, 255);
1410 gst_alpha_set_planar_yuv_ayuv (const guint8 * src, guint8 * dest, gint width,
1411 gint height, GstAlpha * alpha)
1413 gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1414 const guint8 *srcY, *srcY_tmp;
1415 const guint8 *srcU, *srcU_tmp;
1416 const guint8 *srcV, *srcV_tmp;
1418 gint y_stride, uv_stride;
1419 gint v_subs, h_subs;
1421 y_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
1422 uv_stride = gst_video_format_get_row_stride (alpha->in_format, 1, width);
1424 srcY_tmp = srcY = src;
1426 src + gst_video_format_get_component_offset (alpha->in_format, 1, width,
1429 src + gst_video_format_get_component_offset (alpha->in_format, 2, width,
1432 switch (alpha->in_format) {
1433 case GST_VIDEO_FORMAT_I420:
1434 case GST_VIDEO_FORMAT_YV12:
1435 v_subs = h_subs = 2;
1437 case GST_VIDEO_FORMAT_Y444:
1438 v_subs = h_subs = 1;
1440 case GST_VIDEO_FORMAT_Y42B:
1444 case GST_VIDEO_FORMAT_Y41B:
1449 g_assert_not_reached ();
1453 if (alpha->in_sdtv == alpha->out_sdtv) {
1454 for (i = 0; i < height; i++) {
1455 for (j = 0; j < width; j++) {
1463 if ((j + 1) % h_subs == 0) {
1469 srcY_tmp = srcY = srcY_tmp + y_stride;
1470 if ((i + 1) % v_subs == 0) {
1471 srcU_tmp = srcU = srcU_tmp + uv_stride;
1472 srcV_tmp = srcV = srcV_tmp + uv_stride;
1483 alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1484 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1486 for (i = 0; i < height; i++) {
1487 for (j = 0; j < width; j++) {
1494 dest[1] = APPLY_MATRIX (matrix, 0, y, u, v);
1495 dest[2] = APPLY_MATRIX (matrix, 1, y, u, v);
1496 dest[3] = APPLY_MATRIX (matrix, 2, y, u, v);
1500 if ((j + 1) % h_subs == 0) {
1506 srcY_tmp = srcY = srcY_tmp + y_stride;
1507 if ((i + 1) % v_subs == 0) {
1508 srcU_tmp = srcU = srcU_tmp + uv_stride;
1509 srcV_tmp = srcV = srcV_tmp + uv_stride;
1519 gst_alpha_chroma_key_planar_yuv_ayuv (const guint8 * src, guint8 * dest,
1520 gint width, gint height, GstAlpha * alpha)
1522 gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1523 const guint8 *srcY, *srcY_tmp;
1524 const guint8 *srcU, *srcU_tmp;
1525 const guint8 *srcV, *srcV_tmp;
1528 gint y_stride, uv_stride;
1529 gint v_subs, h_subs;
1530 gint smin = 128 - alpha->black_sensitivity;
1531 gint smax = 128 + alpha->white_sensitivity;
1532 gint8 cb = alpha->cb, cr = alpha->cr;
1533 gint8 kg = alpha->kg;
1534 guint8 accept_angle_tg = alpha->accept_angle_tg;
1535 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1536 guint8 one_over_kc = alpha->one_over_kc;
1537 guint8 kfgy_scale = alpha->kfgy_scale;
1538 guint noise_level2 = alpha->noise_level2;
1540 y_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
1541 uv_stride = gst_video_format_get_row_stride (alpha->in_format, 1, width);
1543 srcY_tmp = srcY = src;
1545 src + gst_video_format_get_component_offset (alpha->in_format, 1, width,
1548 src + gst_video_format_get_component_offset (alpha->in_format, 2, width,
1551 switch (alpha->in_format) {
1552 case GST_VIDEO_FORMAT_I420:
1553 case GST_VIDEO_FORMAT_YV12:
1554 v_subs = h_subs = 2;
1556 case GST_VIDEO_FORMAT_Y444:
1557 v_subs = h_subs = 1;
1559 case GST_VIDEO_FORMAT_Y42B:
1563 case GST_VIDEO_FORMAT_Y41B:
1568 g_assert_not_reached ();
1572 if (alpha->in_sdtv == alpha->out_sdtv) {
1573 for (i = 0; i < height; i++) {
1574 for (j = 0; j < width; j++) {
1580 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
1581 smax, accept_angle_tg, accept_angle_ctg,
1582 one_over_kc, kfgy_scale, kg, noise_level2);
1594 if ((j + 1) % h_subs == 0) {
1600 srcY_tmp = srcY = srcY_tmp + y_stride;
1601 if ((i + 1) % v_subs == 0) {
1602 srcU_tmp = srcU = srcU_tmp + uv_stride;
1603 srcV_tmp = srcV = srcV_tmp + uv_stride;
1613 alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1614 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1616 for (i = 0; i < height; i++) {
1617 for (j = 0; j < width; j++) {
1619 y = APPLY_MATRIX (matrix, 0, srcY[0], srcU[0], srcV[0]);
1620 u = APPLY_MATRIX (matrix, 1, srcY[0], srcU[0], srcV[0]) - 128;
1621 v = APPLY_MATRIX (matrix, 2, srcY[0], srcU[0], srcV[0]) - 128;
1623 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
1624 smax, accept_angle_tg, accept_angle_ctg,
1625 one_over_kc, kfgy_scale, kg, noise_level2);
1634 if ((j + 1) % h_subs == 0) {
1640 srcY_tmp = srcY = srcY_tmp + y_stride;
1641 if ((i + 1) % v_subs == 0) {
1642 srcU_tmp = srcU = srcU_tmp + uv_stride;
1643 srcV_tmp = srcV = srcV_tmp + uv_stride;
1653 gst_alpha_set_planar_yuv_argb (const guint8 * src, guint8 * dest, gint width,
1654 gint height, GstAlpha * alpha)
1656 gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1657 const guint8 *srcY, *srcY_tmp;
1658 const guint8 *srcU, *srcU_tmp;
1659 const guint8 *srcV, *srcV_tmp;
1661 gint y_stride, uv_stride;
1662 gint v_subs, h_subs;
1669 gst_video_format_get_component_offset (alpha->out_format, 3, width,
1672 gst_video_format_get_component_offset (alpha->out_format, 0, width,
1675 gst_video_format_get_component_offset (alpha->out_format, 1, width,
1678 gst_video_format_get_component_offset (alpha->out_format, 2, width,
1681 y_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
1682 uv_stride = gst_video_format_get_row_stride (alpha->in_format, 1, width);
1684 srcY_tmp = srcY = src;
1686 src + gst_video_format_get_component_offset (alpha->in_format, 1, width,
1689 src + gst_video_format_get_component_offset (alpha->in_format, 2, width,
1692 switch (alpha->in_format) {
1693 case GST_VIDEO_FORMAT_I420:
1694 case GST_VIDEO_FORMAT_YV12:
1695 v_subs = h_subs = 2;
1697 case GST_VIDEO_FORMAT_Y444:
1698 v_subs = h_subs = 1;
1700 case GST_VIDEO_FORMAT_Y42B:
1704 case GST_VIDEO_FORMAT_Y41B:
1709 g_assert_not_reached ();
1714 alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
1715 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
1717 for (i = 0; i < height; i++) {
1718 for (j = 0; j < width; j++) {
1725 r = APPLY_MATRIX (matrix, 0, y, u, v);
1726 g = APPLY_MATRIX (matrix, 1, y, u, v);
1727 b = APPLY_MATRIX (matrix, 2, y, u, v);
1728 dest[p[1]] = CLAMP (r, 0, 255);
1729 dest[p[2]] = CLAMP (g, 0, 255);
1730 dest[p[3]] = CLAMP (b, 0, 255);
1734 if ((j + 1) % h_subs == 0) {
1740 srcY_tmp = srcY = srcY_tmp + y_stride;
1741 if ((i + 1) % v_subs == 0) {
1742 srcU_tmp = srcU = srcU_tmp + uv_stride;
1743 srcV_tmp = srcV = srcV_tmp + uv_stride;
1752 gst_alpha_chroma_key_planar_yuv_argb (const guint8 * src, guint8 * dest,
1753 gint width, gint height, GstAlpha * alpha)
1755 gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1756 const guint8 *srcY, *srcY_tmp;
1757 const guint8 *srcU, *srcU_tmp;
1758 const guint8 *srcV, *srcV_tmp;
1762 gint y_stride, uv_stride;
1763 gint v_subs, h_subs;
1764 gint smin = 128 - alpha->black_sensitivity;
1765 gint smax = 128 + alpha->white_sensitivity;
1766 gint8 cb = alpha->cb, cr = alpha->cr;
1767 gint8 kg = alpha->kg;
1768 guint8 accept_angle_tg = alpha->accept_angle_tg;
1769 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1770 guint8 one_over_kc = alpha->one_over_kc;
1771 guint8 kfgy_scale = alpha->kfgy_scale;
1772 guint noise_level2 = alpha->noise_level2;
1777 gst_video_format_get_component_offset (alpha->out_format, 3, width,
1780 gst_video_format_get_component_offset (alpha->out_format, 0, width,
1783 gst_video_format_get_component_offset (alpha->out_format, 1, width,
1786 gst_video_format_get_component_offset (alpha->out_format, 2, width,
1789 y_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
1790 uv_stride = gst_video_format_get_row_stride (alpha->in_format, 1, width);
1792 srcY_tmp = srcY = src;
1794 src + gst_video_format_get_component_offset (alpha->in_format, 1, width,
1797 src + gst_video_format_get_component_offset (alpha->in_format, 2, width,
1800 switch (alpha->in_format) {
1801 case GST_VIDEO_FORMAT_I420:
1802 case GST_VIDEO_FORMAT_YV12:
1803 v_subs = h_subs = 2;
1805 case GST_VIDEO_FORMAT_Y444:
1806 v_subs = h_subs = 1;
1808 case GST_VIDEO_FORMAT_Y42B:
1812 case GST_VIDEO_FORMAT_Y41B:
1817 g_assert_not_reached ();
1822 alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
1823 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
1825 for (i = 0; i < height; i++) {
1826 for (j = 0; j < width; j++) {
1832 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
1833 smax, accept_angle_tg, accept_angle_ctg,
1834 one_over_kc, kfgy_scale, kg, noise_level2);
1840 r = APPLY_MATRIX (matrix, 0, y, u, v);
1841 g = APPLY_MATRIX (matrix, 1, y, u, v);
1842 b = APPLY_MATRIX (matrix, 2, y, u, v);
1843 dest[p[1]] = CLAMP (r, 0, 255);
1844 dest[p[2]] = CLAMP (g, 0, 255);
1845 dest[p[3]] = CLAMP (b, 0, 255);
1849 if ((j + 1) % h_subs == 0) {
1855 srcY_tmp = srcY = srcY_tmp + y_stride;
1856 if ((i + 1) % v_subs == 0) {
1857 srcU_tmp = srcU = srcU_tmp + uv_stride;
1858 srcV_tmp = srcV = srcV_tmp + uv_stride;
1867 gst_alpha_set_packed_422_ayuv (const guint8 * src, guint8 * dest, gint width,
1868 gint height, GstAlpha * alpha)
1870 gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1873 gint p[4]; /* Y U Y V */
1875 const guint8 *src_tmp;
1877 src_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
1880 gst_video_format_get_component_offset (alpha->in_format, 0, width,
1884 gst_video_format_get_component_offset (alpha->in_format, 1, width,
1887 gst_video_format_get_component_offset (alpha->in_format, 2, width,
1890 if (alpha->in_sdtv != alpha->out_sdtv) {
1894 alpha->in_sdtv ? cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit :
1895 cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit, 12 * sizeof (gint));
1897 for (i = 0; i < height; i++) {
1900 for (j = 0; j < width - 1; j += 2) {
1904 y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
1905 u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]);
1906 v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]);
1912 y = APPLY_MATRIX (matrix, 0, src[p[2]], src[p[1]], src[p[3]]);
1913 u = APPLY_MATRIX (matrix, 1, src[p[2]], src[p[1]], src[p[3]]);
1914 v = APPLY_MATRIX (matrix, 2, src[p[2]], src[p[1]], src[p[3]]);
1924 if (j == width - 1) {
1927 y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
1928 u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]);
1929 v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]);
1938 src = src_tmp + src_stride;
1941 for (i = 0; i < height; i++) {
1944 for (j = 0; j < width - 1; j += 2) {
1966 if (j == width - 1) {
1980 src = src_tmp + src_stride;
1986 gst_alpha_chroma_key_packed_422_ayuv (const guint8 * src, guint8 * dest,
1987 gint width, gint height, GstAlpha * alpha)
1992 gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1993 gint8 cb = alpha->cb, cr = alpha->cr;
1994 gint8 kg = alpha->kg;
1995 guint8 accept_angle_tg = alpha->accept_angle_tg;
1996 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1997 guint8 one_over_kc = alpha->one_over_kc;
1998 guint8 kfgy_scale = alpha->kfgy_scale;
1999 guint noise_level2 = alpha->noise_level2;
2000 gint p[4]; /* Y U Y V */
2002 const guint8 *src_tmp;
2004 src_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
2007 gst_video_format_get_component_offset (alpha->in_format, 0, width,
2011 gst_video_format_get_component_offset (alpha->in_format, 1, width,
2014 gst_video_format_get_component_offset (alpha->in_format, 2, width,
2017 smin = 128 - alpha->black_sensitivity;
2018 smax = 128 + alpha->white_sensitivity;
2020 if (alpha->in_sdtv != alpha->out_sdtv) {
2024 alpha->in_sdtv ? cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit :
2025 cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit, 12 * sizeof (gint));
2027 for (i = 0; i < height; i++) {
2030 for (j = 0; j < width - 1; j += 2) {
2031 y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
2032 u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]) - 128;
2033 v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]) - 128;
2035 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2036 smin, smax, accept_angle_tg, accept_angle_ctg,
2037 one_over_kc, kfgy_scale, kg, noise_level2);
2044 y = APPLY_MATRIX (matrix, 0, src[p[2]], src[p[1]], src[p[3]]);
2045 u = APPLY_MATRIX (matrix, 1, src[p[2]], src[p[1]], src[p[3]]) - 128;
2046 v = APPLY_MATRIX (matrix, 2, src[p[2]], src[p[1]], src[p[3]]) - 128;
2048 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2049 smin, smax, accept_angle_tg, accept_angle_ctg,
2050 one_over_kc, kfgy_scale, kg, noise_level2);
2061 if (j == width - 1) {
2062 y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
2063 u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]) - 128;
2064 v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]) - 128;
2066 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2067 smin, smax, accept_angle_tg, accept_angle_ctg,
2068 one_over_kc, kfgy_scale, kg, noise_level2);
2078 src = src_tmp + src_stride;
2081 for (i = 0; i < height; i++) {
2084 for (j = 0; j < width - 1; j += 2) {
2086 u = src[p[1]] - 128;
2087 v = src[p[3]] - 128;
2089 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2090 smin, smax, accept_angle_tg, accept_angle_ctg,
2091 one_over_kc, kfgy_scale, kg, noise_level2);
2099 u = src[p[1]] - 128;
2100 v = src[p[3]] - 128;
2102 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2103 smin, smax, accept_angle_tg, accept_angle_ctg,
2104 one_over_kc, kfgy_scale, kg, noise_level2);
2115 if (j == width - 1) {
2117 u = src[p[1]] - 128;
2118 v = src[p[3]] - 128;
2120 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2121 smin, smax, accept_angle_tg, accept_angle_ctg,
2122 one_over_kc, kfgy_scale, kg, noise_level2);
2132 src = src_tmp + src_stride;
2138 gst_alpha_set_packed_422_argb (const guint8 * src, guint8 * dest, gint width,
2139 gint height, GstAlpha * alpha)
2141 gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
2145 const guint8 *src_tmp;
2149 src_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
2152 gst_video_format_get_component_offset (alpha->in_format, 0, width,
2156 gst_video_format_get_component_offset (alpha->in_format, 1, width,
2159 gst_video_format_get_component_offset (alpha->in_format, 2, width,
2163 gst_video_format_get_component_offset (alpha->out_format, 3, width,
2166 gst_video_format_get_component_offset (alpha->out_format, 0, width,
2169 gst_video_format_get_component_offset (alpha->out_format, 1, width,
2172 gst_video_format_get_component_offset (alpha->out_format, 2, width,
2176 alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
2177 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
2179 for (i = 0; i < height; i++) {
2182 for (j = 0; j < width - 1; j += 2) {
2183 r = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[3]]);
2184 g = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[3]]);
2185 b = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[3]]);
2187 dest[p[0]] = s_alpha;
2188 dest[p[1]] = CLAMP (r, 0, 255);
2189 dest[p[2]] = CLAMP (g, 0, 255);
2190 dest[p[3]] = CLAMP (b, 0, 255);
2192 r = APPLY_MATRIX (matrix, 0, src[o[2]], src[o[1]], src[o[3]]);
2193 g = APPLY_MATRIX (matrix, 1, src[o[2]], src[o[1]], src[o[3]]);
2194 b = APPLY_MATRIX (matrix, 2, src[o[2]], src[o[1]], src[o[3]]);
2196 dest[4 + p[0]] = s_alpha;
2197 dest[4 + p[1]] = CLAMP (r, 0, 255);
2198 dest[4 + p[2]] = CLAMP (g, 0, 255);
2199 dest[4 + p[3]] = CLAMP (b, 0, 255);
2205 if (j == width - 1) {
2206 r = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[3]]);
2207 g = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[3]]);
2208 b = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[3]]);
2210 dest[p[0]] = s_alpha;
2211 dest[p[1]] = CLAMP (r, 0, 255);
2212 dest[p[2]] = CLAMP (g, 0, 255);
2213 dest[p[3]] = CLAMP (b, 0, 255);
2218 src = src_tmp + src_stride;
2223 gst_alpha_chroma_key_packed_422_argb (const guint8 * src, guint8 * dest,
2224 gint width, gint height, GstAlpha * alpha)
2230 gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
2231 gint8 cb = alpha->cb, cr = alpha->cr;
2232 gint8 kg = alpha->kg;
2233 guint8 accept_angle_tg = alpha->accept_angle_tg;
2234 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
2235 guint8 one_over_kc = alpha->one_over_kc;
2236 guint8 kfgy_scale = alpha->kfgy_scale;
2237 guint noise_level2 = alpha->noise_level2;
2240 const guint8 *src_tmp;
2243 src_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
2246 gst_video_format_get_component_offset (alpha->in_format, 0, width,
2250 gst_video_format_get_component_offset (alpha->in_format, 1, width,
2253 gst_video_format_get_component_offset (alpha->in_format, 2, width,
2257 gst_video_format_get_component_offset (alpha->out_format, 3, width,
2260 gst_video_format_get_component_offset (alpha->out_format, 0, width,
2263 gst_video_format_get_component_offset (alpha->out_format, 1, width,
2266 gst_video_format_get_component_offset (alpha->out_format, 2, width,
2270 alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
2271 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
2273 smin = 128 - alpha->black_sensitivity;
2274 smax = 128 + alpha->white_sensitivity;
2276 for (i = 0; i < height; i++) {
2279 for (j = 0; j < width - 1; j += 2) {
2281 u = src[o[1]] - 128;
2282 v = src[o[3]] - 128;
2284 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2285 smin, smax, accept_angle_tg, accept_angle_ctg,
2286 one_over_kc, kfgy_scale, kg, noise_level2);
2290 r = APPLY_MATRIX (matrix, 0, y, u, v);
2291 g = APPLY_MATRIX (matrix, 1, y, u, v);
2292 b = APPLY_MATRIX (matrix, 2, y, u, v);
2295 dest[p[1]] = CLAMP (r, 0, 255);
2296 dest[p[2]] = CLAMP (g, 0, 255);
2297 dest[p[3]] = CLAMP (b, 0, 255);
2300 u = src[o[1]] - 128;
2301 v = src[o[3]] - 128;
2303 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2304 smin, smax, accept_angle_tg, accept_angle_ctg,
2305 one_over_kc, kfgy_scale, kg, noise_level2);
2309 r = APPLY_MATRIX (matrix, 0, y, u, v);
2310 g = APPLY_MATRIX (matrix, 1, y, u, v);
2311 b = APPLY_MATRIX (matrix, 2, y, u, v);
2314 dest[4 + p[1]] = CLAMP (r, 0, 255);
2315 dest[4 + p[2]] = CLAMP (g, 0, 255);
2316 dest[4 + p[3]] = CLAMP (b, 0, 255);
2322 if (j == width - 1) {
2324 u = src[o[1]] - 128;
2325 v = src[o[3]] - 128;
2327 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2328 smin, smax, accept_angle_tg, accept_angle_ctg,
2329 one_over_kc, kfgy_scale, kg, noise_level2);
2333 r = APPLY_MATRIX (matrix, 0, y, u, v);
2334 g = APPLY_MATRIX (matrix, 1, y, u, v);
2335 b = APPLY_MATRIX (matrix, 2, y, u, v);
2338 dest[p[1]] = CLAMP (r, 0, 255);
2339 dest[p[2]] = CLAMP (g, 0, 255);
2340 dest[p[3]] = CLAMP (b, 0, 255);
2345 src = src_tmp + src_stride;
2349 /* Protected with the alpha lock */
2351 gst_alpha_init_params (GstAlpha * alpha)
2359 /* RGB->RGB: convert to SDTV YUV, chroma keying, convert back
2360 * YUV->RGB: chroma keying, convert to RGB
2361 * RGB->YUV: convert to YUV, chroma keying
2362 * YUV->YUV: convert matrix, chroma keying
2364 if (gst_video_format_is_rgb (alpha->in_format)
2365 && gst_video_format_is_rgb (alpha->out_format))
2366 matrix = cog_rgb_to_ycbcr_matrix_8bit_sdtv;
2367 else if (gst_video_format_is_yuv (alpha->in_format)
2368 && gst_video_format_is_rgb (alpha->out_format))
2370 (alpha->in_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
2371 cog_rgb_to_ycbcr_matrix_8bit_hdtv;
2372 else if (gst_video_format_is_rgb (alpha->in_format)
2373 && gst_video_format_is_yuv (alpha->out_format))
2375 (alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
2376 cog_rgb_to_ycbcr_matrix_8bit_hdtv;
2377 else /* yuv -> yuv */
2379 (alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
2380 cog_rgb_to_ycbcr_matrix_8bit_hdtv;
2382 y = (matrix[0] * ((gint) alpha->target_r) +
2383 matrix[1] * ((gint) alpha->target_g) +
2384 matrix[2] * ((gint) alpha->target_b) + matrix[3]) >> 8;
2385 /* Cb,Cr without offset here because the chroma keying
2386 * works with them being in range [-128,127]
2389 (matrix[4] * ((gint) alpha->target_r) +
2390 matrix[5] * ((gint) alpha->target_g) +
2391 matrix[6] * ((gint) alpha->target_b)) >> 8;
2393 (matrix[8] * ((gint) alpha->target_r) +
2394 matrix[9] * ((gint) alpha->target_g) +
2395 matrix[10] * ((gint) alpha->target_b)) >> 8;
2397 kgl = sqrt (tmp1 * tmp1 + tmp2 * tmp2);
2398 alpha->cb = 127 * (tmp1 / kgl);
2399 alpha->cr = 127 * (tmp2 / kgl);
2401 tmp = 15 * tan (M_PI * alpha->angle / 180);
2402 tmp = MIN (tmp, 255);
2403 alpha->accept_angle_tg = tmp;
2404 tmp = 15 / tan (M_PI * alpha->angle / 180);
2405 tmp = MIN (tmp, 255);
2406 alpha->accept_angle_ctg = tmp;
2408 alpha->one_over_kc = 255 * 2 * tmp - 255;
2410 tmp = MIN (tmp, 255);
2411 alpha->kfgy_scale = tmp;
2412 alpha->kg = MIN (kgl, 127);
2414 alpha->noise_level2 = alpha->noise_level * alpha->noise_level;
2417 /* Protected with the alpha lock */
2419 gst_alpha_set_process_function (GstAlpha * alpha)
2421 alpha->process = NULL;
2423 switch (alpha->method) {
2424 case ALPHA_METHOD_SET:
2425 switch (alpha->out_format) {
2426 case GST_VIDEO_FORMAT_AYUV:
2427 switch (alpha->in_format) {
2428 case GST_VIDEO_FORMAT_AYUV:
2429 alpha->process = gst_alpha_set_ayuv_ayuv;
2431 case GST_VIDEO_FORMAT_Y444:
2432 case GST_VIDEO_FORMAT_Y42B:
2433 case GST_VIDEO_FORMAT_I420:
2434 case GST_VIDEO_FORMAT_YV12:
2435 case GST_VIDEO_FORMAT_Y41B:
2436 alpha->process = gst_alpha_set_planar_yuv_ayuv;
2438 case GST_VIDEO_FORMAT_YUY2:
2439 case GST_VIDEO_FORMAT_YVYU:
2440 case GST_VIDEO_FORMAT_UYVY:
2441 alpha->process = gst_alpha_set_packed_422_ayuv;
2443 case GST_VIDEO_FORMAT_ARGB:
2444 case GST_VIDEO_FORMAT_ABGR:
2445 case GST_VIDEO_FORMAT_RGBA:
2446 case GST_VIDEO_FORMAT_BGRA:
2447 alpha->process = gst_alpha_set_argb_ayuv;
2449 case GST_VIDEO_FORMAT_xRGB:
2450 case GST_VIDEO_FORMAT_xBGR:
2451 case GST_VIDEO_FORMAT_RGBx:
2452 case GST_VIDEO_FORMAT_BGRx:
2453 case GST_VIDEO_FORMAT_RGB:
2454 case GST_VIDEO_FORMAT_BGR:
2455 alpha->process = gst_alpha_set_rgb_ayuv;
2461 case GST_VIDEO_FORMAT_ARGB:
2462 case GST_VIDEO_FORMAT_ABGR:
2463 case GST_VIDEO_FORMAT_RGBA:
2464 case GST_VIDEO_FORMAT_BGRA:
2465 switch (alpha->in_format) {
2466 case GST_VIDEO_FORMAT_AYUV:
2467 alpha->process = gst_alpha_set_ayuv_argb;
2469 case GST_VIDEO_FORMAT_Y444:
2470 case GST_VIDEO_FORMAT_Y42B:
2471 case GST_VIDEO_FORMAT_I420:
2472 case GST_VIDEO_FORMAT_YV12:
2473 case GST_VIDEO_FORMAT_Y41B:
2474 alpha->process = gst_alpha_set_planar_yuv_argb;
2476 case GST_VIDEO_FORMAT_YUY2:
2477 case GST_VIDEO_FORMAT_YVYU:
2478 case GST_VIDEO_FORMAT_UYVY:
2479 alpha->process = gst_alpha_set_packed_422_argb;
2481 case GST_VIDEO_FORMAT_ARGB:
2482 case GST_VIDEO_FORMAT_ABGR:
2483 case GST_VIDEO_FORMAT_RGBA:
2484 case GST_VIDEO_FORMAT_BGRA:
2485 alpha->process = gst_alpha_set_argb_argb;
2487 case GST_VIDEO_FORMAT_xRGB:
2488 case GST_VIDEO_FORMAT_xBGR:
2489 case GST_VIDEO_FORMAT_RGBx:
2490 case GST_VIDEO_FORMAT_BGRx:
2491 case GST_VIDEO_FORMAT_RGB:
2492 case GST_VIDEO_FORMAT_BGR:
2493 alpha->process = gst_alpha_set_rgb_argb;
2504 case ALPHA_METHOD_GREEN:
2505 case ALPHA_METHOD_BLUE:
2506 case ALPHA_METHOD_CUSTOM:
2507 switch (alpha->out_format) {
2508 case GST_VIDEO_FORMAT_AYUV:
2509 switch (alpha->in_format) {
2510 case GST_VIDEO_FORMAT_AYUV:
2511 alpha->process = gst_alpha_chroma_key_ayuv_ayuv;
2513 case GST_VIDEO_FORMAT_Y444:
2514 case GST_VIDEO_FORMAT_Y42B:
2515 case GST_VIDEO_FORMAT_I420:
2516 case GST_VIDEO_FORMAT_YV12:
2517 case GST_VIDEO_FORMAT_Y41B:
2518 alpha->process = gst_alpha_chroma_key_planar_yuv_ayuv;
2520 case GST_VIDEO_FORMAT_YUY2:
2521 case GST_VIDEO_FORMAT_YVYU:
2522 case GST_VIDEO_FORMAT_UYVY:
2523 alpha->process = gst_alpha_chroma_key_packed_422_ayuv;
2525 case GST_VIDEO_FORMAT_ARGB:
2526 case GST_VIDEO_FORMAT_ABGR:
2527 case GST_VIDEO_FORMAT_RGBA:
2528 case GST_VIDEO_FORMAT_BGRA:
2529 alpha->process = gst_alpha_chroma_key_argb_ayuv;
2531 case GST_VIDEO_FORMAT_xRGB:
2532 case GST_VIDEO_FORMAT_xBGR:
2533 case GST_VIDEO_FORMAT_RGBx:
2534 case GST_VIDEO_FORMAT_BGRx:
2535 case GST_VIDEO_FORMAT_RGB:
2536 case GST_VIDEO_FORMAT_BGR:
2537 alpha->process = gst_alpha_chroma_key_rgb_ayuv;
2543 case GST_VIDEO_FORMAT_ARGB:
2544 case GST_VIDEO_FORMAT_ABGR:
2545 case GST_VIDEO_FORMAT_RGBA:
2546 case GST_VIDEO_FORMAT_BGRA:
2547 switch (alpha->in_format) {
2548 case GST_VIDEO_FORMAT_AYUV:
2549 alpha->process = gst_alpha_chroma_key_ayuv_argb;
2551 case GST_VIDEO_FORMAT_Y444:
2552 case GST_VIDEO_FORMAT_Y42B:
2553 case GST_VIDEO_FORMAT_I420:
2554 case GST_VIDEO_FORMAT_YV12:
2555 case GST_VIDEO_FORMAT_Y41B:
2556 alpha->process = gst_alpha_chroma_key_planar_yuv_argb;
2558 case GST_VIDEO_FORMAT_YUY2:
2559 case GST_VIDEO_FORMAT_YVYU:
2560 case GST_VIDEO_FORMAT_UYVY:
2561 alpha->process = gst_alpha_chroma_key_packed_422_argb;
2563 case GST_VIDEO_FORMAT_ARGB:
2564 case GST_VIDEO_FORMAT_ABGR:
2565 case GST_VIDEO_FORMAT_RGBA:
2566 case GST_VIDEO_FORMAT_BGRA:
2567 alpha->process = gst_alpha_chroma_key_argb_argb;
2569 case GST_VIDEO_FORMAT_xRGB:
2570 case GST_VIDEO_FORMAT_xBGR:
2571 case GST_VIDEO_FORMAT_RGBx:
2572 case GST_VIDEO_FORMAT_BGRx:
2573 case GST_VIDEO_FORMAT_RGB:
2574 case GST_VIDEO_FORMAT_BGR:
2575 alpha->process = gst_alpha_chroma_key_rgb_argb;
2589 return alpha->process != NULL;
2593 gst_alpha_start (GstBaseTransform * btrans)
2595 GstAlpha *alpha = GST_ALPHA (btrans);
2597 GST_ALPHA_LOCK (alpha);
2598 gst_alpha_init_params (alpha);
2599 GST_ALPHA_UNLOCK (alpha);
2605 gst_alpha_before_transform (GstBaseTransform * btrans, GstBuffer * buf)
2607 GstAlpha *alpha = GST_ALPHA (btrans);
2608 GstClockTime timestamp;
2610 timestamp = gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME,
2611 GST_BUFFER_TIMESTAMP (buf));
2612 GST_LOG ("Got stream time of %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
2613 if (GST_CLOCK_TIME_IS_VALID (timestamp))
2614 gst_object_sync_values (G_OBJECT (alpha), timestamp);
2617 static GstFlowReturn
2618 gst_alpha_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out)
2620 GstAlpha *alpha = GST_ALPHA (btrans);
2623 GST_ALPHA_LOCK (alpha);
2625 if (G_UNLIKELY (!alpha->process)) {
2626 GST_ERROR_OBJECT (alpha, "Not negotiated yet");
2627 GST_ALPHA_UNLOCK (alpha);
2628 return GST_FLOW_NOT_NEGOTIATED;
2631 width = alpha->width;
2632 height = alpha->height;
2634 alpha->process (GST_BUFFER_DATA (in),
2635 GST_BUFFER_DATA (out), width, height, alpha);
2637 GST_ALPHA_UNLOCK (alpha);
2643 plugin_init (GstPlugin * plugin)
2645 gst_controller_init (NULL, NULL);
2647 return gst_element_register (plugin, "alpha", GST_RANK_NONE, GST_TYPE_ALPHA);
2650 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2653 "adds an alpha channel to video - constant or via chroma-keying",
2654 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)