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