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