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