Merge commit 'a2337b8af45cb5e8c091ff0e1c3ef4b6cc7b20a3' into 0.11
[platform/upstream/gst-plugins-good.git] / gst / alpha / gstalpha.c
1 /* GStreamer
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>
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 /**
24  * SECTION:element-alpha
25  * 
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.
30  *
31  * Sample pipeline:
32  * |[
33  * gst-launch videotestsrc pattern=smpte75 ! alpha method=green ! \
34  *   videomixer name=mixer ! videoconvert ! 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.
39  */
40
41
42 #ifdef HAVE_CONFIG_H
43 #include "config.h"
44 #endif
45
46 #include "gstalpha.h"
47
48 #include <stdlib.h>
49 #include <string.h>
50 #include <math.h>
51
52 #ifndef M_PI
53 #define M_PI  3.14159265358979323846
54 #endif
55
56 /* Generated by -bad/ext/cog/generate_tables */
57 static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
58   298, 0, 459, -63514,
59   298, -55, -136, 19681,
60   298, 541, 0, -73988,
61 };
62
63 static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
64   298, 0, 409, -57068,
65   298, -100, -208, 34707,
66   298, 516, 0, -70870,
67 };
68
69 static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
70   47, 157, 16, 4096,
71   -26, -87, 112, 32768,
72   112, -102, -10, 32768,
73 };
74
75 static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
76   66, 129, 25, 4096,
77   -38, -74, 112, 32768,
78   112, -94, -18, 32768,
79 };
80
81 static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
82   256, -30, -53, 10600,
83   0, 261, 29, -4367,
84   0, 19, 262, -3289,
85 };
86
87 static const gint cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = {
88   256, 25, 49, -9536,
89   0, 253, -28, 3958,
90   0, -19, 252, 2918,
91 };
92
93 /* Alpha signals and args */
94 enum
95 {
96   /* FILL ME */
97   LAST_SIGNAL
98 };
99
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
110
111 enum
112 {
113   PROP_0,
114   PROP_METHOD,
115   PROP_ALPHA,
116   PROP_TARGET_R,
117   PROP_TARGET_G,
118   PROP_TARGET_B,
119   PROP_ANGLE,
120   PROP_NOISE_LEVEL,
121   PROP_BLACK_SENSITIVITY,
122   PROP_WHITE_SENSITIVITY,
123   PROP_PREFER_PASSTHROUGH,
124   PROP_LAST
125 };
126
127 static GstStaticPadTemplate gst_alpha_src_template =
128 GST_STATIC_PAD_TEMPLATE ("src",
129     GST_PAD_SRC,
130     GST_PAD_ALWAYS,
131     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
132             "ARGB, BGRA, ABGR, RGBA, Y444, xRGB, BGRx, xBGR, "
133             "RGBx, RGB, BGR, Y42B, YUY2, YVYU, UYVY, I420, YV12, Y41B } "))
134     );
135
136 static GstStaticPadTemplate gst_alpha_sink_template =
137 GST_STATIC_PAD_TEMPLATE ("sink",
138     GST_PAD_SINK,
139     GST_PAD_ALWAYS,
140     GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, "
141             "ARGB, BGRA, ABGR, RGBA, Y444, xRGB, BGRx, xBGR, "
142             "RGBx, RGB, BGR, Y42B, YUY2, YVYU, UYVY, I420, YV12, " "Y41B } "))
143     );
144
145 static GstStaticCaps gst_alpha_alpha_caps =
146 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("{ AYUV, ARGB, BGRA, ABGR, RGBA }"));
147
148 #define GST_ALPHA_LOCK(alpha) G_STMT_START { \
149   GST_LOG_OBJECT (alpha, "Locking alpha from thread %p", g_thread_self ()); \
150   g_static_mutex_lock (&alpha->lock); \
151   GST_LOG_OBJECT (alpha, "Locked alpha from thread %p", g_thread_self ()); \
152 } G_STMT_END
153
154 #define GST_ALPHA_UNLOCK(alpha) G_STMT_START { \
155   GST_LOG_OBJECT (alpha, "Unlocking alpha from thread %p", g_thread_self ()); \
156   g_static_mutex_unlock (&alpha->lock); \
157 } G_STMT_END
158
159 static gboolean gst_alpha_get_unit_size (GstBaseTransform * btrans,
160     GstCaps * caps, gsize * size);
161 static GstCaps *gst_alpha_transform_caps (GstBaseTransform * btrans,
162     GstPadDirection direction, GstCaps * caps, GstCaps * filter);
163 static gboolean gst_alpha_set_caps (GstBaseTransform * btrans,
164     GstCaps * incaps, GstCaps * outcaps);
165 static GstFlowReturn gst_alpha_transform (GstBaseTransform * btrans,
166     GstBuffer * in, GstBuffer * out);
167 static void gst_alpha_before_transform (GstBaseTransform * btrans,
168     GstBuffer * buf);
169
170 static void gst_alpha_init_params (GstAlpha * alpha);
171 static gboolean gst_alpha_set_process_function (GstAlpha * alpha);
172
173 static void gst_alpha_set_property (GObject * object, guint prop_id,
174     const GValue * value, GParamSpec * pspec);
175 static void gst_alpha_get_property (GObject * object, guint prop_id,
176     GValue * value, GParamSpec * pspec);
177 static void gst_alpha_finalize (GObject * object);
178
179 #define gst_alpha_parent_class parent_class
180 G_DEFINE_TYPE (GstAlpha, gst_alpha, GST_TYPE_VIDEO_FILTER);
181
182 #define GST_TYPE_ALPHA_METHOD (gst_alpha_method_get_type())
183 static GType
184 gst_alpha_method_get_type (void)
185 {
186   static GType alpha_method_type = 0;
187   static const GEnumValue alpha_method[] = {
188     {ALPHA_METHOD_SET, "Set/adjust alpha channel", "set"},
189     {ALPHA_METHOD_GREEN, "Chroma Key green", "green"},
190     {ALPHA_METHOD_BLUE, "Chroma Key blue", "blue"},
191     {ALPHA_METHOD_CUSTOM, "Chroma Key on target_r/g/b", "custom"},
192     {0, NULL, NULL},
193   };
194
195   if (!alpha_method_type) {
196     alpha_method_type = g_enum_register_static ("GstAlphaMethod", alpha_method);
197   }
198   return alpha_method_type;
199 }
200
201 static void
202 gst_alpha_class_init (GstAlphaClass * klass)
203 {
204   GObjectClass *gobject_class = (GObjectClass *) klass;
205   GstElementClass *gstelement_class = (GstElementClass *) klass;
206   GstBaseTransformClass *btrans_class = (GstBaseTransformClass *) klass;
207
208   GST_DEBUG_CATEGORY_INIT (gst_alpha_debug, "alpha", 0,
209       "alpha - Element for adding alpha channel to streams");
210
211   gobject_class->set_property = gst_alpha_set_property;
212   gobject_class->get_property = gst_alpha_get_property;
213   gobject_class->finalize = gst_alpha_finalize;
214
215   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_METHOD,
216       g_param_spec_enum ("method", "Method",
217           "How the alpha channels should be created", GST_TYPE_ALPHA_METHOD,
218           DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
219   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA,
220       g_param_spec_double ("alpha", "Alpha", "The value for the alpha channel",
221           0.0, 1.0, DEFAULT_ALPHA,
222           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
223   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_R,
224       g_param_spec_uint ("target-r", "Target Red", "The Red target", 0, 255,
225           DEFAULT_TARGET_R,
226           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
227   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_G,
228       g_param_spec_uint ("target-g", "Target Green", "The Green target", 0, 255,
229           DEFAULT_TARGET_G,
230           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
231   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_B,
232       g_param_spec_uint ("target-b", "Target Blue", "The Blue target", 0, 255,
233           DEFAULT_TARGET_B,
234           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
235   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ANGLE,
236       g_param_spec_float ("angle", "Angle", "Size of the colorcube to change",
237           0.0, 90.0, DEFAULT_ANGLE,
238           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
239   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NOISE_LEVEL,
240       g_param_spec_float ("noise-level", "Noise Level", "Size of noise radius",
241           0.0, 64.0, DEFAULT_NOISE_LEVEL,
242           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
243   g_object_class_install_property (G_OBJECT_CLASS (klass),
244       PROP_BLACK_SENSITIVITY, g_param_spec_uint ("black-sensitivity",
245           "Black Sensitivity", "Sensitivity to dark colors", 0, 128,
246           DEFAULT_BLACK_SENSITIVITY,
247           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
248   g_object_class_install_property (G_OBJECT_CLASS (klass),
249       PROP_WHITE_SENSITIVITY, g_param_spec_uint ("white-sensitivity",
250           "Sensitivity", "Sensitivity to bright colors", 0, 128,
251           DEFAULT_WHITE_SENSITIVITY,
252           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
253   g_object_class_install_property (G_OBJECT_CLASS (klass),
254       PROP_PREFER_PASSTHROUGH, g_param_spec_boolean ("prefer-passthrough",
255           "Prefer Passthrough",
256           "Don't do any processing for alpha=1.0 if possible",
257           DEFAULT_PREFER_PASSTHROUGH,
258           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
259
260   gst_element_class_set_details_simple (gstelement_class, "Alpha filter",
261       "Filter/Effect/Video",
262       "Adds an alpha channel to video - uniform or via chroma-keying",
263       "Wim Taymans <wim.taymans@gmail.com>\n"
264       "Edward Hervey <edward.hervey@collabora.co.uk>\n"
265       "Jan Schmidt <thaytan@noraisin.net>");
266
267   gst_element_class_add_pad_template (gstelement_class,
268       gst_static_pad_template_get (&gst_alpha_sink_template));
269   gst_element_class_add_pad_template (gstelement_class,
270       gst_static_pad_template_get (&gst_alpha_src_template));
271
272   btrans_class->transform = GST_DEBUG_FUNCPTR (gst_alpha_transform);
273   btrans_class->before_transform =
274       GST_DEBUG_FUNCPTR (gst_alpha_before_transform);
275   btrans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_alpha_get_unit_size);
276   btrans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_alpha_transform_caps);
277   btrans_class->set_caps = GST_DEBUG_FUNCPTR (gst_alpha_set_caps);
278 }
279
280 static void
281 gst_alpha_init (GstAlpha * alpha)
282 {
283   alpha->alpha = DEFAULT_ALPHA;
284   alpha->method = DEFAULT_METHOD;
285   alpha->target_r = DEFAULT_TARGET_R;
286   alpha->target_g = DEFAULT_TARGET_G;
287   alpha->target_b = DEFAULT_TARGET_B;
288   alpha->angle = DEFAULT_ANGLE;
289   alpha->noise_level = DEFAULT_NOISE_LEVEL;
290   alpha->black_sensitivity = DEFAULT_BLACK_SENSITIVITY;
291   alpha->white_sensitivity = DEFAULT_WHITE_SENSITIVITY;
292
293   g_static_mutex_init (&alpha->lock);
294 }
295
296 static void
297 gst_alpha_finalize (GObject * object)
298 {
299   GstAlpha *alpha = GST_ALPHA (object);
300
301   g_static_mutex_free (&alpha->lock);
302
303   G_OBJECT_CLASS (parent_class)->finalize (object);
304 }
305
306 static void
307 gst_alpha_set_property (GObject * object, guint prop_id,
308     const GValue * value, GParamSpec * pspec)
309 {
310   GstAlpha *alpha = GST_ALPHA (object);
311   gboolean reconfigure = FALSE;
312
313   GST_ALPHA_LOCK (alpha);
314   switch (prop_id) {
315     case PROP_METHOD:{
316       gint method = g_value_get_enum (value);
317
318       reconfigure = (method != alpha->method) && (method == ALPHA_METHOD_SET
319           || alpha->method == ALPHA_METHOD_SET) && (alpha->alpha == 1.0)
320           && (alpha->prefer_passthrough);
321       alpha->method = method;
322
323       switch (alpha->method) {
324         case ALPHA_METHOD_GREEN:
325           alpha->target_r = 0;
326           alpha->target_g = 255;
327           alpha->target_b = 0;
328           break;
329         case ALPHA_METHOD_BLUE:
330           alpha->target_r = 0;
331           alpha->target_g = 0;
332           alpha->target_b = 255;
333           break;
334         default:
335           break;
336       }
337       gst_alpha_set_process_function (alpha);
338       gst_alpha_init_params (alpha);
339       break;
340     }
341     case PROP_ALPHA:{
342       gdouble a = g_value_get_double (value);
343
344       reconfigure = (a != alpha->alpha) && (a == 1.0 || alpha->alpha == 1.0)
345           && (alpha->method == ALPHA_METHOD_SET) && (alpha->prefer_passthrough);
346       alpha->alpha = a;
347       break;
348     }
349     case PROP_TARGET_R:
350       alpha->target_r = g_value_get_uint (value);
351       gst_alpha_init_params (alpha);
352       break;
353     case PROP_TARGET_G:
354       alpha->target_g = g_value_get_uint (value);
355       gst_alpha_init_params (alpha);
356       break;
357     case PROP_TARGET_B:
358       alpha->target_b = g_value_get_uint (value);
359       gst_alpha_init_params (alpha);
360       break;
361     case PROP_ANGLE:
362       alpha->angle = g_value_get_float (value);
363       gst_alpha_init_params (alpha);
364       break;
365     case PROP_NOISE_LEVEL:
366       alpha->noise_level = g_value_get_float (value);
367       gst_alpha_init_params (alpha);
368       break;
369     case PROP_BLACK_SENSITIVITY:
370       alpha->black_sensitivity = g_value_get_uint (value);
371       break;
372     case PROP_WHITE_SENSITIVITY:
373       alpha->white_sensitivity = g_value_get_uint (value);
374       break;
375     case PROP_PREFER_PASSTHROUGH:{
376       gboolean prefer_passthrough = g_value_get_boolean (value);
377
378       reconfigure = ((! !prefer_passthrough) != (! !alpha->prefer_passthrough))
379           && (alpha->method == ALPHA_METHOD_SET) && (alpha->alpha == 1.0);
380       alpha->prefer_passthrough = prefer_passthrough;
381       break;
382     }
383     default:
384       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
385       break;
386   }
387
388   if (reconfigure)
389     gst_base_transform_reconfigure (GST_BASE_TRANSFORM_CAST (alpha));
390
391   GST_ALPHA_UNLOCK (alpha);
392 }
393
394 static void
395 gst_alpha_get_property (GObject * object, guint prop_id, GValue * value,
396     GParamSpec * pspec)
397 {
398   GstAlpha *alpha = GST_ALPHA (object);
399
400   switch (prop_id) {
401     case PROP_METHOD:
402       g_value_set_enum (value, alpha->method);
403       break;
404     case PROP_ALPHA:
405       g_value_set_double (value, alpha->alpha);
406       break;
407     case PROP_TARGET_R:
408       g_value_set_uint (value, alpha->target_r);
409       break;
410     case PROP_TARGET_G:
411       g_value_set_uint (value, alpha->target_g);
412       break;
413     case PROP_TARGET_B:
414       g_value_set_uint (value, alpha->target_b);
415       break;
416     case PROP_ANGLE:
417       g_value_set_float (value, alpha->angle);
418       break;
419     case PROP_NOISE_LEVEL:
420       g_value_set_float (value, alpha->noise_level);
421       break;
422     case PROP_BLACK_SENSITIVITY:
423       g_value_set_uint (value, alpha->black_sensitivity);
424       break;
425     case PROP_WHITE_SENSITIVITY:
426       g_value_set_uint (value, alpha->white_sensitivity);
427       break;
428     case PROP_PREFER_PASSTHROUGH:
429       g_value_set_boolean (value, alpha->prefer_passthrough);
430       break;
431     default:
432       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
433       break;
434   }
435 }
436
437 static gboolean
438 gst_alpha_get_unit_size (GstBaseTransform * btrans,
439     GstCaps * caps, gsize * size)
440 {
441   GstVideoInfo info;
442
443   if (!gst_video_info_from_caps (&info, caps))
444     return FALSE;
445
446   *size = info.size;
447
448   GST_DEBUG_OBJECT (btrans,
449       "unit size = %" G_GSIZE_FORMAT " for format %s w %d height %d", *size,
450       GST_VIDEO_INFO_NAME (&info), GST_VIDEO_INFO_WIDTH (&info),
451       GST_VIDEO_INFO_HEIGHT (&info));
452
453   return TRUE;
454 }
455
456 static GstCaps *
457 gst_alpha_transform_caps (GstBaseTransform * btrans,
458     GstPadDirection direction, GstCaps * caps, GstCaps * filter)
459 {
460   GstAlpha *alpha = GST_ALPHA (btrans);
461   GstCaps *ret, *tmp, *tmp2;
462   GstStructure *structure;
463   gint i;
464
465   tmp = gst_caps_new_empty ();
466
467   GST_ALPHA_LOCK (alpha);
468   for (i = 0; i < gst_caps_get_size (caps); i++) {
469     structure = gst_structure_copy (gst_caps_get_structure (caps, i));
470
471     gst_structure_remove_field (structure, "format");
472     gst_structure_remove_field (structure, "color-matrix");
473     gst_structure_remove_field (structure, "chroma-site");
474
475     gst_caps_append_structure (tmp, structure);
476   }
477
478   if (direction == GST_PAD_SINK) {
479     tmp2 = gst_static_caps_get (&gst_alpha_alpha_caps);
480     ret = gst_caps_intersect (tmp, tmp2);
481     gst_caps_unref (tmp);
482     gst_caps_unref (tmp2);
483     tmp = ret;
484     ret = NULL;
485
486     if (alpha->prefer_passthrough && alpha->method == ALPHA_METHOD_SET
487         && alpha->alpha == 1.0) {
488       ret = gst_caps_copy (caps);
489       gst_caps_append (ret, tmp);
490       tmp = NULL;
491     } else {
492       ret = tmp;
493       tmp = NULL;
494     }
495   } else {
496     ret = tmp;
497     tmp = NULL;
498   }
499
500   GST_DEBUG_OBJECT (alpha,
501       "Transformed %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT, caps, ret);
502
503   if (filter) {
504     GstCaps *intersection;
505
506     GST_DEBUG_OBJECT (alpha, "Using filter caps %" GST_PTR_FORMAT, filter);
507     intersection =
508         gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
509     gst_caps_unref (ret);
510     ret = intersection;
511     GST_DEBUG_OBJECT (alpha, "Intersection %" GST_PTR_FORMAT, ret);
512   }
513
514
515   GST_ALPHA_UNLOCK (alpha);
516
517   return ret;
518 }
519
520 static gboolean
521 gst_alpha_set_caps (GstBaseTransform * btrans,
522     GstCaps * incaps, GstCaps * outcaps)
523 {
524   GstAlpha *alpha = GST_ALPHA (btrans);
525   GstVideoInfo in_info, out_info;
526   gboolean passthrough;
527
528   if (!gst_video_info_from_caps (&in_info, incaps) ||
529       !gst_video_info_from_caps (&out_info, outcaps))
530     goto invalid_format;
531
532   GST_ALPHA_LOCK (alpha);
533
534   alpha->in_sdtv = in_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
535   alpha->out_sdtv = out_info.colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_BT601;
536
537   passthrough = alpha->prefer_passthrough &&
538       GST_VIDEO_INFO_FORMAT (&in_info) == GST_VIDEO_INFO_FORMAT (&out_info)
539       && alpha->in_sdtv == alpha->out_sdtv && alpha->method == ALPHA_METHOD_SET
540       && alpha->alpha == 1.0;
541
542   GST_DEBUG_OBJECT (alpha,
543       "Setting caps %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT
544       " (passthrough: %d)", incaps, outcaps, passthrough);
545   gst_base_transform_set_passthrough (btrans, passthrough);
546
547   alpha->in_info = in_info;
548   alpha->out_info = out_info;
549
550   if (!gst_alpha_set_process_function (alpha) && !passthrough)
551     goto no_process;
552
553   gst_alpha_init_params (alpha);
554
555   GST_ALPHA_UNLOCK (alpha);
556
557   return TRUE;
558
559   /* ERRORS */
560 invalid_format:
561   {
562     GST_WARNING_OBJECT (alpha,
563         "Failed to parse caps %" GST_PTR_FORMAT " -> %" GST_PTR_FORMAT, incaps,
564         outcaps);
565     return FALSE;
566   }
567 no_process:
568   {
569     GST_WARNING_OBJECT (alpha,
570         "No processing function for this caps and no passthrough mode");
571     GST_ALPHA_UNLOCK (alpha);
572     return FALSE;
573   }
574 }
575
576 /* based on http://www.cs.utah.edu/~michael/chroma/
577  */
578 static inline gint
579 chroma_keying_yuv (gint a, gint * y, gint * u,
580     gint * v, gint cr, gint cb, gint smin, gint smax, guint8 accept_angle_tg,
581     guint8 accept_angle_ctg, guint8 one_over_kc, guint8 kfgy_scale, gint8 kg,
582     guint noise_level2)
583 {
584   gint tmp, tmp1;
585   gint x1, y1;
586   gint x, z;
587   gint b_alpha;
588
589   /* too dark or too bright, keep alpha */
590   if (*y < smin || *y > smax)
591     return a;
592
593   /* Convert foreground to XZ coords where X direction is defined by
594      the key color */
595   tmp = ((*u) * cb + (*v) * cr) >> 7;
596   x = CLAMP (tmp, -128, 127);
597   tmp = ((*v) * cb - (*u) * cr) >> 7;
598   z = CLAMP (tmp, -128, 127);
599
600   /* WARNING: accept angle should never be set greater than "somewhat less
601      than 90 degrees" to avoid dealing with negative/infinite tg. In reality,
602      80 degrees should be enough if foreground is reasonable. If this seems
603      to be a problem, go to alternative ways of checking point position
604      (scalar product or line equations). This angle should not be too small
605      either to avoid infinite ctg (used to suppress foreground without use of
606      division) */
607
608   tmp = (x * accept_angle_tg) >> 4;
609   tmp = MIN (tmp, 127);
610
611   if (abs (z) > tmp) {
612     /* keep foreground Kfg = 0 */
613     return a;
614   }
615   /* Compute Kfg (implicitly) and Kbg, suppress foreground in XZ coord
616      according to Kfg */
617   tmp = (z * accept_angle_ctg) >> 4;
618   tmp = CLAMP (tmp, -128, 127);
619   x1 = abs (tmp);
620   y1 = z;
621
622   tmp1 = x - x1;
623   tmp1 = MAX (tmp1, 0);
624   b_alpha = (tmp1 * one_over_kc) / 2;
625   b_alpha = 255 - CLAMP (b_alpha, 0, 255);
626   b_alpha = (a * b_alpha) >> 8;
627
628   tmp = (tmp1 * kfgy_scale) >> 4;
629   tmp1 = MIN (tmp, 255);
630
631   *y = (*y < tmp1) ? 0 : *y - tmp1;
632
633   /* Convert suppressed foreground back to CbCr */
634   tmp = (x1 * cb - y1 * cr) >> 7;
635   *u = CLAMP (tmp, -128, 127);
636
637   tmp = (x1 * cr + y1 * cb) >> 7;
638   *v = CLAMP (tmp, -128, 127);
639
640   /* Deal with noise. For now, a circle around the key color with
641      radius of noise_level treated as exact key color. Introduces
642      sharp transitions.
643    */
644   tmp = z * z + (x - kg) * (x - kg);
645   tmp = MIN (tmp, 0xffff);
646
647   if (tmp < noise_level2)
648     b_alpha = 0;
649
650   return b_alpha;
651 }
652
653 #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)
654
655 static void
656 gst_alpha_set_argb_ayuv (const GstVideoFrame * in_frame,
657     GstVideoFrame * out_frame, GstAlpha * alpha)
658 {
659   gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
660   const guint8 *src;
661   guint8 *dest;
662   gint width, height;
663   gint i, j;
664   gint matrix[12];
665   gint y, u, v;
666   gint o[4];
667
668   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
669   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
670
671   width = GST_VIDEO_FRAME_WIDTH (in_frame);
672   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
673
674   o[0] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 3);
675   o[1] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 0);
676   o[2] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
677   o[3] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
678
679   memcpy (matrix,
680       alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
681       cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
682
683   for (i = 0; i < height; i++) {
684     for (j = 0; j < width; j++) {
685       dest[0] = (src[o[0]] * s_alpha) >> 8;
686
687       y = APPLY_MATRIX (matrix, 0, src[o[1]], src[o[2]], src[o[3]]);
688       u = APPLY_MATRIX (matrix, 1, src[o[1]], src[o[2]], src[o[3]]);
689       v = APPLY_MATRIX (matrix, 2, src[o[1]], src[o[2]], src[o[3]]);
690
691       dest[1] = y;
692       dest[2] = u;
693       dest[3] = v;
694
695       dest += 4;
696       src += 4;
697     }
698   }
699 }
700
701 static void
702 gst_alpha_chroma_key_argb_ayuv (const GstVideoFrame * in_frame,
703     GstVideoFrame * out_frame, GstAlpha * alpha)
704 {
705   const guint8 *src;
706   guint8 *dest;
707   gint width, height;
708   gint i, j;
709   gint a, y, u, v;
710   gint r, g, b;
711   gint smin, smax;
712   gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
713   gint8 cb = alpha->cb, cr = alpha->cr;
714   gint8 kg = alpha->kg;
715   guint8 accept_angle_tg = alpha->accept_angle_tg;
716   guint8 accept_angle_ctg = alpha->accept_angle_ctg;
717   guint8 one_over_kc = alpha->one_over_kc;
718   guint8 kfgy_scale = alpha->kfgy_scale;
719   guint noise_level2 = alpha->noise_level2;
720   gint matrix[12];
721   gint o[4];
722
723   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
724   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
725
726   width = GST_VIDEO_FRAME_WIDTH (in_frame);
727   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
728
729   o[0] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 3);
730   o[1] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 0);
731   o[2] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
732   o[3] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
733
734   smin = 128 - alpha->black_sensitivity;
735   smax = 128 + alpha->white_sensitivity;
736
737   memcpy (matrix,
738       alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
739       cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
740
741   for (i = 0; i < height; i++) {
742     for (j = 0; j < width; j++) {
743       a = (src[o[0]] * pa) >> 8;
744       r = src[o[1]];
745       g = src[o[2]];
746       b = src[o[3]];
747
748       y = APPLY_MATRIX (matrix, 0, r, g, b);
749       u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
750       v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
751
752       a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
753           smin, smax, accept_angle_tg, accept_angle_ctg,
754           one_over_kc, kfgy_scale, kg, noise_level2);
755
756       u += 128;
757       v += 128;
758
759       dest[0] = a;
760       dest[1] = y;
761       dest[2] = u;
762       dest[3] = v;
763
764       src += 4;
765       dest += 4;
766     }
767   }
768 }
769
770 static void
771 gst_alpha_set_argb_argb (const GstVideoFrame * in_frame,
772     GstVideoFrame * out_frame, GstAlpha * alpha)
773 {
774   const guint8 *src;
775   guint8 *dest;
776   gint width, height;
777   gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
778   gint i, j;
779   gint p[4], o[4];
780
781   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
782   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
783
784   width = GST_VIDEO_FRAME_WIDTH (in_frame);
785   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
786
787   p[0] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 3);
788   p[1] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 0);
789   p[2] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 1);
790   p[3] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 2);
791
792   o[0] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 3);
793   o[1] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 0);
794   o[2] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
795   o[3] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
796
797   for (i = 0; i < height; i++) {
798     for (j = 0; j < width; j++) {
799       dest[p[0]] = (src[o[0]] * s_alpha) >> 8;
800
801       dest[p[1]] = src[o[1]];
802       dest[p[2]] = src[o[2]];
803       dest[p[3]] = src[o[3]];
804
805       dest += 4;
806       src += 4;
807     }
808   }
809 }
810
811 static void
812 gst_alpha_chroma_key_argb_argb (const GstVideoFrame * in_frame,
813     GstVideoFrame * out_frame, GstAlpha * alpha)
814 {
815   const guint8 *src;
816   guint8 *dest;
817   gint width, height;
818   gint i, j;
819   gint a, y, u, v;
820   gint r, g, b;
821   gint smin, smax;
822   gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
823   gint8 cb = alpha->cb, cr = alpha->cr;
824   gint8 kg = alpha->kg;
825   guint8 accept_angle_tg = alpha->accept_angle_tg;
826   guint8 accept_angle_ctg = alpha->accept_angle_ctg;
827   guint8 one_over_kc = alpha->one_over_kc;
828   guint8 kfgy_scale = alpha->kfgy_scale;
829   guint noise_level2 = alpha->noise_level2;
830   gint matrix[12], matrix2[12];
831   gint p[4], o[4];
832
833   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
834   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
835
836   width = GST_VIDEO_FRAME_WIDTH (in_frame);
837   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
838
839   p[0] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 3);
840   p[1] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 0);
841   p[2] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 1);
842   p[3] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 2);
843
844   o[0] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 3);
845   o[1] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 0);
846   o[2] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
847   o[3] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
848
849   smin = 128 - alpha->black_sensitivity;
850   smax = 128 + alpha->white_sensitivity;
851
852   memcpy (matrix, cog_rgb_to_ycbcr_matrix_8bit_sdtv, 12 * sizeof (gint));
853   memcpy (matrix2, cog_ycbcr_to_rgb_matrix_8bit_sdtv, 12 * sizeof (gint));
854
855   for (i = 0; i < height; i++) {
856     for (j = 0; j < width; j++) {
857       a = (src[o[0]] * pa) >> 8;
858       r = src[o[1]];
859       g = src[o[2]];
860       b = src[o[3]];
861
862       y = APPLY_MATRIX (matrix, 0, r, g, b);
863       u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
864       v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
865
866       a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
867           smin, smax, accept_angle_tg, accept_angle_ctg,
868           one_over_kc, kfgy_scale, kg, noise_level2);
869
870       u += 128;
871       v += 128;
872
873       r = APPLY_MATRIX (matrix2, 0, y, u, v);
874       g = APPLY_MATRIX (matrix2, 1, y, u, v);
875       b = APPLY_MATRIX (matrix2, 2, y, u, v);
876
877       dest[p[0]] = a;
878       dest[p[1]] = CLAMP (r, 0, 255);
879       dest[p[2]] = CLAMP (g, 0, 255);
880       dest[p[3]] = CLAMP (b, 0, 255);
881
882       src += 4;
883       dest += 4;
884     }
885   }
886 }
887
888 static void
889 gst_alpha_set_ayuv_argb (const GstVideoFrame * in_frame,
890     GstVideoFrame * out_frame, GstAlpha * alpha)
891 {
892   const guint8 *src;
893   guint8 *dest;
894   gint width, height;
895   gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
896   gint y, x;
897   gint matrix[12];
898   gint r, g, b;
899   gint p[4];
900
901   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
902   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
903
904   width = GST_VIDEO_FRAME_WIDTH (in_frame);
905   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
906
907   p[0] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 3);
908   p[1] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 0);
909   p[2] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 1);
910   p[3] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 2);
911
912   memcpy (matrix,
913       alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
914       cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
915
916   for (y = 0; y < height; y++) {
917     for (x = 0; x < width; x++) {
918       dest[p[0]] = (src[0] * s_alpha) >> 8;
919
920       r = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
921       g = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]);
922       b = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]);
923
924       dest[p[1]] = CLAMP (r, 0, 255);
925       dest[p[2]] = CLAMP (g, 0, 255);
926       dest[p[3]] = CLAMP (b, 0, 255);
927
928       dest += 4;
929       src += 4;
930     }
931   }
932 }
933
934 static void
935 gst_alpha_chroma_key_ayuv_argb (const GstVideoFrame * in_frame,
936     GstVideoFrame * out_frame, GstAlpha * alpha)
937 {
938   const guint8 *src;
939   guint8 *dest;
940   gint width, height;
941   gint i, j;
942   gint a, y, u, v;
943   gint r, g, b;
944   gint smin, smax;
945   gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
946   gint8 cb = alpha->cb, cr = alpha->cr;
947   gint8 kg = alpha->kg;
948   guint8 accept_angle_tg = alpha->accept_angle_tg;
949   guint8 accept_angle_ctg = alpha->accept_angle_ctg;
950   guint8 one_over_kc = alpha->one_over_kc;
951   guint8 kfgy_scale = alpha->kfgy_scale;
952   guint noise_level2 = alpha->noise_level2;
953   gint matrix[12];
954   gint p[4];
955
956   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
957   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
958
959   width = GST_VIDEO_FRAME_WIDTH (in_frame);
960   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
961
962   p[0] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 3);
963   p[1] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 0);
964   p[2] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 1);
965   p[3] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 2);
966
967   smin = 128 - alpha->black_sensitivity;
968   smax = 128 + alpha->white_sensitivity;
969
970   memcpy (matrix,
971       alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
972       cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
973
974   for (i = 0; i < height; i++) {
975     for (j = 0; j < width; j++) {
976       a = (src[0] * pa) >> 8;
977       y = src[1];
978       u = src[2] - 128;
979       v = src[3] - 128;
980
981       a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
982           smin, smax, accept_angle_tg, accept_angle_ctg,
983           one_over_kc, kfgy_scale, kg, noise_level2);
984
985       u += 128;
986       v += 128;
987
988       r = APPLY_MATRIX (matrix, 0, y, u, v);
989       g = APPLY_MATRIX (matrix, 1, y, u, v);
990       b = APPLY_MATRIX (matrix, 2, y, u, v);
991
992       dest[p[0]] = a;
993       dest[p[1]] = CLAMP (r, 0, 255);
994       dest[p[2]] = CLAMP (g, 0, 255);
995       dest[p[3]] = CLAMP (b, 0, 255);
996
997       src += 4;
998       dest += 4;
999     }
1000   }
1001 }
1002
1003 static void
1004 gst_alpha_set_ayuv_ayuv (const GstVideoFrame * in_frame,
1005     GstVideoFrame * out_frame, GstAlpha * alpha)
1006 {
1007   const guint8 *src;
1008   guint8 *dest;
1009   gint width, height;
1010   gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
1011   gint y, x;
1012
1013   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1014   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1015
1016   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1017   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1018
1019   if (alpha->in_sdtv == alpha->out_sdtv) {
1020     for (y = 0; y < height; y++) {
1021       for (x = 0; x < width; x++) {
1022         dest[0] = (src[0] * s_alpha) >> 8;
1023         dest[1] = src[1];
1024         dest[2] = src[2];
1025         dest[3] = src[3];
1026
1027         dest += 4;
1028         src += 4;
1029       }
1030     }
1031   } else {
1032     gint matrix[12];
1033
1034     memcpy (matrix,
1035         alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1036         cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1037
1038     for (y = 0; y < height; y++) {
1039       for (x = 0; x < width; x++) {
1040         dest[0] = (src[0] * s_alpha) >> 8;
1041         dest[1] = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
1042         dest[2] = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]);
1043         dest[3] = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]);
1044
1045         dest += 4;
1046         src += 4;
1047       }
1048     }
1049   }
1050 }
1051
1052 static void
1053 gst_alpha_chroma_key_ayuv_ayuv (const GstVideoFrame * in_frame,
1054     GstVideoFrame * out_frame, GstAlpha * alpha)
1055 {
1056   const guint8 *src;
1057   guint8 *dest;
1058   gint width, height;
1059   gint i, j;
1060   gint a, y, u, v;
1061   gint smin, smax;
1062   gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
1063   gint8 cb = alpha->cb, cr = alpha->cr;
1064   gint8 kg = alpha->kg;
1065   guint8 accept_angle_tg = alpha->accept_angle_tg;
1066   guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1067   guint8 one_over_kc = alpha->one_over_kc;
1068   guint8 kfgy_scale = alpha->kfgy_scale;
1069   guint noise_level2 = alpha->noise_level2;
1070
1071   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1072   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1073
1074   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1075   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1076
1077   smin = 128 - alpha->black_sensitivity;
1078   smax = 128 + alpha->white_sensitivity;
1079
1080   if (alpha->in_sdtv == alpha->out_sdtv) {
1081     for (i = 0; i < height; i++) {
1082       for (j = 0; j < width; j++) {
1083         a = (src[0] * pa) >> 8;
1084         y = src[1];
1085         u = src[2] - 128;
1086         v = src[3] - 128;
1087
1088         a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1089             smin, smax, accept_angle_tg, accept_angle_ctg,
1090             one_over_kc, kfgy_scale, kg, noise_level2);
1091
1092         u += 128;
1093         v += 128;
1094
1095         dest[0] = a;
1096         dest[1] = y;
1097         dest[2] = u;
1098         dest[3] = v;
1099
1100         src += 4;
1101         dest += 4;
1102       }
1103     }
1104   } else {
1105     gint matrix[12];
1106
1107     memcpy (matrix,
1108         alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1109         cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1110
1111     for (i = 0; i < height; i++) {
1112       for (j = 0; j < width; j++) {
1113         a = (src[0] * pa) >> 8;
1114         y = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
1115         u = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]) - 128;
1116         v = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]) - 128;
1117
1118         a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1119             smin, smax, accept_angle_tg, accept_angle_ctg,
1120             one_over_kc, kfgy_scale, kg, noise_level2);
1121
1122         u += 128;
1123         v += 128;
1124
1125         dest[0] = a;
1126         dest[1] = y;
1127         dest[2] = u;
1128         dest[3] = v;
1129
1130         src += 4;
1131         dest += 4;
1132       }
1133     }
1134   }
1135 }
1136
1137 static void
1138 gst_alpha_set_rgb_ayuv (const GstVideoFrame * in_frame,
1139     GstVideoFrame * out_frame, GstAlpha * alpha)
1140 {
1141   const guint8 *src;
1142   guint8 *dest;
1143   gint width, height;
1144   gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1145   gint i, j;
1146   gint matrix[12];
1147   gint y, u, v;
1148   gint o[3];
1149   gint bpp;
1150
1151   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1152   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1153
1154   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1155   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1156
1157   bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (in_frame, 0);
1158   o[0] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 0);
1159   o[1] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
1160   o[2] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
1161
1162   memcpy (matrix,
1163       alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
1164       cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
1165
1166   for (i = 0; i < height; i++) {
1167     for (j = 0; j < width; j++) {
1168       dest[0] = s_alpha;
1169
1170       y = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[2]]);
1171       u = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[2]]);
1172       v = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[2]]);
1173
1174       dest[1] = y;
1175       dest[2] = u;
1176       dest[3] = v;
1177
1178       dest += 4;
1179       src += bpp;
1180     }
1181   }
1182 }
1183
1184 static void
1185 gst_alpha_chroma_key_rgb_ayuv (const GstVideoFrame * in_frame,
1186     GstVideoFrame * out_frame, GstAlpha * alpha)
1187 {
1188   const guint8 *src;
1189   guint8 *dest;
1190   gint width, height;
1191   gint i, j;
1192   gint a, y, u, v;
1193   gint r, g, b;
1194   gint smin, smax;
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;
1203   gint matrix[12];
1204   gint o[3];
1205   gint bpp;
1206
1207   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1208   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1209
1210   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1211   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1212
1213   bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (in_frame, 0);
1214
1215   o[0] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 0);
1216   o[1] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
1217   o[2] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
1218
1219   smin = 128 - alpha->black_sensitivity;
1220   smax = 128 + alpha->white_sensitivity;
1221
1222   memcpy (matrix,
1223       alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
1224       cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint));
1225
1226   for (i = 0; i < height; i++) {
1227     for (j = 0; j < width; j++) {
1228       a = pa;
1229       r = src[o[0]];
1230       g = src[o[1]];
1231       b = src[o[2]];
1232
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;
1236
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);
1240
1241       u += 128;
1242       v += 128;
1243
1244       dest[0] = a;
1245       dest[1] = y;
1246       dest[2] = u;
1247       dest[3] = v;
1248
1249       src += bpp;
1250       dest += 4;
1251     }
1252   }
1253 }
1254
1255 static void
1256 gst_alpha_set_rgb_argb (const GstVideoFrame * in_frame,
1257     GstVideoFrame * out_frame, GstAlpha * alpha)
1258 {
1259   const guint8 *src;
1260   guint8 *dest;
1261   gint width, height;
1262   gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1263   gint i, j;
1264   gint p[4], o[3];
1265   gint bpp;
1266
1267   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1268   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1269
1270   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1271   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1272
1273   bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (in_frame, 0);
1274
1275   o[0] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 0);
1276   o[1] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
1277   o[2] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
1278
1279   p[0] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 3);
1280   p[1] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 0);
1281   p[2] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 1);
1282   p[3] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 2);
1283
1284   for (i = 0; i < height; i++) {
1285     for (j = 0; j < width; j++) {
1286       dest[p[0]] = s_alpha;
1287
1288       dest[p[1]] = src[o[0]];
1289       dest[p[2]] = src[o[1]];
1290       dest[p[3]] = src[o[2]];
1291
1292       dest += 4;
1293       src += bpp;
1294     }
1295   }
1296 }
1297
1298 static void
1299 gst_alpha_chroma_key_rgb_argb (const GstVideoFrame * in_frame,
1300     GstVideoFrame * out_frame, GstAlpha * alpha)
1301 {
1302   const guint8 *src;
1303   guint8 *dest;
1304   gint width, height;
1305   gint i, j;
1306   gint a, y, u, v;
1307   gint r, g, b;
1308   gint smin, smax;
1309   gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1310   gint8 cb = alpha->cb, cr = alpha->cr;
1311   gint8 kg = alpha->kg;
1312   guint8 accept_angle_tg = alpha->accept_angle_tg;
1313   guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1314   guint8 one_over_kc = alpha->one_over_kc;
1315   guint8 kfgy_scale = alpha->kfgy_scale;
1316   guint noise_level2 = alpha->noise_level2;
1317   gint matrix[12], matrix2[12];
1318   gint p[4], o[3];
1319   gint bpp;
1320
1321   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1322   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1323
1324   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1325   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1326
1327   bpp = GST_VIDEO_FRAME_COMP_PSTRIDE (in_frame, 0);
1328
1329   o[0] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 0);
1330   o[1] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
1331   o[2] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
1332
1333   p[0] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 3);
1334   p[1] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 0);
1335   p[2] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 1);
1336   p[3] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 2);
1337
1338   smin = 128 - alpha->black_sensitivity;
1339   smax = 128 + alpha->white_sensitivity;
1340
1341   memcpy (matrix, cog_rgb_to_ycbcr_matrix_8bit_sdtv, 12 * sizeof (gint));
1342   memcpy (matrix2, cog_ycbcr_to_rgb_matrix_8bit_sdtv, 12 * sizeof (gint));
1343
1344   for (i = 0; i < height; i++) {
1345     for (j = 0; j < width; j++) {
1346       a = pa;
1347       r = src[o[0]];
1348       g = src[o[1]];
1349       b = src[o[2]];
1350
1351       y = APPLY_MATRIX (matrix, 0, r, g, b);
1352       u = APPLY_MATRIX (matrix, 1, r, g, b) - 128;
1353       v = APPLY_MATRIX (matrix, 2, r, g, b) - 128;
1354
1355       a = chroma_keying_yuv (a, &y, &u, &v, cr, cb,
1356           smin, smax, accept_angle_tg, accept_angle_ctg,
1357           one_over_kc, kfgy_scale, kg, noise_level2);
1358
1359       u += 128;
1360       v += 128;
1361
1362       r = APPLY_MATRIX (matrix2, 0, y, u, v);
1363       g = APPLY_MATRIX (matrix2, 1, y, u, v);
1364       b = APPLY_MATRIX (matrix2, 2, y, u, v);
1365
1366       dest[p[0]] = a;
1367       dest[p[1]] = CLAMP (r, 0, 255);
1368       dest[p[2]] = CLAMP (g, 0, 255);
1369       dest[p[3]] = CLAMP (b, 0, 255);
1370
1371       src += bpp;
1372       dest += 4;
1373     }
1374   }
1375 }
1376
1377 static void
1378 gst_alpha_set_planar_yuv_ayuv (const GstVideoFrame * in_frame,
1379     GstVideoFrame * out_frame, GstAlpha * alpha)
1380 {
1381   const guint8 *src;
1382   guint8 *dest;
1383   gint width, height;
1384   gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1385   const guint8 *srcY, *srcY_tmp;
1386   const guint8 *srcU, *srcU_tmp;
1387   const guint8 *srcV, *srcV_tmp;
1388   gint i, j;
1389   gint y_stride, uv_stride;
1390   gint v_subs, h_subs;
1391
1392   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1393   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1394
1395   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1396   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1397
1398   y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
1399   uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
1400
1401   srcY_tmp = srcY = src;
1402   srcU_tmp = srcU = src + GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
1403   srcV_tmp = srcV = src + GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
1404
1405   switch (GST_VIDEO_FRAME_FORMAT (in_frame)) {
1406     case GST_VIDEO_FORMAT_I420:
1407     case GST_VIDEO_FORMAT_YV12:
1408       v_subs = h_subs = 2;
1409       break;
1410     case GST_VIDEO_FORMAT_Y444:
1411       v_subs = h_subs = 1;
1412       break;
1413     case GST_VIDEO_FORMAT_Y42B:
1414       v_subs = 1;
1415       h_subs = 2;
1416       break;
1417     case GST_VIDEO_FORMAT_Y41B:
1418       v_subs = 1;
1419       h_subs = 4;
1420       break;
1421     default:
1422       g_assert_not_reached ();
1423       return;
1424   }
1425
1426   if (alpha->in_sdtv == alpha->out_sdtv) {
1427     for (i = 0; i < height; i++) {
1428       for (j = 0; j < width; j++) {
1429         dest[0] = b_alpha;
1430         dest[1] = srcY[0];
1431         dest[2] = srcU[0];
1432         dest[3] = srcV[0];
1433
1434         dest += 4;
1435         srcY++;
1436         if ((j + 1) % h_subs == 0) {
1437           srcU++;
1438           srcV++;
1439         }
1440       }
1441
1442       srcY_tmp = srcY = srcY_tmp + y_stride;
1443       if ((i + 1) % v_subs == 0) {
1444         srcU_tmp = srcU = srcU_tmp + uv_stride;
1445         srcV_tmp = srcV = srcV_tmp + uv_stride;
1446       } else {
1447         srcU = srcU_tmp;
1448         srcV = srcV_tmp;
1449       }
1450     }
1451   } else {
1452     gint matrix[12];
1453     gint a, y, u, v;
1454
1455     memcpy (matrix,
1456         alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1457         cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1458
1459     for (i = 0; i < height; i++) {
1460       for (j = 0; j < width; j++) {
1461         a = b_alpha;
1462         y = srcY[0];
1463         u = srcU[0];
1464         v = srcV[0];
1465
1466         dest[0] = a;
1467         dest[1] = APPLY_MATRIX (matrix, 0, y, u, v);
1468         dest[2] = APPLY_MATRIX (matrix, 1, y, u, v);
1469         dest[3] = APPLY_MATRIX (matrix, 2, y, u, v);
1470
1471         dest += 4;
1472         srcY++;
1473         if ((j + 1) % h_subs == 0) {
1474           srcU++;
1475           srcV++;
1476         }
1477       }
1478
1479       srcY_tmp = srcY = srcY_tmp + y_stride;
1480       if ((i + 1) % v_subs == 0) {
1481         srcU_tmp = srcU = srcU_tmp + uv_stride;
1482         srcV_tmp = srcV = srcV_tmp + uv_stride;
1483       } else {
1484         srcU = srcU_tmp;
1485         srcV = srcV_tmp;
1486       }
1487     }
1488   }
1489 }
1490
1491 static void
1492 gst_alpha_chroma_key_planar_yuv_ayuv (const GstVideoFrame * in_frame,
1493     GstVideoFrame * out_frame, GstAlpha * alpha)
1494 {
1495   const guint8 *src;
1496   guint8 *dest;
1497   gint width, height;
1498   gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1499   const guint8 *srcY, *srcY_tmp;
1500   const guint8 *srcU, *srcU_tmp;
1501   const guint8 *srcV, *srcV_tmp;
1502   gint i, j;
1503   gint a, y, u, v;
1504   gint y_stride, uv_stride;
1505   gint v_subs, h_subs;
1506   gint smin = 128 - alpha->black_sensitivity;
1507   gint smax = 128 + alpha->white_sensitivity;
1508   gint8 cb = alpha->cb, cr = alpha->cr;
1509   gint8 kg = alpha->kg;
1510   guint8 accept_angle_tg = alpha->accept_angle_tg;
1511   guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1512   guint8 one_over_kc = alpha->one_over_kc;
1513   guint8 kfgy_scale = alpha->kfgy_scale;
1514   guint noise_level2 = alpha->noise_level2;
1515
1516   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1517   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1518
1519   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1520   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1521
1522   y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
1523   uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
1524
1525   srcY_tmp = srcY = src;
1526   srcU_tmp = srcU = src + GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
1527   srcV_tmp = srcV = src + GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
1528
1529   switch (GST_VIDEO_FRAME_FORMAT (in_frame)) {
1530     case GST_VIDEO_FORMAT_I420:
1531     case GST_VIDEO_FORMAT_YV12:
1532       v_subs = h_subs = 2;
1533       break;
1534     case GST_VIDEO_FORMAT_Y444:
1535       v_subs = h_subs = 1;
1536       break;
1537     case GST_VIDEO_FORMAT_Y42B:
1538       v_subs = 1;
1539       h_subs = 2;
1540       break;
1541     case GST_VIDEO_FORMAT_Y41B:
1542       v_subs = 1;
1543       h_subs = 4;
1544       break;
1545     default:
1546       g_assert_not_reached ();
1547       return;
1548   }
1549
1550   if (alpha->in_sdtv == alpha->out_sdtv) {
1551     for (i = 0; i < height; i++) {
1552       for (j = 0; j < width; j++) {
1553         a = b_alpha;
1554         y = srcY[0];
1555         u = srcU[0] - 128;
1556         v = srcV[0] - 128;
1557
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);
1561
1562         u += 128;
1563         v += 128;
1564
1565         dest[0] = a;
1566         dest[1] = y;
1567         dest[2] = u;
1568         dest[3] = v;
1569
1570         dest += 4;
1571         srcY++;
1572         if ((j + 1) % h_subs == 0) {
1573           srcU++;
1574           srcV++;
1575         }
1576       }
1577
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;
1582       } else {
1583         srcU = srcU_tmp;
1584         srcV = srcV_tmp;
1585       }
1586     }
1587   } else {
1588     gint matrix[12];
1589
1590     memcpy (matrix,
1591         alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1592         cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1593
1594     for (i = 0; i < height; i++) {
1595       for (j = 0; j < width; j++) {
1596         a = b_alpha;
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;
1600
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);
1604
1605         dest[0] = a;
1606         dest[1] = y;
1607         dest[2] = u + 128;
1608         dest[3] = v + 128;
1609
1610         dest += 4;
1611         srcY++;
1612         if ((j + 1) % h_subs == 0) {
1613           srcU++;
1614           srcV++;
1615         }
1616       }
1617
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;
1622       } else {
1623         srcU = srcU_tmp;
1624         srcV = srcV_tmp;
1625       }
1626     }
1627   }
1628 }
1629
1630 static void
1631 gst_alpha_set_planar_yuv_argb (const GstVideoFrame * in_frame,
1632     GstVideoFrame * out_frame, GstAlpha * alpha)
1633 {
1634   const guint8 *src;
1635   guint8 *dest;
1636   gint width, height;
1637   gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1638   const guint8 *srcY, *srcY_tmp;
1639   const guint8 *srcU, *srcU_tmp;
1640   const guint8 *srcV, *srcV_tmp;
1641   gint i, j;
1642   gint y_stride, uv_stride;
1643   gint v_subs, h_subs;
1644   gint matrix[12];
1645   gint a, y, u, v;
1646   gint r, g, b;
1647   gint p[4];
1648
1649   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1650   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1651
1652   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1653   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1654
1655   p[0] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 3);
1656   p[1] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 0);
1657   p[2] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 1);
1658   p[3] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 2);
1659
1660   y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
1661   uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
1662
1663   srcY_tmp = srcY = src;
1664   srcU_tmp = srcU = src + GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
1665   srcV_tmp = srcV = src + GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
1666
1667   switch (GST_VIDEO_FRAME_FORMAT (in_frame)) {
1668     case GST_VIDEO_FORMAT_I420:
1669     case GST_VIDEO_FORMAT_YV12:
1670       v_subs = h_subs = 2;
1671       break;
1672     case GST_VIDEO_FORMAT_Y444:
1673       v_subs = h_subs = 1;
1674       break;
1675     case GST_VIDEO_FORMAT_Y42B:
1676       v_subs = 1;
1677       h_subs = 2;
1678       break;
1679     case GST_VIDEO_FORMAT_Y41B:
1680       v_subs = 1;
1681       h_subs = 4;
1682       break;
1683     default:
1684       g_assert_not_reached ();
1685       return;
1686   }
1687
1688   memcpy (matrix,
1689       alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
1690       cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
1691
1692   for (i = 0; i < height; i++) {
1693     for (j = 0; j < width; j++) {
1694       a = b_alpha;
1695       y = srcY[0];
1696       u = srcU[0];
1697       v = srcV[0];
1698
1699       dest[p[0]] = a;
1700       r = APPLY_MATRIX (matrix, 0, y, u, v);
1701       g = APPLY_MATRIX (matrix, 1, y, u, v);
1702       b = APPLY_MATRIX (matrix, 2, y, u, v);
1703       dest[p[1]] = CLAMP (r, 0, 255);
1704       dest[p[2]] = CLAMP (g, 0, 255);
1705       dest[p[3]] = CLAMP (b, 0, 255);
1706
1707       dest += 4;
1708       srcY++;
1709       if ((j + 1) % h_subs == 0) {
1710         srcU++;
1711         srcV++;
1712       }
1713     }
1714
1715     srcY_tmp = srcY = srcY_tmp + y_stride;
1716     if ((i + 1) % v_subs == 0) {
1717       srcU_tmp = srcU = srcU_tmp + uv_stride;
1718       srcV_tmp = srcV = srcV_tmp + uv_stride;
1719     } else {
1720       srcU = srcU_tmp;
1721       srcV = srcV_tmp;
1722     }
1723   }
1724 }
1725
1726 static void
1727 gst_alpha_chroma_key_planar_yuv_argb (const GstVideoFrame * in_frame,
1728     GstVideoFrame * out_frame, GstAlpha * alpha)
1729 {
1730   const guint8 *src;
1731   guint8 *dest;
1732   gint width, height;
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;
1737   gint i, j;
1738   gint a, y, u, v;
1739   gint r, g, b;
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;
1751   gint matrix[12];
1752   gint p[4];
1753
1754   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1755   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1756
1757   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1758   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1759
1760   p[0] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 3);
1761   p[1] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 0);
1762   p[2] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 1);
1763   p[3] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 2);
1764
1765   y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
1766   uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
1767
1768   srcY_tmp = srcY = src;
1769   srcU_tmp = srcU = src + GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
1770   srcV_tmp = srcV = src + GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
1771
1772   switch (GST_VIDEO_FRAME_FORMAT (in_frame)) {
1773     case GST_VIDEO_FORMAT_I420:
1774     case GST_VIDEO_FORMAT_YV12:
1775       v_subs = h_subs = 2;
1776       break;
1777     case GST_VIDEO_FORMAT_Y444:
1778       v_subs = h_subs = 1;
1779       break;
1780     case GST_VIDEO_FORMAT_Y42B:
1781       v_subs = 1;
1782       h_subs = 2;
1783       break;
1784     case GST_VIDEO_FORMAT_Y41B:
1785       v_subs = 1;
1786       h_subs = 4;
1787       break;
1788     default:
1789       g_assert_not_reached ();
1790       return;
1791   }
1792
1793   memcpy (matrix,
1794       alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
1795       cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
1796
1797   for (i = 0; i < height; i++) {
1798     for (j = 0; j < width; j++) {
1799       a = b_alpha;
1800       y = srcY[0];
1801       u = srcU[0] - 128;
1802       v = srcV[0] - 128;
1803
1804       a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
1805           smax, accept_angle_tg, accept_angle_ctg,
1806           one_over_kc, kfgy_scale, kg, noise_level2);
1807
1808       u += 128;
1809       v += 128;
1810
1811       dest[p[0]] = a;
1812       r = APPLY_MATRIX (matrix, 0, y, u, v);
1813       g = APPLY_MATRIX (matrix, 1, y, u, v);
1814       b = APPLY_MATRIX (matrix, 2, y, u, v);
1815       dest[p[1]] = CLAMP (r, 0, 255);
1816       dest[p[2]] = CLAMP (g, 0, 255);
1817       dest[p[3]] = CLAMP (b, 0, 255);
1818
1819       dest += 4;
1820       srcY++;
1821       if ((j + 1) % h_subs == 0) {
1822         srcU++;
1823         srcV++;
1824       }
1825     }
1826
1827     srcY_tmp = srcY = srcY_tmp + y_stride;
1828     if ((i + 1) % v_subs == 0) {
1829       srcU_tmp = srcU = srcU_tmp + uv_stride;
1830       srcV_tmp = srcV = srcV_tmp + uv_stride;
1831     } else {
1832       srcU = srcU_tmp;
1833       srcV = srcV_tmp;
1834     }
1835   }
1836 }
1837
1838 static void
1839 gst_alpha_set_packed_422_ayuv (const GstVideoFrame * in_frame,
1840     GstVideoFrame * out_frame, GstAlpha * alpha)
1841 {
1842   const guint8 *src;
1843   guint8 *dest;
1844   gint width, height;
1845   gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1846   gint i, j;
1847   gint y, u, v;
1848   gint p[4];                    /* Y U Y V */
1849   gint src_stride;
1850   const guint8 *src_tmp;
1851
1852   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1853   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1854
1855   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1856   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1857
1858   src_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
1859
1860   p[0] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 0);
1861   p[2] = p[0] + 2;
1862   p[1] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
1863   p[3] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
1864
1865   if (alpha->in_sdtv != alpha->out_sdtv) {
1866     gint matrix[12];
1867
1868     memcpy (matrix,
1869         alpha->in_sdtv ? cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit :
1870         cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit, 12 * sizeof (gint));
1871
1872     for (i = 0; i < height; i++) {
1873       src_tmp = src;
1874
1875       for (j = 0; j < width - 1; j += 2) {
1876         dest[0] = s_alpha;
1877         dest[4] = s_alpha;
1878
1879         y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
1880         u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]);
1881         v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]);
1882
1883         dest[1] = y;
1884         dest[2] = u;
1885         dest[3] = v;
1886
1887         y = APPLY_MATRIX (matrix, 0, src[p[2]], src[p[1]], src[p[3]]);
1888         u = APPLY_MATRIX (matrix, 1, src[p[2]], src[p[1]], src[p[3]]);
1889         v = APPLY_MATRIX (matrix, 2, src[p[2]], src[p[1]], src[p[3]]);
1890
1891         dest[5] = y;
1892         dest[6] = u;
1893         dest[7] = v;
1894
1895         dest += 8;
1896         src += 4;
1897       }
1898
1899       if (j == width - 1) {
1900         dest[0] = s_alpha;
1901
1902         y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
1903         u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]);
1904         v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]);
1905
1906         dest[1] = y;
1907         dest[2] = u;
1908         dest[3] = v;
1909
1910         dest += 4;
1911       }
1912
1913       src = src_tmp + src_stride;
1914     }
1915   } else {
1916     for (i = 0; i < height; i++) {
1917       src_tmp = src;
1918
1919       for (j = 0; j < width - 1; j += 2) {
1920         dest[0] = s_alpha;
1921         dest[4] = s_alpha;
1922
1923         y = src[p[0]];
1924         u = src[p[1]];
1925         v = src[p[3]];;
1926
1927         dest[1] = y;
1928         dest[2] = u;
1929         dest[3] = v;
1930
1931         y = src[p[2]];
1932
1933         dest[5] = y;
1934         dest[6] = u;
1935         dest[7] = v;
1936
1937         dest += 8;
1938         src += 4;
1939       }
1940
1941       if (j == width - 1) {
1942         dest[0] = s_alpha;
1943
1944         y = src[p[0]];
1945         u = src[p[1]];
1946         v = src[p[3]];;
1947
1948         dest[1] = y;
1949         dest[2] = u;
1950         dest[3] = v;
1951
1952         dest += 4;
1953       }
1954
1955       src = src_tmp + src_stride;
1956     }
1957   }
1958 }
1959
1960 static void
1961 gst_alpha_chroma_key_packed_422_ayuv (const GstVideoFrame * in_frame,
1962     GstVideoFrame * out_frame, GstAlpha * alpha)
1963 {
1964   const guint8 *src;
1965   guint8 *dest;
1966   gint width, height;
1967   gint i, j;
1968   gint a, y, u, v;
1969   gint smin, smax;
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 */
1979   gint src_stride;
1980   const guint8 *src_tmp;
1981
1982   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1983   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1984
1985   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1986   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1987
1988   src_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
1989
1990   p[0] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 0);
1991   p[2] = p[0] + 2;
1992   p[1] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
1993   p[3] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
1994
1995   smin = 128 - alpha->black_sensitivity;
1996   smax = 128 + alpha->white_sensitivity;
1997
1998   if (alpha->in_sdtv != alpha->out_sdtv) {
1999     gint matrix[12];
2000
2001     memcpy (matrix,
2002         alpha->in_sdtv ? cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit :
2003         cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit, 12 * sizeof (gint));
2004
2005     for (i = 0; i < height; i++) {
2006       src_tmp = src;
2007
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;
2012
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);
2016
2017         dest[0] = a;
2018         dest[1] = y;
2019         dest[2] = u + 128;
2020         dest[3] = v + 128;
2021
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;
2025
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);
2029
2030         dest[4] = a;
2031         dest[5] = y;
2032         dest[6] = u + 128;
2033         dest[7] = v + 128;
2034
2035         dest += 8;
2036         src += 4;
2037       }
2038
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;
2043
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);
2047
2048         dest[0] = a;
2049         dest[1] = y;
2050         dest[2] = u + 128;
2051         dest[3] = v + 128;
2052
2053         dest += 4;
2054       }
2055
2056       src = src_tmp + src_stride;
2057     }
2058   } else {
2059     for (i = 0; i < height; i++) {
2060       src_tmp = src;
2061
2062       for (j = 0; j < width - 1; j += 2) {
2063         y = src[p[0]];
2064         u = src[p[1]] - 128;
2065         v = src[p[3]] - 128;
2066
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);
2070
2071         dest[0] = a;
2072         dest[1] = y;
2073         dest[2] = u + 128;
2074         dest[3] = v + 128;
2075
2076         y = src[p[2]];
2077         u = src[p[1]] - 128;
2078         v = src[p[3]] - 128;
2079
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);
2083
2084         dest[4] = a;
2085         dest[5] = y;
2086         dest[6] = u + 128;
2087         dest[7] = v + 128;
2088
2089         dest += 8;
2090         src += 4;
2091       }
2092
2093       if (j == width - 1) {
2094         y = src[p[0]];
2095         u = src[p[1]] - 128;
2096         v = src[p[3]] - 128;
2097
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);
2101
2102         dest[0] = a;
2103         dest[1] = y;
2104         dest[2] = u + 128;
2105         dest[3] = v + 128;
2106
2107         dest += 4;
2108       }
2109
2110       src = src_tmp + src_stride;
2111     }
2112   }
2113 }
2114
2115 static void
2116 gst_alpha_set_packed_422_argb (const GstVideoFrame * in_frame,
2117     GstVideoFrame * out_frame, GstAlpha * alpha)
2118 {
2119   const guint8 *src;
2120   guint8 *dest;
2121   gint width, height;
2122   gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
2123   gint i, j;
2124   gint p[4], o[4];
2125   gint src_stride;
2126   const guint8 *src_tmp;
2127   gint matrix[12];
2128   gint r, g, b;
2129
2130   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
2131   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
2132
2133   width = GST_VIDEO_FRAME_WIDTH (in_frame);
2134   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
2135
2136   src_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
2137
2138   o[0] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 0);
2139   o[2] = o[0] + 2;
2140   o[1] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
2141   o[3] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
2142
2143   p[0] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 3);
2144   p[1] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 0);
2145   p[2] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 1);
2146   p[3] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 2);
2147
2148   memcpy (matrix,
2149       alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
2150       cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
2151
2152   for (i = 0; i < height; i++) {
2153     src_tmp = src;
2154
2155     for (j = 0; j < width - 1; j += 2) {
2156       r = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[3]]);
2157       g = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[3]]);
2158       b = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[3]]);
2159
2160       dest[p[0]] = s_alpha;
2161       dest[p[1]] = CLAMP (r, 0, 255);
2162       dest[p[2]] = CLAMP (g, 0, 255);
2163       dest[p[3]] = CLAMP (b, 0, 255);
2164
2165       r = APPLY_MATRIX (matrix, 0, src[o[2]], src[o[1]], src[o[3]]);
2166       g = APPLY_MATRIX (matrix, 1, src[o[2]], src[o[1]], src[o[3]]);
2167       b = APPLY_MATRIX (matrix, 2, src[o[2]], src[o[1]], src[o[3]]);
2168
2169       dest[4 + p[0]] = s_alpha;
2170       dest[4 + p[1]] = CLAMP (r, 0, 255);
2171       dest[4 + p[2]] = CLAMP (g, 0, 255);
2172       dest[4 + p[3]] = CLAMP (b, 0, 255);
2173
2174       dest += 8;
2175       src += 4;
2176     }
2177
2178     if (j == width - 1) {
2179       r = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[3]]);
2180       g = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[3]]);
2181       b = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[3]]);
2182
2183       dest[p[0]] = s_alpha;
2184       dest[p[1]] = CLAMP (r, 0, 255);
2185       dest[p[2]] = CLAMP (g, 0, 255);
2186       dest[p[3]] = CLAMP (b, 0, 255);
2187
2188       dest += 4;
2189     }
2190
2191     src = src_tmp + src_stride;
2192   }
2193 }
2194
2195 static void
2196 gst_alpha_chroma_key_packed_422_argb (const GstVideoFrame * in_frame,
2197     GstVideoFrame * out_frame, GstAlpha * alpha)
2198 {
2199   const guint8 *src;
2200   guint8 *dest;
2201   gint width, height;
2202   gint i, j;
2203   gint a, y, u, v;
2204   gint r, g, b;
2205   gint smin, smax;
2206   gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
2207   gint8 cb = alpha->cb, cr = alpha->cr;
2208   gint8 kg = alpha->kg;
2209   guint8 accept_angle_tg = alpha->accept_angle_tg;
2210   guint8 accept_angle_ctg = alpha->accept_angle_ctg;
2211   guint8 one_over_kc = alpha->one_over_kc;
2212   guint8 kfgy_scale = alpha->kfgy_scale;
2213   guint noise_level2 = alpha->noise_level2;
2214   gint p[4], o[4];
2215   gint src_stride;
2216   const guint8 *src_tmp;
2217   gint matrix[12];
2218
2219   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
2220   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
2221
2222   width = GST_VIDEO_FRAME_WIDTH (in_frame);
2223   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
2224
2225   src_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
2226
2227   o[0] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 0);
2228   o[2] = o[0] + 2;
2229   o[1] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 1);
2230   o[3] = GST_VIDEO_FRAME_COMP_OFFSET (in_frame, 2);
2231
2232   p[0] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 3);
2233   p[1] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 0);
2234   p[2] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 1);
2235   p[3] = GST_VIDEO_FRAME_COMP_OFFSET (out_frame, 2);
2236
2237   memcpy (matrix,
2238       alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
2239       cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
2240
2241   smin = 128 - alpha->black_sensitivity;
2242   smax = 128 + alpha->white_sensitivity;
2243
2244   for (i = 0; i < height; i++) {
2245     src_tmp = src;
2246
2247     for (j = 0; j < width - 1; j += 2) {
2248       y = src[o[0]];
2249       u = src[o[1]] - 128;
2250       v = src[o[3]] - 128;
2251
2252       a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2253           smin, smax, accept_angle_tg, accept_angle_ctg,
2254           one_over_kc, kfgy_scale, kg, noise_level2);
2255       u += 128;
2256       v += 128;
2257
2258       r = APPLY_MATRIX (matrix, 0, y, u, v);
2259       g = APPLY_MATRIX (matrix, 1, y, u, v);
2260       b = APPLY_MATRIX (matrix, 2, y, u, v);
2261
2262       dest[p[0]] = a;
2263       dest[p[1]] = CLAMP (r, 0, 255);
2264       dest[p[2]] = CLAMP (g, 0, 255);
2265       dest[p[3]] = CLAMP (b, 0, 255);
2266
2267       y = src[o[2]];
2268       u = src[o[1]] - 128;
2269       v = src[o[3]] - 128;
2270
2271       a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2272           smin, smax, accept_angle_tg, accept_angle_ctg,
2273           one_over_kc, kfgy_scale, kg, noise_level2);
2274       u += 128;
2275       v += 128;
2276
2277       r = APPLY_MATRIX (matrix, 0, y, u, v);
2278       g = APPLY_MATRIX (matrix, 1, y, u, v);
2279       b = APPLY_MATRIX (matrix, 2, y, u, v);
2280
2281       dest[4 + p[0]] = a;
2282       dest[4 + p[1]] = CLAMP (r, 0, 255);
2283       dest[4 + p[2]] = CLAMP (g, 0, 255);
2284       dest[4 + p[3]] = CLAMP (b, 0, 255);
2285
2286       dest += 8;
2287       src += 4;
2288     }
2289
2290     if (j == width - 1) {
2291       y = src[o[0]];
2292       u = src[o[1]] - 128;
2293       v = src[o[3]] - 128;
2294
2295       a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2296           smin, smax, accept_angle_tg, accept_angle_ctg,
2297           one_over_kc, kfgy_scale, kg, noise_level2);
2298       u += 128;
2299       v += 128;
2300
2301       r = APPLY_MATRIX (matrix, 0, y, u, v);
2302       g = APPLY_MATRIX (matrix, 1, y, u, v);
2303       b = APPLY_MATRIX (matrix, 2, y, u, v);
2304
2305       dest[p[0]] = a;
2306       dest[p[1]] = CLAMP (r, 0, 255);
2307       dest[p[2]] = CLAMP (g, 0, 255);
2308       dest[p[3]] = CLAMP (b, 0, 255);
2309
2310       dest += 4;
2311     }
2312
2313     src = src_tmp + src_stride;
2314   }
2315 }
2316
2317 /* Protected with the alpha lock */
2318 static void
2319 gst_alpha_init_params (GstAlpha * alpha)
2320 {
2321   gfloat kgl;
2322   gfloat tmp;
2323   gfloat tmp1, tmp2;
2324   gfloat y;
2325   const GstVideoFormatInfo *in_info, *out_info;
2326   const gint *matrix;
2327
2328   in_info = alpha->in_info.finfo;
2329   out_info = alpha->out_info.finfo;
2330
2331   /* RGB->RGB: convert to SDTV YUV, chroma keying, convert back
2332    * YUV->RGB: chroma keying, convert to RGB
2333    * RGB->YUV: convert to YUV, chroma keying
2334    * YUV->YUV: convert matrix, chroma keying
2335    */
2336   if (GST_VIDEO_FORMAT_INFO_IS_RGB (in_info)
2337       && GST_VIDEO_FORMAT_INFO_IS_RGB (out_info))
2338     matrix = cog_rgb_to_ycbcr_matrix_8bit_sdtv;
2339   else if (GST_VIDEO_FORMAT_INFO_IS_YUV (in_info)
2340       && GST_VIDEO_FORMAT_INFO_IS_RGB (out_info))
2341     matrix =
2342         (alpha->in_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
2343         cog_rgb_to_ycbcr_matrix_8bit_hdtv;
2344   else if (GST_VIDEO_FORMAT_INFO_IS_RGB (in_info)
2345       && GST_VIDEO_FORMAT_INFO_IS_YUV (out_info))
2346     matrix =
2347         (alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
2348         cog_rgb_to_ycbcr_matrix_8bit_hdtv;
2349   else                          /* yuv -> yuv */
2350     matrix =
2351         (alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
2352         cog_rgb_to_ycbcr_matrix_8bit_hdtv;
2353
2354   y = (matrix[0] * ((gint) alpha->target_r) +
2355       matrix[1] * ((gint) alpha->target_g) +
2356       matrix[2] * ((gint) alpha->target_b) + matrix[3]) >> 8;
2357   /* Cb,Cr without offset here because the chroma keying
2358    * works with them being in range [-128,127]
2359    */
2360   tmp1 =
2361       (matrix[4] * ((gint) alpha->target_r) +
2362       matrix[5] * ((gint) alpha->target_g) +
2363       matrix[6] * ((gint) alpha->target_b)) >> 8;
2364   tmp2 =
2365       (matrix[8] * ((gint) alpha->target_r) +
2366       matrix[9] * ((gint) alpha->target_g) +
2367       matrix[10] * ((gint) alpha->target_b)) >> 8;
2368
2369   kgl = sqrt (tmp1 * tmp1 + tmp2 * tmp2);
2370   alpha->cb = 127 * (tmp1 / kgl);
2371   alpha->cr = 127 * (tmp2 / kgl);
2372
2373   tmp = 15 * tan (M_PI * alpha->angle / 180);
2374   tmp = MIN (tmp, 255);
2375   alpha->accept_angle_tg = tmp;
2376   tmp = 15 / tan (M_PI * alpha->angle / 180);
2377   tmp = MIN (tmp, 255);
2378   alpha->accept_angle_ctg = tmp;
2379   tmp = 1 / (kgl);
2380   alpha->one_over_kc = 255 * 2 * tmp - 255;
2381   tmp = 15 * y / kgl;
2382   tmp = MIN (tmp, 255);
2383   alpha->kfgy_scale = tmp;
2384   alpha->kg = MIN (kgl, 127);
2385
2386   alpha->noise_level2 = alpha->noise_level * alpha->noise_level;
2387 }
2388
2389 /* Protected with the alpha lock */
2390 static gboolean
2391 gst_alpha_set_process_function (GstAlpha * alpha)
2392 {
2393   alpha->process = NULL;
2394
2395   switch (alpha->method) {
2396     case ALPHA_METHOD_SET:
2397       switch (GST_VIDEO_INFO_FORMAT (&alpha->out_info)) {
2398         case GST_VIDEO_FORMAT_AYUV:
2399           switch (GST_VIDEO_INFO_FORMAT (&alpha->in_info)) {
2400             case GST_VIDEO_FORMAT_AYUV:
2401               alpha->process = gst_alpha_set_ayuv_ayuv;
2402               break;
2403             case GST_VIDEO_FORMAT_Y444:
2404             case GST_VIDEO_FORMAT_Y42B:
2405             case GST_VIDEO_FORMAT_I420:
2406             case GST_VIDEO_FORMAT_YV12:
2407             case GST_VIDEO_FORMAT_Y41B:
2408               alpha->process = gst_alpha_set_planar_yuv_ayuv;
2409               break;
2410             case GST_VIDEO_FORMAT_YUY2:
2411             case GST_VIDEO_FORMAT_YVYU:
2412             case GST_VIDEO_FORMAT_UYVY:
2413               alpha->process = gst_alpha_set_packed_422_ayuv;
2414               break;
2415             case GST_VIDEO_FORMAT_ARGB:
2416             case GST_VIDEO_FORMAT_ABGR:
2417             case GST_VIDEO_FORMAT_RGBA:
2418             case GST_VIDEO_FORMAT_BGRA:
2419               alpha->process = gst_alpha_set_argb_ayuv;
2420               break;
2421             case GST_VIDEO_FORMAT_xRGB:
2422             case GST_VIDEO_FORMAT_xBGR:
2423             case GST_VIDEO_FORMAT_RGBx:
2424             case GST_VIDEO_FORMAT_BGRx:
2425             case GST_VIDEO_FORMAT_RGB:
2426             case GST_VIDEO_FORMAT_BGR:
2427               alpha->process = gst_alpha_set_rgb_ayuv;
2428               break;
2429             default:
2430               break;
2431           }
2432           break;
2433         case GST_VIDEO_FORMAT_ARGB:
2434         case GST_VIDEO_FORMAT_ABGR:
2435         case GST_VIDEO_FORMAT_RGBA:
2436         case GST_VIDEO_FORMAT_BGRA:
2437           switch (GST_VIDEO_INFO_FORMAT (&alpha->in_info)) {
2438             case GST_VIDEO_FORMAT_AYUV:
2439               alpha->process = gst_alpha_set_ayuv_argb;
2440               break;
2441             case GST_VIDEO_FORMAT_Y444:
2442             case GST_VIDEO_FORMAT_Y42B:
2443             case GST_VIDEO_FORMAT_I420:
2444             case GST_VIDEO_FORMAT_YV12:
2445             case GST_VIDEO_FORMAT_Y41B:
2446               alpha->process = gst_alpha_set_planar_yuv_argb;
2447               break;
2448             case GST_VIDEO_FORMAT_YUY2:
2449             case GST_VIDEO_FORMAT_YVYU:
2450             case GST_VIDEO_FORMAT_UYVY:
2451               alpha->process = gst_alpha_set_packed_422_argb;
2452               break;
2453             case GST_VIDEO_FORMAT_ARGB:
2454             case GST_VIDEO_FORMAT_ABGR:
2455             case GST_VIDEO_FORMAT_RGBA:
2456             case GST_VIDEO_FORMAT_BGRA:
2457               alpha->process = gst_alpha_set_argb_argb;
2458               break;
2459             case GST_VIDEO_FORMAT_xRGB:
2460             case GST_VIDEO_FORMAT_xBGR:
2461             case GST_VIDEO_FORMAT_RGBx:
2462             case GST_VIDEO_FORMAT_BGRx:
2463             case GST_VIDEO_FORMAT_RGB:
2464             case GST_VIDEO_FORMAT_BGR:
2465               alpha->process = gst_alpha_set_rgb_argb;
2466               break;
2467             default:
2468               break;
2469           }
2470           break;
2471           break;
2472         default:
2473           break;
2474       }
2475       break;
2476     case ALPHA_METHOD_GREEN:
2477     case ALPHA_METHOD_BLUE:
2478     case ALPHA_METHOD_CUSTOM:
2479       switch (GST_VIDEO_INFO_FORMAT (&alpha->out_info)) {
2480         case GST_VIDEO_FORMAT_AYUV:
2481           switch (GST_VIDEO_INFO_FORMAT (&alpha->in_info)) {
2482             case GST_VIDEO_FORMAT_AYUV:
2483               alpha->process = gst_alpha_chroma_key_ayuv_ayuv;
2484               break;
2485             case GST_VIDEO_FORMAT_Y444:
2486             case GST_VIDEO_FORMAT_Y42B:
2487             case GST_VIDEO_FORMAT_I420:
2488             case GST_VIDEO_FORMAT_YV12:
2489             case GST_VIDEO_FORMAT_Y41B:
2490               alpha->process = gst_alpha_chroma_key_planar_yuv_ayuv;
2491               break;
2492             case GST_VIDEO_FORMAT_YUY2:
2493             case GST_VIDEO_FORMAT_YVYU:
2494             case GST_VIDEO_FORMAT_UYVY:
2495               alpha->process = gst_alpha_chroma_key_packed_422_ayuv;
2496               break;
2497             case GST_VIDEO_FORMAT_ARGB:
2498             case GST_VIDEO_FORMAT_ABGR:
2499             case GST_VIDEO_FORMAT_RGBA:
2500             case GST_VIDEO_FORMAT_BGRA:
2501               alpha->process = gst_alpha_chroma_key_argb_ayuv;
2502               break;
2503             case GST_VIDEO_FORMAT_xRGB:
2504             case GST_VIDEO_FORMAT_xBGR:
2505             case GST_VIDEO_FORMAT_RGBx:
2506             case GST_VIDEO_FORMAT_BGRx:
2507             case GST_VIDEO_FORMAT_RGB:
2508             case GST_VIDEO_FORMAT_BGR:
2509               alpha->process = gst_alpha_chroma_key_rgb_ayuv;
2510               break;
2511             default:
2512               break;
2513           }
2514           break;
2515         case GST_VIDEO_FORMAT_ARGB:
2516         case GST_VIDEO_FORMAT_ABGR:
2517         case GST_VIDEO_FORMAT_RGBA:
2518         case GST_VIDEO_FORMAT_BGRA:
2519           switch (GST_VIDEO_INFO_FORMAT (&alpha->in_info)) {
2520             case GST_VIDEO_FORMAT_AYUV:
2521               alpha->process = gst_alpha_chroma_key_ayuv_argb;
2522               break;
2523             case GST_VIDEO_FORMAT_Y444:
2524             case GST_VIDEO_FORMAT_Y42B:
2525             case GST_VIDEO_FORMAT_I420:
2526             case GST_VIDEO_FORMAT_YV12:
2527             case GST_VIDEO_FORMAT_Y41B:
2528               alpha->process = gst_alpha_chroma_key_planar_yuv_argb;
2529               break;
2530             case GST_VIDEO_FORMAT_YUY2:
2531             case GST_VIDEO_FORMAT_YVYU:
2532             case GST_VIDEO_FORMAT_UYVY:
2533               alpha->process = gst_alpha_chroma_key_packed_422_argb;
2534               break;
2535             case GST_VIDEO_FORMAT_ARGB:
2536             case GST_VIDEO_FORMAT_ABGR:
2537             case GST_VIDEO_FORMAT_RGBA:
2538             case GST_VIDEO_FORMAT_BGRA:
2539               alpha->process = gst_alpha_chroma_key_argb_argb;
2540               break;
2541             case GST_VIDEO_FORMAT_xRGB:
2542             case GST_VIDEO_FORMAT_xBGR:
2543             case GST_VIDEO_FORMAT_RGBx:
2544             case GST_VIDEO_FORMAT_BGRx:
2545             case GST_VIDEO_FORMAT_RGB:
2546             case GST_VIDEO_FORMAT_BGR:
2547               alpha->process = gst_alpha_chroma_key_rgb_argb;
2548               break;
2549             default:
2550               break;
2551           }
2552           break;
2553           break;
2554         default:
2555           break;
2556       }
2557       break;
2558     default:
2559       break;
2560   }
2561   return alpha->process != NULL;
2562 }
2563
2564 static void
2565 gst_alpha_before_transform (GstBaseTransform * btrans, GstBuffer * buf)
2566 {
2567   GstAlpha *alpha = GST_ALPHA (btrans);
2568   GstClockTime timestamp;
2569
2570   timestamp = gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME,
2571       GST_BUFFER_TIMESTAMP (buf));
2572   GST_LOG ("Got stream time of %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
2573   if (GST_CLOCK_TIME_IS_VALID (timestamp))
2574     gst_object_sync_values (GST_OBJECT (alpha), timestamp);
2575 }
2576
2577 static GstFlowReturn
2578 gst_alpha_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out)
2579 {
2580   GstAlpha *alpha = GST_ALPHA (btrans);
2581   GstVideoFrame in_frame, out_frame;
2582
2583   GST_ALPHA_LOCK (alpha);
2584
2585   if (G_UNLIKELY (!alpha->process))
2586     goto not_negotiated;
2587
2588   if (!gst_video_frame_map (&in_frame, &alpha->in_info, in, GST_MAP_READ))
2589     goto invalid_in;
2590
2591   if (!gst_video_frame_map (&out_frame, &alpha->out_info, out, GST_MAP_WRITE))
2592     goto invalid_out;
2593
2594   alpha->process (&in_frame, &out_frame, alpha);
2595
2596   gst_video_frame_unmap (&out_frame);
2597   gst_video_frame_unmap (&in_frame);
2598
2599   GST_ALPHA_UNLOCK (alpha);
2600
2601   return GST_FLOW_OK;
2602
2603   /* ERRORS */
2604 not_negotiated:
2605   {
2606     GST_ERROR_OBJECT (alpha, "Not negotiated yet");
2607     GST_ALPHA_UNLOCK (alpha);
2608     return GST_FLOW_NOT_NEGOTIATED;
2609   }
2610 invalid_in:
2611   {
2612     GST_ERROR_OBJECT (alpha, "Invalid input frame");
2613     GST_ALPHA_UNLOCK (alpha);
2614     return GST_FLOW_OK;
2615   }
2616 invalid_out:
2617   {
2618     GST_ERROR_OBJECT (alpha, "Invalid output frame");
2619     gst_video_frame_unmap (&in_frame);
2620     GST_ALPHA_UNLOCK (alpha);
2621     return GST_FLOW_OK;
2622   }
2623 }
2624
2625 static gboolean
2626 plugin_init (GstPlugin * plugin)
2627 {
2628   return gst_element_register (plugin, "alpha", GST_RANK_NONE, GST_TYPE_ALPHA);
2629 }
2630
2631 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2632     GST_VERSION_MINOR,
2633     "alpha",
2634     "adds an alpha channel to video - constant or via chroma-keying",
2635     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)