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