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, "green_mask");
gst_structure_remove_field (structure, "blue_mask"); gst_structure_remove_field (structure, "blue_mask");
gst_structure_remove_field (structure, "alpha_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_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); gst_caps_append_structure (local_caps, structure);
} }
@ -155,45 +157,60 @@ gst_alpha_color_transform_caps (GstBaseTransform * btrans,
return result; return result;
} }
static gboolean /* Generated by -bad/ext/cog/generate_tables */
gst_alpha_color_set_caps (GstBaseTransform * btrans, GstCaps * incaps, static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = {
GstCaps * outcaps) 298, 0, 459, -63514,
{ 298, -55, -136, 19681,
GstAlphaColor *alpha = GST_ALPHA_COLOR (btrans); 298, 541, 0, -73988,
gboolean ret; };
gint w, h;
gint w2, h2;
GstVideoFormat in_format, out_format;
ret = gst_video_format_parse_caps (incaps, &in_format, &w, &h); static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
ret &= gst_video_format_parse_caps (outcaps, &out_format, &w2, &h2); 298, 0, 409, -57068,
298, -100, -208, 34707,
298, 516, 0, -70870,
};
if (!ret || w != w2 || h != h2) { static const gint cog_rgb_to_ycbcr_matrix_8bit_hdtv[] = {
GST_DEBUG_OBJECT (alpha, "incomplete or invalid caps!"); 47, 157, 16, 4096,
return FALSE; -26, -87, 112, 32768,
} 112, -102, -10, 32768,
};
alpha->in_format = in_format; static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
alpha->out_format = out_format; 66, 129, 25, 4096,
alpha->width = w; -38, -74, 112, 32768,
alpha->height = h; 112, -94, -18, 32768,
};
if (in_format == out_format) static const gint cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = {
gst_base_transform_set_passthrough (btrans, TRUE); 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) \ #define DEFINE_ARGB_AYUV_FUNCTIONS(name, A, R, G, B) \
static void \ 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) { \ while (size > 0) { \
y = data[R] * 0.299 + data[G] * 0.587 + data[B] * 0.114 + 0; \ y = (data[R] * yc[0] + data[G] * yc[1] + data[B] * yc[2] + yc[3]) >> 8; \
u = data[R] * -0.169 + data[G] * -0.332 + data[B] * 0.500 + 128; \ u = (data[R] * uc[0] + data[G] * uc[1] + data[B] * uc[2] + uc[3]) >> 8; \
v = data[R] * 0.500 + data[R] * -0.419 + data[B] * -0.0813 + 128; \ v = (data[R] * vc[0] + data[G] * vc[1] + data[B] * vc[2] + vc[3]) >> 8; \
\ \
data[0] = data[A]; \ data[0] = data[A]; \
data[1] = y; \ data[1] = y; \
@ -206,20 +223,26 @@ transform_##name##_ayuv (guint8 * data, gint size) \
} \ } \
\ \
static void \ 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) { \ while (size > 0) { \
r = data[1] + (0.419 / 0.299) * (data[3] - 128); \ r = (data[1] * rc[0] + data[2] * rc[1] + data[3] * rc[2] + rc[3]) >> 8; \
g = data[1] + (-0.114 / 0.331) * (data[2] - 128) + \ g = (data[1] * gc[0] + data[2] * gc[1] + data[3] * gc[2] + gc[3]) >> 8; \
(-0.299 / 0.419) * (data[3] - 128); \ b = (data[1] * bc[0] + data[2] * bc[1] + data[3] * bc[2] + bc[3]) >> 8; \
b = data[1] + (0.587 / 0.331) * (data[2] - 128); \
\ \
data[A] = data[0]; \ data[A] = data[0]; \
data[R] = r; \ data[R] = CLAMP (r, 0, 255); \
data[G] = g; \ data[G] = CLAMP (g, 0, 255); \
data[B] = b; \ data[B] = CLAMP (b, 0, 255); \
\ \
data += 4; \ data += 4; \
size -= 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); DEFINE_ARGB_AYUV_FUNCTIONS (abgr, 0, 3, 2, 1);
static void 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) { while (size > 0) {
r = data[1]; r = data[1];
@ -254,9 +307,9 @@ transform_argb_bgra (guint8 * data, gint size)
#define transform_abgr_rgba transform_argb_bgra #define transform_abgr_rgba transform_argb_bgra
static void 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) { while (size > 0) {
r = data[1]; r = data[1];
@ -276,9 +329,9 @@ transform_argb_abgr (guint8 * data, gint size)
#define transform_abgr_argb transform_argb_abgr #define transform_abgr_argb transform_argb_abgr
static void 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) { while (size > 0) {
r = data[0]; r = data[0];
@ -298,9 +351,9 @@ transform_rgba_bgra (guint8 * data, gint size)
#define transform_bgra_rgba transform_rgba_bgra #define transform_bgra_rgba transform_rgba_bgra
static void 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) { while (size > 0) {
r = data[1]; r = data[1];
@ -320,9 +373,9 @@ transform_argb_rgba (guint8 * data, gint size)
#define transform_abgr_bgra transform_argb_rgba #define transform_abgr_bgra transform_argb_rgba
static void 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) { while (size > 0) {
r = data[2]; r = data[2];
@ -342,9 +395,9 @@ transform_bgra_argb (guint8 * data, gint size)
#define transform_rgba_abgr transform_bgra_argb #define transform_rgba_abgr transform_bgra_argb
static void 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) { while (size > 0) {
r = data[0]; r = data[0];
@ -363,6 +416,217 @@ transform_rgba_argb (guint8 * data, gint size)
#define transform_bgra_abgr transform_rgba_argb #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 static GstFlowReturn
gst_alpha_color_transform_ip (GstBaseTransform * btrans, GstBuffer * inbuf) 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; return GST_FLOW_ERROR;
} }
/* Transform in place */ if (G_UNLIKELY (!alpha->process)) {
switch (alpha->in_format) { GST_ERROR_OBJECT (alpha, "Not negotiated yet");
case GST_VIDEO_FORMAT_ARGB: return GST_FLOW_NOT_NEGOTIATED;
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;
} }
/* Transform in place */
alpha->process (GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf),
alpha->matrix);
return ret; return ret;
} }

View file

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