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