alpha: Fix one_over_kc calculation
[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=snow ! mixer.sink_0 \
34  *   videotestsrc pattern=smpte75 ! alpha method=green ! mixer.sink_1 \
35  *   videomixer name=mixer sink_0::zorder=0 sink_1::zorder=1 ! \
36  *   videoconvert ! autovideosink
37  * ]| This pipeline adds a alpha channel to the SMPTE color bars
38  * with green as the transparent color and overlays the output on
39  * top of a snow video stream.
40  */
41
42
43 #ifdef HAVE_CONFIG_H
44 #include "config.h"
45 #endif
46
47 #include "gstalpha.h"
48
49 #include <stdlib.h>
50 #include <string.h>
51 #include <math.h>
52
53 #ifndef M_PI
54 #define M_PI  3.14159265358979323846
55 #endif
56
57 /* Generated by -bad/ext/cog/generate_tables */
58 static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
59   298, 0, 459, -63514,
60   298, -55, -136, 19681,
61   298, 541, 0, -73988,
62 };
63
64 static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
65   298, 0, 409, -57068,
66   298, -100, -208, 34707,
67   298, 516, 0, -70870,
68 };
69
70 static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
71   47, 157, 16, 4096,
72   -26, -87, 112, 32768,
73   112, -102, -10, 32768,
74 };
75
76 static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
77   66, 129, 25, 4096,
78   -38, -74, 112, 32768,
79   112, -94, -18, 32768,
80 };
81
82 static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
83   256, -30, -53, 10600,
84   0, 261, 29, -4367,
85   0, 19, 262, -3289,
86 };
87
88 static const gint cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = {
89   256, 25, 49, -9536,
90   0, 253, -28, 3958,
91   0, -19, 252, 2918,
92 };
93
94 /* Alpha signals and args */
95 enum
96 {
97   /* FILL ME */
98   LAST_SIGNAL
99 };
100
101 #define DEFAULT_METHOD ALPHA_METHOD_SET
102 #define DEFAULT_ALPHA 1.0
103 #define DEFAULT_TARGET_R 0
104 #define DEFAULT_TARGET_G 255
105 #define DEFAULT_TARGET_B 0
106 #define DEFAULT_ANGLE 20.0
107 #define DEFAULT_NOISE_LEVEL 2.0
108 #define DEFAULT_BLACK_SENSITIVITY 100
109 #define DEFAULT_WHITE_SENSITIVITY 100
110 #define DEFAULT_PREFER_PASSTHROUGH FALSE
111
112 enum
113 {
114   PROP_0,
115   PROP_METHOD,
116   PROP_ALPHA,
117   PROP_TARGET_R,
118   PROP_TARGET_G,
119   PROP_TARGET_B,
120   PROP_ANGLE,
121   PROP_NOISE_LEVEL,
122   PROP_BLACK_SENSITIVITY,
123   PROP_WHITE_SENSITIVITY,
124   PROP_PREFER_PASSTHROUGH
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_static_pad_template (gstelement_class,
277       &gst_alpha_sink_template);
278   gst_element_class_add_static_pad_template (gstelement_class,
279       &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_POFFSET (in_frame, 3);
641   o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
642   o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
643   o[3] = GST_VIDEO_FRAME_COMP_POFFSET (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_POFFSET (in_frame, 3);
696   o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
697   o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
698   o[3] = GST_VIDEO_FRAME_COMP_POFFSET (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_POFFSET (out_frame, 3);
754   p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
755   p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
756   p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
757
758   o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 3);
759   o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
760   o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
761   o[3] = GST_VIDEO_FRAME_COMP_POFFSET (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_POFFSET (out_frame, 3);
806   p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
807   p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
808   p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
809
810   o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 3);
811   o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
812   o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
813   o[3] = GST_VIDEO_FRAME_COMP_POFFSET (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_POFFSET (out_frame, 3);
874   p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
875   p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
876   p[3] = GST_VIDEO_FRAME_COMP_POFFSET (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_POFFSET (out_frame, 3);
929   p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
930   p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
931   p[3] = GST_VIDEO_FRAME_COMP_POFFSET (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_POFFSET (in_frame, 0);
1125   o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
1126   o[2] = GST_VIDEO_FRAME_COMP_POFFSET (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_POFFSET (in_frame, 0);
1182   o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
1183   o[2] = GST_VIDEO_FRAME_COMP_POFFSET (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_POFFSET (in_frame, 0);
1242   o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
1243   o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
1244
1245   p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
1246   p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
1247   p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
1248   p[3] = GST_VIDEO_FRAME_COMP_POFFSET (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_POFFSET (in_frame, 0);
1296   o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
1297   o[2] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
1298
1299   p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
1300   p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
1301   p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
1302   p[3] = GST_VIDEO_FRAME_COMP_POFFSET (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   guint8 *dest;
1348   gint width, height;
1349   gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1350   const guint8 *srcY, *srcY_tmp;
1351   const guint8 *srcU, *srcU_tmp;
1352   const guint8 *srcV, *srcV_tmp;
1353   gint i, j;
1354   gint y_stride, uv_stride;
1355   gint v_subs, h_subs;
1356
1357   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1358
1359   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1360   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1361
1362   y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
1363   uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
1364
1365   srcY_tmp = srcY = GST_VIDEO_FRAME_COMP_DATA (in_frame, 0);
1366   srcU_tmp = srcU = GST_VIDEO_FRAME_COMP_DATA (in_frame, 1);
1367   srcV_tmp = srcV = GST_VIDEO_FRAME_COMP_DATA (in_frame, 2);
1368
1369   switch (GST_VIDEO_FRAME_FORMAT (in_frame)) {
1370     case GST_VIDEO_FORMAT_I420:
1371     case GST_VIDEO_FORMAT_YV12:
1372       v_subs = h_subs = 2;
1373       break;
1374     case GST_VIDEO_FORMAT_Y444:
1375       v_subs = h_subs = 1;
1376       break;
1377     case GST_VIDEO_FORMAT_Y42B:
1378       v_subs = 1;
1379       h_subs = 2;
1380       break;
1381     case GST_VIDEO_FORMAT_Y41B:
1382       v_subs = 1;
1383       h_subs = 4;
1384       break;
1385     default:
1386       g_assert_not_reached ();
1387       return;
1388   }
1389
1390   if (alpha->in_sdtv == alpha->out_sdtv) {
1391     for (i = 0; i < height; i++) {
1392       for (j = 0; j < width; j++) {
1393         dest[0] = b_alpha;
1394         dest[1] = srcY[0];
1395         dest[2] = srcU[0];
1396         dest[3] = srcV[0];
1397
1398         dest += 4;
1399         srcY++;
1400         if ((j + 1) % h_subs == 0) {
1401           srcU++;
1402           srcV++;
1403         }
1404       }
1405
1406       srcY_tmp = srcY = srcY_tmp + y_stride;
1407       if ((i + 1) % v_subs == 0) {
1408         srcU_tmp = srcU = srcU_tmp + uv_stride;
1409         srcV_tmp = srcV = srcV_tmp + uv_stride;
1410       } else {
1411         srcU = srcU_tmp;
1412         srcV = srcV_tmp;
1413       }
1414     }
1415   } else {
1416     gint matrix[12];
1417     gint a, y, u, v;
1418
1419     memcpy (matrix,
1420         alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1421         cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1422
1423     for (i = 0; i < height; i++) {
1424       for (j = 0; j < width; j++) {
1425         a = b_alpha;
1426         y = srcY[0];
1427         u = srcU[0];
1428         v = srcV[0];
1429
1430         dest[0] = a;
1431         dest[1] = APPLY_MATRIX (matrix, 0, y, u, v);
1432         dest[2] = APPLY_MATRIX (matrix, 1, y, u, v);
1433         dest[3] = APPLY_MATRIX (matrix, 2, y, u, v);
1434
1435         dest += 4;
1436         srcY++;
1437         if ((j + 1) % h_subs == 0) {
1438           srcU++;
1439           srcV++;
1440         }
1441       }
1442
1443       srcY_tmp = srcY = srcY_tmp + y_stride;
1444       if ((i + 1) % v_subs == 0) {
1445         srcU_tmp = srcU = srcU_tmp + uv_stride;
1446         srcV_tmp = srcV = srcV_tmp + uv_stride;
1447       } else {
1448         srcU = srcU_tmp;
1449         srcV = srcV_tmp;
1450       }
1451     }
1452   }
1453 }
1454
1455 static void
1456 gst_alpha_chroma_key_planar_yuv_ayuv (const GstVideoFrame * in_frame,
1457     GstVideoFrame * out_frame, GstAlpha * alpha)
1458 {
1459   guint8 *dest;
1460   gint width, height;
1461   gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1462   const guint8 *srcY, *srcY_tmp;
1463   const guint8 *srcU, *srcU_tmp;
1464   const guint8 *srcV, *srcV_tmp;
1465   gint i, j;
1466   gint a, y, u, v;
1467   gint y_stride, uv_stride;
1468   gint v_subs, h_subs;
1469   gint smin = 128 - alpha->black_sensitivity;
1470   gint smax = 128 + alpha->white_sensitivity;
1471   gint8 cb = alpha->cb, cr = alpha->cr;
1472   gint8 kg = alpha->kg;
1473   guint8 accept_angle_tg = alpha->accept_angle_tg;
1474   guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1475   guint8 one_over_kc = alpha->one_over_kc;
1476   guint8 kfgy_scale = alpha->kfgy_scale;
1477   guint noise_level2 = alpha->noise_level2;
1478
1479   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1480
1481   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1482   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1483
1484   y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
1485   uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
1486
1487   srcY_tmp = srcY = GST_VIDEO_FRAME_COMP_DATA (in_frame, 0);
1488   srcU_tmp = srcU = GST_VIDEO_FRAME_COMP_DATA (in_frame, 1);
1489   srcV_tmp = srcV = GST_VIDEO_FRAME_COMP_DATA (in_frame, 2);
1490
1491   switch (GST_VIDEO_FRAME_FORMAT (in_frame)) {
1492     case GST_VIDEO_FORMAT_I420:
1493     case GST_VIDEO_FORMAT_YV12:
1494       v_subs = h_subs = 2;
1495       break;
1496     case GST_VIDEO_FORMAT_Y444:
1497       v_subs = h_subs = 1;
1498       break;
1499     case GST_VIDEO_FORMAT_Y42B:
1500       v_subs = 1;
1501       h_subs = 2;
1502       break;
1503     case GST_VIDEO_FORMAT_Y41B:
1504       v_subs = 1;
1505       h_subs = 4;
1506       break;
1507     default:
1508       g_assert_not_reached ();
1509       return;
1510   }
1511
1512   if (alpha->in_sdtv == alpha->out_sdtv) {
1513     for (i = 0; i < height; i++) {
1514       for (j = 0; j < width; j++) {
1515         a = b_alpha;
1516         y = srcY[0];
1517         u = srcU[0] - 128;
1518         v = srcV[0] - 128;
1519
1520         a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
1521             smax, accept_angle_tg, accept_angle_ctg,
1522             one_over_kc, kfgy_scale, kg, noise_level2);
1523
1524         u += 128;
1525         v += 128;
1526
1527         dest[0] = a;
1528         dest[1] = y;
1529         dest[2] = u;
1530         dest[3] = v;
1531
1532         dest += 4;
1533         srcY++;
1534         if ((j + 1) % h_subs == 0) {
1535           srcU++;
1536           srcV++;
1537         }
1538       }
1539
1540       srcY_tmp = srcY = srcY_tmp + y_stride;
1541       if ((i + 1) % v_subs == 0) {
1542         srcU_tmp = srcU = srcU_tmp + uv_stride;
1543         srcV_tmp = srcV = srcV_tmp + uv_stride;
1544       } else {
1545         srcU = srcU_tmp;
1546         srcV = srcV_tmp;
1547       }
1548     }
1549   } else {
1550     gint matrix[12];
1551
1552     memcpy (matrix,
1553         alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
1554         cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
1555
1556     for (i = 0; i < height; i++) {
1557       for (j = 0; j < width; j++) {
1558         a = b_alpha;
1559         y = APPLY_MATRIX (matrix, 0, srcY[0], srcU[0], srcV[0]);
1560         u = APPLY_MATRIX (matrix, 1, srcY[0], srcU[0], srcV[0]) - 128;
1561         v = APPLY_MATRIX (matrix, 2, srcY[0], srcU[0], srcV[0]) - 128;
1562
1563         a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
1564             smax, accept_angle_tg, accept_angle_ctg,
1565             one_over_kc, kfgy_scale, kg, noise_level2);
1566
1567         dest[0] = a;
1568         dest[1] = y;
1569         dest[2] = u + 128;
1570         dest[3] = v + 128;
1571
1572         dest += 4;
1573         srcY++;
1574         if ((j + 1) % h_subs == 0) {
1575           srcU++;
1576           srcV++;
1577         }
1578       }
1579
1580       srcY_tmp = srcY = srcY_tmp + y_stride;
1581       if ((i + 1) % v_subs == 0) {
1582         srcU_tmp = srcU = srcU_tmp + uv_stride;
1583         srcV_tmp = srcV = srcV_tmp + uv_stride;
1584       } else {
1585         srcU = srcU_tmp;
1586         srcV = srcV_tmp;
1587       }
1588     }
1589   }
1590 }
1591
1592 static void
1593 gst_alpha_set_planar_yuv_argb (const GstVideoFrame * in_frame,
1594     GstVideoFrame * out_frame, GstAlpha * alpha)
1595 {
1596   guint8 *dest;
1597   gint width, height;
1598   gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1599   const guint8 *srcY, *srcY_tmp;
1600   const guint8 *srcU, *srcU_tmp;
1601   const guint8 *srcV, *srcV_tmp;
1602   gint i, j;
1603   gint y_stride, uv_stride;
1604   gint v_subs, h_subs;
1605   gint matrix[12];
1606   gint a, y, u, v;
1607   gint r, g, b;
1608   gint p[4];
1609
1610   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1611
1612   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1613   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1614
1615   p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
1616   p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
1617   p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
1618   p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
1619
1620   y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
1621   uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
1622
1623   srcY_tmp = srcY = GST_VIDEO_FRAME_COMP_DATA (in_frame, 0);
1624   srcU_tmp = srcU = GST_VIDEO_FRAME_COMP_DATA (in_frame, 1);
1625   srcV_tmp = srcV = GST_VIDEO_FRAME_COMP_DATA (in_frame, 2);
1626
1627   switch (GST_VIDEO_FRAME_FORMAT (in_frame)) {
1628     case GST_VIDEO_FORMAT_I420:
1629     case GST_VIDEO_FORMAT_YV12:
1630       v_subs = h_subs = 2;
1631       break;
1632     case GST_VIDEO_FORMAT_Y444:
1633       v_subs = h_subs = 1;
1634       break;
1635     case GST_VIDEO_FORMAT_Y42B:
1636       v_subs = 1;
1637       h_subs = 2;
1638       break;
1639     case GST_VIDEO_FORMAT_Y41B:
1640       v_subs = 1;
1641       h_subs = 4;
1642       break;
1643     default:
1644       g_assert_not_reached ();
1645       return;
1646   }
1647
1648   memcpy (matrix,
1649       alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
1650       cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
1651
1652   for (i = 0; i < height; i++) {
1653     for (j = 0; j < width; j++) {
1654       a = b_alpha;
1655       y = srcY[0];
1656       u = srcU[0];
1657       v = srcV[0];
1658
1659       dest[p[0]] = a;
1660       r = APPLY_MATRIX (matrix, 0, y, u, v);
1661       g = APPLY_MATRIX (matrix, 1, y, u, v);
1662       b = APPLY_MATRIX (matrix, 2, y, u, v);
1663       dest[p[1]] = CLAMP (r, 0, 255);
1664       dest[p[2]] = CLAMP (g, 0, 255);
1665       dest[p[3]] = CLAMP (b, 0, 255);
1666
1667       dest += 4;
1668       srcY++;
1669       if ((j + 1) % h_subs == 0) {
1670         srcU++;
1671         srcV++;
1672       }
1673     }
1674
1675     srcY_tmp = srcY = srcY_tmp + y_stride;
1676     if ((i + 1) % v_subs == 0) {
1677       srcU_tmp = srcU = srcU_tmp + uv_stride;
1678       srcV_tmp = srcV = srcV_tmp + uv_stride;
1679     } else {
1680       srcU = srcU_tmp;
1681       srcV = srcV_tmp;
1682     }
1683   }
1684 }
1685
1686 static void
1687 gst_alpha_chroma_key_planar_yuv_argb (const GstVideoFrame * in_frame,
1688     GstVideoFrame * out_frame, GstAlpha * alpha)
1689 {
1690   guint8 *dest;
1691   gint width, height;
1692   gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1693   const guint8 *srcY, *srcY_tmp;
1694   const guint8 *srcU, *srcU_tmp;
1695   const guint8 *srcV, *srcV_tmp;
1696   gint i, j;
1697   gint a, y, u, v;
1698   gint r, g, b;
1699   gint y_stride, uv_stride;
1700   gint v_subs, h_subs;
1701   gint smin = 128 - alpha->black_sensitivity;
1702   gint smax = 128 + alpha->white_sensitivity;
1703   gint8 cb = alpha->cb, cr = alpha->cr;
1704   gint8 kg = alpha->kg;
1705   guint8 accept_angle_tg = alpha->accept_angle_tg;
1706   guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1707   guint8 one_over_kc = alpha->one_over_kc;
1708   guint8 kfgy_scale = alpha->kfgy_scale;
1709   guint noise_level2 = alpha->noise_level2;
1710   gint matrix[12];
1711   gint p[4];
1712
1713   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1714
1715   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1716   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1717
1718   p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
1719   p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
1720   p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
1721   p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
1722
1723   y_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
1724   uv_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 1);
1725
1726   srcY_tmp = srcY = GST_VIDEO_FRAME_COMP_DATA (in_frame, 0);
1727   srcU_tmp = srcU = GST_VIDEO_FRAME_COMP_DATA (in_frame, 1);
1728   srcV_tmp = srcV = GST_VIDEO_FRAME_COMP_DATA (in_frame, 2);
1729
1730   switch (GST_VIDEO_FRAME_FORMAT (in_frame)) {
1731     case GST_VIDEO_FORMAT_I420:
1732     case GST_VIDEO_FORMAT_YV12:
1733       v_subs = h_subs = 2;
1734       break;
1735     case GST_VIDEO_FORMAT_Y444:
1736       v_subs = h_subs = 1;
1737       break;
1738     case GST_VIDEO_FORMAT_Y42B:
1739       v_subs = 1;
1740       h_subs = 2;
1741       break;
1742     case GST_VIDEO_FORMAT_Y41B:
1743       v_subs = 1;
1744       h_subs = 4;
1745       break;
1746     default:
1747       g_assert_not_reached ();
1748       return;
1749   }
1750
1751   memcpy (matrix,
1752       alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
1753       cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
1754
1755   for (i = 0; i < height; i++) {
1756     for (j = 0; j < width; j++) {
1757       a = b_alpha;
1758       y = srcY[0];
1759       u = srcU[0] - 128;
1760       v = srcV[0] - 128;
1761
1762       a = chroma_keying_yuv (a, &y, &u, &v, cr, cb, smin,
1763           smax, accept_angle_tg, accept_angle_ctg,
1764           one_over_kc, kfgy_scale, kg, noise_level2);
1765
1766       u += 128;
1767       v += 128;
1768
1769       dest[p[0]] = a;
1770       r = APPLY_MATRIX (matrix, 0, y, u, v);
1771       g = APPLY_MATRIX (matrix, 1, y, u, v);
1772       b = APPLY_MATRIX (matrix, 2, y, u, v);
1773       dest[p[1]] = CLAMP (r, 0, 255);
1774       dest[p[2]] = CLAMP (g, 0, 255);
1775       dest[p[3]] = CLAMP (b, 0, 255);
1776
1777       dest += 4;
1778       srcY++;
1779       if ((j + 1) % h_subs == 0) {
1780         srcU++;
1781         srcV++;
1782       }
1783     }
1784
1785     srcY_tmp = srcY = srcY_tmp + y_stride;
1786     if ((i + 1) % v_subs == 0) {
1787       srcU_tmp = srcU = srcU_tmp + uv_stride;
1788       srcV_tmp = srcV = srcV_tmp + uv_stride;
1789     } else {
1790       srcU = srcU_tmp;
1791       srcV = srcV_tmp;
1792     }
1793   }
1794 }
1795
1796 static void
1797 gst_alpha_set_packed_422_ayuv (const GstVideoFrame * in_frame,
1798     GstVideoFrame * out_frame, GstAlpha * alpha)
1799 {
1800   const guint8 *src;
1801   guint8 *dest;
1802   gint width, height;
1803   gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1804   gint i, j;
1805   gint y, u, v;
1806   gint p[4];                    /* Y U Y V */
1807   gint src_stride;
1808   const guint8 *src_tmp;
1809
1810   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1811   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1812
1813   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1814   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1815
1816   src_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
1817
1818   p[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
1819   p[2] = p[0] + 2;
1820   p[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
1821   p[3] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
1822
1823   if (alpha->in_sdtv != alpha->out_sdtv) {
1824     gint matrix[12];
1825
1826     memcpy (matrix,
1827         alpha->in_sdtv ? cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit :
1828         cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit, 12 * sizeof (gint));
1829
1830     for (i = 0; i < height; i++) {
1831       src_tmp = src;
1832
1833       for (j = 0; j < width - 1; j += 2) {
1834         dest[0] = s_alpha;
1835         dest[4] = s_alpha;
1836
1837         y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
1838         u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]);
1839         v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]);
1840
1841         dest[1] = y;
1842         dest[2] = u;
1843         dest[3] = v;
1844
1845         y = APPLY_MATRIX (matrix, 0, src[p[2]], src[p[1]], src[p[3]]);
1846         u = APPLY_MATRIX (matrix, 1, src[p[2]], src[p[1]], src[p[3]]);
1847         v = APPLY_MATRIX (matrix, 2, src[p[2]], src[p[1]], src[p[3]]);
1848
1849         dest[5] = y;
1850         dest[6] = u;
1851         dest[7] = v;
1852
1853         dest += 8;
1854         src += 4;
1855       }
1856
1857       if (j == width - 1) {
1858         dest[0] = s_alpha;
1859
1860         y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
1861         u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]);
1862         v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]);
1863
1864         dest[1] = y;
1865         dest[2] = u;
1866         dest[3] = v;
1867
1868         dest += 4;
1869       }
1870
1871       src = src_tmp + src_stride;
1872     }
1873   } else {
1874     for (i = 0; i < height; i++) {
1875       src_tmp = src;
1876
1877       for (j = 0; j < width - 1; j += 2) {
1878         dest[0] = s_alpha;
1879         dest[4] = s_alpha;
1880
1881         y = src[p[0]];
1882         u = src[p[1]];
1883         v = src[p[3]];
1884
1885         dest[1] = y;
1886         dest[2] = u;
1887         dest[3] = v;
1888
1889         y = src[p[2]];
1890
1891         dest[5] = y;
1892         dest[6] = u;
1893         dest[7] = v;
1894
1895         dest += 8;
1896         src += 4;
1897       }
1898
1899       if (j == width - 1) {
1900         dest[0] = s_alpha;
1901
1902         y = src[p[0]];
1903         u = src[p[1]];
1904         v = src[p[3]];
1905
1906         dest[1] = y;
1907         dest[2] = u;
1908         dest[3] = v;
1909
1910         dest += 4;
1911       }
1912
1913       src = src_tmp + src_stride;
1914     }
1915   }
1916 }
1917
1918 static void
1919 gst_alpha_chroma_key_packed_422_ayuv (const GstVideoFrame * in_frame,
1920     GstVideoFrame * out_frame, GstAlpha * alpha)
1921 {
1922   const guint8 *src;
1923   guint8 *dest;
1924   gint width, height;
1925   gint i, j;
1926   gint a, y, u, v;
1927   gint smin, smax;
1928   gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
1929   gint8 cb = alpha->cb, cr = alpha->cr;
1930   gint8 kg = alpha->kg;
1931   guint8 accept_angle_tg = alpha->accept_angle_tg;
1932   guint8 accept_angle_ctg = alpha->accept_angle_ctg;
1933   guint8 one_over_kc = alpha->one_over_kc;
1934   guint8 kfgy_scale = alpha->kfgy_scale;
1935   guint noise_level2 = alpha->noise_level2;
1936   gint p[4];                    /* Y U Y V */
1937   gint src_stride;
1938   const guint8 *src_tmp;
1939
1940   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
1941   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
1942
1943   width = GST_VIDEO_FRAME_WIDTH (in_frame);
1944   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
1945
1946   src_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
1947
1948   p[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
1949   p[2] = p[0] + 2;
1950   p[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
1951   p[3] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
1952
1953   smin = 128 - alpha->black_sensitivity;
1954   smax = 128 + alpha->white_sensitivity;
1955
1956   if (alpha->in_sdtv != alpha->out_sdtv) {
1957     gint matrix[12];
1958
1959     memcpy (matrix,
1960         alpha->in_sdtv ? cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit :
1961         cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit, 12 * sizeof (gint));
1962
1963     for (i = 0; i < height; i++) {
1964       src_tmp = src;
1965
1966       for (j = 0; j < width - 1; j += 2) {
1967         y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
1968         u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]) - 128;
1969         v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]) - 128;
1970
1971         a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
1972             smin, smax, accept_angle_tg, accept_angle_ctg,
1973             one_over_kc, kfgy_scale, kg, noise_level2);
1974
1975         dest[0] = a;
1976         dest[1] = y;
1977         dest[2] = u + 128;
1978         dest[3] = v + 128;
1979
1980         y = APPLY_MATRIX (matrix, 0, src[p[2]], src[p[1]], src[p[3]]);
1981         u = APPLY_MATRIX (matrix, 1, src[p[2]], src[p[1]], src[p[3]]) - 128;
1982         v = APPLY_MATRIX (matrix, 2, src[p[2]], src[p[1]], src[p[3]]) - 128;
1983
1984         a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
1985             smin, smax, accept_angle_tg, accept_angle_ctg,
1986             one_over_kc, kfgy_scale, kg, noise_level2);
1987
1988         dest[4] = a;
1989         dest[5] = y;
1990         dest[6] = u + 128;
1991         dest[7] = v + 128;
1992
1993         dest += 8;
1994         src += 4;
1995       }
1996
1997       if (j == width - 1) {
1998         y = APPLY_MATRIX (matrix, 0, src[p[0]], src[p[1]], src[p[3]]);
1999         u = APPLY_MATRIX (matrix, 1, src[p[0]], src[p[1]], src[p[3]]) - 128;
2000         v = APPLY_MATRIX (matrix, 2, src[p[0]], src[p[1]], src[p[3]]) - 128;
2001
2002         a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2003             smin, smax, accept_angle_tg, accept_angle_ctg,
2004             one_over_kc, kfgy_scale, kg, noise_level2);
2005
2006         dest[0] = a;
2007         dest[1] = y;
2008         dest[2] = u + 128;
2009         dest[3] = v + 128;
2010
2011         dest += 4;
2012       }
2013
2014       src = src_tmp + src_stride;
2015     }
2016   } else {
2017     for (i = 0; i < height; i++) {
2018       src_tmp = src;
2019
2020       for (j = 0; j < width - 1; j += 2) {
2021         y = src[p[0]];
2022         u = src[p[1]] - 128;
2023         v = src[p[3]] - 128;
2024
2025         a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2026             smin, smax, accept_angle_tg, accept_angle_ctg,
2027             one_over_kc, kfgy_scale, kg, noise_level2);
2028
2029         dest[0] = a;
2030         dest[1] = y;
2031         dest[2] = u + 128;
2032         dest[3] = v + 128;
2033
2034         y = src[p[2]];
2035         u = src[p[1]] - 128;
2036         v = src[p[3]] - 128;
2037
2038         a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2039             smin, smax, accept_angle_tg, accept_angle_ctg,
2040             one_over_kc, kfgy_scale, kg, noise_level2);
2041
2042         dest[4] = a;
2043         dest[5] = y;
2044         dest[6] = u + 128;
2045         dest[7] = v + 128;
2046
2047         dest += 8;
2048         src += 4;
2049       }
2050
2051       if (j == width - 1) {
2052         y = src[p[0]];
2053         u = src[p[1]] - 128;
2054         v = src[p[3]] - 128;
2055
2056         a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2057             smin, smax, accept_angle_tg, accept_angle_ctg,
2058             one_over_kc, kfgy_scale, kg, noise_level2);
2059
2060         dest[0] = a;
2061         dest[1] = y;
2062         dest[2] = u + 128;
2063         dest[3] = v + 128;
2064
2065         dest += 4;
2066       }
2067
2068       src = src_tmp + src_stride;
2069     }
2070   }
2071 }
2072
2073 static void
2074 gst_alpha_set_packed_422_argb (const GstVideoFrame * in_frame,
2075     GstVideoFrame * out_frame, GstAlpha * alpha)
2076 {
2077   const guint8 *src;
2078   guint8 *dest;
2079   gint width, height;
2080   gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
2081   gint i, j;
2082   gint p[4], o[4];
2083   gint src_stride;
2084   const guint8 *src_tmp;
2085   gint matrix[12];
2086   gint r, g, b;
2087
2088   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
2089   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
2090
2091   width = GST_VIDEO_FRAME_WIDTH (in_frame);
2092   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
2093
2094   src_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
2095
2096   o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
2097   o[2] = o[0] + 2;
2098   o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
2099   o[3] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
2100
2101   p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
2102   p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
2103   p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
2104   p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
2105
2106   memcpy (matrix,
2107       alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
2108       cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
2109
2110   for (i = 0; i < height; i++) {
2111     src_tmp = src;
2112
2113     for (j = 0; j < width - 1; j += 2) {
2114       r = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[3]]);
2115       g = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[3]]);
2116       b = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[3]]);
2117
2118       dest[p[0]] = s_alpha;
2119       dest[p[1]] = CLAMP (r, 0, 255);
2120       dest[p[2]] = CLAMP (g, 0, 255);
2121       dest[p[3]] = CLAMP (b, 0, 255);
2122
2123       r = APPLY_MATRIX (matrix, 0, src[o[2]], src[o[1]], src[o[3]]);
2124       g = APPLY_MATRIX (matrix, 1, src[o[2]], src[o[1]], src[o[3]]);
2125       b = APPLY_MATRIX (matrix, 2, src[o[2]], src[o[1]], src[o[3]]);
2126
2127       dest[4 + p[0]] = s_alpha;
2128       dest[4 + p[1]] = CLAMP (r, 0, 255);
2129       dest[4 + p[2]] = CLAMP (g, 0, 255);
2130       dest[4 + p[3]] = CLAMP (b, 0, 255);
2131
2132       dest += 8;
2133       src += 4;
2134     }
2135
2136     if (j == width - 1) {
2137       r = APPLY_MATRIX (matrix, 0, src[o[0]], src[o[1]], src[o[3]]);
2138       g = APPLY_MATRIX (matrix, 1, src[o[0]], src[o[1]], src[o[3]]);
2139       b = APPLY_MATRIX (matrix, 2, src[o[0]], src[o[1]], src[o[3]]);
2140
2141       dest[p[0]] = s_alpha;
2142       dest[p[1]] = CLAMP (r, 0, 255);
2143       dest[p[2]] = CLAMP (g, 0, 255);
2144       dest[p[3]] = CLAMP (b, 0, 255);
2145
2146       dest += 4;
2147     }
2148
2149     src = src_tmp + src_stride;
2150   }
2151 }
2152
2153 static void
2154 gst_alpha_chroma_key_packed_422_argb (const GstVideoFrame * in_frame,
2155     GstVideoFrame * out_frame, GstAlpha * alpha)
2156 {
2157   const guint8 *src;
2158   guint8 *dest;
2159   gint width, height;
2160   gint i, j;
2161   gint a, y, u, v;
2162   gint r, g, b;
2163   gint smin, smax;
2164   gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
2165   gint8 cb = alpha->cb, cr = alpha->cr;
2166   gint8 kg = alpha->kg;
2167   guint8 accept_angle_tg = alpha->accept_angle_tg;
2168   guint8 accept_angle_ctg = alpha->accept_angle_ctg;
2169   guint8 one_over_kc = alpha->one_over_kc;
2170   guint8 kfgy_scale = alpha->kfgy_scale;
2171   guint noise_level2 = alpha->noise_level2;
2172   gint p[4], o[4];
2173   gint src_stride;
2174   const guint8 *src_tmp;
2175   gint matrix[12];
2176
2177   src = GST_VIDEO_FRAME_PLANE_DATA (in_frame, 0);
2178   dest = GST_VIDEO_FRAME_PLANE_DATA (out_frame, 0);
2179
2180   width = GST_VIDEO_FRAME_WIDTH (in_frame);
2181   height = GST_VIDEO_FRAME_HEIGHT (in_frame);
2182
2183   src_stride = GST_VIDEO_FRAME_COMP_STRIDE (in_frame, 0);
2184
2185   o[0] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 0);
2186   o[2] = o[0] + 2;
2187   o[1] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 1);
2188   o[3] = GST_VIDEO_FRAME_COMP_POFFSET (in_frame, 2);
2189
2190   p[0] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 3);
2191   p[1] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 0);
2192   p[2] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 1);
2193   p[3] = GST_VIDEO_FRAME_COMP_POFFSET (out_frame, 2);
2194
2195   memcpy (matrix,
2196       alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
2197       cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint));
2198
2199   smin = 128 - alpha->black_sensitivity;
2200   smax = 128 + alpha->white_sensitivity;
2201
2202   for (i = 0; i < height; i++) {
2203     src_tmp = src;
2204
2205     for (j = 0; j < width - 1; j += 2) {
2206       y = src[o[0]];
2207       u = src[o[1]] - 128;
2208       v = src[o[3]] - 128;
2209
2210       a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2211           smin, smax, accept_angle_tg, accept_angle_ctg,
2212           one_over_kc, kfgy_scale, kg, noise_level2);
2213       u += 128;
2214       v += 128;
2215
2216       r = APPLY_MATRIX (matrix, 0, y, u, v);
2217       g = APPLY_MATRIX (matrix, 1, y, u, v);
2218       b = APPLY_MATRIX (matrix, 2, y, u, v);
2219
2220       dest[p[0]] = a;
2221       dest[p[1]] = CLAMP (r, 0, 255);
2222       dest[p[2]] = CLAMP (g, 0, 255);
2223       dest[p[3]] = CLAMP (b, 0, 255);
2224
2225       y = src[o[2]];
2226       u = src[o[1]] - 128;
2227       v = src[o[3]] - 128;
2228
2229       a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2230           smin, smax, accept_angle_tg, accept_angle_ctg,
2231           one_over_kc, kfgy_scale, kg, noise_level2);
2232       u += 128;
2233       v += 128;
2234
2235       r = APPLY_MATRIX (matrix, 0, y, u, v);
2236       g = APPLY_MATRIX (matrix, 1, y, u, v);
2237       b = APPLY_MATRIX (matrix, 2, y, u, v);
2238
2239       dest[4 + p[0]] = a;
2240       dest[4 + p[1]] = CLAMP (r, 0, 255);
2241       dest[4 + p[2]] = CLAMP (g, 0, 255);
2242       dest[4 + p[3]] = CLAMP (b, 0, 255);
2243
2244       dest += 8;
2245       src += 4;
2246     }
2247
2248     if (j == width - 1) {
2249       y = src[o[0]];
2250       u = src[o[1]] - 128;
2251       v = src[o[3]] - 128;
2252
2253       a = chroma_keying_yuv (pa, &y, &u, &v, cr, cb,
2254           smin, smax, accept_angle_tg, accept_angle_ctg,
2255           one_over_kc, kfgy_scale, kg, noise_level2);
2256       u += 128;
2257       v += 128;
2258
2259       r = APPLY_MATRIX (matrix, 0, y, u, v);
2260       g = APPLY_MATRIX (matrix, 1, y, u, v);
2261       b = APPLY_MATRIX (matrix, 2, y, u, v);
2262
2263       dest[p[0]] = a;
2264       dest[p[1]] = CLAMP (r, 0, 255);
2265       dest[p[2]] = CLAMP (g, 0, 255);
2266       dest[p[3]] = CLAMP (b, 0, 255);
2267
2268       dest += 4;
2269     }
2270
2271     src = src_tmp + src_stride;
2272   }
2273 }
2274
2275 /* Protected with the alpha lock */
2276 static void
2277 gst_alpha_init_params_full (GstAlpha * alpha,
2278     const GstVideoFormatInfo * in_info, const GstVideoFormatInfo * out_info)
2279 {
2280   gfloat kgl;
2281   gfloat tmp;
2282   gfloat tmp1, tmp2;
2283   gfloat y;
2284   guint target_r = alpha->target_r;
2285   guint target_g = alpha->target_g;
2286   guint target_b = alpha->target_b;
2287   const gint *matrix;
2288
2289   switch (alpha->method) {
2290     case ALPHA_METHOD_GREEN:
2291       target_r = 0;
2292       target_g = 255;
2293       target_b = 0;
2294       break;
2295     case ALPHA_METHOD_BLUE:
2296       target_r = 0;
2297       target_g = 0;
2298       target_b = 255;
2299       break;
2300     default:
2301       break;
2302   }
2303
2304   /* RGB->RGB: convert to SDTV YUV, chroma keying, convert back
2305    * YUV->RGB: chroma keying, convert to RGB
2306    * RGB->YUV: convert to YUV, chroma keying
2307    * YUV->YUV: convert matrix, chroma keying
2308    */
2309   if (GST_VIDEO_FORMAT_INFO_IS_RGB (in_info)
2310       && GST_VIDEO_FORMAT_INFO_IS_RGB (out_info))
2311     matrix = cog_rgb_to_ycbcr_matrix_8bit_sdtv;
2312   else if (GST_VIDEO_FORMAT_INFO_IS_YUV (in_info)
2313       && GST_VIDEO_FORMAT_INFO_IS_RGB (out_info))
2314     matrix =
2315         (alpha->in_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
2316         cog_rgb_to_ycbcr_matrix_8bit_hdtv;
2317   else if (GST_VIDEO_FORMAT_INFO_IS_RGB (in_info)
2318       && GST_VIDEO_FORMAT_INFO_IS_YUV (out_info))
2319     matrix =
2320         (alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
2321         cog_rgb_to_ycbcr_matrix_8bit_hdtv;
2322   else                          /* yuv -> yuv */
2323     matrix =
2324         (alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
2325         cog_rgb_to_ycbcr_matrix_8bit_hdtv;
2326
2327   y = (matrix[0] * ((gint) target_r) +
2328       matrix[1] * ((gint) target_g) +
2329       matrix[2] * ((gint) target_b) + matrix[3]) >> 8;
2330   /* Cb,Cr without offset here because the chroma keying
2331    * works with them being in range [-128,127]
2332    */
2333   tmp1 =
2334       (matrix[4] * ((gint) target_r) +
2335       matrix[5] * ((gint) target_g) + matrix[6] * ((gint) target_b)) >> 8;
2336   tmp2 =
2337       (matrix[8] * ((gint) target_r) +
2338       matrix[9] * ((gint) target_g) + matrix[10] * ((gint) target_b)) >> 8;
2339
2340   kgl = sqrt (tmp1 * tmp1 + tmp2 * tmp2);
2341   alpha->cb = 127 * (tmp1 / kgl);
2342   alpha->cr = 127 * (tmp2 / kgl);
2343
2344   tmp = 15 * tan (M_PI * alpha->angle / 180);
2345   tmp = MIN (tmp, 255);
2346   alpha->accept_angle_tg = tmp;
2347   tmp = 15 / tan (M_PI * alpha->angle / 180);
2348   tmp = MIN (tmp, 255);
2349   alpha->accept_angle_ctg = tmp;
2350   tmp = 1 / (kgl);
2351   alpha->one_over_kc = (gint) (255 * 2 * tmp - 255);
2352   tmp = 15 * y / kgl;
2353   tmp = MIN (tmp, 255);
2354   alpha->kfgy_scale = tmp;
2355   alpha->kg = MIN (kgl, 127);
2356
2357   alpha->noise_level2 = alpha->noise_level * alpha->noise_level;
2358 }
2359
2360 static void
2361 gst_alpha_init_params (GstAlpha * alpha)
2362 {
2363   const GstVideoFormatInfo *finfo_in, *finfo_out;
2364
2365   finfo_in = GST_VIDEO_FILTER (alpha)->in_info.finfo;
2366   finfo_out = GST_VIDEO_FILTER (alpha)->out_info.finfo;
2367
2368   if (finfo_in != NULL && finfo_out != NULL) {
2369     gst_alpha_init_params_full (alpha, finfo_in, finfo_out);
2370   } else {
2371     GST_DEBUG_OBJECT (alpha, "video formats not set yet");
2372   }
2373 }
2374
2375 /* Protected with the alpha lock */
2376 static gboolean
2377 gst_alpha_set_process_function_full (GstAlpha * alpha, GstVideoInfo * in_info,
2378     GstVideoInfo * out_info)
2379 {
2380   alpha->process = NULL;
2381
2382   switch (alpha->method) {
2383     case ALPHA_METHOD_SET:
2384       switch (GST_VIDEO_INFO_FORMAT (out_info)) {
2385         case GST_VIDEO_FORMAT_AYUV:
2386           switch (GST_VIDEO_INFO_FORMAT (in_info)) {
2387             case GST_VIDEO_FORMAT_AYUV:
2388               alpha->process = gst_alpha_set_ayuv_ayuv;
2389               break;
2390             case GST_VIDEO_FORMAT_Y444:
2391             case GST_VIDEO_FORMAT_Y42B:
2392             case GST_VIDEO_FORMAT_I420:
2393             case GST_VIDEO_FORMAT_YV12:
2394             case GST_VIDEO_FORMAT_Y41B:
2395               alpha->process = gst_alpha_set_planar_yuv_ayuv;
2396               break;
2397             case GST_VIDEO_FORMAT_YUY2:
2398             case GST_VIDEO_FORMAT_YVYU:
2399             case GST_VIDEO_FORMAT_UYVY:
2400               alpha->process = gst_alpha_set_packed_422_ayuv;
2401               break;
2402             case GST_VIDEO_FORMAT_ARGB:
2403             case GST_VIDEO_FORMAT_ABGR:
2404             case GST_VIDEO_FORMAT_RGBA:
2405             case GST_VIDEO_FORMAT_BGRA:
2406               alpha->process = gst_alpha_set_argb_ayuv;
2407               break;
2408             case GST_VIDEO_FORMAT_xRGB:
2409             case GST_VIDEO_FORMAT_xBGR:
2410             case GST_VIDEO_FORMAT_RGBx:
2411             case GST_VIDEO_FORMAT_BGRx:
2412             case GST_VIDEO_FORMAT_RGB:
2413             case GST_VIDEO_FORMAT_BGR:
2414               alpha->process = gst_alpha_set_rgb_ayuv;
2415               break;
2416             default:
2417               break;
2418           }
2419           break;
2420         case GST_VIDEO_FORMAT_ARGB:
2421         case GST_VIDEO_FORMAT_ABGR:
2422         case GST_VIDEO_FORMAT_RGBA:
2423         case GST_VIDEO_FORMAT_BGRA:
2424           switch (GST_VIDEO_INFO_FORMAT (in_info)) {
2425             case GST_VIDEO_FORMAT_AYUV:
2426               alpha->process = gst_alpha_set_ayuv_argb;
2427               break;
2428             case GST_VIDEO_FORMAT_Y444:
2429             case GST_VIDEO_FORMAT_Y42B:
2430             case GST_VIDEO_FORMAT_I420:
2431             case GST_VIDEO_FORMAT_YV12:
2432             case GST_VIDEO_FORMAT_Y41B:
2433               alpha->process = gst_alpha_set_planar_yuv_argb;
2434               break;
2435             case GST_VIDEO_FORMAT_YUY2:
2436             case GST_VIDEO_FORMAT_YVYU:
2437             case GST_VIDEO_FORMAT_UYVY:
2438               alpha->process = gst_alpha_set_packed_422_argb;
2439               break;
2440             case GST_VIDEO_FORMAT_ARGB:
2441             case GST_VIDEO_FORMAT_ABGR:
2442             case GST_VIDEO_FORMAT_RGBA:
2443             case GST_VIDEO_FORMAT_BGRA:
2444               alpha->process = gst_alpha_set_argb_argb;
2445               break;
2446             case GST_VIDEO_FORMAT_xRGB:
2447             case GST_VIDEO_FORMAT_xBGR:
2448             case GST_VIDEO_FORMAT_RGBx:
2449             case GST_VIDEO_FORMAT_BGRx:
2450             case GST_VIDEO_FORMAT_RGB:
2451             case GST_VIDEO_FORMAT_BGR:
2452               alpha->process = gst_alpha_set_rgb_argb;
2453               break;
2454             default:
2455               break;
2456           }
2457           break;
2458         default:
2459           break;
2460       }
2461       break;
2462     case ALPHA_METHOD_GREEN:
2463     case ALPHA_METHOD_BLUE:
2464     case ALPHA_METHOD_CUSTOM:
2465       switch (GST_VIDEO_INFO_FORMAT (out_info)) {
2466         case GST_VIDEO_FORMAT_AYUV:
2467           switch (GST_VIDEO_INFO_FORMAT (in_info)) {
2468             case GST_VIDEO_FORMAT_AYUV:
2469               alpha->process = gst_alpha_chroma_key_ayuv_ayuv;
2470               break;
2471             case GST_VIDEO_FORMAT_Y444:
2472             case GST_VIDEO_FORMAT_Y42B:
2473             case GST_VIDEO_FORMAT_I420:
2474             case GST_VIDEO_FORMAT_YV12:
2475             case GST_VIDEO_FORMAT_Y41B:
2476               alpha->process = gst_alpha_chroma_key_planar_yuv_ayuv;
2477               break;
2478             case GST_VIDEO_FORMAT_YUY2:
2479             case GST_VIDEO_FORMAT_YVYU:
2480             case GST_VIDEO_FORMAT_UYVY:
2481               alpha->process = gst_alpha_chroma_key_packed_422_ayuv;
2482               break;
2483             case GST_VIDEO_FORMAT_ARGB:
2484             case GST_VIDEO_FORMAT_ABGR:
2485             case GST_VIDEO_FORMAT_RGBA:
2486             case GST_VIDEO_FORMAT_BGRA:
2487               alpha->process = gst_alpha_chroma_key_argb_ayuv;
2488               break;
2489             case GST_VIDEO_FORMAT_xRGB:
2490             case GST_VIDEO_FORMAT_xBGR:
2491             case GST_VIDEO_FORMAT_RGBx:
2492             case GST_VIDEO_FORMAT_BGRx:
2493             case GST_VIDEO_FORMAT_RGB:
2494             case GST_VIDEO_FORMAT_BGR:
2495               alpha->process = gst_alpha_chroma_key_rgb_ayuv;
2496               break;
2497             default:
2498               break;
2499           }
2500           break;
2501         case GST_VIDEO_FORMAT_ARGB:
2502         case GST_VIDEO_FORMAT_ABGR:
2503         case GST_VIDEO_FORMAT_RGBA:
2504         case GST_VIDEO_FORMAT_BGRA:
2505           switch (GST_VIDEO_INFO_FORMAT (in_info)) {
2506             case GST_VIDEO_FORMAT_AYUV:
2507               alpha->process = gst_alpha_chroma_key_ayuv_argb;
2508               break;
2509             case GST_VIDEO_FORMAT_Y444:
2510             case GST_VIDEO_FORMAT_Y42B:
2511             case GST_VIDEO_FORMAT_I420:
2512             case GST_VIDEO_FORMAT_YV12:
2513             case GST_VIDEO_FORMAT_Y41B:
2514               alpha->process = gst_alpha_chroma_key_planar_yuv_argb;
2515               break;
2516             case GST_VIDEO_FORMAT_YUY2:
2517             case GST_VIDEO_FORMAT_YVYU:
2518             case GST_VIDEO_FORMAT_UYVY:
2519               alpha->process = gst_alpha_chroma_key_packed_422_argb;
2520               break;
2521             case GST_VIDEO_FORMAT_ARGB:
2522             case GST_VIDEO_FORMAT_ABGR:
2523             case GST_VIDEO_FORMAT_RGBA:
2524             case GST_VIDEO_FORMAT_BGRA:
2525               alpha->process = gst_alpha_chroma_key_argb_argb;
2526               break;
2527             case GST_VIDEO_FORMAT_xRGB:
2528             case GST_VIDEO_FORMAT_xBGR:
2529             case GST_VIDEO_FORMAT_RGBx:
2530             case GST_VIDEO_FORMAT_BGRx:
2531             case GST_VIDEO_FORMAT_RGB:
2532             case GST_VIDEO_FORMAT_BGR:
2533               alpha->process = gst_alpha_chroma_key_rgb_argb;
2534               break;
2535             default:
2536               break;
2537           }
2538           break;
2539         default:
2540           break;
2541       }
2542       break;
2543     default:
2544       break;
2545   }
2546   return alpha->process != NULL;
2547 }
2548
2549 static void
2550 gst_alpha_set_process_function (GstAlpha * alpha)
2551 {
2552   GstVideoInfo *info_in, *info_out;
2553
2554   info_in = &GST_VIDEO_FILTER (alpha)->in_info;
2555   info_out = &GST_VIDEO_FILTER (alpha)->out_info;
2556
2557   if (info_in->finfo != NULL && info_out->finfo != NULL) {
2558     gst_alpha_set_process_function_full (alpha, info_in, info_out);
2559   } else {
2560     GST_DEBUG_OBJECT (alpha, "video formats not set yet");
2561   }
2562 }
2563
2564 static void
2565 gst_alpha_before_transform (GstBaseTransform * btrans, GstBuffer * buf)
2566 {
2567   GstAlpha *alpha = GST_ALPHA (btrans);
2568   GstClockTime timestamp;
2569
2570   timestamp = gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME,
2571       GST_BUFFER_TIMESTAMP (buf));
2572   GST_LOG ("Got stream time of %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
2573   if (GST_CLOCK_TIME_IS_VALID (timestamp))
2574     gst_object_sync_values (GST_OBJECT (alpha), timestamp);
2575 }
2576
2577 static GstFlowReturn
2578 gst_alpha_transform_frame (GstVideoFilter * filter, GstVideoFrame * in_frame,
2579     GstVideoFrame * out_frame)
2580 {
2581   GstAlpha *alpha = GST_ALPHA (filter);
2582
2583   GST_ALPHA_LOCK (alpha);
2584
2585   if (G_UNLIKELY (!alpha->process))
2586     goto not_negotiated;
2587
2588   alpha->process (in_frame, out_frame, alpha);
2589
2590   GST_ALPHA_UNLOCK (alpha);
2591
2592   return GST_FLOW_OK;
2593
2594   /* ERRORS */
2595 not_negotiated:
2596   {
2597     GST_ERROR_OBJECT (alpha, "Not negotiated yet");
2598     GST_ALPHA_UNLOCK (alpha);
2599     return GST_FLOW_NOT_NEGOTIATED;
2600   }
2601 }
2602
2603 static gboolean
2604 plugin_init (GstPlugin * plugin)
2605 {
2606   return gst_element_register (plugin, "alpha", GST_RANK_NONE, GST_TYPE_ALPHA);
2607 }
2608
2609 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2610     GST_VERSION_MINOR,
2611     alpha,
2612     "adds an alpha channel to video - constant or via chroma-keying",
2613     plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)