From e3584bf52cf0b02376724d499483905c394e61e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Fri, 19 Mar 2010 16:44:00 +0100 Subject: [PATCH] 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. --- gst/alpha/gstalphacolor.c | 503 ++++++++++++++++++++++++-------------- gst/alpha/gstalphacolor.h | 3 + 2 files changed, 325 insertions(+), 181 deletions(-) diff --git a/gst/alpha/gstalphacolor.c b/gst/alpha/gstalphacolor.c index 67f5f08050..15edaf1e72 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; +/* 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; } diff --git a/gst/alpha/gstalphacolor.h b/gst/alpha/gstalphacolor.h index ab9951d718..636d83289b 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