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