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