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