alphacolor: Implement color-matrix support and use integer arithmetic only

Alphacolor now uses the correct matrixes for SDTV and HDTV and can
convert between them.
This commit is contained in:
Sebastian Dröge 2010-03-19 16:44:00 +01:00
parent ef804589ca
commit e3584bf52c
2 changed files with 325 additions and 181 deletions

View file

@ -129,10 +129,12 @@ gst_alpha_color_transform_caps (GstBaseTransform * btrans,
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 (local_caps, gst_structure_copy (structure));
gst_structure_set_name (structure, "video/x-raw-rgb");
gst_caps_append_structure (local_caps, gst_structure_copy (structure));
gst_structure_set_name (structure, "video/x-raw-yuv");
gst_caps_append_structure (local_caps, structure);
}
@ -155,45 +157,60 @@ gst_alpha_color_transform_caps (GstBaseTransform * btrans,
return result;
}
static gboolean
gst_alpha_color_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
GstCaps * outcaps)
{
GstAlphaColor *alpha = GST_ALPHA_COLOR (btrans);
gboolean ret;
gint w, h;
gint w2, h2;
GstVideoFormat in_format, out_format;
/* 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,
};
ret = gst_video_format_parse_caps (incaps, &in_format, &w, &h);
ret &= gst_video_format_parse_caps (outcaps, &out_format, &w2, &h2);
static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
298, 0, 409, -57068,
298, -100, -208, 34707,
298, 516, 0, -70870,
};
if (!ret || w != w2 || h != h2) {
GST_DEBUG_OBJECT (alpha, "incomplete or invalid caps!");
return FALSE;
}
static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
47, 157, 16, 4096,
-26, -87, 112, 32768,
112, -102, -10, 32768,
};
alpha->in_format = in_format;
alpha->out_format = out_format;
alpha->width = w;
alpha->height = h;
static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
66, 129, 25, 4096,
-38, -74, 112, 32768,
112, -94, -18, 32768,
};
if (in_format == out_format)
gst_base_transform_set_passthrough (btrans, TRUE);
static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
256, -30, -53, 10600,
0, 261, 29, -4367,
0, 19, 262, -3289,
};
return TRUE;
}
static const gint cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = {
256, 25, 49, -9536,
0, 253, -28, 3958,
0, -19, 252, 2918,
};
#define DEFINE_ARGB_AYUV_FUNCTIONS(name, A, R, G, B) \
static void \
transform_##name##_ayuv (guint8 * data, gint size) \
transform_##name##_ayuv (guint8 * data, gint size, const gint *matrix) \
{ \
guint8 y, u, v; \
gint y, u, v; \
gint yc[4]; \
gint uc[4]; \
gint vc[4]; \
\
memcpy (yc, matrix, 4 * sizeof (gint)); \
memcpy (uc, matrix + 4, 4 * sizeof (gint)); \
memcpy (vc, matrix + 8, 4 * sizeof (gint)); \
\
while (size > 0) { \
y = data[R] * 0.299 + data[G] * 0.587 + data[B] * 0.114 + 0; \
u = data[R] * -0.169 + data[G] * -0.332 + data[B] * 0.500 + 128; \
v = data[R] * 0.500 + data[R] * -0.419 + data[B] * -0.0813 + 128; \
y = (data[R] * yc[0] + data[G] * yc[1] + data[B] * yc[2] + yc[3]) >> 8; \
u = (data[R] * uc[0] + data[G] * uc[1] + data[B] * uc[2] + uc[3]) >> 8; \
v = (data[R] * vc[0] + data[G] * vc[1] + data[B] * vc[2] + vc[3]) >> 8; \
\
data[0] = data[A]; \
data[1] = y; \
@ -206,20 +223,26 @@ transform_##name##_ayuv (guint8 * data, gint size) \
} \
\
static void \
transform_ayuv_##name (guint8 * data, gint size) \
transform_ayuv_##name (guint8 * data, gint size, const gint *matrix) \
{ \
guint8 r, g, b; \
gint r, g, b; \
gint rc[4]; \
gint gc[4]; \
gint bc[4]; \
\
memcpy (rc, matrix, 4 * sizeof (gint)); \
memcpy (gc, matrix + 4, 4 * sizeof (gint)); \
memcpy (bc, matrix + 8, 4 * sizeof (gint)); \
\
while (size > 0) { \
r = data[1] + (0.419 / 0.299) * (data[3] - 128); \
g = data[1] + (-0.114 / 0.331) * (data[2] - 128) + \
(-0.299 / 0.419) * (data[3] - 128); \
b = data[1] + (0.587 / 0.331) * (data[2] - 128); \
r = (data[1] * rc[0] + data[2] * rc[1] + data[3] * rc[2] + rc[3]) >> 8; \
g = (data[1] * gc[0] + data[2] * gc[1] + data[3] * gc[2] + gc[3]) >> 8; \
b = (data[1] * bc[0] + data[2] * bc[1] + data[3] * bc[2] + bc[3]) >> 8; \
\
data[A] = data[0]; \
data[R] = r; \
data[G] = g; \
data[B] = b; \
data[R] = CLAMP (r, 0, 255); \
data[G] = CLAMP (g, 0, 255); \
data[B] = CLAMP (b, 0, 255); \
\
data += 4; \
size -= 4; \
@ -232,9 +255,39 @@ DEFINE_ARGB_AYUV_FUNCTIONS (argb, 0, 1, 2, 3);
DEFINE_ARGB_AYUV_FUNCTIONS (abgr, 0, 3, 2, 1);
static void
transform_argb_bgra (guint8 * data, gint size)
transform_ayuv_ayuv (guint8 * data, gint size, const gint * matrix)
{
guint8 r, g, b;
gint y, u, v;
gint yc[4];
gint uc[4];
gint vc[4];
if (matrix == NULL)
return;
memcpy (yc, matrix, 4 * sizeof (gint));
memcpy (uc, matrix + 4, 4 * sizeof (gint));
memcpy (vc, matrix + 8, 4 * sizeof (gint));
while (size > 0) {
y = (data[1] * yc[0] + data[2] * yc[1] + data[3] * yc[2] + yc[3]) >> 8;
u = (data[1] * uc[0] + data[2] * uc[1] + data[3] * uc[2] + uc[3]) >> 8;
v = (data[1] * vc[0] + data[2] * vc[1] + data[3] * vc[2] + vc[3]) >> 8;
data[0] = data[0];
data[1] = y;
data[2] = u;
data[3] = v;
data += 4;
size -= 4;
}
}
static void
transform_argb_bgra (guint8 * data, gint size, const gint * matrix)
{
gint r, g, b;
while (size > 0) {
r = data[1];
@ -254,9 +307,9 @@ transform_argb_bgra (guint8 * data, gint size)
#define transform_abgr_rgba transform_argb_bgra
static void
transform_argb_abgr (guint8 * data, gint size)
transform_argb_abgr (guint8 * data, gint size, const gint * matrix)
{
guint8 r, g, b;
gint r, g, b;
while (size > 0) {
r = data[1];
@ -276,9 +329,9 @@ transform_argb_abgr (guint8 * data, gint size)
#define transform_abgr_argb transform_argb_abgr
static void
transform_rgba_bgra (guint8 * data, gint size)
transform_rgba_bgra (guint8 * data, gint size, const gint * matrix)
{
guint8 r, g, b;
gint r, g, b;
while (size > 0) {
r = data[0];
@ -298,9 +351,9 @@ transform_rgba_bgra (guint8 * data, gint size)
#define transform_bgra_rgba transform_rgba_bgra
static void
transform_argb_rgba (guint8 * data, gint size)
transform_argb_rgba (guint8 * data, gint size, const gint * matrix)
{
guint8 r, g, b;
gint r, g, b;
while (size > 0) {
r = data[1];
@ -320,9 +373,9 @@ transform_argb_rgba (guint8 * data, gint size)
#define transform_abgr_bgra transform_argb_rgba
static void
transform_bgra_argb (guint8 * data, gint size)
transform_bgra_argb (guint8 * data, gint size, const gint * matrix)
{
guint8 r, g, b;
gint r, g, b;
while (size > 0) {
r = data[2];
@ -342,9 +395,9 @@ transform_bgra_argb (guint8 * data, gint size)
#define transform_rgba_abgr transform_bgra_argb
static void
transform_rgba_argb (guint8 * data, gint size)
transform_rgba_argb (guint8 * data, gint size, const gint * matrix)
{
guint8 r, g, b;
gint r, g, b;
while (size > 0) {
r = data[0];
@ -363,6 +416,217 @@ transform_rgba_argb (guint8 * data, gint size)
#define transform_bgra_abgr transform_rgba_argb
static gboolean
gst_alpha_color_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
GstCaps * outcaps)
{
GstAlphaColor *alpha = GST_ALPHA_COLOR (btrans);
gboolean ret;
gint w, h;
gint w2, h2;
GstVideoFormat in_format, out_format;
const gchar *matrix;
gboolean in_sdtv, out_sdtv;
alpha->process = NULL;
alpha->matrix = NULL;
ret = gst_video_format_parse_caps (incaps, &in_format, &w, &h);
ret &= gst_video_format_parse_caps (outcaps, &out_format, &w2, &h2);
if (!ret || w != w2 || h != h2) {
GST_DEBUG_OBJECT (alpha, "incomplete or invalid caps!");
return FALSE;
}
matrix = gst_video_parse_caps_color_matrix (incaps);
in_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
matrix = gst_video_parse_caps_color_matrix (outcaps);
out_sdtv = matrix ? g_str_equal (matrix, "sdtv") : TRUE;
alpha->in_format = in_format;
alpha->out_format = out_format;
alpha->width = w;
alpha->height = h;
switch (alpha->in_format) {
case GST_VIDEO_FORMAT_ARGB:
switch (alpha->out_format) {
case GST_VIDEO_FORMAT_ARGB:
alpha->process = NULL;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_BGRA:
alpha->process = transform_argb_bgra;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_ABGR:
alpha->process = transform_argb_abgr;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_RGBA:
alpha->process = transform_argb_rgba;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_AYUV:
alpha->process = transform_argb_ayuv;
alpha->matrix =
out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
cog_rgb_to_ycbcr_matrix_8bit_hdtv;
break;
default:
alpha->process = NULL;
alpha->matrix = NULL;
break;
}
break;
case GST_VIDEO_FORMAT_BGRA:
switch (alpha->out_format) {
case GST_VIDEO_FORMAT_BGRA:
alpha->process = NULL;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_ARGB:
alpha->process = transform_bgra_argb;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_ABGR:
alpha->process = transform_bgra_abgr;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_RGBA:
alpha->process = transform_bgra_rgba;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_AYUV:
alpha->process = transform_bgra_ayuv;
alpha->matrix =
out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
cog_rgb_to_ycbcr_matrix_8bit_hdtv;
break;
default:
alpha->process = NULL;
alpha->matrix = NULL;
break;
}
break;
case GST_VIDEO_FORMAT_ABGR:
switch (alpha->out_format) {
case GST_VIDEO_FORMAT_ABGR:
alpha->process = NULL;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_RGBA:
alpha->process = transform_abgr_rgba;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_ARGB:
alpha->process = transform_abgr_argb;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_BGRA:
alpha->process = transform_abgr_bgra;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_AYUV:
alpha->process = transform_abgr_ayuv;
alpha->matrix =
out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
cog_rgb_to_ycbcr_matrix_8bit_hdtv;
break;
default:
alpha->process = NULL;
alpha->matrix = NULL;
break;
}
break;
case GST_VIDEO_FORMAT_RGBA:
switch (alpha->out_format) {
case GST_VIDEO_FORMAT_RGBA:
alpha->process = NULL;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_ARGB:
alpha->process = transform_rgba_argb;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_ABGR:
alpha->process = transform_rgba_abgr;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_BGRA:
alpha->process = transform_rgba_bgra;
alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_AYUV:
alpha->process = transform_rgba_ayuv;
alpha->matrix =
out_sdtv ? cog_rgb_to_ycbcr_matrix_8bit_sdtv :
cog_rgb_to_ycbcr_matrix_8bit_hdtv;
break;
default:
alpha->process = NULL;
alpha->matrix = NULL;
break;
}
break;
case GST_VIDEO_FORMAT_AYUV:
switch (alpha->out_format) {
case GST_VIDEO_FORMAT_AYUV:
if (in_sdtv == out_sdtv) {
alpha->process = transform_ayuv_ayuv;
alpha->matrix = NULL;
} else {
alpha->process = transform_ayuv_ayuv;
alpha->matrix =
out_sdtv ? cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit :
cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit;
}
break;
case GST_VIDEO_FORMAT_ARGB:
alpha->process = transform_ayuv_argb;
alpha->matrix =
in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
cog_ycbcr_to_rgb_matrix_8bit_hdtv;
break;
case GST_VIDEO_FORMAT_BGRA:
alpha->process = transform_ayuv_bgra;
alpha->matrix =
in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
cog_ycbcr_to_rgb_matrix_8bit_hdtv;
break;
case GST_VIDEO_FORMAT_ABGR:
alpha->process = transform_ayuv_abgr;
alpha->matrix =
in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
cog_ycbcr_to_rgb_matrix_8bit_hdtv;
break;
case GST_VIDEO_FORMAT_RGBA:
alpha->process = transform_ayuv_rgba;
alpha->matrix =
in_sdtv ? cog_ycbcr_to_rgb_matrix_8bit_sdtv :
cog_ycbcr_to_rgb_matrix_8bit_hdtv;
break;
default:
alpha->process = NULL;
alpha->matrix = NULL;
break;
}
break;
default:
alpha->process = NULL;
alpha->matrix = NULL;
break;
}
if (in_format == out_format && in_sdtv == out_sdtv)
gst_base_transform_set_passthrough (btrans, TRUE);
else if (!alpha->process)
return FALSE;
return TRUE;
}
static GstFlowReturn
gst_alpha_color_transform_ip (GstBaseTransform * btrans, GstBuffer * inbuf)
{
@ -375,138 +639,15 @@ gst_alpha_color_transform_ip (GstBaseTransform * btrans, GstBuffer * inbuf)
return GST_FLOW_ERROR;
}
/* Transform in place */
switch (alpha->in_format) {
case GST_VIDEO_FORMAT_ARGB:
switch (alpha->out_format) {
case GST_VIDEO_FORMAT_ARGB:
break;
case GST_VIDEO_FORMAT_BGRA:
transform_argb_bgra (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_ABGR:
transform_argb_abgr (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_RGBA:
transform_argb_rgba (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_AYUV:
transform_argb_ayuv (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
default:
g_assert_not_reached ();
break;
}
break;
case GST_VIDEO_FORMAT_BGRA:
switch (alpha->out_format) {
case GST_VIDEO_FORMAT_BGRA:
break;
case GST_VIDEO_FORMAT_ARGB:
transform_bgra_argb (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_ABGR:
transform_bgra_abgr (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_RGBA:
transform_bgra_rgba (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_AYUV:
transform_bgra_ayuv (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
default:
g_assert_not_reached ();
break;
}
break;
case GST_VIDEO_FORMAT_ABGR:
switch (alpha->out_format) {
case GST_VIDEO_FORMAT_ABGR:
break;
case GST_VIDEO_FORMAT_RGBA:
transform_abgr_rgba (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_ARGB:
transform_abgr_argb (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_BGRA:
transform_abgr_bgra (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_AYUV:
transform_abgr_ayuv (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
default:
g_assert_not_reached ();
break;
}
break;
case GST_VIDEO_FORMAT_RGBA:
switch (alpha->out_format) {
case GST_VIDEO_FORMAT_RGBA:
break;
case GST_VIDEO_FORMAT_ARGB:
transform_rgba_argb (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_ABGR:
transform_rgba_abgr (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_BGRA:
transform_rgba_bgra (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_AYUV:
transform_rgba_ayuv (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
default:
g_assert_not_reached ();
break;
}
break;
case GST_VIDEO_FORMAT_AYUV:
switch (alpha->out_format) {
case GST_VIDEO_FORMAT_AYUV:
break;
case GST_VIDEO_FORMAT_ARGB:
transform_ayuv_argb (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_BGRA:
transform_ayuv_bgra (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_ABGR:
transform_ayuv_abgr (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
case GST_VIDEO_FORMAT_RGBA:
transform_ayuv_rgba (GST_BUFFER_DATA (inbuf),
GST_BUFFER_SIZE (inbuf));
break;
default:
g_assert_not_reached ();
break;
}
break;
default:
g_assert_not_reached ();
break;
if (G_UNLIKELY (!alpha->process)) {
GST_ERROR_OBJECT (alpha, "Not negotiated yet");
return GST_FLOW_NOT_NEGOTIATED;
}
/* Transform in place */
alpha->process (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf),
alpha->matrix);
return ret;
}

View file

@ -45,6 +45,9 @@ struct _GstAlphaColor
/* caps */
GstVideoFormat in_format, out_format;
gint width, height;
void (*process) (guint8 * data, gint size, const gint * matrix);
const gint *matrix;
};
struct _GstAlphaColorClass