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