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