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