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