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 #define GST_ALPHA_LOCK(alpha) G_STMT_START { \
165 GST_LOG_OBJECT (alpha, "Locking alpha from thread %p", g_thread_self ()); \
166 g_static_mutex_lock (&alpha->lock); \
167 GST_LOG_OBJECT (alpha, "Locked alpha from thread %p", g_thread_self ()); \
170 #define GST_ALPHA_UNLOCK(alpha) G_STMT_START { \
171 GST_LOG_OBJECT (alpha, "Unlocking alpha from thread %p", g_thread_self ()); \
172 g_static_mutex_unlock (&alpha->lock); \
175 static gboolean gst_alpha_start (GstBaseTransform * trans);
176 static gboolean gst_alpha_get_unit_size (GstBaseTransform * btrans,
177 GstCaps * caps, guint * size);
178 static GstCaps *gst_alpha_transform_caps (GstBaseTransform * btrans,
179 GstPadDirection direction, GstCaps * caps);
180 static gboolean gst_alpha_set_caps (GstBaseTransform * btrans,
181 GstCaps * incaps, GstCaps * outcaps);
182 static GstFlowReturn gst_alpha_transform (GstBaseTransform * btrans,
183 GstBuffer * in, GstBuffer * out);
184 static void gst_alpha_before_transform (GstBaseTransform * btrans,
187 static void gst_alpha_init_params (GstAlpha * alpha);
188 static gboolean gst_alpha_set_process_function (GstAlpha * alpha);
190 static void gst_alpha_set_property (GObject * object, guint prop_id,
191 const GValue * value, GParamSpec * pspec);
192 static void gst_alpha_get_property (GObject * object, guint prop_id,
193 GValue * value, GParamSpec * pspec);
194 static void gst_alpha_finalize (GObject * object);
196 GST_BOILERPLATE (GstAlpha, gst_alpha, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
198 #define GST_TYPE_ALPHA_METHOD (gst_alpha_method_get_type())
200 gst_alpha_method_get_type (void)
202 static GType alpha_method_type = 0;
203 static const GEnumValue alpha_method[] = {
204 {ALPHA_METHOD_SET, "Set/adjust alpha channel", "set"},
205 {ALPHA_METHOD_GREEN, "Chroma Key green", "green"},
206 {ALPHA_METHOD_BLUE, "Chroma Key blue", "blue"},
207 {ALPHA_METHOD_CUSTOM, "Chroma Key on target_r/g/b", "custom"},
211 if (!alpha_method_type) {
212 alpha_method_type = g_enum_register_static ("GstAlphaMethod", alpha_method);
214 return alpha_method_type;
218 gst_alpha_base_init (gpointer g_class)
220 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
222 gst_element_class_set_details_simple (element_class, "Alpha filter",
223 "Filter/Effect/Video",
224 "Adds an alpha channel to video - uniform or via chroma-keying",
225 "Wim Taymans <wim@fluendo.com>\n"
226 "Edward Hervey <edward.hervey@collabora.co.uk>\n"
227 "Jan Schmidt <thaytan@noraisin.net>");
229 gst_element_class_add_static_pad_template (element_class,
230 &gst_alpha_sink_template);
231 gst_element_class_add_static_pad_template (element_class,
232 &gst_alpha_src_template);
234 GST_DEBUG_CATEGORY_INIT (gst_alpha_debug, "alpha", 0,
235 "alpha - Element for adding alpha channel to streams");
239 gst_alpha_class_init (GstAlphaClass * klass)
241 GObjectClass *gobject_class = (GObjectClass *) klass;
242 GstBaseTransformClass *btrans_class = (GstBaseTransformClass *) klass;
244 gobject_class->set_property = gst_alpha_set_property;
245 gobject_class->get_property = gst_alpha_get_property;
246 gobject_class->finalize = gst_alpha_finalize;
248 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_METHOD,
249 g_param_spec_enum ("method", "Method",
250 "How the alpha channels should be created", GST_TYPE_ALPHA_METHOD,
251 DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
252 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA,
253 g_param_spec_double ("alpha", "Alpha", "The value for the alpha channel",
254 0.0, 1.0, DEFAULT_ALPHA,
255 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
256 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_R,
257 g_param_spec_uint ("target-r", "Target Red", "The Red target", 0, 255,
259 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
260 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_G,
261 g_param_spec_uint ("target-g", "Target Green", "The Green target", 0, 255,
263 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
264 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_B,
265 g_param_spec_uint ("target-b", "Target Blue", "The Blue target", 0, 255,
267 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
268 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ANGLE,
269 g_param_spec_float ("angle", "Angle", "Size of the colorcube to change",
270 0.0, 90.0, DEFAULT_ANGLE,
271 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
272 g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NOISE_LEVEL,
273 g_param_spec_float ("noise-level", "Noise Level", "Size of noise radius",
274 0.0, 64.0, DEFAULT_NOISE_LEVEL,
275 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
276 g_object_class_install_property (G_OBJECT_CLASS (klass),
277 PROP_BLACK_SENSITIVITY, g_param_spec_uint ("black-sensitivity",
278 "Black Sensitivity", "Sensitivity to dark colors", 0, 128,
279 DEFAULT_BLACK_SENSITIVITY,
280 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
281 g_object_class_install_property (G_OBJECT_CLASS (klass),
282 PROP_WHITE_SENSITIVITY, g_param_spec_uint ("white-sensitivity",
283 "Sensitivity", "Sensitivity to bright colors", 0, 128,
284 DEFAULT_WHITE_SENSITIVITY,
285 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
286 g_object_class_install_property (G_OBJECT_CLASS (klass),
287 PROP_PREFER_PASSTHROUGH, g_param_spec_boolean ("prefer-passthrough",
288 "Prefer Passthrough",
289 "Don't do any processing for alpha=1.0 if possible",
290 DEFAULT_PREFER_PASSTHROUGH,
291 G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
293 btrans_class->start = GST_DEBUG_FUNCPTR (gst_alpha_start);
294 btrans_class->transform = GST_DEBUG_FUNCPTR (gst_alpha_transform);
295 btrans_class->before_transform =
296 GST_DEBUG_FUNCPTR (gst_alpha_before_transform);
297 btrans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_alpha_get_unit_size);
298 btrans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_alpha_transform_caps);
299 btrans_class->set_caps = GST_DEBUG_FUNCPTR (gst_alpha_set_caps);
303 gst_alpha_init (GstAlpha * alpha, GstAlphaClass * klass)
305 alpha->alpha = DEFAULT_ALPHA;
306 alpha->method = DEFAULT_METHOD;
307 alpha->target_r = DEFAULT_TARGET_R;
308 alpha->target_g = DEFAULT_TARGET_G;
309 alpha->target_b = DEFAULT_TARGET_B;
310 alpha->angle = DEFAULT_ANGLE;
311 alpha->noise_level = DEFAULT_NOISE_LEVEL;
312 alpha->black_sensitivity = DEFAULT_BLACK_SENSITIVITY;
313 alpha->white_sensitivity = DEFAULT_WHITE_SENSITIVITY;
315 g_static_mutex_init (&alpha->lock);
319 gst_alpha_finalize (GObject * object)
321 GstAlpha *alpha = GST_ALPHA (object);
323 g_static_mutex_free (&alpha->lock);
325 G_OBJECT_CLASS (parent_class)->finalize (object);
329 gst_alpha_set_property (GObject * object, guint prop_id,
330 const GValue * value, GParamSpec * pspec)
332 GstAlpha *alpha = GST_ALPHA (object);
333 gboolean reconfigure = FALSE;
335 GST_ALPHA_LOCK (alpha);
338 gint method = g_value_get_enum (value);
340 reconfigure = (method != alpha->method) && (method == ALPHA_METHOD_SET
341 || alpha->method == ALPHA_METHOD_SET) && (alpha->alpha == 1.0)
342 && (alpha->prefer_passthrough);
343 alpha->method = method;
345 switch (alpha->method) {
346 case ALPHA_METHOD_GREEN:
348 alpha->target_g = 255;
351 case ALPHA_METHOD_BLUE:
354 alpha->target_b = 255;
359 gst_alpha_set_process_function (alpha);
360 gst_alpha_init_params (alpha);
364 gdouble a = g_value_get_double (value);
366 reconfigure = (a != alpha->alpha) && (a == 1.0 || alpha->alpha == 1.0)
367 && (alpha->method == ALPHA_METHOD_SET) && (alpha->prefer_passthrough);
372 alpha->target_r = g_value_get_uint (value);
373 gst_alpha_init_params (alpha);
376 alpha->target_g = g_value_get_uint (value);
377 gst_alpha_init_params (alpha);
380 alpha->target_b = g_value_get_uint (value);
381 gst_alpha_init_params (alpha);
384 alpha->angle = g_value_get_float (value);
385 gst_alpha_init_params (alpha);
387 case PROP_NOISE_LEVEL:
388 alpha->noise_level = g_value_get_float (value);
389 gst_alpha_init_params (alpha);
391 case PROP_BLACK_SENSITIVITY:
392 alpha->black_sensitivity = g_value_get_uint (value);
394 case PROP_WHITE_SENSITIVITY:
395 alpha->white_sensitivity = g_value_get_uint (value);
397 case PROP_PREFER_PASSTHROUGH:{
398 gboolean prefer_passthrough = g_value_get_boolean (value);
400 reconfigure = ((! !prefer_passthrough) != (! !alpha->prefer_passthrough))
401 && (alpha->method == ALPHA_METHOD_SET) && (alpha->alpha == 1.0);
402 alpha->prefer_passthrough = prefer_passthrough;
406 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
411 gst_base_transform_reconfigure (GST_BASE_TRANSFORM_CAST (alpha));
413 GST_ALPHA_UNLOCK (alpha);
417 gst_alpha_get_property (GObject * object, guint prop_id, GValue * value,
420 GstAlpha *alpha = GST_ALPHA (object);
424 g_value_set_enum (value, alpha->method);
427 g_value_set_double (value, alpha->alpha);
430 g_value_set_uint (value, alpha->target_r);
433 g_value_set_uint (value, alpha->target_g);
436 g_value_set_uint (value, alpha->target_b);
439 g_value_set_float (value, alpha->angle);
441 case PROP_NOISE_LEVEL:
442 g_value_set_float (value, alpha->noise_level);
444 case PROP_BLACK_SENSITIVITY:
445 g_value_set_uint (value, alpha->black_sensitivity);
447 case PROP_WHITE_SENSITIVITY:
448 g_value_set_uint (value, alpha->white_sensitivity);
450 case PROP_PREFER_PASSTHROUGH:
451 g_value_set_boolean (value, alpha->prefer_passthrough);
454 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
460 gst_alpha_get_unit_size (GstBaseTransform * btrans,
461 GstCaps * caps, guint * size)
463 GstVideoFormat format;
466 if (!gst_video_format_parse_caps (caps, &format, &width, &height))
469 *size = gst_video_format_get_size (format, width, height);
471 GST_DEBUG_OBJECT (btrans, "unit size = %d for format %d w %d height %d",
472 *size, format, width, height);
478 gst_alpha_transform_caps (GstBaseTransform * btrans,
479 GstPadDirection direction, GstCaps * caps)
481 GstAlpha *alpha = GST_ALPHA (btrans);
482 GstCaps *ret, *tmp, *tmp2;
483 GstStructure *structure;
486 tmp = gst_caps_new_empty ();
488 GST_ALPHA_LOCK (alpha);
489 for (i = 0; i < gst_caps_get_size (caps); i++) {
490 structure = gst_structure_copy (gst_caps_get_structure (caps, i));
492 gst_structure_remove_field (structure, "format");
493 gst_structure_remove_field (structure, "endianness");
494 gst_structure_remove_field (structure, "depth");
495 gst_structure_remove_field (structure, "bpp");
496 gst_structure_remove_field (structure, "red_mask");
497 gst_structure_remove_field (structure, "green_mask");
498 gst_structure_remove_field (structure, "blue_mask");
499 gst_structure_remove_field (structure, "alpha_mask");
500 gst_structure_remove_field (structure, "color-matrix");
501 gst_structure_remove_field (structure, "chroma-site");
503 gst_structure_set_name (structure, "video/x-raw-yuv");
504 gst_caps_append_structure (tmp, gst_structure_copy (structure));
505 gst_structure_set_name (structure, "video/x-raw-rgb");
506 gst_caps_append_structure (tmp, structure);
509 if (direction == GST_PAD_SINK) {
510 tmp2 = gst_static_caps_get (&gst_alpha_alpha_caps);
511 ret = gst_caps_intersect (tmp, tmp2);
512 gst_caps_unref (tmp);
513 gst_caps_unref (tmp2);
517 if (alpha->prefer_passthrough && alpha->method == ALPHA_METHOD_SET
518 && alpha->alpha == 1.0) {
519 ret = gst_caps_copy (caps);
520 gst_caps_append (ret, tmp);
531 GST_DEBUG_OBJECT (alpha,
532 "Transformed %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT, caps, ret);
534 GST_ALPHA_UNLOCK (alpha);
540 gst_alpha_set_caps (GstBaseTransform * btrans,
541 GstCaps * incaps, GstCaps * outcaps)
543 GstAlpha *alpha = GST_ALPHA (btrans);
545 gboolean passthrough;
547 GST_ALPHA_LOCK (alpha);
549 if (!gst_video_format_parse_caps (incaps, &alpha->in_format,
550 &alpha->width, &alpha->height) ||
551 !gst_video_format_parse_caps (outcaps, &alpha->out_format,
552 &alpha->width, &alpha->height)) {
553 GST_WARNING_OBJECT (alpha,
554 "Failed to parse caps %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT, incaps,
556 GST_ALPHA_UNLOCK (alpha);
560 matrix = gst_video_parse_caps_color_matrix (incaps);
561 alpha->in_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
563 matrix = gst_video_parse_caps_color_matrix (outcaps);
564 alpha->out_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
566 passthrough = alpha->prefer_passthrough &&
567 alpha->in_format == alpha->out_format && alpha->in_sdtv == alpha->out_sdtv
568 && alpha->method == ALPHA_METHOD_SET && alpha->alpha == 1.0;
570 GST_DEBUG_OBJECT (alpha,
571 "Setting caps %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT
572 " (passthrough: %d)", incaps, outcaps, passthrough);
573 gst_base_transform_set_passthrough (btrans, passthrough);
575 if (!gst_alpha_set_process_function (alpha) && !passthrough) {
576 GST_WARNING_OBJECT (alpha,
577 "No processing function for this caps and no passthrough mode");
578 GST_ALPHA_UNLOCK (alpha);
582 gst_alpha_init_params (alpha);
584 GST_ALPHA_UNLOCK (alpha);
589 /* based on http://www.cs.utah.edu/~michael/chroma/
592 chroma_keying_yuv (gint a, gint * y, gint * u,
593 gint * v, gint cr, gint cb, gint smin, gint smax, guint8 accept_angle_tg,
594 guint8 accept_angle_ctg, guint8 one_over_kc, guint8 kfgy_scale, gint8 kg,
602 /* too dark or too bright, keep alpha */
603 if (*y < smin || *y > smax)
606 /* Convert foreground to XZ coords where X direction is defined by
608 tmp = ((*u) * cb + (*v) * cr) >> 7;
609 x = CLAMP (tmp, -128, 127);
610 tmp = ((*v) * cb - (*u) * cr) >> 7;
611 z = CLAMP (tmp, -128, 127);
613 /* WARNING: accept angle should never be set greater than "somewhat less
614 than 90 degrees" to avoid dealing with negative/infinite tg. In reality,
615 80 degrees should be enough if foreground is reasonable. If this seems
616 to be a problem, go to alternative ways of checking point position
617 (scalar product or line equations). This angle should not be too small
618 either to avoid infinite ctg (used to suppress foreground without use of
621 tmp = (x * accept_angle_tg) >> 4;
622 tmp = MIN (tmp, 127);
625 /* keep foreground Kfg = 0 */
628 /* Compute Kfg (implicitly) and Kbg, suppress foreground in XZ coord
630 tmp = (z * accept_angle_ctg) >> 4;
631 tmp = CLAMP (tmp, -128, 127);
636 tmp1 = MAX (tmp1, 0);
637 b_alpha = (tmp1 * one_over_kc) / 2;
638 b_alpha = 255 - CLAMP (b_alpha, 0, 255);
639 b_alpha = (a * b_alpha) >> 8;
641 tmp = (tmp1 * kfgy_scale) >> 4;
642 tmp1 = MIN (tmp, 255);
644 *y = (*y < tmp1) ? 0 : *y - tmp1;
646 /* Convert suppressed foreground back to CbCr */
647 tmp = (x1 * cb - y1 * cr) >> 7;
648 *u = CLAMP (tmp, -128, 127);
650 tmp = (x1 * cr + y1 * cb) >> 7;
651 *v = CLAMP (tmp, -128, 127);
653 /* Deal with noise. For now, a circle around the key color with
654 radius of noise_level treated as exact key color. Introduces
657 tmp = z * z + (x - kg) * (x - kg);
658 tmp = MIN (tmp, 0xffff);
660 if (tmp < noise_level2)
666 #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)
669 gst_alpha_set_argb_ayuv (const guint8 * src, guint8 * dest, gint width,
670 gint height, GstAlpha * alpha)
672 gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
679 gst_video_format_get_component_offset (alpha->in_format, 3, width,
682 gst_video_format_get_component_offset (alpha->in_format, 0, width,
685 gst_video_format_get_component_offset (alpha->in_format, 1, width,
688 gst_video_format_get_component_offset (alpha->in_format, 2, width,
692 alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
693 cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
695 for (i = 0; i < height; i++) {
696 for (j = 0; j < width; j++) {
697 dest[0] = (src[o[0]] * s_alpha) >> 8;
699 y = APPLY_MATRIX (matrix, 0, src[o[1]], src[o[2]], src[o[3]]);
700 u = APPLY_MATRIX (matrix, 1, src[o[1]], src[o[2]], src[o[3]]);
701 v = APPLY_MATRIX (matrix, 2, src[o[1]], src[o[2]], src[o[3]]);
714 gst_alpha_chroma_key_argb_ayuv (const guint8 * src, guint8 * dest, gint width,
715 gint height, GstAlpha * alpha)
721 gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
722 gint8 cb = alpha->cb, cr = alpha->cr;
723 gint8 kg = alpha->kg;
724 guint8 accept_angle_tg = alpha->accept_angle_tg;
725 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
726 guint8 one_over_kc = alpha->one_over_kc;
727 guint8 kfgy_scale = alpha->kfgy_scale;
728 guint noise_level2 = alpha->noise_level2;
733 gst_video_format_get_component_offset (alpha->in_format, 3, width,
736 gst_video_format_get_component_offset (alpha->in_format, 0, width,
739 gst_video_format_get_component_offset (alpha->in_format, 1, width,
742 gst_video_format_get_component_offset (alpha->in_format, 2, width,
745 smin = 128 - alpha->black_sensitivity;
746 smax = 128 + alpha->white_sensitivity;
749 alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
750 cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
752 for (i = 0; i < height; i++) {
753 for (j = 0; j < width; j++) {
754 a = (src[o[0]] * pa) >> 8;
759 y = APPLY_MATRIX (matrix, 0, r, g, b);
760 u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
761 v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
763 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
764 smin, smax, accept_angle_tg, accept_angle_ctg,
765 one_over_kc, kfgy_scale, kg, noise_level2);
782 gst_alpha_set_argb_argb (const guint8 * src, guint8 * dest, gint width,
783 gint height, GstAlpha * alpha)
785 gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
790 gst_video_format_get_component_offset (alpha->out_format, 3, width,
793 gst_video_format_get_component_offset (alpha->out_format, 0, width,
796 gst_video_format_get_component_offset (alpha->out_format, 1, width,
799 gst_video_format_get_component_offset (alpha->out_format, 2, width,
803 gst_video_format_get_component_offset (alpha->in_format, 3, width,
806 gst_video_format_get_component_offset (alpha->in_format, 0, width,
809 gst_video_format_get_component_offset (alpha->in_format, 1, width,
812 gst_video_format_get_component_offset (alpha->in_format, 2, width,
815 for (i = 0; i < height; i++) {
816 for (j = 0; j < width; j++) {
817 dest[p[0]] = (src[o[0]] * s_alpha) >> 8;
819 dest[p[1]] = src[o[1]];
820 dest[p[2]] = src[o[2]];
821 dest[p[3]] = src[o[3]];
830 gst_alpha_chroma_key_argb_argb (const guint8 * src, guint8 * dest, gint width,
831 gint height, GstAlpha * alpha)
837 gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
838 gint8 cb = alpha->cb, cr = alpha->cr;
839 gint8 kg = alpha->kg;
840 guint8 accept_angle_tg = alpha->accept_angle_tg;
841 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
842 guint8 one_over_kc = alpha->one_over_kc;
843 guint8 kfgy_scale = alpha->kfgy_scale;
844 guint noise_level2 = alpha->noise_level2;
845 gint matrix[12], matrix2[12];
849 gst_video_format_get_component_offset (alpha->out_format, 3, width,
852 gst_video_format_get_component_offset (alpha->out_format, 0, width,
855 gst_video_format_get_component_offset (alpha->out_format, 1, width,
858 gst_video_format_get_component_offset (alpha->out_format, 2, width,
862 gst_video_format_get_component_offset (alpha->in_format, 3, width,
865 gst_video_format_get_component_offset (alpha->in_format, 0, width,
868 gst_video_format_get_component_offset (alpha->in_format, 1, width,
871 gst_video_format_get_component_offset (alpha->in_format, 2, width,
874 smin = 128 - alpha->black_sensitivity;
875 smax = 128 + alpha->white_sensitivity;
877 memcpy (matrix, cog_rgb_to_ycbcr_matrix_8bit_sdtv, 12 * sizeof (gint));
878 memcpy (matrix2, cog_ycbcr_to_rgb_matrix_8bit_sdtv, 12 * sizeof (gint));
880 for (i = 0; i < height; i++) {
881 for (j = 0; j < width; j++) {
882 a = (src[o[0]] * pa) >> 8;
887 y = APPLY_MATRIX (matrix, 0, r, g, b);
888 u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
889 v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
891 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
892 smin, smax, accept_angle_tg, accept_angle_ctg,
893 one_over_kc, kfgy_scale, kg, noise_level2);
898 r = APPLY_MATRIX (matrix2, 0, y, u, v);
899 g = APPLY_MATRIX (matrix2, 1, y, u, v);
900 b = APPLY_MATRIX (matrix2, 2, y, u, v);
903 dest[p[1]] = CLAMP (r, 0, 255);
904 dest[p[2]] = CLAMP (g, 0, 255);
905 dest[p[3]] = CLAMP (b, 0, 255);
914 gst_alpha_set_ayuv_argb (const guint8 * src, guint8 * dest, gint width,
915 gint height, GstAlpha * alpha)
917 gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
924 gst_video_format_get_component_offset (alpha->out_format, 3, width,
927 gst_video_format_get_component_offset (alpha->out_format, 0, width,
930 gst_video_format_get_component_offset (alpha->out_format, 1, width,
933 gst_video_format_get_component_offset (alpha->out_format, 2, width,
937 alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
938 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
940 for (y = 0; y < height; y++) {
941 for (x = 0; x < width; x++) {
942 dest[p[0]] = (src[0] * s_alpha) >> 8;
944 r = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
945 g = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]);
946 b = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]);
948 dest[p[1]] = CLAMP (r, 0, 255);
949 dest[p[2]] = CLAMP (g, 0, 255);
950 dest[p[3]] = CLAMP (b, 0, 255);
959 gst_alpha_chroma_key_ayuv_argb (const guint8 * src, guint8 * dest, gint width,
960 gint height, GstAlpha * alpha)
966 gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
967 gint8 cb = alpha->cb, cr = alpha->cr;
968 gint8 kg = alpha->kg;
969 guint8 accept_angle_tg = alpha->accept_angle_tg;
970 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
971 guint8 one_over_kc = alpha->one_over_kc;
972 guint8 kfgy_scale = alpha->kfgy_scale;
973 guint noise_level2 = alpha->noise_level2;
978 gst_video_format_get_component_offset (alpha->out_format, 3, width,
981 gst_video_format_get_component_offset (alpha->out_format, 0, width,
984 gst_video_format_get_component_offset (alpha->out_format, 1, width,
987 gst_video_format_get_component_offset (alpha->out_format, 2, width,
990 smin = 128 - alpha->black_sensitivity;
991 smax = 128 + alpha->white_sensitivity;
994 alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
995 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
997 for (i = 0; i < height; i++) {
998 for (j = 0; j < width; j++) {
999 a = (src[0] * pa) >> 8;
1004 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1005 smin, smax, accept_angle_tg, accept_angle_ctg,
1006 one_over_kc, kfgy_scale, kg, noise_level2);
1011 r = APPLY_MATRIX (matrix, 0, y, u, v);
1012 g = APPLY_MATRIX (matrix, 1, y, u, v);
1013 b = APPLY_MATRIX (matrix, 2, y, u, v);
1016 dest[p[1]] = CLAMP (r, 0, 255);
1017 dest[p[2]] = CLAMP (g, 0, 255);
1018 dest[p[3]] = CLAMP (b, 0, 255);
1027 gst_alpha_set_ayuv_ayuv (const guint8 * src, guint8 * dest, gint width,
1028 gint height, GstAlpha * alpha)
1030 gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
1033 if (alpha->in_sdtv == alpha->out_sdtv) {
1034 for (y = 0; y < height; y++) {
1035 for (x = 0; x < width; x++) {
1036 dest[0] = (src[0] * s_alpha) >> 8;
1049 alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1050 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1052 for (y = 0; y < height; y++) {
1053 for (x = 0; x < width; x++) {
1054 dest[0] = (src[0] * s_alpha) >> 8;
1055 dest[1] = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
1056 dest[2] = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]);
1057 dest[3] = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]);
1067 gst_alpha_chroma_key_ayuv_ayuv (const guint8 * src, guint8 * dest,
1068 gint width, gint height, GstAlpha * alpha)
1073 gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
1074 gint8 cb = alpha->cb, cr = alpha->cr;
1075 gint8 kg = alpha->kg;
1076 guint8 accept_angle_tg = alpha->accept_angle_tg;
1077 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1078 guint8 one_over_kc = alpha->one_over_kc;
1079 guint8 kfgy_scale = alpha->kfgy_scale;
1080 guint noise_level2 = alpha->noise_level2;
1082 smin = 128 - alpha->black_sensitivity;
1083 smax = 128 + alpha->white_sensitivity;
1085 if (alpha->in_sdtv == alpha->out_sdtv) {
1086 for (i = 0; i < height; i++) {
1087 for (j = 0; j < width; j++) {
1088 a = (src[0] * pa) >> 8;
1093 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1094 smin, smax, accept_angle_tg, accept_angle_ctg,
1095 one_over_kc, kfgy_scale, kg, noise_level2);
1113 alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1114 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1116 for (i = 0; i < height; i++) {
1117 for (j = 0; j < width; j++) {
1118 a = (src[0] * pa) >> 8;
1119 y = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
1120 u = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]) - 128;
1121 v = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]) - 128;
1123 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1124 smin, smax, accept_angle_tg, accept_angle_ctg,
1125 one_over_kc, kfgy_scale, kg, noise_level2);
1143 gst_alpha_set_rgb_ayuv (const guint8 * src, guint8 * dest, gint width,
1144 gint height, GstAlpha * alpha)
1146 gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1153 bpp = gst_video_format_get_pixel_stride (alpha->in_format, 0);
1156 gst_video_format_get_component_offset (alpha->in_format, 0, width,
1159 gst_video_format_get_component_offset (alpha->in_format, 1, width,
1162 gst_video_format_get_component_offset (alpha->in_format, 2, width,
1166 alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
1167 cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
1169 for (i = 0; i < height; i++) {
1170 for (j = 0; j < width; j++) {
1173 y = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[2]]);
1174 u = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[2]]);
1175 v = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[2]]);
1188 gst_alpha_chroma_key_rgb_ayuv (const guint8 * src, guint8 * dest, gint width,
1189 gint height, GstAlpha * alpha)
1195 gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1196 gint8 cb = alpha->cb, cr = alpha->cr;
1197 gint8 kg = alpha->kg;
1198 guint8 accept_angle_tg = alpha->accept_angle_tg;
1199 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1200 guint8 one_over_kc = alpha->one_over_kc;
1201 guint8 kfgy_scale = alpha->kfgy_scale;
1202 guint noise_level2 = alpha->noise_level2;
1207 bpp = gst_video_format_get_pixel_stride (alpha->in_format, 0);
1210 gst_video_format_get_component_offset (alpha->in_format, 0, width,
1213 gst_video_format_get_component_offset (alpha->in_format, 1, width,
1216 gst_video_format_get_component_offset (alpha->in_format, 2, width,
1219 smin = 128 - alpha->black_sensitivity;
1220 smax = 128 + alpha->white_sensitivity;
1223 alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
1224 cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
1226 for (i = 0; i < height; i++) {
1227 for (j = 0; j < width; j++) {
1233 y = APPLY_MATRIX (matrix, 0, r, g, b);
1234 u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
1235 v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
1237 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1238 smin, smax, accept_angle_tg, accept_angle_ctg,
1239 one_over_kc, kfgy_scale, kg, noise_level2);
1256 gst_alpha_set_rgb_argb (const guint8 * src, guint8 * dest, gint width,
1257 gint height, GstAlpha * alpha)
1259 gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1264 bpp = gst_video_format_get_pixel_stride (alpha->in_format, 0);
1267 gst_video_format_get_component_offset (alpha->in_format, 0, width,
1270 gst_video_format_get_component_offset (alpha->in_format, 1, width,
1273 gst_video_format_get_component_offset (alpha->in_format, 2, width,
1277 gst_video_format_get_component_offset (alpha->out_format, 3, width,
1280 gst_video_format_get_component_offset (alpha->out_format, 0, width,
1283 gst_video_format_get_component_offset (alpha->out_format, 1, width,
1286 gst_video_format_get_component_offset (alpha->out_format, 2, width,
1289 for (i = 0; i < height; i++) {
1290 for (j = 0; j < width; j++) {
1291 dest[p[0]] = s_alpha;
1293 dest[p[1]] = src[o[0]];
1294 dest[p[2]] = src[o[1]];
1295 dest[p[3]] = src[o[2]];
1304 gst_alpha_chroma_key_rgb_argb (const guint8 * src, guint8 * dest, gint width,
1305 gint height, GstAlpha * alpha)
1311 gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1312 gint8 cb = alpha->cb, cr = alpha->cr;
1313 gint8 kg = alpha->kg;
1314 guint8 accept_angle_tg = alpha->accept_angle_tg;
1315 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1316 guint8 one_over_kc = alpha->one_over_kc;
1317 guint8 kfgy_scale = alpha->kfgy_scale;
1318 guint noise_level2 = alpha->noise_level2;
1319 gint matrix[12], matrix2[12];
1323 bpp = gst_video_format_get_pixel_stride (alpha->in_format, 0);
1326 gst_video_format_get_component_offset (alpha->in_format, 0, width,
1329 gst_video_format_get_component_offset (alpha->in_format, 1, width,
1332 gst_video_format_get_component_offset (alpha->in_format, 2, width,
1336 gst_video_format_get_component_offset (alpha->out_format, 3, width,
1339 gst_video_format_get_component_offset (alpha->out_format, 0, width,
1342 gst_video_format_get_component_offset (alpha->out_format, 1, width,
1345 gst_video_format_get_component_offset (alpha->out_format, 2, width,
1348 smin = 128 - alpha->black_sensitivity;
1349 smax = 128 + alpha->white_sensitivity;
1351 memcpy (matrix, cog_rgb_to_ycbcr_matrix_8bit_sdtv, 12 * sizeof (gint));
1352 memcpy (matrix2, cog_ycbcr_to_rgb_matrix_8bit_sdtv, 12 * sizeof (gint));
1354 for (i = 0; i < height; i++) {
1355 for (j = 0; j < width; j++) {
1361 y = APPLY_MATRIX (matrix, 0, r, g, b);
1362 u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
1363 v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
1365 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1366 smin, smax, accept_angle_tg, accept_angle_ctg,
1367 one_over_kc, kfgy_scale, kg, noise_level2);
1372 r = APPLY_MATRIX (matrix2, 0, y, u, v);
1373 g = APPLY_MATRIX (matrix2, 1, y, u, v);
1374 b = APPLY_MATRIX (matrix2, 2, y, u, v);
1377 dest[p[1]] = CLAMP (r, 0, 255);
1378 dest[p[2]] = CLAMP (g, 0, 255);
1379 dest[p[3]] = CLAMP (b, 0, 255);
1388 gst_alpha_set_planar_yuv_ayuv (const guint8 * src, guint8 * dest, gint width,
1389 gint height, GstAlpha * alpha)
1391 gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1392 const guint8 *srcY, *srcY_tmp;
1393 const guint8 *srcU, *srcU_tmp;
1394 const guint8 *srcV, *srcV_tmp;
1396 gint y_stride, uv_stride;
1397 gint v_subs, h_subs;
1399 y_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
1400 uv_stride = gst_video_format_get_row_stride (alpha->in_format, 1, width);
1402 srcY_tmp = srcY = src;
1404 src + gst_video_format_get_component_offset (alpha->in_format, 1, width,
1407 src + gst_video_format_get_component_offset (alpha->in_format, 2, width,
1410 switch (alpha->in_format) {
1411 case GST_VIDEO_FORMAT_I420:
1412 case GST_VIDEO_FORMAT_YV12:
1413 v_subs = h_subs = 2;
1415 case GST_VIDEO_FORMAT_Y444:
1416 v_subs = h_subs = 1;
1418 case GST_VIDEO_FORMAT_Y42B:
1422 case GST_VIDEO_FORMAT_Y41B:
1427 g_assert_not_reached ();
1431 if (alpha->in_sdtv == alpha->out_sdtv) {
1432 for (i = 0; i < height; i++) {
1433 for (j = 0; j < width; j++) {
1441 if ((j + 1) % h_subs == 0) {
1447 srcY_tmp = srcY = srcY_tmp + y_stride;
1448 if ((i + 1) % v_subs == 0) {
1449 srcU_tmp = srcU = srcU_tmp + uv_stride;
1450 srcV_tmp = srcV = srcV_tmp + uv_stride;
1461 alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1462 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1464 for (i = 0; i < height; i++) {
1465 for (j = 0; j < width; j++) {
1472 dest[1] = APPLY_MATRIX (matrix, 0, y, u, v);
1473 dest[2] = APPLY_MATRIX (matrix, 1, y, u, v);
1474 dest[3] = APPLY_MATRIX (matrix, 2, y, u, v);
1478 if ((j + 1) % h_subs == 0) {
1484 srcY_tmp = srcY = srcY_tmp + y_stride;
1485 if ((i + 1) % v_subs == 0) {
1486 srcU_tmp = srcU = srcU_tmp + uv_stride;
1487 srcV_tmp = srcV = srcV_tmp + uv_stride;
1497 gst_alpha_chroma_key_planar_yuv_ayuv (const guint8 * src, guint8 * dest,
1498 gint width, gint height, GstAlpha * alpha)
1500 gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1501 const guint8 *srcY, *srcY_tmp;
1502 const guint8 *srcU, *srcU_tmp;
1503 const guint8 *srcV, *srcV_tmp;
1506 gint y_stride, uv_stride;
1507 gint v_subs, h_subs;
1508 gint smin = 128 - alpha->black_sensitivity;
1509 gint smax = 128 + alpha->white_sensitivity;
1510 gint8 cb = alpha->cb, cr = alpha->cr;
1511 gint8 kg = alpha->kg;
1512 guint8 accept_angle_tg = alpha->accept_angle_tg;
1513 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1514 guint8 one_over_kc = alpha->one_over_kc;
1515 guint8 kfgy_scale = alpha->kfgy_scale;
1516 guint noise_level2 = alpha->noise_level2;
1518 y_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
1519 uv_stride = gst_video_format_get_row_stride (alpha->in_format, 1, width);
1521 srcY_tmp = srcY = src;
1523 src + gst_video_format_get_component_offset (alpha->in_format, 1, width,
1526 src + gst_video_format_get_component_offset (alpha->in_format, 2, width,
1529 switch (alpha->in_format) {
1530 case GST_VIDEO_FORMAT_I420:
1531 case GST_VIDEO_FORMAT_YV12:
1532 v_subs = h_subs = 2;
1534 case GST_VIDEO_FORMAT_Y444:
1535 v_subs = h_subs = 1;
1537 case GST_VIDEO_FORMAT_Y42B:
1541 case GST_VIDEO_FORMAT_Y41B:
1546 g_assert_not_reached ();
1550 if (alpha->in_sdtv == alpha->out_sdtv) {
1551 for (i = 0; i < height; i++) {
1552 for (j = 0; j < width; j++) {
1558 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
1559 smax, accept_angle_tg, accept_angle_ctg,
1560 one_over_kc, kfgy_scale, kg, noise_level2);
1572 if ((j + 1) % h_subs == 0) {
1578 srcY_tmp = srcY = srcY_tmp + y_stride;
1579 if ((i + 1) % v_subs == 0) {
1580 srcU_tmp = srcU = srcU_tmp + uv_stride;
1581 srcV_tmp = srcV = srcV_tmp + uv_stride;
1591 alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1592 cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1594 for (i = 0; i < height; i++) {
1595 for (j = 0; j < width; j++) {
1597 y = APPLY_MATRIX (matrix, 0, srcY[0], srcU[0], srcV[0]);
1598 u = APPLY_MATRIX (matrix, 1, srcY[0], srcU[0], srcV[0]) - 128;
1599 v = APPLY_MATRIX (matrix, 2, srcY[0], srcU[0], srcV[0]) - 128;
1601 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
1602 smax, accept_angle_tg, accept_angle_ctg,
1603 one_over_kc, kfgy_scale, kg, noise_level2);
1612 if ((j + 1) % h_subs == 0) {
1618 srcY_tmp = srcY = srcY_tmp + y_stride;
1619 if ((i + 1) % v_subs == 0) {
1620 srcU_tmp = srcU = srcU_tmp + uv_stride;
1621 srcV_tmp = srcV = srcV_tmp + uv_stride;
1631 gst_alpha_set_planar_yuv_argb (const guint8 * src, guint8 * dest, gint width,
1632 gint height, GstAlpha * alpha)
1634 gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1635 const guint8 *srcY, *srcY_tmp;
1636 const guint8 *srcU, *srcU_tmp;
1637 const guint8 *srcV, *srcV_tmp;
1639 gint y_stride, uv_stride;
1640 gint v_subs, h_subs;
1647 gst_video_format_get_component_offset (alpha->out_format, 3, width,
1650 gst_video_format_get_component_offset (alpha->out_format, 0, width,
1653 gst_video_format_get_component_offset (alpha->out_format, 1, width,
1656 gst_video_format_get_component_offset (alpha->out_format, 2, width,
1659 y_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
1660 uv_stride = gst_video_format_get_row_stride (alpha->in_format, 1, width);
1662 srcY_tmp = srcY = src;
1664 src + gst_video_format_get_component_offset (alpha->in_format, 1, width,
1667 src + gst_video_format_get_component_offset (alpha->in_format, 2, width,
1670 switch (alpha->in_format) {
1671 case GST_VIDEO_FORMAT_I420:
1672 case GST_VIDEO_FORMAT_YV12:
1673 v_subs = h_subs = 2;
1675 case GST_VIDEO_FORMAT_Y444:
1676 v_subs = h_subs = 1;
1678 case GST_VIDEO_FORMAT_Y42B:
1682 case GST_VIDEO_FORMAT_Y41B:
1687 g_assert_not_reached ();
1692 alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
1693 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
1695 for (i = 0; i < height; i++) {
1696 for (j = 0; j < width; j++) {
1703 r = APPLY_MATRIX (matrix, 0, y, u, v);
1704 g = APPLY_MATRIX (matrix, 1, y, u, v);
1705 b = APPLY_MATRIX (matrix, 2, y, u, v);
1706 dest[p[1]] = CLAMP (r, 0, 255);
1707 dest[p[2]] = CLAMP (g, 0, 255);
1708 dest[p[3]] = CLAMP (b, 0, 255);
1712 if ((j + 1) % h_subs == 0) {
1718 srcY_tmp = srcY = srcY_tmp + y_stride;
1719 if ((i + 1) % v_subs == 0) {
1720 srcU_tmp = srcU = srcU_tmp + uv_stride;
1721 srcV_tmp = srcV = srcV_tmp + uv_stride;
1730 gst_alpha_chroma_key_planar_yuv_argb (const guint8 * src, guint8 * dest,
1731 gint width, gint height, GstAlpha * alpha)
1733 gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1734 const guint8 *srcY, *srcY_tmp;
1735 const guint8 *srcU, *srcU_tmp;
1736 const guint8 *srcV, *srcV_tmp;
1740 gint y_stride, uv_stride;
1741 gint v_subs, h_subs;
1742 gint smin = 128 - alpha->black_sensitivity;
1743 gint smax = 128 + alpha->white_sensitivity;
1744 gint8 cb = alpha->cb, cr = alpha->cr;
1745 gint8 kg = alpha->kg;
1746 guint8 accept_angle_tg = alpha->accept_angle_tg;
1747 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1748 guint8 one_over_kc = alpha->one_over_kc;
1749 guint8 kfgy_scale = alpha->kfgy_scale;
1750 guint noise_level2 = alpha->noise_level2;
1755 gst_video_format_get_component_offset (alpha->out_format, 3, width,
1758 gst_video_format_get_component_offset (alpha->out_format, 0, width,
1761 gst_video_format_get_component_offset (alpha->out_format, 1, width,
1764 gst_video_format_get_component_offset (alpha->out_format, 2, width,
1767 y_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
1768 uv_stride = gst_video_format_get_row_stride (alpha->in_format, 1, width);
1770 srcY_tmp = srcY = src;
1772 src + gst_video_format_get_component_offset (alpha->in_format, 1, width,
1775 src + gst_video_format_get_component_offset (alpha->in_format, 2, width,
1778 switch (alpha->in_format) {
1779 case GST_VIDEO_FORMAT_I420:
1780 case GST_VIDEO_FORMAT_YV12:
1781 v_subs = h_subs = 2;
1783 case GST_VIDEO_FORMAT_Y444:
1784 v_subs = h_subs = 1;
1786 case GST_VIDEO_FORMAT_Y42B:
1790 case GST_VIDEO_FORMAT_Y41B:
1795 g_assert_not_reached ();
1800 alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
1801 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
1803 for (i = 0; i < height; i++) {
1804 for (j = 0; j < width; j++) {
1810 a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
1811 smax, accept_angle_tg, accept_angle_ctg,
1812 one_over_kc, kfgy_scale, kg, noise_level2);
1818 r = APPLY_MATRIX (matrix, 0, y, u, v);
1819 g = APPLY_MATRIX (matrix, 1, y, u, v);
1820 b = APPLY_MATRIX (matrix, 2, y, u, v);
1821 dest[p[1]] = CLAMP (r, 0, 255);
1822 dest[p[2]] = CLAMP (g, 0, 255);
1823 dest[p[3]] = CLAMP (b, 0, 255);
1827 if ((j + 1) % h_subs == 0) {
1833 srcY_tmp = srcY = srcY_tmp + y_stride;
1834 if ((i + 1) % v_subs == 0) {
1835 srcU_tmp = srcU = srcU_tmp + uv_stride;
1836 srcV_tmp = srcV = srcV_tmp + uv_stride;
1845 gst_alpha_set_packed_422_ayuv (const guint8 * src, guint8 * dest, gint width,
1846 gint height, GstAlpha * alpha)
1848 gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1851 gint p[4]; /* Y U Y V */
1853 const guint8 *src_tmp;
1855 src_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
1858 gst_video_format_get_component_offset (alpha->in_format, 0, width,
1862 gst_video_format_get_component_offset (alpha->in_format, 1, width,
1865 gst_video_format_get_component_offset (alpha->in_format, 2, width,
1868 if (alpha->in_sdtv != alpha->out_sdtv) {
1872 alpha->in_sdtv ? cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit :
1873 cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit, 12 * sizeof (gint));
1875 for (i = 0; i < height; i++) {
1878 for (j = 0; j < width - 1; j += 2) {
1882 y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
1883 u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]);
1884 v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]);
1890 y = APPLY_MATRIX (matrix, 0, src[p[2]], src[p[1]], src[p[3]]);
1891 u = APPLY_MATRIX (matrix, 1, src[p[2]], src[p[1]], src[p[3]]);
1892 v = APPLY_MATRIX (matrix, 2, src[p[2]], src[p[1]], src[p[3]]);
1902 if (j == width - 1) {
1905 y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
1906 u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]);
1907 v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]);
1916 src = src_tmp + src_stride;
1919 for (i = 0; i < height; i++) {
1922 for (j = 0; j < width - 1; j += 2) {
1944 if (j == width - 1) {
1958 src = src_tmp + src_stride;
1964 gst_alpha_chroma_key_packed_422_ayuv (const guint8 * src, guint8 * dest,
1965 gint width, gint height, GstAlpha * alpha)
1970 gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1971 gint8 cb = alpha->cb, cr = alpha->cr;
1972 gint8 kg = alpha->kg;
1973 guint8 accept_angle_tg = alpha->accept_angle_tg;
1974 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1975 guint8 one_over_kc = alpha->one_over_kc;
1976 guint8 kfgy_scale = alpha->kfgy_scale;
1977 guint noise_level2 = alpha->noise_level2;
1978 gint p[4]; /* Y U Y V */
1980 const guint8 *src_tmp;
1982 src_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
1985 gst_video_format_get_component_offset (alpha->in_format, 0, width,
1989 gst_video_format_get_component_offset (alpha->in_format, 1, width,
1992 gst_video_format_get_component_offset (alpha->in_format, 2, width,
1995 smin = 128 - alpha->black_sensitivity;
1996 smax = 128 + alpha->white_sensitivity;
1998 if (alpha->in_sdtv != alpha->out_sdtv) {
2002 alpha->in_sdtv ? cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit :
2003 cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit, 12 * sizeof (gint));
2005 for (i = 0; i < height; i++) {
2008 for (j = 0; j < width - 1; j += 2) {
2009 y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
2010 u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]) - 128;
2011 v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]) - 128;
2013 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2014 smin, smax, accept_angle_tg, accept_angle_ctg,
2015 one_over_kc, kfgy_scale, kg, noise_level2);
2022 y = APPLY_MATRIX (matrix, 0, src[p[2]], src[p[1]], src[p[3]]);
2023 u = APPLY_MATRIX (matrix, 1, src[p[2]], src[p[1]], src[p[3]]) - 128;
2024 v = APPLY_MATRIX (matrix, 2, src[p[2]], src[p[1]], src[p[3]]) - 128;
2026 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2027 smin, smax, accept_angle_tg, accept_angle_ctg,
2028 one_over_kc, kfgy_scale, kg, noise_level2);
2039 if (j == width - 1) {
2040 y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
2041 u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]) - 128;
2042 v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]) - 128;
2044 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2045 smin, smax, accept_angle_tg, accept_angle_ctg,
2046 one_over_kc, kfgy_scale, kg, noise_level2);
2056 src = src_tmp + src_stride;
2059 for (i = 0; i < height; i++) {
2062 for (j = 0; j < width - 1; j += 2) {
2064 u = src[p[1]] - 128;
2065 v = src[p[3]] - 128;
2067 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2068 smin, smax, accept_angle_tg, accept_angle_ctg,
2069 one_over_kc, kfgy_scale, kg, noise_level2);
2077 u = src[p[1]] - 128;
2078 v = src[p[3]] - 128;
2080 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2081 smin, smax, accept_angle_tg, accept_angle_ctg,
2082 one_over_kc, kfgy_scale, kg, noise_level2);
2093 if (j == width - 1) {
2095 u = src[p[1]] - 128;
2096 v = src[p[3]] - 128;
2098 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2099 smin, smax, accept_angle_tg, accept_angle_ctg,
2100 one_over_kc, kfgy_scale, kg, noise_level2);
2110 src = src_tmp + src_stride;
2116 gst_alpha_set_packed_422_argb (const guint8 * src, guint8 * dest, gint width,
2117 gint height, GstAlpha * alpha)
2119 gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
2123 const guint8 *src_tmp;
2127 src_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
2130 gst_video_format_get_component_offset (alpha->in_format, 0, width,
2134 gst_video_format_get_component_offset (alpha->in_format, 1, width,
2137 gst_video_format_get_component_offset (alpha->in_format, 2, width,
2141 gst_video_format_get_component_offset (alpha->out_format, 3, width,
2144 gst_video_format_get_component_offset (alpha->out_format, 0, width,
2147 gst_video_format_get_component_offset (alpha->out_format, 1, width,
2150 gst_video_format_get_component_offset (alpha->out_format, 2, width,
2154 alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
2155 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
2157 for (i = 0; i < height; i++) {
2160 for (j = 0; j < width - 1; j += 2) {
2161 r = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[3]]);
2162 g = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[3]]);
2163 b = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[3]]);
2165 dest[p[0]] = s_alpha;
2166 dest[p[1]] = CLAMP (r, 0, 255);
2167 dest[p[2]] = CLAMP (g, 0, 255);
2168 dest[p[3]] = CLAMP (b, 0, 255);
2170 r = APPLY_MATRIX (matrix, 0, src[o[2]], src[o[1]], src[o[3]]);
2171 g = APPLY_MATRIX (matrix, 1, src[o[2]], src[o[1]], src[o[3]]);
2172 b = APPLY_MATRIX (matrix, 2, src[o[2]], src[o[1]], src[o[3]]);
2174 dest[4 + p[0]] = s_alpha;
2175 dest[4 + p[1]] = CLAMP (r, 0, 255);
2176 dest[4 + p[2]] = CLAMP (g, 0, 255);
2177 dest[4 + p[3]] = CLAMP (b, 0, 255);
2183 if (j == width - 1) {
2184 r = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[3]]);
2185 g = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[3]]);
2186 b = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[3]]);
2188 dest[p[0]] = s_alpha;
2189 dest[p[1]] = CLAMP (r, 0, 255);
2190 dest[p[2]] = CLAMP (g, 0, 255);
2191 dest[p[3]] = CLAMP (b, 0, 255);
2196 src = src_tmp + src_stride;
2201 gst_alpha_chroma_key_packed_422_argb (const guint8 * src, guint8 * dest,
2202 gint width, gint height, GstAlpha * alpha)
2208 gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
2209 gint8 cb = alpha->cb, cr = alpha->cr;
2210 gint8 kg = alpha->kg;
2211 guint8 accept_angle_tg = alpha->accept_angle_tg;
2212 guint8 accept_angle_ctg = alpha->accept_angle_ctg;
2213 guint8 one_over_kc = alpha->one_over_kc;
2214 guint8 kfgy_scale = alpha->kfgy_scale;
2215 guint noise_level2 = alpha->noise_level2;
2218 const guint8 *src_tmp;
2221 src_stride = gst_video_format_get_row_stride (alpha->in_format, 0, width);
2224 gst_video_format_get_component_offset (alpha->in_format, 0, width,
2228 gst_video_format_get_component_offset (alpha->in_format, 1, width,
2231 gst_video_format_get_component_offset (alpha->in_format, 2, width,
2235 gst_video_format_get_component_offset (alpha->out_format, 3, width,
2238 gst_video_format_get_component_offset (alpha->out_format, 0, width,
2241 gst_video_format_get_component_offset (alpha->out_format, 1, width,
2244 gst_video_format_get_component_offset (alpha->out_format, 2, width,
2248 alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
2249 cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
2251 smin = 128 - alpha->black_sensitivity;
2252 smax = 128 + alpha->white_sensitivity;
2254 for (i = 0; i < height; i++) {
2257 for (j = 0; j < width - 1; j += 2) {
2259 u = src[o[1]] - 128;
2260 v = src[o[3]] - 128;
2262 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2263 smin, smax, accept_angle_tg, accept_angle_ctg,
2264 one_over_kc, kfgy_scale, kg, noise_level2);
2268 r = APPLY_MATRIX (matrix, 0, y, u, v);
2269 g = APPLY_MATRIX (matrix, 1, y, u, v);
2270 b = APPLY_MATRIX (matrix, 2, y, u, v);
2273 dest[p[1]] = CLAMP (r, 0, 255);
2274 dest[p[2]] = CLAMP (g, 0, 255);
2275 dest[p[3]] = CLAMP (b, 0, 255);
2278 u = src[o[1]] - 128;
2279 v = src[o[3]] - 128;
2281 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2282 smin, smax, accept_angle_tg, accept_angle_ctg,
2283 one_over_kc, kfgy_scale, kg, noise_level2);
2287 r = APPLY_MATRIX (matrix, 0, y, u, v);
2288 g = APPLY_MATRIX (matrix, 1, y, u, v);
2289 b = APPLY_MATRIX (matrix, 2, y, u, v);
2292 dest[4 + p[1]] = CLAMP (r, 0, 255);
2293 dest[4 + p[2]] = CLAMP (g, 0, 255);
2294 dest[4 + p[3]] = CLAMP (b, 0, 255);
2300 if (j == width - 1) {
2302 u = src[o[1]] - 128;
2303 v = src[o[3]] - 128;
2305 a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2306 smin, smax, accept_angle_tg, accept_angle_ctg,
2307 one_over_kc, kfgy_scale, kg, noise_level2);
2311 r = APPLY_MATRIX (matrix, 0, y, u, v);
2312 g = APPLY_MATRIX (matrix, 1, y, u, v);
2313 b = APPLY_MATRIX (matrix, 2, y, u, v);
2316 dest[p[1]] = CLAMP (r, 0, 255);
2317 dest[p[2]] = CLAMP (g, 0, 255);
2318 dest[p[3]] = CLAMP (b, 0, 255);
2323 src = src_tmp + src_stride;
2327 /* Protected with the alpha lock */
2329 gst_alpha_init_params (GstAlpha * alpha)
2337 /* RGB->RGB: convert to SDTV YUV, chroma keying, convert back
2338 * YUV->RGB: chroma keying, convert to RGB
2339 * RGB->YUV: convert to YUV, chroma keying
2340 * YUV->YUV: convert matrix, chroma keying
2342 if (gst_video_format_is_rgb (alpha->in_format)
2343 && gst_video_format_is_rgb (alpha->out_format))
2344 matrix = cog_rgb_to_ycbcr_matrix_8bit_sdtv;
2345 else if (gst_video_format_is_yuv (alpha->in_format)
2346 && gst_video_format_is_rgb (alpha->out_format))
2348 (alpha->in_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
2349 cog_rgb_to_ycbcr_matrix_8bit_hdtv;
2350 else if (gst_video_format_is_rgb (alpha->in_format)
2351 && gst_video_format_is_yuv (alpha->out_format))
2353 (alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
2354 cog_rgb_to_ycbcr_matrix_8bit_hdtv;
2355 else /* yuv -> yuv */
2357 (alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
2358 cog_rgb_to_ycbcr_matrix_8bit_hdtv;
2360 y = (matrix[0] * ((gint) alpha->target_r) +
2361 matrix[1] * ((gint) alpha->target_g) +
2362 matrix[2] * ((gint) alpha->target_b) + matrix[3]) >> 8;
2363 /* Cb,Cr without offset here because the chroma keying
2364 * works with them being in range [-128,127]
2367 (matrix[4] * ((gint) alpha->target_r) +
2368 matrix[5] * ((gint) alpha->target_g) +
2369 matrix[6] * ((gint) alpha->target_b)) >> 8;
2371 (matrix[8] * ((gint) alpha->target_r) +
2372 matrix[9] * ((gint) alpha->target_g) +
2373 matrix[10] * ((gint) alpha->target_b)) >> 8;
2375 kgl = sqrt (tmp1 * tmp1 + tmp2 * tmp2);
2376 alpha->cb = 127 * (tmp1 / kgl);
2377 alpha->cr = 127 * (tmp2 / kgl);
2379 tmp = 15 * tan (M_PI * alpha->angle / 180);
2380 tmp = MIN (tmp, 255);
2381 alpha->accept_angle_tg = tmp;
2382 tmp = 15 / tan (M_PI * alpha->angle / 180);
2383 tmp = MIN (tmp, 255);
2384 alpha->accept_angle_ctg = tmp;
2386 alpha->one_over_kc = 255 * 2 * tmp - 255;
2388 tmp = MIN (tmp, 255);
2389 alpha->kfgy_scale = tmp;
2390 alpha->kg = MIN (kgl, 127);
2392 alpha->noise_level2 = alpha->noise_level * alpha->noise_level;
2395 /* Protected with the alpha lock */
2397 gst_alpha_set_process_function (GstAlpha * alpha)
2399 alpha->process = NULL;
2401 switch (alpha->method) {
2402 case ALPHA_METHOD_SET:
2403 switch (alpha->out_format) {
2404 case GST_VIDEO_FORMAT_AYUV:
2405 switch (alpha->in_format) {
2406 case GST_VIDEO_FORMAT_AYUV:
2407 alpha->process = gst_alpha_set_ayuv_ayuv;
2409 case GST_VIDEO_FORMAT_Y444:
2410 case GST_VIDEO_FORMAT_Y42B:
2411 case GST_VIDEO_FORMAT_I420:
2412 case GST_VIDEO_FORMAT_YV12:
2413 case GST_VIDEO_FORMAT_Y41B:
2414 alpha->process = gst_alpha_set_planar_yuv_ayuv;
2416 case GST_VIDEO_FORMAT_YUY2:
2417 case GST_VIDEO_FORMAT_YVYU:
2418 case GST_VIDEO_FORMAT_UYVY:
2419 alpha->process = gst_alpha_set_packed_422_ayuv;
2421 case GST_VIDEO_FORMAT_ARGB:
2422 case GST_VIDEO_FORMAT_ABGR:
2423 case GST_VIDEO_FORMAT_RGBA:
2424 case GST_VIDEO_FORMAT_BGRA:
2425 alpha->process = gst_alpha_set_argb_ayuv;
2427 case GST_VIDEO_FORMAT_xRGB:
2428 case GST_VIDEO_FORMAT_xBGR:
2429 case GST_VIDEO_FORMAT_RGBx:
2430 case GST_VIDEO_FORMAT_BGRx:
2431 case GST_VIDEO_FORMAT_RGB:
2432 case GST_VIDEO_FORMAT_BGR:
2433 alpha->process = gst_alpha_set_rgb_ayuv;
2439 case GST_VIDEO_FORMAT_ARGB:
2440 case GST_VIDEO_FORMAT_ABGR:
2441 case GST_VIDEO_FORMAT_RGBA:
2442 case GST_VIDEO_FORMAT_BGRA:
2443 switch (alpha->in_format) {
2444 case GST_VIDEO_FORMAT_AYUV:
2445 alpha->process = gst_alpha_set_ayuv_argb;
2447 case GST_VIDEO_FORMAT_Y444:
2448 case GST_VIDEO_FORMAT_Y42B:
2449 case GST_VIDEO_FORMAT_I420:
2450 case GST_VIDEO_FORMAT_YV12:
2451 case GST_VIDEO_FORMAT_Y41B:
2452 alpha->process = gst_alpha_set_planar_yuv_argb;
2454 case GST_VIDEO_FORMAT_YUY2:
2455 case GST_VIDEO_FORMAT_YVYU:
2456 case GST_VIDEO_FORMAT_UYVY:
2457 alpha->process = gst_alpha_set_packed_422_argb;
2459 case GST_VIDEO_FORMAT_ARGB:
2460 case GST_VIDEO_FORMAT_ABGR:
2461 case GST_VIDEO_FORMAT_RGBA:
2462 case GST_VIDEO_FORMAT_BGRA:
2463 alpha->process = gst_alpha_set_argb_argb;
2465 case GST_VIDEO_FORMAT_xRGB:
2466 case GST_VIDEO_FORMAT_xBGR:
2467 case GST_VIDEO_FORMAT_RGBx:
2468 case GST_VIDEO_FORMAT_BGRx:
2469 case GST_VIDEO_FORMAT_RGB:
2470 case GST_VIDEO_FORMAT_BGR:
2471 alpha->process = gst_alpha_set_rgb_argb;
2482 case ALPHA_METHOD_GREEN:
2483 case ALPHA_METHOD_BLUE:
2484 case ALPHA_METHOD_CUSTOM:
2485 switch (alpha->out_format) {
2486 case GST_VIDEO_FORMAT_AYUV:
2487 switch (alpha->in_format) {
2488 case GST_VIDEO_FORMAT_AYUV:
2489 alpha->process = gst_alpha_chroma_key_ayuv_ayuv;
2491 case GST_VIDEO_FORMAT_Y444:
2492 case GST_VIDEO_FORMAT_Y42B:
2493 case GST_VIDEO_FORMAT_I420:
2494 case GST_VIDEO_FORMAT_YV12:
2495 case GST_VIDEO_FORMAT_Y41B:
2496 alpha->process = gst_alpha_chroma_key_planar_yuv_ayuv;
2498 case GST_VIDEO_FORMAT_YUY2:
2499 case GST_VIDEO_FORMAT_YVYU:
2500 case GST_VIDEO_FORMAT_UYVY:
2501 alpha->process = gst_alpha_chroma_key_packed_422_ayuv;
2503 case GST_VIDEO_FORMAT_ARGB:
2504 case GST_VIDEO_FORMAT_ABGR:
2505 case GST_VIDEO_FORMAT_RGBA:
2506 case GST_VIDEO_FORMAT_BGRA:
2507 alpha->process = gst_alpha_chroma_key_argb_ayuv;
2509 case GST_VIDEO_FORMAT_xRGB:
2510 case GST_VIDEO_FORMAT_xBGR:
2511 case GST_VIDEO_FORMAT_RGBx:
2512 case GST_VIDEO_FORMAT_BGRx:
2513 case GST_VIDEO_FORMAT_RGB:
2514 case GST_VIDEO_FORMAT_BGR:
2515 alpha->process = gst_alpha_chroma_key_rgb_ayuv;
2521 case GST_VIDEO_FORMAT_ARGB:
2522 case GST_VIDEO_FORMAT_ABGR:
2523 case GST_VIDEO_FORMAT_RGBA:
2524 case GST_VIDEO_FORMAT_BGRA:
2525 switch (alpha->in_format) {
2526 case GST_VIDEO_FORMAT_AYUV:
2527 alpha->process = gst_alpha_chroma_key_ayuv_argb;
2529 case GST_VIDEO_FORMAT_Y444:
2530 case GST_VIDEO_FORMAT_Y42B:
2531 case GST_VIDEO_FORMAT_I420:
2532 case GST_VIDEO_FORMAT_YV12:
2533 case GST_VIDEO_FORMAT_Y41B:
2534 alpha->process = gst_alpha_chroma_key_planar_yuv_argb;
2536 case GST_VIDEO_FORMAT_YUY2:
2537 case GST_VIDEO_FORMAT_YVYU:
2538 case GST_VIDEO_FORMAT_UYVY:
2539 alpha->process = gst_alpha_chroma_key_packed_422_argb;
2541 case GST_VIDEO_FORMAT_ARGB:
2542 case GST_VIDEO_FORMAT_ABGR:
2543 case GST_VIDEO_FORMAT_RGBA:
2544 case GST_VIDEO_FORMAT_BGRA:
2545 alpha->process = gst_alpha_chroma_key_argb_argb;
2547 case GST_VIDEO_FORMAT_xRGB:
2548 case GST_VIDEO_FORMAT_xBGR:
2549 case GST_VIDEO_FORMAT_RGBx:
2550 case GST_VIDEO_FORMAT_BGRx:
2551 case GST_VIDEO_FORMAT_RGB:
2552 case GST_VIDEO_FORMAT_BGR:
2553 alpha->process = gst_alpha_chroma_key_rgb_argb;
2567 return alpha->process != NULL;
2571 gst_alpha_start (GstBaseTransform * btrans)
2573 GstAlpha *alpha = GST_ALPHA (btrans);
2575 GST_ALPHA_LOCK (alpha);
2576 gst_alpha_init_params (alpha);
2577 GST_ALPHA_UNLOCK (alpha);
2583 gst_alpha_before_transform (GstBaseTransform * btrans, GstBuffer * buf)
2585 GstAlpha *alpha = GST_ALPHA (btrans);
2586 GstClockTime timestamp;
2588 timestamp = gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME,
2589 GST_BUFFER_TIMESTAMP (buf));
2590 GST_LOG ("Got stream time of %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
2591 if (GST_CLOCK_TIME_IS_VALID (timestamp))
2592 gst_object_sync_values (G_OBJECT (alpha), timestamp);
2595 static GstFlowReturn
2596 gst_alpha_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out)
2598 GstAlpha *alpha = GST_ALPHA (btrans);
2601 GST_ALPHA_LOCK (alpha);
2603 if (G_UNLIKELY (!alpha->process)) {
2604 GST_ERROR_OBJECT (alpha, "Not negotiated yet");
2605 GST_ALPHA_UNLOCK (alpha);
2606 return GST_FLOW_NOT_NEGOTIATED;
2609 width = alpha->width;
2610 height = alpha->height;
2612 alpha->process (GST_BUFFER_DATA (in),
2613 GST_BUFFER_DATA (out), width, height, alpha);
2615 GST_ALPHA_UNLOCK (alpha);
2621 plugin_init (GstPlugin * plugin)
2623 gst_controller_init (NULL, NULL);
2625 return gst_element_register (plugin, "alpha", GST_RANK_NONE, GST_TYPE_ALPHA);
2628 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2631 "adds an alpha channel to video - constant or via chroma-keying",
2632 plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)