summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian.droege@collabora.co.uk>2010-03-19 16:44:00 +0100
committerSebastian Dröge <sebastian.droege@collabora.co.uk>2010-03-19 16:45:07 +0100
commite3584bf52cf0b02376724d499483905c394e61e7 (patch)
tree792929a5ff753cdc7c1a1319192b78ddfcb7ce66
parentef804589cafcafba9c596d621ef6e415c29768f8 (diff)
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.
-rw-r--r--gst/alpha/gstalphacolor.c361
-rw-r--r--gst/alpha/gstalphacolor.h3
2 files changed, 254 insertions, 110 deletions
diff --git a/gst/alpha/gstalphacolor.c b/gst/alpha/gstalphacolor.c
index 67f5f0805..15edaf1e7 100644
--- a/gst/alpha/gstalphacolor.c
+++ b/gst/alpha/gstalphacolor.c
@@ -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;
-
- 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;
- }
-
- alpha->in_format = in_format;
- alpha->out_format = out_format;
- alpha->width = w;
- alpha->height = h;
-
- if (in_format == out_format)
- gst_base_transform_set_passthrough (btrans, TRUE);
-
- return TRUE;
-}
+/* 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,
+};
#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)
+{
+ 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)
{
- guint8 r, g, b;
+ 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,150 +416,238 @@ transform_rgba_argb (guint8 * data, gint size)
#define transform_bgra_abgr transform_rgba_argb
-static GstFlowReturn
-gst_alpha_color_transform_ip (GstBaseTransform * btrans, GstBuffer * inbuf)
+static gboolean
+gst_alpha_color_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
+ GstCaps * outcaps)
{
- GstFlowReturn ret = GST_FLOW_OK;
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;
- if (G_UNLIKELY (GST_BUFFER_SIZE (inbuf) != 4 * alpha->width * alpha->height)) {
- GST_ERROR_OBJECT (alpha, "Invalid buffer size (was %u, expected %u)",
- GST_BUFFER_SIZE (inbuf), alpha->width * alpha->height);
- return GST_FLOW_ERROR;
+ 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;
}
- /* Transform in place */
+ 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:
- transform_argb_bgra (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ alpha->process = transform_argb_bgra;
+ alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_ABGR:
- transform_argb_abgr (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ alpha->process = transform_argb_abgr;
+ alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_RGBA:
- transform_argb_rgba (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ alpha->process = transform_argb_rgba;
+ alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_AYUV:
- transform_argb_ayuv (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ 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:
- g_assert_not_reached ();
+ 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:
- transform_bgra_argb (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ alpha->process = transform_bgra_argb;
+ alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_ABGR:
- transform_bgra_abgr (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ alpha->process = transform_bgra_abgr;
+ alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_RGBA:
- transform_bgra_rgba (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ alpha->process = transform_bgra_rgba;
+ alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_AYUV:
- transform_bgra_ayuv (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ 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:
- g_assert_not_reached ();
+ 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:
- transform_abgr_rgba (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ alpha->process = transform_abgr_rgba;
+ alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_ARGB:
- transform_abgr_argb (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ alpha->process = transform_abgr_argb;
+ alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_BGRA:
- transform_abgr_bgra (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ alpha->process = transform_abgr_bgra;
+ alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_AYUV:
- transform_abgr_ayuv (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ 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:
- g_assert_not_reached ();
+ 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:
- transform_rgba_argb (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ alpha->process = transform_rgba_argb;
+ alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_ABGR:
- transform_rgba_abgr (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ alpha->process = transform_rgba_abgr;
+ alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_BGRA:
- transform_rgba_bgra (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ alpha->process = transform_rgba_bgra;
+ alpha->matrix = NULL;
break;
case GST_VIDEO_FORMAT_AYUV:
- transform_rgba_ayuv (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ 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:
- g_assert_not_reached ();
+ 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:
- transform_ayuv_argb (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ 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:
- transform_ayuv_bgra (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ 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:
- transform_ayuv_abgr (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ 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:
- transform_ayuv_rgba (GST_BUFFER_DATA (inbuf),
- GST_BUFFER_SIZE (inbuf));
+ 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:
- g_assert_not_reached ();
+ alpha->process = NULL;
+ alpha->matrix = NULL;
break;
}
break;
default:
- g_assert_not_reached ();
+ 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)
+{
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstAlphaColor *alpha = GST_ALPHA_COLOR (btrans);
+
+ if (G_UNLIKELY (GST_BUFFER_SIZE (inbuf) != 4 * alpha->width * alpha->height)) {
+ GST_ERROR_OBJECT (alpha, "Invalid buffer size (was %u, expected %u)",
+ GST_BUFFER_SIZE (inbuf), alpha->width * alpha->height);
+ return GST_FLOW_ERROR;
+ }
+
+ 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;
}
diff --git a/gst/alpha/gstalphacolor.h b/gst/alpha/gstalphacolor.h
index ab9951d71..636d83289 100644
--- a/gst/alpha/gstalphacolor.h
+++ b/gst/alpha/gstalphacolor.h
@@ -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