mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-09 10:59:39 +00:00
2266 lines
70 KiB
C
2266 lines
70 KiB
C
/* GStreamer
|
|
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
|
* Copyright (C) <2007> Wim Taymans <wim.taymans@collabora.co.uk>
|
|
* Copyright (C) <2007> Edward Hervey <edward.hervey@collabora.co.uk>
|
|
* Copyright (C) <2007> Jan Schmidt <thaytan@noraisin.net>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:element-alpha
|
|
*
|
|
* The alpha element adds an alpha channel to a video stream. The values
|
|
* of the alpha channel can be either be set to a constant or can be
|
|
* dynamically calculated via chroma keying, e.g. blue can be set as
|
|
* the transparent color.
|
|
*
|
|
* Sample pipeline:
|
|
* |[
|
|
* gst-launch videotestsrc pattern=smpte75 ! alpha method=green ! \
|
|
* videomixer name=mixer ! ffmpegcolorspace ! autovideosink \
|
|
* videotestsrc pattern=snow ! mixer.
|
|
* ]| This pipeline adds a alpha channel to the SMPTE color bars
|
|
* with green as the transparent color and mixes the output with
|
|
* a snow video stream.
|
|
*/
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "gstalpha.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#ifndef M_PI
|
|
#define M_PI 3.14159265358979323846
|
|
#endif
|
|
|
|
/* Generated by -bad/ext/cog/generate_tables */
|
|
static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
|
|
298, 0, 459, -63514,
|
|
298, -55, -136, 19681,
|
|
298, 541, 0, -73988,
|
|
};
|
|
|
|
static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
|
|
298, 0, 409, -57068,
|
|
298, -100, -208, 34707,
|
|
298, 516, 0, -70870,
|
|
};
|
|
|
|
static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
|
|
47, 157, 16, 4096,
|
|
-26, -87, 112, 32768,
|
|
112, -102, -10, 32768,
|
|
};
|
|
|
|
static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
|
|
66, 129, 25, 4096,
|
|
-38, -74, 112, 32768,
|
|
112, -94, -18, 32768,
|
|
};
|
|
|
|
static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
|
|
256, -30, -53, 10600,
|
|
0, 261, 29, -4367,
|
|
0, 19, 262, -3289,
|
|
};
|
|
|
|
static const gint cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = {
|
|
256, 25, 49, -9536,
|
|
0, 253, -28, 3958,
|
|
0, -19, 252, 2918,
|
|
};
|
|
|
|
/* Alpha signals and args */
|
|
enum
|
|
{
|
|
/* FILL ME */
|
|
LAST_SIGNAL
|
|
};
|
|
|
|
#define DEFAULT_METHOD ALPHA_METHOD_SET
|
|
#define DEFAULT_ALPHA 1.0
|
|
#define DEFAULT_TARGET_R 0
|
|
#define DEFAULT_TARGET_G 255
|
|
#define DEFAULT_TARGET_B 0
|
|
#define DEFAULT_ANGLE 20.0
|
|
#define DEFAULT_NOISE_LEVEL 2.0
|
|
#define DEFAULT_BLACK_SENSITIVITY 100
|
|
#define DEFAULT_WHITE_SENSITIVITY 100
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_METHOD,
|
|
PROP_ALPHA,
|
|
PROP_TARGET_R,
|
|
PROP_TARGET_G,
|
|
PROP_TARGET_B,
|
|
PROP_ANGLE,
|
|
PROP_NOISE_LEVEL,
|
|
PROP_BLACK_SENSITIVITY,
|
|
PROP_WHITE_SENSITIVITY,
|
|
PROP_LAST
|
|
};
|
|
|
|
static GstStaticPadTemplate gst_alpha_src_template =
|
|
GST_STATIC_PAD_TEMPLATE ("src",
|
|
GST_PAD_SRC,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";"
|
|
GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";"
|
|
GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_RGBA)
|
|
);
|
|
|
|
static GstStaticPadTemplate gst_alpha_sink_template =
|
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
|
GST_PAD_SINK,
|
|
GST_PAD_ALWAYS,
|
|
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") ";" GST_VIDEO_CAPS_YUV ("I420")
|
|
";" GST_VIDEO_CAPS_ARGB ";" GST_VIDEO_CAPS_BGRA ";" GST_VIDEO_CAPS_ABGR
|
|
";" GST_VIDEO_CAPS_RGBA
|
|
";" GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_BGRx ";" GST_VIDEO_CAPS_xBGR
|
|
";" GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR)
|
|
);
|
|
|
|
static gboolean gst_alpha_start (GstBaseTransform * trans);
|
|
static gboolean gst_alpha_get_unit_size (GstBaseTransform * btrans,
|
|
GstCaps * caps, guint * size);
|
|
static GstCaps *gst_alpha_transform_caps (GstBaseTransform * btrans,
|
|
GstPadDirection direction, GstCaps * caps);
|
|
static gboolean gst_alpha_set_caps (GstBaseTransform * btrans,
|
|
GstCaps * incaps, GstCaps * outcaps);
|
|
static GstFlowReturn gst_alpha_transform (GstBaseTransform * btrans,
|
|
GstBuffer * in, GstBuffer * out);
|
|
|
|
static void gst_alpha_init_params (GstAlpha * alpha);
|
|
static gboolean gst_alpha_set_process_function (GstAlpha * alpha);
|
|
|
|
static void gst_alpha_set_property (GObject * object, guint prop_id,
|
|
const GValue * value, GParamSpec * pspec);
|
|
static void gst_alpha_get_property (GObject * object, guint prop_id,
|
|
GValue * value, GParamSpec * pspec);
|
|
|
|
GST_BOILERPLATE (GstAlpha, gst_alpha, GstVideoFilter, GST_TYPE_VIDEO_FILTER);
|
|
|
|
#define GST_TYPE_ALPHA_METHOD (gst_alpha_method_get_type())
|
|
static GType
|
|
gst_alpha_method_get_type (void)
|
|
{
|
|
static GType alpha_method_type = 0;
|
|
static const GEnumValue alpha_method[] = {
|
|
{ALPHA_METHOD_SET, "Set/adjust alpha channel", "set"},
|
|
{ALPHA_METHOD_GREEN, "Chroma Key green", "green"},
|
|
{ALPHA_METHOD_BLUE, "Chroma Key blue", "blue"},
|
|
{ALPHA_METHOD_CUSTOM, "Chroma Key on target_r/g/b", "custom"},
|
|
{0, NULL, NULL},
|
|
};
|
|
|
|
if (!alpha_method_type) {
|
|
alpha_method_type = g_enum_register_static ("GstAlphaMethod", alpha_method);
|
|
}
|
|
return alpha_method_type;
|
|
}
|
|
|
|
static void
|
|
gst_alpha_base_init (gpointer g_class)
|
|
{
|
|
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
|
|
|
gst_element_class_set_details_simple (element_class, "Alpha filter",
|
|
"Filter/Effect/Video",
|
|
"Adds an alpha channel to video - uniform or via chroma-keying",
|
|
"Wim Taymans <wim@fluendo.com>\n"
|
|
"Edward Hervey <edward.hervey@collabora.co.uk>\n"
|
|
"Jan Schmidt <thaytan@noraisin.net>");
|
|
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&gst_alpha_sink_template));
|
|
gst_element_class_add_pad_template (element_class,
|
|
gst_static_pad_template_get (&gst_alpha_src_template));
|
|
|
|
GST_DEBUG_CATEGORY_INIT (gst_alpha_debug, "alpha", 0,
|
|
"alpha - Element for adding alpha channel to streams");
|
|
}
|
|
|
|
static void
|
|
gst_alpha_class_init (GstAlphaClass * klass)
|
|
{
|
|
GObjectClass *gobject_class = (GObjectClass *) klass;
|
|
GstBaseTransformClass *btrans_class = (GstBaseTransformClass *) klass;
|
|
|
|
gobject_class->set_property = gst_alpha_set_property;
|
|
gobject_class->get_property = gst_alpha_get_property;
|
|
|
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_METHOD,
|
|
g_param_spec_enum ("method", "Method",
|
|
"How the alpha channels should be created", GST_TYPE_ALPHA_METHOD,
|
|
DEFAULT_METHOD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ALPHA,
|
|
g_param_spec_double ("alpha", "Alpha", "The value for the alpha channel",
|
|
0.0, 1.0, DEFAULT_ALPHA,
|
|
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_R,
|
|
g_param_spec_uint ("target-r", "Target Red", "The Red target", 0, 255,
|
|
DEFAULT_TARGET_R,
|
|
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_G,
|
|
g_param_spec_uint ("target-g", "Target Green", "The Green target", 0, 255,
|
|
DEFAULT_TARGET_G,
|
|
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TARGET_B,
|
|
g_param_spec_uint ("target-b", "Target Blue", "The Blue target", 0, 255,
|
|
DEFAULT_TARGET_B,
|
|
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ANGLE,
|
|
g_param_spec_float ("angle", "Angle", "Size of the colorcube to change",
|
|
0.0, 90.0, DEFAULT_ANGLE,
|
|
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_NOISE_LEVEL,
|
|
g_param_spec_float ("noise-level", "Noise Level", "Size of noise radius",
|
|
0.0, 64.0, DEFAULT_NOISE_LEVEL,
|
|
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
|
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
|
PROP_BLACK_SENSITIVITY, g_param_spec_uint ("black-sensitivity",
|
|
"Black Sensitivity", "Sensitivity to dark colors", 0, 128,
|
|
DEFAULT_BLACK_SENSITIVITY,
|
|
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
|
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
|
PROP_WHITE_SENSITIVITY, g_param_spec_uint ("white-sensitivity",
|
|
"Sensitivity", "Sensitivity to bright colors", 0, 128,
|
|
DEFAULT_WHITE_SENSITIVITY,
|
|
G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
|
|
|
|
|
|
btrans_class->start = GST_DEBUG_FUNCPTR (gst_alpha_start);
|
|
btrans_class->transform = GST_DEBUG_FUNCPTR (gst_alpha_transform);
|
|
btrans_class->get_unit_size = GST_DEBUG_FUNCPTR (gst_alpha_get_unit_size);
|
|
btrans_class->transform_caps = GST_DEBUG_FUNCPTR (gst_alpha_transform_caps);
|
|
btrans_class->set_caps = GST_DEBUG_FUNCPTR (gst_alpha_set_caps);
|
|
}
|
|
|
|
static void
|
|
gst_alpha_init (GstAlpha * alpha, GstAlphaClass * klass)
|
|
{
|
|
alpha->alpha = DEFAULT_ALPHA;
|
|
alpha->method = DEFAULT_METHOD;
|
|
alpha->target_r = DEFAULT_TARGET_R;
|
|
alpha->target_g = DEFAULT_TARGET_G;
|
|
alpha->target_b = DEFAULT_TARGET_B;
|
|
alpha->angle = DEFAULT_ANGLE;
|
|
alpha->noise_level = DEFAULT_NOISE_LEVEL;
|
|
alpha->black_sensitivity = DEFAULT_BLACK_SENSITIVITY;
|
|
alpha->white_sensitivity = DEFAULT_WHITE_SENSITIVITY;
|
|
}
|
|
|
|
/* do we need this function? */
|
|
static void
|
|
gst_alpha_set_property (GObject * object, guint prop_id,
|
|
const GValue * value, GParamSpec * pspec)
|
|
{
|
|
GstAlpha *alpha = GST_ALPHA (object);
|
|
|
|
GST_OBJECT_LOCK (alpha);
|
|
switch (prop_id) {
|
|
case PROP_METHOD:
|
|
alpha->method = g_value_get_enum (value);
|
|
switch (alpha->method) {
|
|
case ALPHA_METHOD_GREEN:
|
|
alpha->target_r = 0;
|
|
alpha->target_g = 255;
|
|
alpha->target_b = 0;
|
|
break;
|
|
case ALPHA_METHOD_BLUE:
|
|
alpha->target_r = 0;
|
|
alpha->target_g = 0;
|
|
alpha->target_b = 255;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
gst_alpha_set_process_function (alpha);
|
|
gst_alpha_init_params (alpha);
|
|
break;
|
|
case PROP_ALPHA:
|
|
alpha->alpha = g_value_get_double (value);
|
|
break;
|
|
case PROP_TARGET_R:
|
|
alpha->target_r = g_value_get_uint (value);
|
|
gst_alpha_init_params (alpha);
|
|
break;
|
|
case PROP_TARGET_G:
|
|
alpha->target_g = g_value_get_uint (value);
|
|
gst_alpha_init_params (alpha);
|
|
break;
|
|
case PROP_TARGET_B:
|
|
alpha->target_b = g_value_get_uint (value);
|
|
gst_alpha_init_params (alpha);
|
|
break;
|
|
case PROP_ANGLE:
|
|
alpha->angle = g_value_get_float (value);
|
|
gst_alpha_init_params (alpha);
|
|
break;
|
|
case PROP_NOISE_LEVEL:
|
|
alpha->noise_level = g_value_get_float (value);
|
|
gst_alpha_init_params (alpha);
|
|
break;
|
|
case PROP_BLACK_SENSITIVITY:
|
|
alpha->black_sensitivity = g_value_get_uint (value);
|
|
break;
|
|
case PROP_WHITE_SENSITIVITY:
|
|
alpha->white_sensitivity = g_value_get_uint (value);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
GST_OBJECT_UNLOCK (alpha);
|
|
}
|
|
|
|
static void
|
|
gst_alpha_get_property (GObject * object, guint prop_id, GValue * value,
|
|
GParamSpec * pspec)
|
|
{
|
|
GstAlpha *alpha = GST_ALPHA (object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_METHOD:
|
|
g_value_set_enum (value, alpha->method);
|
|
break;
|
|
case PROP_ALPHA:
|
|
g_value_set_double (value, alpha->alpha);
|
|
break;
|
|
case PROP_TARGET_R:
|
|
g_value_set_uint (value, alpha->target_r);
|
|
break;
|
|
case PROP_TARGET_G:
|
|
g_value_set_uint (value, alpha->target_g);
|
|
break;
|
|
case PROP_TARGET_B:
|
|
g_value_set_uint (value, alpha->target_b);
|
|
break;
|
|
case PROP_ANGLE:
|
|
g_value_set_float (value, alpha->angle);
|
|
break;
|
|
case PROP_NOISE_LEVEL:
|
|
g_value_set_float (value, alpha->noise_level);
|
|
break;
|
|
case PROP_BLACK_SENSITIVITY:
|
|
g_value_set_uint (value, alpha->black_sensitivity);
|
|
break;
|
|
case PROP_WHITE_SENSITIVITY:
|
|
g_value_set_uint (value, alpha->white_sensitivity);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
gst_alpha_get_unit_size (GstBaseTransform * btrans,
|
|
GstCaps * caps, guint * size)
|
|
{
|
|
GstVideoFormat format;
|
|
gint width, height;
|
|
|
|
if (!gst_video_format_parse_caps (caps, &format, &width, &height))
|
|
return FALSE;
|
|
|
|
*size = gst_video_format_get_size (format, width, height);
|
|
|
|
GST_DEBUG_OBJECT (btrans, "unit size = %d for format %d w %d height %d",
|
|
*size, format, width, height);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GstCaps *
|
|
gst_alpha_transform_caps (GstBaseTransform * btrans,
|
|
GstPadDirection direction, GstCaps * caps)
|
|
{
|
|
GstCaps *ret;
|
|
GstStructure *structure;
|
|
gint i;
|
|
|
|
ret = gst_caps_new_empty ();
|
|
|
|
for (i = 0; i < gst_caps_get_size (caps); i++) {
|
|
structure = gst_structure_copy (gst_caps_get_structure (caps, i));
|
|
|
|
gst_structure_remove_field (structure, "format");
|
|
gst_structure_remove_field (structure, "endianness");
|
|
gst_structure_remove_field (structure, "depth");
|
|
gst_structure_remove_field (structure, "bpp");
|
|
gst_structure_remove_field (structure, "red_mask");
|
|
gst_structure_remove_field (structure, "green_mask");
|
|
gst_structure_remove_field (structure, "blue_mask");
|
|
gst_structure_remove_field (structure, "alpha_mask");
|
|
gst_structure_remove_field (structure, "color-matrix");
|
|
gst_structure_remove_field (structure, "chroma-site");
|
|
|
|
gst_structure_set_name (structure, "video/x-raw-yuv");
|
|
gst_caps_append_structure (ret, gst_structure_copy (structure));
|
|
gst_structure_set_name (structure, "video/x-raw-rgb");
|
|
gst_caps_append_structure (ret, structure);
|
|
}
|
|
|
|
gst_caps_do_simplify (ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static gboolean
|
|
gst_alpha_set_caps (GstBaseTransform * btrans,
|
|
GstCaps * incaps, GstCaps * outcaps)
|
|
{
|
|
GstAlpha *alpha = GST_ALPHA (btrans);
|
|
const gchar *matrix;
|
|
|
|
GST_OBJECT_LOCK (alpha);
|
|
|
|
if (!gst_video_format_parse_caps (incaps, &alpha->in_format,
|
|
&alpha->width, &alpha->height) ||
|
|
!gst_video_format_parse_caps (outcaps, &alpha->out_format,
|
|
&alpha->width, &alpha->height)) {
|
|
GST_OBJECT_UNLOCK (alpha);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!gst_alpha_set_process_function (alpha)) {
|
|
GST_OBJECT_UNLOCK (alpha);
|
|
return FALSE;
|
|
}
|
|
|
|
matrix = gst_video_parse_caps_color_matrix (incaps);
|
|
alpha->in_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
|
|
|
|
matrix = gst_video_parse_caps_color_matrix (outcaps);
|
|
alpha->out_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
|
|
|
|
gst_alpha_init_params (alpha);
|
|
GST_OBJECT_UNLOCK (alpha);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/* based on http://www.cs.utah.edu/~michael/chroma/
|
|
*/
|
|
static inline gint
|
|
chroma_keying_yuv (gint a, gint * y, guint ny, 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)
|
|
{
|
|
gint tmp, tmp1;
|
|
gint x1, y1;
|
|
gint x, z;
|
|
gint b_alpha;
|
|
|
|
for (tmp = 0; tmp < ny; tmp++) {
|
|
/* too dark or too bright, keep alpha */
|
|
if (y[tmp] < smin || y[tmp] > smax)
|
|
return a;
|
|
}
|
|
|
|
/* Convert foreground to XZ coords where X direction is defined by
|
|
the key color */
|
|
tmp = ((*u) * cb + (*v) * cr) >> 7;
|
|
x = CLAMP (tmp, -128, 127);
|
|
tmp = ((*v) * cb - (*u) * cr) >> 7;
|
|
z = CLAMP (tmp, -128, 127);
|
|
|
|
/* WARNING: accept angle should never be set greater than "somewhat less
|
|
than 90 degrees" to avoid dealing with negative/infinite tg. In reality,
|
|
80 degrees should be enough if foreground is reasonable. If this seems
|
|
to be a problem, go to alternative ways of checking point position
|
|
(scalar product or line equations). This angle should not be too small
|
|
either to avoid infinite ctg (used to suppress foreground without use of
|
|
division) */
|
|
|
|
tmp = (x * accept_angle_tg) >> 4;
|
|
tmp = MIN (tmp, 127);
|
|
|
|
if (abs (z) > tmp) {
|
|
/* keep foreground Kfg = 0 */
|
|
return a;
|
|
}
|
|
/* Compute Kfg (implicitly) and Kbg, suppress foreground in XZ coord
|
|
according to Kfg */
|
|
tmp = (z * accept_angle_ctg) >> 4;
|
|
tmp = CLAMP (tmp, -128, 127);
|
|
x1 = abs (tmp);
|
|
y1 = z;
|
|
|
|
tmp1 = x - x1;
|
|
tmp1 = MAX (tmp1, 0);
|
|
b_alpha = (tmp1 * one_over_kc) / 2;
|
|
b_alpha = 255 - CLAMP (b_alpha, 0, 255);
|
|
b_alpha = (a * b_alpha) >> 8;
|
|
|
|
tmp = (tmp1 * kfgy_scale) >> 4;
|
|
tmp1 = MIN (tmp, 255);
|
|
|
|
for (tmp = 0; tmp < ny; tmp++)
|
|
y[tmp] = (y[tmp] < tmp1) ? 0 : y[tmp] - tmp1;
|
|
|
|
/* Convert suppressed foreground back to CbCr */
|
|
tmp = (x1 * cb - y1 * cr) >> 7;
|
|
*u = CLAMP (tmp, -128, 127);
|
|
|
|
tmp = (x1 * cr + y1 * cb) >> 7;
|
|
*v = CLAMP (tmp, -128, 127);
|
|
|
|
/* Deal with noise. For now, a circle around the key color with
|
|
radius of noise_level treated as exact key color. Introduces
|
|
sharp transitions.
|
|
*/
|
|
tmp = z * z + (x - kg) * (x - kg);
|
|
tmp = MIN (tmp, 0xffff);
|
|
|
|
if (tmp < noise_level2)
|
|
b_alpha = 0;
|
|
|
|
return b_alpha;
|
|
}
|
|
|
|
#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)
|
|
|
|
#define CREATE_ARGB_AYUV_FUNCTIONS(name, A, R, G, B) \
|
|
static void \
|
|
gst_alpha_set_##name##_ayuv (const guint8 * src, guint8 * dest, gint width, \
|
|
gint height, GstAlpha * alpha) \
|
|
{ \
|
|
gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256); \
|
|
gint i, j; \
|
|
gint matrix[12]; \
|
|
gint y, u, v; \
|
|
\
|
|
memcpy (matrix, \
|
|
alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv : \
|
|
cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint)); \
|
|
\
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < width; j++) { \
|
|
dest[0] = (src[A] * s_alpha) >> 8; \
|
|
\
|
|
y = APPLY_MATRIX (matrix, 0, src[R], src[G], src[B]); \
|
|
u = APPLY_MATRIX (matrix, 1, src[R], src[G], src[B]); \
|
|
v = APPLY_MATRIX (matrix, 2, src[R], src[G], src[B]); \
|
|
\
|
|
dest[1] = y; \
|
|
dest[2] = u; \
|
|
dest[3] = v; \
|
|
\
|
|
dest += 4; \
|
|
src += 4; \
|
|
} \
|
|
} \
|
|
} \
|
|
\
|
|
static void \
|
|
gst_alpha_chroma_key_##name##_ayuv (const guint8 * src, guint8 * dest, gint width, \
|
|
gint height, GstAlpha * alpha) \
|
|
{ \
|
|
gint i, j; \
|
|
gint a, y, u, v; \
|
|
gint r, g, b; \
|
|
gint smin, smax; \
|
|
gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256); \
|
|
gint8 cb = alpha->cb, cr = alpha->cr; \
|
|
gint8 kg = alpha->kg; \
|
|
guint8 accept_angle_tg = alpha->accept_angle_tg; \
|
|
guint8 accept_angle_ctg = alpha->accept_angle_ctg; \
|
|
guint8 one_over_kc = alpha->one_over_kc; \
|
|
guint8 kfgy_scale = alpha->kfgy_scale; \
|
|
guint noise_level2 = alpha->noise_level2; \
|
|
gint matrix[12]; \
|
|
\
|
|
smin = 128 - alpha->black_sensitivity; \
|
|
smax = 128 + alpha->white_sensitivity; \
|
|
\
|
|
memcpy (matrix, \
|
|
alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv : \
|
|
cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint)); \
|
|
\
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < width; j++) { \
|
|
a = (src[A] * pa) >> 8; \
|
|
r = src[R]; \
|
|
g = src[G]; \
|
|
b = src[B]; \
|
|
\
|
|
y = APPLY_MATRIX (matrix, 0, r, g, b); \
|
|
u = APPLY_MATRIX (matrix, 1, r, g, b) - 128; \
|
|
v = APPLY_MATRIX (matrix, 2, r, g, b) - 128; \
|
|
\
|
|
a = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, \
|
|
smin, smax, accept_angle_tg, accept_angle_ctg, \
|
|
one_over_kc, kfgy_scale, kg, noise_level2); \
|
|
\
|
|
u += 128; \
|
|
v += 128; \
|
|
\
|
|
dest[0] = a; \
|
|
dest[1] = y; \
|
|
dest[2] = u; \
|
|
dest[3] = v; \
|
|
\
|
|
src += 4; \
|
|
dest += 4; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
CREATE_ARGB_AYUV_FUNCTIONS (argb, 0, 1, 2, 3);
|
|
CREATE_ARGB_AYUV_FUNCTIONS (abgr, 0, 3, 2, 1);
|
|
CREATE_ARGB_AYUV_FUNCTIONS (rgba, 3, 0, 1, 2);
|
|
CREATE_ARGB_AYUV_FUNCTIONS (bgra, 3, 2, 1, 0);
|
|
|
|
#define CREATE_ARGB_ARGB_FUNCTIONS(name, name2, A, R, G, B, A2, R2, G2, B2) \
|
|
static void \
|
|
gst_alpha_set_##name##_##name2 (const guint8 * src, guint8 * dest, gint width, \
|
|
gint height, GstAlpha * alpha) \
|
|
{ \
|
|
gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256); \
|
|
gint i, j; \
|
|
\
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < width; j++) { \
|
|
dest[A2] = (src[A] * s_alpha) >> 8; \
|
|
\
|
|
dest[R2] = src[R]; \
|
|
dest[G2] = src[G]; \
|
|
dest[B2] = src[B]; \
|
|
\
|
|
dest += 4; \
|
|
src += 4; \
|
|
} \
|
|
} \
|
|
} \
|
|
\
|
|
static void \
|
|
gst_alpha_chroma_key_##name##_##name2 (const guint8 * src, guint8 * dest, gint width, \
|
|
gint height, GstAlpha * alpha) \
|
|
{ \
|
|
gint i, j; \
|
|
gint a, y, u, v; \
|
|
gint r, g, b; \
|
|
gint smin, smax; \
|
|
gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256); \
|
|
gint8 cb = alpha->cb, cr = alpha->cr; \
|
|
gint8 kg = alpha->kg; \
|
|
guint8 accept_angle_tg = alpha->accept_angle_tg; \
|
|
guint8 accept_angle_ctg = alpha->accept_angle_ctg; \
|
|
guint8 one_over_kc = alpha->one_over_kc; \
|
|
guint8 kfgy_scale = alpha->kfgy_scale; \
|
|
guint noise_level2 = alpha->noise_level2; \
|
|
gint matrix[12], matrix2[12]; \
|
|
\
|
|
smin = 128 - alpha->black_sensitivity; \
|
|
smax = 128 + alpha->white_sensitivity; \
|
|
\
|
|
memcpy (matrix, \
|
|
cog_rgb_to_ycbcr_matrix_8bit_sdtv, \
|
|
12 * sizeof (gint)); \
|
|
memcpy (matrix2, \
|
|
cog_ycbcr_to_rgb_matrix_8bit_sdtv, \
|
|
12 * sizeof (gint)); \
|
|
\
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < width; j++) { \
|
|
a = (src[A] * pa) >> 8; \
|
|
r = src[R]; \
|
|
g = src[G]; \
|
|
b = src[B]; \
|
|
\
|
|
y = APPLY_MATRIX (matrix, 0, r, g, b); \
|
|
u = APPLY_MATRIX (matrix, 1, r, g, b) - 128; \
|
|
v = APPLY_MATRIX (matrix, 2, r, g, b) - 128; \
|
|
\
|
|
a = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, \
|
|
smin, smax, accept_angle_tg, accept_angle_ctg, \
|
|
one_over_kc, kfgy_scale, kg, noise_level2); \
|
|
\
|
|
u += 128; \
|
|
v += 128; \
|
|
\
|
|
r = APPLY_MATRIX (matrix2, 0, y, u, v); \
|
|
g = APPLY_MATRIX (matrix2, 1, y, u, v); \
|
|
b = APPLY_MATRIX (matrix2, 2, y, u, v); \
|
|
\
|
|
dest[A2] = a; \
|
|
dest[R2] = CLAMP (r, 0, 255); \
|
|
dest[G2] = CLAMP (g, 0, 255); \
|
|
dest[B2] = CLAMP (b, 0, 255); \
|
|
\
|
|
src += 4; \
|
|
dest += 4; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
CREATE_ARGB_ARGB_FUNCTIONS (argb, argb, 0, 1, 2, 3, 0, 1, 2, 3);
|
|
CREATE_ARGB_ARGB_FUNCTIONS (argb, abgr, 0, 1, 2, 3, 0, 3, 2, 1);
|
|
CREATE_ARGB_ARGB_FUNCTIONS (argb, rgba, 0, 1, 2, 3, 3, 0, 1, 2);
|
|
CREATE_ARGB_ARGB_FUNCTIONS (argb, bgra, 0, 1, 2, 3, 3, 2, 1, 0);
|
|
|
|
CREATE_ARGB_ARGB_FUNCTIONS (abgr, argb, 0, 3, 2, 1, 0, 1, 2, 3);
|
|
CREATE_ARGB_ARGB_FUNCTIONS (abgr, abgr, 0, 3, 2, 1, 0, 3, 2, 1);
|
|
CREATE_ARGB_ARGB_FUNCTIONS (abgr, rgba, 0, 3, 2, 1, 3, 0, 1, 2);
|
|
CREATE_ARGB_ARGB_FUNCTIONS (abgr, bgra, 0, 3, 2, 1, 3, 2, 1, 0);
|
|
|
|
CREATE_ARGB_ARGB_FUNCTIONS (rgba, argb, 3, 0, 1, 2, 0, 1, 2, 3);
|
|
CREATE_ARGB_ARGB_FUNCTIONS (rgba, abgr, 3, 0, 1, 2, 0, 3, 2, 1);
|
|
CREATE_ARGB_ARGB_FUNCTIONS (rgba, rgba, 3, 0, 1, 2, 3, 0, 1, 2);
|
|
CREATE_ARGB_ARGB_FUNCTIONS (rgba, bgra, 3, 0, 1, 2, 3, 2, 1, 0);
|
|
|
|
CREATE_ARGB_ARGB_FUNCTIONS (bgra, argb, 3, 2, 1, 0, 0, 1, 2, 3);
|
|
CREATE_ARGB_ARGB_FUNCTIONS (bgra, abgr, 3, 2, 1, 0, 0, 3, 2, 1);
|
|
CREATE_ARGB_ARGB_FUNCTIONS (bgra, rgba, 3, 2, 1, 0, 3, 0, 1, 2);
|
|
CREATE_ARGB_ARGB_FUNCTIONS (bgra, bgra, 3, 2, 1, 0, 3, 2, 1, 0);
|
|
|
|
#define CREATE_AYUV_ARGB_FUNCTIONS(name, A, R, G, B) \
|
|
static void \
|
|
gst_alpha_set_ayuv_##name (const guint8 * src, guint8 * dest, gint width, \
|
|
gint height, GstAlpha * alpha) \
|
|
{ \
|
|
gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256); \
|
|
gint y, x; \
|
|
gint matrix[12]; \
|
|
gint r, g, b; \
|
|
\
|
|
memcpy (matrix, \
|
|
alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv : \
|
|
cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint)); \
|
|
\
|
|
for (y = 0; y < height; y++) { \
|
|
for (x = 0; x < width; x++) { \
|
|
dest[A] = (src[0] * s_alpha) >> 8; \
|
|
\
|
|
r = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]); \
|
|
g = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]); \
|
|
b = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]); \
|
|
\
|
|
dest[R] = CLAMP (r, 0, 255); \
|
|
dest[G] = CLAMP (g, 0, 255); \
|
|
dest[B] = CLAMP (b, 0, 255); \
|
|
\
|
|
dest += 4; \
|
|
src += 4; \
|
|
} \
|
|
} \
|
|
} \
|
|
\
|
|
static void \
|
|
gst_alpha_chroma_key_ayuv_##name (const guint8 * src, guint8 * dest, gint width, \
|
|
gint height, GstAlpha * alpha) \
|
|
{ \
|
|
gint i, j; \
|
|
gint a, y, u, v; \
|
|
gint r, g, b; \
|
|
gint smin, smax; \
|
|
gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256); \
|
|
gint8 cb = alpha->cb, cr = alpha->cr; \
|
|
gint8 kg = alpha->kg; \
|
|
guint8 accept_angle_tg = alpha->accept_angle_tg; \
|
|
guint8 accept_angle_ctg = alpha->accept_angle_ctg; \
|
|
guint8 one_over_kc = alpha->one_over_kc; \
|
|
guint8 kfgy_scale = alpha->kfgy_scale; \
|
|
guint noise_level2 = alpha->noise_level2; \
|
|
gint matrix[12]; \
|
|
\
|
|
smin = 128 - alpha->black_sensitivity; \
|
|
smax = 128 + alpha->white_sensitivity; \
|
|
\
|
|
memcpy (matrix, \
|
|
alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv : \
|
|
cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint)); \
|
|
\
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < width; j++) { \
|
|
a = (src[0] * pa) >> 8; \
|
|
y = src[1]; \
|
|
u = src[2] - 128; \
|
|
v = src[3] - 128; \
|
|
\
|
|
a = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, \
|
|
smin, smax, accept_angle_tg, accept_angle_ctg, \
|
|
one_over_kc, kfgy_scale, kg, noise_level2); \
|
|
\
|
|
u += 128; \
|
|
v += 128; \
|
|
\
|
|
r = APPLY_MATRIX (matrix, 0, y, u, v); \
|
|
g = APPLY_MATRIX (matrix, 1, y, u, v); \
|
|
b = APPLY_MATRIX (matrix, 2, y, u, v); \
|
|
\
|
|
dest[A] = a; \
|
|
dest[R] = CLAMP (r, 0, 255); \
|
|
dest[G] = CLAMP (g, 0, 255); \
|
|
dest[B] = CLAMP (b, 0, 255); \
|
|
\
|
|
src += 4; \
|
|
dest += 4; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
CREATE_AYUV_ARGB_FUNCTIONS (argb, 0, 1, 2, 3);
|
|
CREATE_AYUV_ARGB_FUNCTIONS (abgr, 0, 3, 2, 1);
|
|
CREATE_AYUV_ARGB_FUNCTIONS (rgba, 3, 0, 1, 2);
|
|
CREATE_AYUV_ARGB_FUNCTIONS (bgra, 3, 2, 1, 0);
|
|
|
|
static void
|
|
gst_alpha_set_ayuv_ayuv (const guint8 * src, guint8 * dest, gint width,
|
|
gint height, GstAlpha * alpha)
|
|
{
|
|
gint s_alpha = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
|
|
gint y, x;
|
|
|
|
if (alpha->in_sdtv == alpha->out_sdtv) {
|
|
for (y = 0; y < height; y++) {
|
|
for (x = 0; x < width; x++) {
|
|
dest[0] = (src[0] * s_alpha) >> 8;
|
|
dest[1] = src[1];
|
|
dest[2] = src[2];
|
|
dest[3] = src[3];
|
|
|
|
dest += 4;
|
|
src += 4;
|
|
}
|
|
}
|
|
} else {
|
|
gint matrix[12];
|
|
|
|
memcpy (matrix,
|
|
alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
|
|
cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
|
|
|
|
for (y = 0; y < height; y++) {
|
|
for (x = 0; x < width; x++) {
|
|
dest[0] = (src[0] * s_alpha) >> 8;
|
|
dest[1] = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
|
|
dest[2] = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]);
|
|
dest[3] = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]);
|
|
|
|
dest += 4;
|
|
src += 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_alpha_chroma_key_ayuv_ayuv (const guint8 * src, guint8 * dest,
|
|
gint width, gint height, GstAlpha * alpha)
|
|
{
|
|
gint i, j;
|
|
gint a, y, u, v;
|
|
gint smin, smax;
|
|
gint pa = CLAMP ((gint) (alpha->alpha * 256), 0, 256);
|
|
gint8 cb = alpha->cb, cr = alpha->cr;
|
|
gint8 kg = alpha->kg;
|
|
guint8 accept_angle_tg = alpha->accept_angle_tg;
|
|
guint8 accept_angle_ctg = alpha->accept_angle_ctg;
|
|
guint8 one_over_kc = alpha->one_over_kc;
|
|
guint8 kfgy_scale = alpha->kfgy_scale;
|
|
guint noise_level2 = alpha->noise_level2;
|
|
|
|
smin = 128 - alpha->black_sensitivity;
|
|
smax = 128 + alpha->white_sensitivity;
|
|
|
|
if (alpha->in_sdtv == alpha->out_sdtv) {
|
|
for (i = 0; i < height; i++) {
|
|
for (j = 0; j < width; j++) {
|
|
a = (src[0] * pa) >> 8;
|
|
y = src[1];
|
|
u = src[2] - 128;
|
|
v = src[3] - 128;
|
|
|
|
a = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb,
|
|
smin, smax, accept_angle_tg, accept_angle_ctg,
|
|
one_over_kc, kfgy_scale, kg, noise_level2);
|
|
|
|
u += 128;
|
|
v += 128;
|
|
|
|
dest[0] = a;
|
|
dest[1] = y;
|
|
dest[2] = u;
|
|
dest[3] = v;
|
|
|
|
src += 4;
|
|
dest += 4;
|
|
}
|
|
}
|
|
} else {
|
|
gint matrix[12];
|
|
|
|
memcpy (matrix,
|
|
alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
|
|
cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
|
|
|
|
for (i = 0; i < height; i++) {
|
|
for (j = 0; j < width; j++) {
|
|
a = (src[0] * pa) >> 8;
|
|
y = APPLY_MATRIX (matrix, 0, src[1], src[2], src[3]);
|
|
u = APPLY_MATRIX (matrix, 1, src[1], src[2], src[3]) - 128;
|
|
v = APPLY_MATRIX (matrix, 2, src[1], src[2], src[3]) - 128;
|
|
|
|
a = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb,
|
|
smin, smax, accept_angle_tg, accept_angle_ctg,
|
|
one_over_kc, kfgy_scale, kg, noise_level2);
|
|
|
|
u += 128;
|
|
v += 128;
|
|
|
|
dest[0] = a;
|
|
dest[1] = y;
|
|
dest[2] = u;
|
|
dest[3] = v;
|
|
|
|
src += 4;
|
|
dest += 4;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#define CREATE_I420_ARGB_FUNCTIONS(name, A, R, G, B) \
|
|
static void \
|
|
gst_alpha_set_i420_##name (const guint8 * src, guint8 * dest, gint width, \
|
|
gint height, GstAlpha * alpha) \
|
|
{ \
|
|
gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255); \
|
|
const guint8 *srcY; \
|
|
const guint8 *srcU; \
|
|
const guint8 *srcV; \
|
|
gint i, j; \
|
|
gint src_wrap, src_uv_wrap; \
|
|
gint y_stride, uv_stride; \
|
|
gboolean odd_width; \
|
|
gint matrix[12]; \
|
|
gint r, g, b; \
|
|
\
|
|
y_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, width); \
|
|
uv_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, width); \
|
|
\
|
|
src_wrap = y_stride - width; \
|
|
src_uv_wrap = uv_stride - (width / 2); \
|
|
\
|
|
srcY = src; \
|
|
srcU = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, \
|
|
1, width, height); \
|
|
srcV = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, \
|
|
2, width, height); \
|
|
\
|
|
odd_width = (width % 2 != 0); \
|
|
\
|
|
memcpy (matrix, \
|
|
alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv : \
|
|
cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint)); \
|
|
\
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < width / 2; j++) { \
|
|
dest[A] = b_alpha; \
|
|
r = APPLY_MATRIX (matrix, 0, srcY[0], srcU[0], srcV[0]); \
|
|
g = APPLY_MATRIX (matrix, 1, srcY[0], srcU[0], srcV[0]); \
|
|
b = APPLY_MATRIX (matrix, 2, srcY[0], srcU[0], srcV[0]); \
|
|
dest[R] = CLAMP (r, 0, 255); \
|
|
dest[G] = CLAMP (g, 0, 255); \
|
|
dest[B] = CLAMP (b, 0, 255); \
|
|
\
|
|
dest[4 + A] = b_alpha; \
|
|
r = APPLY_MATRIX (matrix, 0, srcY[1], srcU[0], srcV[0]); \
|
|
g = APPLY_MATRIX (matrix, 1, srcY[1], srcU[0], srcV[0]); \
|
|
b = APPLY_MATRIX (matrix, 2, srcY[1], srcU[0], srcV[0]); \
|
|
dest[4 + R] = CLAMP (r, 0, 255); \
|
|
dest[4 + G] = CLAMP (g, 0, 255); \
|
|
dest[4 + B] = CLAMP (b, 0, 255); \
|
|
\
|
|
dest += 8; \
|
|
srcY += 2; \
|
|
srcU++; \
|
|
srcV++; \
|
|
} \
|
|
/* Might have one odd column left to do */ \
|
|
if (odd_width) { \
|
|
dest[A] = b_alpha; \
|
|
r = APPLY_MATRIX (matrix, 0, srcY[0], srcU[0], srcV[0]); \
|
|
g = APPLY_MATRIX (matrix, 1, srcY[0], srcU[0], srcV[0]); \
|
|
b = APPLY_MATRIX (matrix, 2, srcY[0], srcU[0], srcV[0]); \
|
|
dest[R] = CLAMP (r, 0, 255); \
|
|
dest[G] = CLAMP (g, 0, 255); \
|
|
dest[B] = CLAMP (b, 0, 255); \
|
|
\
|
|
dest += 4; \
|
|
srcY++; \
|
|
} \
|
|
if (i % 2 == 0) { \
|
|
srcU -= width / 2; \
|
|
srcV -= width / 2; \
|
|
} else { \
|
|
srcU += src_uv_wrap; \
|
|
srcV += src_uv_wrap; \
|
|
} \
|
|
srcY += src_wrap; \
|
|
} \
|
|
} \
|
|
\
|
|
static inline void \
|
|
gst_alpha_chromakey_row_i420_##name (GstAlpha * alpha, guint8 * dest1, \
|
|
guint8 * dest2, const guint8 * srcY1, const guint8 * srcY2, \
|
|
const guint8 * srcU, const guint8 * srcV, gint width) \
|
|
{ \
|
|
gint xpos; \
|
|
gint a, a2, u, v; \
|
|
gint r, g, b; \
|
|
gint smin, smax; \
|
|
gint8 cb = alpha->cb, cr = alpha->cr; \
|
|
gint8 kg = alpha->kg; \
|
|
guint8 accept_angle_tg = alpha->accept_angle_tg; \
|
|
guint8 accept_angle_ctg = alpha->accept_angle_ctg; \
|
|
guint8 one_over_kc = alpha->one_over_kc; \
|
|
guint8 kfgy_scale = alpha->kfgy_scale; \
|
|
guint noise_level2 = alpha->noise_level2; \
|
|
gint matrix[12], y; \
|
|
\
|
|
a = CLAMP ((gint) (alpha->alpha * 255), 0, 255); \
|
|
smin = 128 - alpha->black_sensitivity; \
|
|
smax = 128 + alpha->white_sensitivity; \
|
|
\
|
|
memcpy (matrix, \
|
|
alpha->in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv : \
|
|
cog_ycbcr_to_rgb_matrix_8bit_hdtv, 12 * sizeof (gint)); \
|
|
\
|
|
for (xpos = 0; xpos < width / 2; xpos++) { \
|
|
y = srcY1[0]; \
|
|
u = srcU[0] - 128; \
|
|
v = srcV[0] - 128; \
|
|
\
|
|
a2 = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, smin, \
|
|
smax, accept_angle_tg, accept_angle_ctg, \
|
|
one_over_kc, kfgy_scale, kg, noise_level2); \
|
|
\
|
|
u += 128; \
|
|
v += 128; \
|
|
\
|
|
r = APPLY_MATRIX (matrix, 0, y, u, v); \
|
|
g = APPLY_MATRIX (matrix, 1, y, u, v); \
|
|
b = APPLY_MATRIX (matrix, 2, y, u, v); \
|
|
\
|
|
dest1[A] = a2; \
|
|
dest1[R] = CLAMP (r, 0, 255); \
|
|
dest1[G] = CLAMP (g, 0, 255); \
|
|
dest1[B] = CLAMP (b, 0, 255); \
|
|
\
|
|
y = srcY1[1]; \
|
|
u = srcU[0] - 128; \
|
|
v = srcV[0] - 128; \
|
|
\
|
|
a2 = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, smin, \
|
|
smax, accept_angle_tg, accept_angle_ctg, \
|
|
one_over_kc, kfgy_scale, kg, noise_level2); \
|
|
\
|
|
u += 128; \
|
|
v += 128; \
|
|
\
|
|
r = APPLY_MATRIX (matrix, 0, y, u, v); \
|
|
g = APPLY_MATRIX (matrix, 1, y, u, v); \
|
|
b = APPLY_MATRIX (matrix, 2, y, u, v); \
|
|
\
|
|
dest1[4 + A] = a2; \
|
|
dest1[4 + R] = CLAMP (r, 0, 255); \
|
|
dest1[4 + G] = CLAMP (g, 0, 255); \
|
|
dest1[4 + B] = CLAMP (b, 0, 255); \
|
|
\
|
|
y = srcY2[0]; \
|
|
u = srcU[0] - 128; \
|
|
v = srcV[0] - 128; \
|
|
\
|
|
a2 = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, smin, \
|
|
smax, accept_angle_tg, accept_angle_ctg, \
|
|
one_over_kc, kfgy_scale, kg, noise_level2); \
|
|
\
|
|
u += 128; \
|
|
v += 128; \
|
|
\
|
|
r = APPLY_MATRIX (matrix, 0, y, u, v); \
|
|
g = APPLY_MATRIX (matrix, 1, y, u, v); \
|
|
b = APPLY_MATRIX (matrix, 2, y, u, v); \
|
|
\
|
|
dest2[A] = a2; \
|
|
dest2[R] = CLAMP (r, 0, 255); \
|
|
dest2[G] = CLAMP (g, 0, 255); \
|
|
dest2[B] = CLAMP (b, 0, 255); \
|
|
\
|
|
y = srcY2[1]; \
|
|
u = srcU[0] - 128; \
|
|
v = srcV[0] - 128; \
|
|
\
|
|
a2 = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, smin, \
|
|
smax, accept_angle_tg, accept_angle_ctg, \
|
|
one_over_kc, kfgy_scale, kg, noise_level2); \
|
|
\
|
|
u += 128; \
|
|
v += 128; \
|
|
\
|
|
r = APPLY_MATRIX (matrix, 0, y, u, v); \
|
|
g = APPLY_MATRIX (matrix, 1, y, u, v); \
|
|
b = APPLY_MATRIX (matrix, 2, y, u, v); \
|
|
\
|
|
dest2[4 + A] = a2; \
|
|
dest2[4 + R] = CLAMP (r, 0, 255); \
|
|
dest2[4 + G] = CLAMP (g, 0, 255); \
|
|
dest2[4 + B] = CLAMP (b, 0, 255); \
|
|
\
|
|
srcY1 += 2; \
|
|
srcY2 += 2; \
|
|
srcU++; \
|
|
srcV++; \
|
|
dest1 += 8; \
|
|
dest2 += 8; \
|
|
} \
|
|
} \
|
|
\
|
|
static void \
|
|
gst_alpha_chroma_key_i420_##name (const guint8 * src, guint8 * dest, \
|
|
gint width, gint height, GstAlpha * alpha) \
|
|
{ \
|
|
const guint8 *srcY1, *srcY2, *srcU, *srcV; \
|
|
guint8 *dest1, *dest2; \
|
|
gint ypos; \
|
|
gint dest_stride, src_y_stride, src_uv_stride; \
|
|
\
|
|
dest_stride = \
|
|
gst_video_format_get_row_stride (GST_VIDEO_FORMAT_AYUV, 0, width); \
|
|
src_y_stride = \
|
|
gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, width); \
|
|
src_uv_stride = \
|
|
gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, width); \
|
|
\
|
|
srcY1 = src; \
|
|
srcY2 = src + src_y_stride; \
|
|
\
|
|
srcU = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, \
|
|
1, width, height); \
|
|
srcV = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420, \
|
|
2, width, height); \
|
|
\
|
|
dest1 = dest; \
|
|
dest2 = dest + dest_stride; \
|
|
\
|
|
/* Redefine Y strides to skip 2 lines at a time ... */ \
|
|
dest_stride *= 2; \
|
|
src_y_stride *= 2; \
|
|
\
|
|
for (ypos = 0; ypos < height / 2; ypos++) { \
|
|
gst_alpha_chromakey_row_i420_##name (alpha, dest1, dest2, \
|
|
srcY1, srcY2, srcU, srcV, width); \
|
|
\
|
|
dest1 += dest_stride; \
|
|
dest2 += dest_stride; \
|
|
srcY1 += src_y_stride; \
|
|
srcY2 += src_y_stride; \
|
|
srcU += src_uv_stride; \
|
|
srcV += src_uv_stride; \
|
|
} \
|
|
}
|
|
|
|
CREATE_I420_ARGB_FUNCTIONS (argb, 0, 1, 2, 3);
|
|
CREATE_I420_ARGB_FUNCTIONS (abgr, 0, 3, 2, 1);
|
|
CREATE_I420_ARGB_FUNCTIONS (rgba, 3, 0, 1, 2);
|
|
CREATE_I420_ARGB_FUNCTIONS (bgra, 3, 2, 1, 0);
|
|
|
|
#define CREATE_RGB_AYUV_FUNCTIONS(name, R, G, B, bpp) \
|
|
static void \
|
|
gst_alpha_set_##name##_ayuv (const guint8 * src, guint8 * dest, gint width, \
|
|
gint height, GstAlpha * alpha) \
|
|
{ \
|
|
gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255); \
|
|
gint i, j; \
|
|
gint matrix[12]; \
|
|
gint y, u, v; \
|
|
\
|
|
memcpy (matrix, \
|
|
alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv : \
|
|
cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint)); \
|
|
\
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < width; j++) { \
|
|
dest[0] = s_alpha; \
|
|
\
|
|
y = APPLY_MATRIX (matrix, 0, src[R], src[G], src[B]); \
|
|
u = APPLY_MATRIX (matrix, 1, src[R], src[G], src[B]); \
|
|
v = APPLY_MATRIX (matrix, 2, src[R], src[G], src[B]); \
|
|
\
|
|
dest[1] = y; \
|
|
dest[2] = u; \
|
|
dest[3] = v; \
|
|
\
|
|
dest += 4; \
|
|
src += bpp; \
|
|
} \
|
|
} \
|
|
} \
|
|
\
|
|
static void \
|
|
gst_alpha_chroma_key_##name##_ayuv (const guint8 * src, guint8 * dest, gint width, \
|
|
gint height, GstAlpha * alpha) \
|
|
{ \
|
|
gint i, j; \
|
|
gint a, y, u, v; \
|
|
gint r, g, b; \
|
|
gint smin, smax; \
|
|
gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255); \
|
|
gint8 cb = alpha->cb, cr = alpha->cr; \
|
|
gint8 kg = alpha->kg; \
|
|
guint8 accept_angle_tg = alpha->accept_angle_tg; \
|
|
guint8 accept_angle_ctg = alpha->accept_angle_ctg; \
|
|
guint8 one_over_kc = alpha->one_over_kc; \
|
|
guint8 kfgy_scale = alpha->kfgy_scale; \
|
|
guint noise_level2 = alpha->noise_level2; \
|
|
gint matrix[12]; \
|
|
\
|
|
smin = 128 - alpha->black_sensitivity; \
|
|
smax = 128 + alpha->white_sensitivity; \
|
|
\
|
|
memcpy (matrix, \
|
|
alpha->out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv : \
|
|
cog_rgb_to_ycbcr_matrix_8bit_hdtv, 12 * sizeof (gint)); \
|
|
\
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < width; j++) { \
|
|
a = pa; \
|
|
r = src[R]; \
|
|
g = src[G]; \
|
|
b = src[B]; \
|
|
\
|
|
y = APPLY_MATRIX (matrix, 0, r, g, b); \
|
|
u = APPLY_MATRIX (matrix, 1, r, g, b) - 128; \
|
|
v = APPLY_MATRIX (matrix, 2, r, g, b) - 128; \
|
|
\
|
|
a = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, \
|
|
smin, smax, accept_angle_tg, accept_angle_ctg, \
|
|
one_over_kc, kfgy_scale, kg, noise_level2); \
|
|
\
|
|
u += 128; \
|
|
v += 128; \
|
|
\
|
|
dest[0] = a; \
|
|
dest[1] = y; \
|
|
dest[2] = u; \
|
|
dest[3] = v; \
|
|
\
|
|
src += bpp; \
|
|
dest += 4; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
CREATE_RGB_AYUV_FUNCTIONS (xrgb, 1, 2, 3, 4);
|
|
CREATE_RGB_AYUV_FUNCTIONS (xbgr, 3, 2, 1, 4);
|
|
CREATE_RGB_AYUV_FUNCTIONS (rgbx, 0, 1, 2, 4);
|
|
CREATE_RGB_AYUV_FUNCTIONS (bgrx, 2, 1, 0, 4);
|
|
CREATE_RGB_AYUV_FUNCTIONS (rgb, 0, 1, 2, 3);
|
|
CREATE_RGB_AYUV_FUNCTIONS (bgr, 2, 1, 0, 3);
|
|
|
|
#define CREATE_RGB_ARGB_FUNCTIONS(name, name2, R, G, B, A2, R2, G2, B2, bpp) \
|
|
static void \
|
|
gst_alpha_set_##name##_##name2 (const guint8 * src, guint8 * dest, gint width, \
|
|
gint height, GstAlpha * alpha) \
|
|
{ \
|
|
gint s_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255); \
|
|
gint i, j; \
|
|
\
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < width; j++) { \
|
|
dest[A2] = s_alpha; \
|
|
\
|
|
dest[R2] = src[R]; \
|
|
dest[G2] = src[G]; \
|
|
dest[B2] = src[B]; \
|
|
\
|
|
dest += 4; \
|
|
src += bpp; \
|
|
} \
|
|
} \
|
|
} \
|
|
\
|
|
static void \
|
|
gst_alpha_chroma_key_##name##_##name2 (const guint8 * src, guint8 * dest, gint width, \
|
|
gint height, GstAlpha * alpha) \
|
|
{ \
|
|
gint i, j; \
|
|
gint a, y, u, v; \
|
|
gint r, g, b; \
|
|
gint smin, smax; \
|
|
gint pa = CLAMP ((gint) (alpha->alpha * 255), 0, 255); \
|
|
gint8 cb = alpha->cb, cr = alpha->cr; \
|
|
gint8 kg = alpha->kg; \
|
|
guint8 accept_angle_tg = alpha->accept_angle_tg; \
|
|
guint8 accept_angle_ctg = alpha->accept_angle_ctg; \
|
|
guint8 one_over_kc = alpha->one_over_kc; \
|
|
guint8 kfgy_scale = alpha->kfgy_scale; \
|
|
guint noise_level2 = alpha->noise_level2; \
|
|
gint matrix[12], matrix2[12]; \
|
|
\
|
|
smin = 128 - alpha->black_sensitivity; \
|
|
smax = 128 + alpha->white_sensitivity; \
|
|
\
|
|
memcpy (matrix, \
|
|
cog_rgb_to_ycbcr_matrix_8bit_sdtv, \
|
|
12 * sizeof (gint)); \
|
|
memcpy (matrix2, \
|
|
cog_ycbcr_to_rgb_matrix_8bit_sdtv, \
|
|
12 * sizeof (gint)); \
|
|
\
|
|
for (i = 0; i < height; i++) { \
|
|
for (j = 0; j < width; j++) { \
|
|
a = pa; \
|
|
r = src[R]; \
|
|
g = src[G]; \
|
|
b = src[B]; \
|
|
\
|
|
y = APPLY_MATRIX (matrix, 0, r, g, b); \
|
|
u = APPLY_MATRIX (matrix, 1, r, g, b) - 128; \
|
|
v = APPLY_MATRIX (matrix, 2, r, g, b) - 128; \
|
|
\
|
|
a = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, \
|
|
smin, smax, accept_angle_tg, accept_angle_ctg, \
|
|
one_over_kc, kfgy_scale, kg, noise_level2); \
|
|
\
|
|
u += 128; \
|
|
v += 128; \
|
|
\
|
|
r = APPLY_MATRIX (matrix2, 0, y, u, v); \
|
|
g = APPLY_MATRIX (matrix2, 1, y, u, v); \
|
|
b = APPLY_MATRIX (matrix2, 2, y, u, v); \
|
|
\
|
|
dest[A2] = a; \
|
|
dest[R2] = CLAMP (r, 0, 255); \
|
|
dest[G2] = CLAMP (g, 0, 255); \
|
|
dest[B2] = CLAMP (b, 0, 255); \
|
|
\
|
|
src += bpp; \
|
|
dest += 4; \
|
|
} \
|
|
} \
|
|
}
|
|
|
|
CREATE_RGB_ARGB_FUNCTIONS (xrgb, argb, 1, 2, 3, 0, 1, 2, 3, 4);
|
|
CREATE_RGB_ARGB_FUNCTIONS (xrgb, abgr, 1, 2, 3, 0, 3, 2, 1, 4);
|
|
CREATE_RGB_ARGB_FUNCTIONS (xrgb, rgba, 1, 2, 3, 3, 0, 1, 2, 4);
|
|
CREATE_RGB_ARGB_FUNCTIONS (xrgb, bgra, 1, 2, 3, 3, 2, 1, 0, 4);
|
|
|
|
CREATE_RGB_ARGB_FUNCTIONS (xbgr, argb, 3, 2, 1, 0, 1, 2, 3, 4);
|
|
CREATE_RGB_ARGB_FUNCTIONS (xbgr, abgr, 3, 2, 1, 0, 3, 2, 1, 4);
|
|
CREATE_RGB_ARGB_FUNCTIONS (xbgr, rgba, 3, 2, 1, 3, 0, 1, 2, 4);
|
|
CREATE_RGB_ARGB_FUNCTIONS (xbgr, bgra, 3, 2, 1, 3, 2, 1, 0, 4);
|
|
|
|
CREATE_RGB_ARGB_FUNCTIONS (rgbx, argb, 0, 1, 2, 0, 1, 2, 3, 4);
|
|
CREATE_RGB_ARGB_FUNCTIONS (rgbx, abgr, 0, 1, 2, 0, 3, 2, 1, 4);
|
|
CREATE_RGB_ARGB_FUNCTIONS (rgbx, rgba, 0, 1, 2, 3, 0, 1, 2, 4);
|
|
CREATE_RGB_ARGB_FUNCTIONS (rgbx, bgra, 0, 1, 2, 3, 2, 1, 0, 4);
|
|
|
|
CREATE_RGB_ARGB_FUNCTIONS (bgrx, argb, 2, 1, 0, 0, 1, 2, 3, 4);
|
|
CREATE_RGB_ARGB_FUNCTIONS (bgrx, abgr, 2, 1, 0, 0, 3, 2, 1, 4);
|
|
CREATE_RGB_ARGB_FUNCTIONS (bgrx, rgba, 2, 1, 0, 3, 0, 1, 2, 4);
|
|
CREATE_RGB_ARGB_FUNCTIONS (bgrx, bgra, 2, 1, 0, 3, 2, 1, 0, 4);
|
|
|
|
CREATE_RGB_ARGB_FUNCTIONS (rgb, argb, 0, 1, 2, 0, 1, 2, 3, 3);
|
|
CREATE_RGB_ARGB_FUNCTIONS (rgb, abgr, 0, 1, 2, 0, 3, 2, 1, 3);
|
|
CREATE_RGB_ARGB_FUNCTIONS (rgb, rgba, 0, 1, 2, 3, 0, 1, 2, 3);
|
|
CREATE_RGB_ARGB_FUNCTIONS (rgb, bgra, 0, 1, 2, 3, 2, 1, 0, 3);
|
|
|
|
CREATE_RGB_ARGB_FUNCTIONS (bgr, argb, 2, 1, 0, 0, 1, 2, 3, 3);
|
|
CREATE_RGB_ARGB_FUNCTIONS (bgr, abgr, 2, 1, 0, 0, 3, 2, 1, 3);
|
|
CREATE_RGB_ARGB_FUNCTIONS (bgr, rgba, 2, 1, 0, 3, 0, 1, 2, 3);
|
|
CREATE_RGB_ARGB_FUNCTIONS (bgr, bgra, 2, 1, 0, 3, 2, 1, 0, 3);
|
|
|
|
static void
|
|
gst_alpha_set_i420_ayuv (const guint8 * src, guint8 * dest, gint width,
|
|
gint height, GstAlpha * alpha)
|
|
{
|
|
gint b_alpha = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
|
|
const guint8 *srcY;
|
|
const guint8 *srcU;
|
|
const guint8 *srcV;
|
|
gint i, j;
|
|
gint src_wrap, src_uv_wrap;
|
|
gint y_stride, uv_stride;
|
|
gboolean odd_width;
|
|
|
|
y_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, width);
|
|
uv_stride = gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, width);
|
|
|
|
src_wrap = y_stride - width;
|
|
src_uv_wrap = uv_stride - (width / 2);
|
|
|
|
srcY = src;
|
|
srcU = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420,
|
|
1, width, height);
|
|
srcV = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420,
|
|
2, width, height);
|
|
|
|
odd_width = (width % 2 != 0);
|
|
|
|
if (alpha->in_sdtv == alpha->out_sdtv) {
|
|
for (i = 0; i < height; i++) {
|
|
for (j = 0; j < width / 2; j++) {
|
|
dest[0] = b_alpha;
|
|
dest[1] = srcY[0];
|
|
dest[2] = srcU[0];
|
|
dest[3] = srcV[0];
|
|
dest[4] = b_alpha;
|
|
dest[5] = srcY[1];
|
|
dest[6] = srcU[0];
|
|
dest[7] = srcV[0];
|
|
|
|
dest += 8;
|
|
srcY += 2;
|
|
srcU++;
|
|
srcV++;
|
|
}
|
|
/* Might have one odd column left to do */
|
|
if (odd_width) {
|
|
dest[0] = b_alpha;
|
|
dest[1] = srcY[0];
|
|
dest[2] = srcU[0];
|
|
dest[3] = srcV[0];
|
|
|
|
dest += 4;
|
|
srcY++;
|
|
}
|
|
if (i % 2 == 0) {
|
|
srcU -= width / 2;
|
|
srcV -= width / 2;
|
|
} else {
|
|
srcU += src_uv_wrap;
|
|
srcV += src_uv_wrap;
|
|
}
|
|
srcY += src_wrap;
|
|
}
|
|
} else {
|
|
gint matrix[12];
|
|
|
|
memcpy (matrix,
|
|
alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
|
|
cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
|
|
|
|
for (i = 0; i < height; i++) {
|
|
for (j = 0; j < width / 2; j++) {
|
|
dest[0] = b_alpha;
|
|
dest[1] = APPLY_MATRIX (matrix, 0, srcY[0], srcU[0], srcV[0]);
|
|
dest[2] = APPLY_MATRIX (matrix, 1, srcY[0], srcU[0], srcV[0]);
|
|
dest[3] = APPLY_MATRIX (matrix, 2, srcY[0], srcU[0], srcV[0]);
|
|
dest[4] = b_alpha;
|
|
dest[5] = APPLY_MATRIX (matrix, 0, srcY[1], srcU[0], srcV[0]);
|
|
dest[6] = APPLY_MATRIX (matrix, 1, srcY[1], srcU[0], srcV[0]);
|
|
dest[7] = APPLY_MATRIX (matrix, 2, srcY[1], srcU[0], srcV[0]);
|
|
|
|
dest += 8;
|
|
srcY += 2;
|
|
srcU++;
|
|
srcV++;
|
|
}
|
|
/* Might have one odd column left to do */
|
|
if (odd_width) {
|
|
dest[0] = b_alpha;
|
|
dest[1] = APPLY_MATRIX (matrix, 0, srcY[0], srcU[0], srcV[0]);
|
|
dest[2] = APPLY_MATRIX (matrix, 1, srcY[0], srcU[0], srcV[0]);
|
|
dest[3] = APPLY_MATRIX (matrix, 2, srcY[0], srcU[0], srcV[0]);
|
|
|
|
dest += 4;
|
|
srcY++;
|
|
}
|
|
if (i % 2 == 0) {
|
|
srcU -= width / 2;
|
|
srcV -= width / 2;
|
|
} else {
|
|
srcU += src_uv_wrap;
|
|
srcV += src_uv_wrap;
|
|
}
|
|
srcY += src_wrap;
|
|
}
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
gst_alpha_chromakey_row_i420_ayuv (GstAlpha * alpha, guint8 * dest1,
|
|
guint8 * dest2, const guint8 * srcY1, const guint8 * srcY2,
|
|
const guint8 * srcU, const guint8 * srcV, gint width)
|
|
{
|
|
gint xpos;
|
|
gint a, a2, u, v;
|
|
gint smin, smax;
|
|
gint8 cb = alpha->cb, cr = alpha->cr;
|
|
gint8 kg = alpha->kg;
|
|
guint8 accept_angle_tg = alpha->accept_angle_tg;
|
|
guint8 accept_angle_ctg = alpha->accept_angle_ctg;
|
|
guint8 one_over_kc = alpha->one_over_kc;
|
|
guint8 kfgy_scale = alpha->kfgy_scale;
|
|
guint noise_level2 = alpha->noise_level2;
|
|
|
|
a = CLAMP ((gint) (alpha->alpha * 255), 0, 255);
|
|
smin = 128 - alpha->black_sensitivity;
|
|
smax = 128 + alpha->white_sensitivity;
|
|
|
|
if (alpha->in_sdtv == alpha->out_sdtv) {
|
|
gint y[4];
|
|
|
|
for (xpos = 0; xpos < width / 2; xpos++) {
|
|
y[0] = srcY1[0];
|
|
y[1] = srcY1[1];
|
|
y[2] = srcY2[0];
|
|
y[3] = srcY2[1];
|
|
u = srcU[0] - 128;
|
|
v = srcV[0] - 128;
|
|
|
|
a2 = chroma_keying_yuv (a, y, 4, &u, &v, cr, cb, smin,
|
|
smax, accept_angle_tg, accept_angle_ctg,
|
|
one_over_kc, kfgy_scale, kg, noise_level2);
|
|
|
|
u += 128;
|
|
v += 128;
|
|
|
|
dest1[0] = a2;
|
|
dest1[1] = y[0];
|
|
dest1[2] = u;
|
|
dest1[3] = v;
|
|
dest1[4] = a2;
|
|
dest1[5] = y[1];
|
|
dest1[6] = u;
|
|
dest1[7] = v;
|
|
|
|
dest2[0] = a2;
|
|
dest2[1] = y[2];
|
|
dest2[2] = u;
|
|
dest2[3] = v;
|
|
dest2[4] = a2;
|
|
dest2[5] = y[3];
|
|
dest2[6] = u;
|
|
dest2[7] = v;
|
|
|
|
srcY1 += 2;
|
|
srcY2 += 2;
|
|
srcU++;
|
|
srcV++;
|
|
dest1 += 8;
|
|
dest2 += 8;
|
|
}
|
|
} else {
|
|
gint matrix[12], y;
|
|
|
|
memcpy (matrix,
|
|
alpha->out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
|
|
cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit, 12 * sizeof (gint));
|
|
|
|
for (xpos = 0; xpos < width / 2; xpos++) {
|
|
y = APPLY_MATRIX (matrix, 0, srcY1[0], srcU[0], srcV[0]);
|
|
u = APPLY_MATRIX (matrix, 1, srcY1[0], srcU[0], srcV[0]) - 128;
|
|
v = APPLY_MATRIX (matrix, 2, srcY1[0], srcU[0], srcV[0]) - 128;
|
|
|
|
a2 = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, smin,
|
|
smax, accept_angle_tg, accept_angle_ctg,
|
|
one_over_kc, kfgy_scale, kg, noise_level2);
|
|
|
|
u += 128;
|
|
v += 128;
|
|
|
|
dest1[0] = a2;
|
|
dest1[1] = y;
|
|
dest1[2] = u;
|
|
dest1[3] = v;
|
|
|
|
y = APPLY_MATRIX (matrix, 0, srcY1[1], srcU[0], srcV[0]);
|
|
u = APPLY_MATRIX (matrix, 1, srcY1[1], srcU[0], srcV[0]) - 128;
|
|
v = APPLY_MATRIX (matrix, 2, srcY1[1], srcU[0], srcV[0]) - 128;
|
|
|
|
a2 = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, smin,
|
|
smax, accept_angle_tg, accept_angle_ctg,
|
|
one_over_kc, kfgy_scale, kg, noise_level2);
|
|
|
|
u += 128;
|
|
v += 128;
|
|
|
|
dest1[4] = a2;
|
|
dest1[5] = y;
|
|
dest1[6] = u;
|
|
dest1[7] = v;
|
|
|
|
y = APPLY_MATRIX (matrix, 0, srcY2[0], srcU[0], srcV[0]);
|
|
u = APPLY_MATRIX (matrix, 1, srcY2[0], srcU[0], srcV[0]) - 128;
|
|
v = APPLY_MATRIX (matrix, 2, srcY2[0], srcU[0], srcV[0]) - 128;
|
|
|
|
a2 = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, smin,
|
|
smax, accept_angle_tg, accept_angle_ctg,
|
|
one_over_kc, kfgy_scale, kg, noise_level2);
|
|
|
|
u += 128;
|
|
v += 128;
|
|
|
|
dest2[0] = a2;
|
|
dest2[1] = y;
|
|
dest2[2] = u;
|
|
dest2[3] = v;
|
|
|
|
y = APPLY_MATRIX (matrix, 0, srcY2[1], srcU[0], srcV[0]);
|
|
u = APPLY_MATRIX (matrix, 1, srcY2[1], srcU[0], srcV[0]) - 128;
|
|
v = APPLY_MATRIX (matrix, 2, srcY2[1], srcU[0], srcV[0]) - 128;
|
|
|
|
a2 = chroma_keying_yuv (a, &y, 1, &u, &v, cr, cb, smin,
|
|
smax, accept_angle_tg, accept_angle_ctg,
|
|
one_over_kc, kfgy_scale, kg, noise_level2);
|
|
|
|
u += 128;
|
|
v += 128;
|
|
|
|
dest2[4] = a2;
|
|
dest2[5] = y;
|
|
dest2[6] = u;
|
|
dest2[7] = v;
|
|
|
|
srcY1 += 2;
|
|
srcY2 += 2;
|
|
srcU++;
|
|
srcV++;
|
|
dest1 += 8;
|
|
dest2 += 8;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_alpha_chroma_key_i420_ayuv (const guint8 * src, guint8 * dest,
|
|
gint width, gint height, GstAlpha * alpha)
|
|
{
|
|
const guint8 *srcY1, *srcY2, *srcU, *srcV;
|
|
guint8 *dest1, *dest2;
|
|
gint ypos;
|
|
gint dest_stride, src_y_stride, src_uv_stride;
|
|
|
|
dest_stride =
|
|
gst_video_format_get_row_stride (GST_VIDEO_FORMAT_AYUV, 0, width);
|
|
src_y_stride =
|
|
gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 0, width);
|
|
src_uv_stride =
|
|
gst_video_format_get_row_stride (GST_VIDEO_FORMAT_I420, 1, width);
|
|
|
|
srcY1 = src;
|
|
srcY2 = src + src_y_stride;
|
|
|
|
srcU = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420,
|
|
1, width, height);
|
|
srcV = src + gst_video_format_get_component_offset (GST_VIDEO_FORMAT_I420,
|
|
2, width, height);
|
|
|
|
dest1 = dest;
|
|
dest2 = dest + dest_stride;
|
|
|
|
/* Redefine Y strides to skip 2 lines at a time ... */
|
|
dest_stride *= 2;
|
|
src_y_stride *= 2;
|
|
|
|
for (ypos = 0; ypos < height / 2; ypos++) {
|
|
gst_alpha_chromakey_row_i420_ayuv (alpha, dest1, dest2,
|
|
srcY1, srcY2, srcU, srcV, width);
|
|
|
|
dest1 += dest_stride;
|
|
dest2 += dest_stride;
|
|
srcY1 += src_y_stride;
|
|
srcY2 += src_y_stride;
|
|
srcU += src_uv_stride;
|
|
srcV += src_uv_stride;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gst_alpha_init_params (GstAlpha * alpha)
|
|
{
|
|
gfloat kgl;
|
|
gfloat tmp;
|
|
gfloat tmp1, tmp2;
|
|
gfloat y;
|
|
const gint *matrix;
|
|
|
|
/* RGB->RGB: convert to SDTV YUV, chroma keying, convert back
|
|
* YUV->RGB: chroma keying, convert to RGB
|
|
* RGB->YUV: convert to YUV, chroma keying
|
|
* YUV->YUV: convert matrix, chroma keying
|
|
*/
|
|
if (gst_video_format_is_rgb (alpha->in_format)
|
|
&& gst_video_format_is_rgb (alpha->out_format))
|
|
matrix = cog_rgb_to_ycbcr_matrix_8bit_sdtv;
|
|
else if (gst_video_format_is_yuv (alpha->in_format)
|
|
&& gst_video_format_is_rgb (alpha->out_format))
|
|
matrix =
|
|
(alpha->in_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
|
|
cog_rgb_to_ycbcr_matrix_8bit_hdtv;
|
|
else if (gst_video_format_is_rgb (alpha->in_format)
|
|
&& gst_video_format_is_yuv (alpha->out_format))
|
|
matrix =
|
|
(alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
|
|
cog_rgb_to_ycbcr_matrix_8bit_hdtv;
|
|
else /* yuv -> yuv */
|
|
matrix =
|
|
(alpha->out_sdtv) ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
|
|
cog_rgb_to_ycbcr_matrix_8bit_hdtv;
|
|
|
|
y = (matrix[0] * ((gint) alpha->target_r) +
|
|
matrix[1] * ((gint) alpha->target_g) +
|
|
matrix[2] * ((gint) alpha->target_b) + matrix[3]) >> 8;
|
|
/* Cb,Cr without offset here because the chroma keying
|
|
* works with them being in range [-128,127]
|
|
*/
|
|
tmp1 =
|
|
(matrix[4] * ((gint) alpha->target_r) +
|
|
matrix[5] * ((gint) alpha->target_g) +
|
|
matrix[6] * ((gint) alpha->target_b)) >> 8;
|
|
tmp2 =
|
|
(matrix[8] * ((gint) alpha->target_r) +
|
|
matrix[9] * ((gint) alpha->target_g) +
|
|
matrix[10] * ((gint) alpha->target_b)) >> 8;
|
|
|
|
kgl = sqrt (tmp1 * tmp1 + tmp2 * tmp2);
|
|
alpha->cb = 127 * (tmp1 / kgl);
|
|
alpha->cr = 127 * (tmp2 / kgl);
|
|
|
|
tmp = 15 * tan (M_PI * alpha->angle / 180);
|
|
tmp = MIN (tmp, 255);
|
|
alpha->accept_angle_tg = tmp;
|
|
tmp = 15 / tan (M_PI * alpha->angle / 180);
|
|
tmp = MIN (tmp, 255);
|
|
alpha->accept_angle_ctg = tmp;
|
|
tmp = 1 / (kgl);
|
|
alpha->one_over_kc = 255 * 2 * tmp - 255;
|
|
tmp = 15 * y / kgl;
|
|
tmp = MIN (tmp, 255);
|
|
alpha->kfgy_scale = tmp;
|
|
alpha->kg = MIN (kgl, 127);
|
|
|
|
alpha->noise_level2 = alpha->noise_level * alpha->noise_level;
|
|
}
|
|
|
|
static gboolean
|
|
gst_alpha_set_process_function (GstAlpha * alpha)
|
|
{
|
|
alpha->process = NULL;
|
|
|
|
switch (alpha->method) {
|
|
case ALPHA_METHOD_SET:
|
|
switch (alpha->out_format) {
|
|
case GST_VIDEO_FORMAT_AYUV:
|
|
switch (alpha->in_format) {
|
|
case GST_VIDEO_FORMAT_AYUV:
|
|
alpha->process = gst_alpha_set_ayuv_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_I420:
|
|
alpha->process = gst_alpha_set_i420_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ARGB:
|
|
alpha->process = gst_alpha_set_argb_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ABGR:
|
|
alpha->process = gst_alpha_set_abgr_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBA:
|
|
alpha->process = gst_alpha_set_rgba_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
alpha->process = gst_alpha_set_bgra_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xRGB:
|
|
alpha->process = gst_alpha_set_xrgb_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xBGR:
|
|
alpha->process = gst_alpha_set_xbgr_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBx:
|
|
alpha->process = gst_alpha_set_rgbx_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRx:
|
|
alpha->process = gst_alpha_set_bgrx_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGB:
|
|
alpha->process = gst_alpha_set_rgb_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGR:
|
|
alpha->process = gst_alpha_set_bgr_ayuv;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case GST_VIDEO_FORMAT_ARGB:
|
|
switch (alpha->in_format) {
|
|
case GST_VIDEO_FORMAT_AYUV:
|
|
alpha->process = gst_alpha_set_ayuv_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_I420:
|
|
alpha->process = gst_alpha_set_i420_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ARGB:
|
|
alpha->process = gst_alpha_set_argb_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ABGR:
|
|
alpha->process = gst_alpha_set_abgr_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBA:
|
|
alpha->process = gst_alpha_set_rgba_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
alpha->process = gst_alpha_set_bgra_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xRGB:
|
|
alpha->process = gst_alpha_set_xrgb_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xBGR:
|
|
alpha->process = gst_alpha_set_xbgr_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBx:
|
|
alpha->process = gst_alpha_set_rgbx_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRx:
|
|
alpha->process = gst_alpha_set_bgrx_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGB:
|
|
alpha->process = gst_alpha_set_rgb_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGR:
|
|
alpha->process = gst_alpha_set_bgr_argb;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case GST_VIDEO_FORMAT_ABGR:
|
|
switch (alpha->in_format) {
|
|
case GST_VIDEO_FORMAT_AYUV:
|
|
alpha->process = gst_alpha_set_ayuv_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_I420:
|
|
alpha->process = gst_alpha_set_i420_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ARGB:
|
|
alpha->process = gst_alpha_set_argb_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ABGR:
|
|
alpha->process = gst_alpha_set_abgr_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBA:
|
|
alpha->process = gst_alpha_set_rgba_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
alpha->process = gst_alpha_set_bgra_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xRGB:
|
|
alpha->process = gst_alpha_set_xrgb_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xBGR:
|
|
alpha->process = gst_alpha_set_xbgr_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBx:
|
|
alpha->process = gst_alpha_set_rgbx_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRx:
|
|
alpha->process = gst_alpha_set_bgrx_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGB:
|
|
alpha->process = gst_alpha_set_rgb_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGR:
|
|
alpha->process = gst_alpha_set_bgr_abgr;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBA:
|
|
switch (alpha->in_format) {
|
|
case GST_VIDEO_FORMAT_AYUV:
|
|
alpha->process = gst_alpha_set_ayuv_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_I420:
|
|
alpha->process = gst_alpha_set_i420_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ARGB:
|
|
alpha->process = gst_alpha_set_argb_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ABGR:
|
|
alpha->process = gst_alpha_set_abgr_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBA:
|
|
alpha->process = gst_alpha_set_rgba_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
alpha->process = gst_alpha_set_bgra_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xRGB:
|
|
alpha->process = gst_alpha_set_xrgb_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xBGR:
|
|
alpha->process = gst_alpha_set_xbgr_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBx:
|
|
alpha->process = gst_alpha_set_rgbx_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRx:
|
|
alpha->process = gst_alpha_set_bgrx_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGB:
|
|
alpha->process = gst_alpha_set_rgb_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGR:
|
|
alpha->process = gst_alpha_set_bgr_rgba;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
switch (alpha->in_format) {
|
|
case GST_VIDEO_FORMAT_AYUV:
|
|
alpha->process = gst_alpha_set_ayuv_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_I420:
|
|
alpha->process = gst_alpha_set_i420_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ARGB:
|
|
alpha->process = gst_alpha_set_argb_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ABGR:
|
|
alpha->process = gst_alpha_set_abgr_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBA:
|
|
alpha->process = gst_alpha_set_rgba_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
alpha->process = gst_alpha_set_bgra_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xRGB:
|
|
alpha->process = gst_alpha_set_xrgb_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xBGR:
|
|
alpha->process = gst_alpha_set_xbgr_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBx:
|
|
alpha->process = gst_alpha_set_rgbx_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRx:
|
|
alpha->process = gst_alpha_set_bgrx_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGB:
|
|
alpha->process = gst_alpha_set_rgb_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGR:
|
|
alpha->process = gst_alpha_set_bgr_bgra;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case ALPHA_METHOD_GREEN:
|
|
case ALPHA_METHOD_BLUE:
|
|
case ALPHA_METHOD_CUSTOM:
|
|
switch (alpha->out_format) {
|
|
case GST_VIDEO_FORMAT_AYUV:
|
|
switch (alpha->in_format) {
|
|
case GST_VIDEO_FORMAT_AYUV:
|
|
alpha->process = gst_alpha_chroma_key_ayuv_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_I420:
|
|
alpha->process = gst_alpha_chroma_key_i420_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ARGB:
|
|
alpha->process = gst_alpha_chroma_key_argb_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ABGR:
|
|
alpha->process = gst_alpha_chroma_key_abgr_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBA:
|
|
alpha->process = gst_alpha_chroma_key_rgba_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
alpha->process = gst_alpha_chroma_key_bgra_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xRGB:
|
|
alpha->process = gst_alpha_chroma_key_xrgb_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xBGR:
|
|
alpha->process = gst_alpha_chroma_key_xbgr_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBx:
|
|
alpha->process = gst_alpha_chroma_key_rgbx_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRx:
|
|
alpha->process = gst_alpha_chroma_key_bgrx_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGB:
|
|
alpha->process = gst_alpha_chroma_key_rgb_ayuv;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGR:
|
|
alpha->process = gst_alpha_chroma_key_bgr_ayuv;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case GST_VIDEO_FORMAT_ARGB:
|
|
switch (alpha->in_format) {
|
|
case GST_VIDEO_FORMAT_AYUV:
|
|
alpha->process = gst_alpha_chroma_key_ayuv_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_I420:
|
|
alpha->process = gst_alpha_chroma_key_i420_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ARGB:
|
|
alpha->process = gst_alpha_chroma_key_argb_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ABGR:
|
|
alpha->process = gst_alpha_chroma_key_abgr_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBA:
|
|
alpha->process = gst_alpha_chroma_key_rgba_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
alpha->process = gst_alpha_chroma_key_bgra_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xRGB:
|
|
alpha->process = gst_alpha_chroma_key_xrgb_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xBGR:
|
|
alpha->process = gst_alpha_chroma_key_xbgr_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBx:
|
|
alpha->process = gst_alpha_chroma_key_rgbx_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRx:
|
|
alpha->process = gst_alpha_chroma_key_bgrx_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGB:
|
|
alpha->process = gst_alpha_chroma_key_rgb_argb;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGR:
|
|
alpha->process = gst_alpha_chroma_key_bgr_argb;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case GST_VIDEO_FORMAT_ABGR:
|
|
switch (alpha->in_format) {
|
|
case GST_VIDEO_FORMAT_AYUV:
|
|
alpha->process = gst_alpha_chroma_key_ayuv_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_I420:
|
|
alpha->process = gst_alpha_chroma_key_i420_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ARGB:
|
|
alpha->process = gst_alpha_chroma_key_argb_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ABGR:
|
|
alpha->process = gst_alpha_chroma_key_abgr_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBA:
|
|
alpha->process = gst_alpha_chroma_key_rgba_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
alpha->process = gst_alpha_chroma_key_bgra_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xRGB:
|
|
alpha->process = gst_alpha_chroma_key_xrgb_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xBGR:
|
|
alpha->process = gst_alpha_chroma_key_xbgr_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBx:
|
|
alpha->process = gst_alpha_chroma_key_rgbx_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRx:
|
|
alpha->process = gst_alpha_chroma_key_bgrx_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGB:
|
|
alpha->process = gst_alpha_chroma_key_rgb_abgr;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGR:
|
|
alpha->process = gst_alpha_chroma_key_bgr_abgr;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBA:
|
|
switch (alpha->in_format) {
|
|
case GST_VIDEO_FORMAT_AYUV:
|
|
alpha->process = gst_alpha_chroma_key_ayuv_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_I420:
|
|
alpha->process = gst_alpha_chroma_key_i420_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ARGB:
|
|
alpha->process = gst_alpha_chroma_key_argb_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ABGR:
|
|
alpha->process = gst_alpha_chroma_key_abgr_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBA:
|
|
alpha->process = gst_alpha_chroma_key_rgba_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
alpha->process = gst_alpha_chroma_key_bgra_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xRGB:
|
|
alpha->process = gst_alpha_chroma_key_xrgb_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xBGR:
|
|
alpha->process = gst_alpha_chroma_key_xbgr_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBx:
|
|
alpha->process = gst_alpha_chroma_key_rgbx_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRx:
|
|
alpha->process = gst_alpha_chroma_key_bgrx_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGB:
|
|
alpha->process = gst_alpha_chroma_key_rgb_rgba;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGR:
|
|
alpha->process = gst_alpha_chroma_key_bgr_rgba;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
switch (alpha->in_format) {
|
|
case GST_VIDEO_FORMAT_AYUV:
|
|
alpha->process = gst_alpha_chroma_key_ayuv_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_I420:
|
|
alpha->process = gst_alpha_chroma_key_i420_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ARGB:
|
|
alpha->process = gst_alpha_chroma_key_argb_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_ABGR:
|
|
alpha->process = gst_alpha_chroma_key_abgr_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBA:
|
|
alpha->process = gst_alpha_chroma_key_rgba_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRA:
|
|
alpha->process = gst_alpha_chroma_key_bgra_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xRGB:
|
|
alpha->process = gst_alpha_chroma_key_xrgb_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_xBGR:
|
|
alpha->process = gst_alpha_chroma_key_xbgr_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGBx:
|
|
alpha->process = gst_alpha_chroma_key_rgbx_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGRx:
|
|
alpha->process = gst_alpha_chroma_key_bgrx_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_RGB:
|
|
alpha->process = gst_alpha_chroma_key_rgb_bgra;
|
|
break;
|
|
case GST_VIDEO_FORMAT_BGR:
|
|
alpha->process = gst_alpha_chroma_key_bgr_bgra;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return alpha->process != NULL;
|
|
}
|
|
|
|
static gboolean
|
|
gst_alpha_start (GstBaseTransform * btrans)
|
|
{
|
|
GstAlpha *alpha = GST_ALPHA (btrans);
|
|
|
|
gst_alpha_init_params (alpha);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static GstFlowReturn
|
|
gst_alpha_transform (GstBaseTransform * btrans, GstBuffer * in, GstBuffer * out)
|
|
{
|
|
GstAlpha *alpha = GST_ALPHA (btrans);
|
|
gint width, height;
|
|
GstClockTime timestamp;
|
|
|
|
width = alpha->width;
|
|
height = alpha->height;
|
|
|
|
GST_BUFFER_TIMESTAMP (out) = GST_BUFFER_TIMESTAMP (in);
|
|
GST_BUFFER_DURATION (out) = GST_BUFFER_DURATION (in);
|
|
timestamp = gst_segment_to_stream_time (&btrans->segment, GST_FORMAT_TIME,
|
|
GST_BUFFER_TIMESTAMP (in));
|
|
GST_LOG ("Got stream time of %" GST_TIME_FORMAT, GST_TIME_ARGS (timestamp));
|
|
if (GST_CLOCK_TIME_IS_VALID (timestamp))
|
|
gst_object_sync_values (G_OBJECT (alpha), timestamp);
|
|
|
|
GST_OBJECT_LOCK (alpha);
|
|
if (G_UNLIKELY (!alpha->process)) {
|
|
GST_ERROR_OBJECT (alpha, "Not negotiated yet");
|
|
GST_OBJECT_UNLOCK (alpha);
|
|
return GST_FLOW_NOT_NEGOTIATED;
|
|
}
|
|
|
|
alpha->process (GST_BUFFER_DATA (in),
|
|
GST_BUFFER_DATA (out), width, height, alpha);
|
|
GST_OBJECT_UNLOCK (alpha);
|
|
|
|
return GST_FLOW_OK;
|
|
}
|
|
|
|
static gboolean
|
|
plugin_init (GstPlugin * plugin)
|
|
{
|
|
gst_controller_init (NULL, NULL);
|
|
|
|
return gst_element_register (plugin, "alpha", GST_RANK_NONE, GST_TYPE_ALPHA);
|
|
}
|
|
|
|
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
|
GST_VERSION_MINOR,
|
|
"alpha",
|
|
"adds an alpha channel to video - constant or via chroma-keying",
|
|
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|