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