From a4c24b92225c006f703b371b2081a0ac00382c59 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Thu, 8 Oct 2009 14:33:28 -0700 Subject: [PATCH] cog: Add color matrix selection to cogcolorspace Eventually hook it up to caps via gstvideo --- ext/cog/Makefile.am | 1 + ext/cog/cogframe.h | 6 ++++ ext/cog/cogvirtframe.c | 66 ++++++++++++++++++++++++++++++++------ ext/cog/cogvirtframe.h | 4 +-- ext/cog/generate_tables.c | 64 ++++++++++++++++++++++++++++++++++++ ext/cog/gstcogcolorspace.c | 63 ++++++++++++++++++++++-------------- ext/cog/gstlogoinsert.c | 2 +- 7 files changed, 169 insertions(+), 37 deletions(-) diff --git a/ext/cog/Makefile.am b/ext/cog/Makefile.am index dff47fab95..95c6e8fe28 100644 --- a/ext/cog/Makefile.am +++ b/ext/cog/Makefile.am @@ -36,6 +36,7 @@ libgstcog_la_SOURCES = \ gstcms.c noinst_PROGRAMS = generate_tables +generate_tables_SOURCES = generate_tables.c gstcms.c generate_tables_CFLAGS = $(GST_CFLAGS) generate_tables_LDADD = $(GST_LIBS) diff --git a/ext/cog/cogframe.h b/ext/cog/cogframe.h index 488c96859c..2aa7a02f57 100644 --- a/ext/cog/cogframe.h +++ b/ext/cog/cogframe.h @@ -13,6 +13,12 @@ typedef struct _CogUpsampledFrame CogUpsampledFrame; typedef void (*CogFrameFreeFunc)(CogFrame *frame, void *priv); typedef void (*CogFrameRenderFunc)(CogFrame *frame, void *dest, int component, int i); +typedef enum _CogColorMatrix { + COG_COLOR_MATRIX_UNKNOWN = 0, + COG_COLOR_MATRIX_HDTV, + COG_COLOR_MATRIX_SDTV +} CogColorMatrix; + /* bit pattern: * 0x100 - 0: normal, 1: indirect (packed) * 0x001 - horizontal chroma subsampling: 0: 1, 1: 2 diff --git a/ext/cog/cogvirtframe.c b/ext/cog/cogvirtframe.c index 1ff6cdd3c6..21d0e4c4a3 100644 --- a/ext/cog/cogvirtframe.c +++ b/ext/cog/cogvirtframe.c @@ -1330,6 +1330,31 @@ color_matrix_RGB_to_YCbCr (CogFrame * frame, void *_dest, int component, int i) } + +static const int cog_ycbcr_to_rgb_matrix_6bit_sdtv[] = { + 75, 0, 102, -14267, + 75, -25, -52, 8677, + 75, 129, 0, -17717, +}; + +static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = { + 42, 0, 153, -57068, + 42, -100, -208, 34707, + 42, 4, 0, -70870, +}; + +static const int cog_ycbcr_to_rgb_matrix_6bit_hdtv[] = { + 75, 0, 115, -15878, + 75, -14, -34, 4920, + 75, 135, 0, -18497, +}; + +static const int cog_ycbcr_to_rgb_matrix_8bit_hdtv[] = { + 42, 0, 203, -63514, + 42, -55, -136, 19681, + 42, 29, 0, -73988, +}; + static void color_matrix_YCbCr_to_RGB_6bit (CogFrame * frame, void *_dest, int component, int i) @@ -1338,6 +1363,7 @@ color_matrix_YCbCr_to_RGB_6bit (CogFrame * frame, void *_dest, int component, uint8_t *src1; uint8_t *src2; uint8_t *src3; + int *matrix = frame->virt_priv2; src1 = cog_virt_frame_get_line (frame->virt_frame1, 0, i); src2 = cog_virt_frame_get_line (frame->virt_frame1, 1, i); @@ -1348,20 +1374,22 @@ color_matrix_YCbCr_to_RGB_6bit (CogFrame * frame, void *_dest, int component, /* m1 = 1.1644; * m2 = 0; * m3 = 1.596; */ - orc_matrix2_u8 (dest, src1, src3, 75, 102, -14269 + 32, frame->width); + orc_matrix2_u8 (dest, src1, src3, matrix[0], matrix[2], matrix[3] + 32, + frame->width); break; case 1: /* m1 = 1.1644; * m2 = -0.39176; * m3 = -0.81297; */ - orc_matrix3_u8 (dest, src1, src2, src3, 75, -25, -52, 8677 + 32, - frame->width); + orc_matrix3_u8 (dest, src1, src2, src3, matrix[4], matrix[5], matrix[6], + matrix[7] + 32, frame->width); break; case 2: /* m1 = 1.1644; * m2 = 2.0172; * m3 = 0; */ - orc_matrix2_u8 (dest, src1, src2, 75, 129, -17718 + 32, frame->width); + orc_matrix2_u8 (dest, src1, src2, + matrix[8], matrix[9], matrix[11] + 32, frame->width); break; default: break; @@ -1376,6 +1404,7 @@ color_matrix_YCbCr_to_RGB_8bit (CogFrame * frame, void *_dest, int component, uint8_t *src1; uint8_t *src2; uint8_t *src3; + int *matrix = frame->virt_priv2; src1 = cog_virt_frame_get_line (frame->virt_frame1, 0, i); src2 = cog_virt_frame_get_line (frame->virt_frame1, 1, i); @@ -1383,23 +1412,26 @@ color_matrix_YCbCr_to_RGB_8bit (CogFrame * frame, void *_dest, int component, switch (component) { case 0: + /* m1 = 1.1644; * m2 = 0; * m3 = 1.596; */ - orc_matrix2_11_u8 (dest, src1, src3, 42, 153, 128, 8, frame->width); + orc_matrix2_11_u8 (dest, src1, src3, + matrix[0], matrix[2], 128, 8, frame->width); break; case 1: /* m1 = 1.1644; * m2 = -0.39176; * m3 = -0.81297; */ - orc_matrix3_100_u8 (dest, src1, src2, src3, 42, -100, -208, 128, 8, - frame->width); + orc_matrix3_100_u8 (dest, src1, src2, src3, + matrix[4], matrix[5], matrix[6], 128, 8, frame->width); break; case 2: /* m1 = 1.1644; * m2 = 2.0172; * m3 = 0; */ - orc_matrix2_12_u8 (dest, src1, src2, 42, 4, 128, 8, frame->width); + orc_matrix2_12_u8 (dest, src1, src2, + matrix[8], matrix[9], 128, 8, frame->width); break; default: break; @@ -1407,24 +1439,37 @@ color_matrix_YCbCr_to_RGB_8bit (CogFrame * frame, void *_dest, int component, } CogFrame * -cog_virt_frame_new_color_matrix_YCbCr_to_RGB (CogFrame * vf, int bits) +cog_virt_frame_new_color_matrix_YCbCr_to_RGB (CogFrame * vf, + CogColorMatrix color_matrix, int bits) { CogFrame *virt_frame; + //int *matrix = frame->virt_priv2; virt_frame = cog_frame_new_virtual (NULL, COG_FRAME_FORMAT_U8_444, vf->width, vf->height); virt_frame->virt_frame1 = vf; if (bits <= 6) { virt_frame->render_line = color_matrix_YCbCr_to_RGB_6bit; + if (color_matrix == COG_COLOR_MATRIX_HDTV) { + virt_frame->virt_priv2 = (void *) cog_ycbcr_to_rgb_matrix_6bit_hdtv; + } else { + virt_frame->virt_priv2 = (void *) cog_ycbcr_to_rgb_matrix_6bit_sdtv; + } } else { virt_frame->render_line = color_matrix_YCbCr_to_RGB_8bit; + if (color_matrix == COG_COLOR_MATRIX_HDTV) { + virt_frame->virt_priv2 = (void *) cog_ycbcr_to_rgb_matrix_8bit_hdtv; + } else { + virt_frame->virt_priv2 = (void *) cog_ycbcr_to_rgb_matrix_8bit_sdtv; + } } return virt_frame; } CogFrame * -cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf) +cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf, + CogColorMatrix color_matrix) { CogFrame *virt_frame; @@ -1432,6 +1477,7 @@ cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf) vf->width, vf->height); virt_frame->virt_frame1 = vf; virt_frame->render_line = color_matrix_RGB_to_YCbCr; + virt_frame->param1 = color_matrix; return virt_frame; } diff --git a/ext/cog/cogvirtframe.h b/ext/cog/cogvirtframe.h index c4625c3159..eca491446f 100644 --- a/ext/cog/cogvirtframe.h +++ b/ext/cog/cogvirtframe.h @@ -27,8 +27,8 @@ CogFrame *cog_virt_frame_new_pack_AYUV (CogFrame *vf); CogFrame *cog_virt_frame_new_pack_v216 (CogFrame *vf); CogFrame *cog_virt_frame_new_pack_v210 (CogFrame *vf); CogFrame *cog_virt_frame_new_pack_RGB (CogFrame *vf); -CogFrame *cog_virt_frame_new_color_matrix_YCbCr_to_RGB (CogFrame *vf, int bits); -CogFrame * cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf); +CogFrame *cog_virt_frame_new_color_matrix_YCbCr_to_RGB (CogFrame *vf, CogColorMatrix color_matrix, int bits); +CogFrame * cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf, CogColorMatrix color_matrix); CogFrame *cog_virt_frame_new_subsample (CogFrame *vf, CogFrameFormat format); CogFrame * cog_virt_frame_new_convert_u8 (CogFrame *vf); diff --git a/ext/cog/generate_tables.c b/ext/cog/generate_tables.c index 562ba9bdf2..a04946d9ea 100644 --- a/ext/cog/generate_tables.c +++ b/ext/cog/generate_tables.c @@ -4,6 +4,8 @@ #include #include +#include "gstcms.h" + #define SCALE 256 void @@ -66,5 +68,67 @@ main (int argc, char *argv[]) g_print ("};\n"); g_print ("\n"); + + { + int cm, bits; + + for (cm = 0; cm < 2; cm++) { + for (bits = 6; bits <= 8; bits += 2) { + + ColorMatrix matrix; + + /* + * At this point, everything is in YCbCr + * All components are in the range [0,255] + */ + color_matrix_set_identity (&matrix); + + /* offset required to get input video black to (0.,0.,0.) */ + /* we don't do this because the code does it for us */ + color_matrix_offset_components (&matrix, -16, -128, -128); + + color_matrix_scale_components (&matrix, (1 / 219.0), (1 / 224.0), + (1 / 224.0)); + + /* colour matrix, YCbCr -> RGB */ + /* Requires Y in [0,1.0], Cb&Cr in [-0.5,0.5] */ + if (cm) { + color_matrix_YCbCr_to_RGB (&matrix, 0.2126, 0.0722); /* HD */ + } else { + color_matrix_YCbCr_to_RGB (&matrix, 0.2990, 0.1140); /* SD */ + } + + /* + * We are now in RGB space + */ + + /* scale to output range. */ + color_matrix_scale_components (&matrix, 255.0, 255.0, 255.0); + + /* because we're doing 8-bit matrix coefficients */ + color_matrix_scale_components (&matrix, 1 << bits, 1 << bits, + 1 << bits); + + g_print ("static const int cog_ycbcr_to_rgb_matrix_%dbit_%s[] = {\n", + bits, cm ? "hdtv" : "sdtv"); + g_print (" %d, %d, %d, %d,\n", + (int) rint (matrix.m[0][0] - ((bits == 8) ? 256 : 0)), + (int) rint (matrix.m[0][1]), + (int) rint (matrix.m[0][2] - ((bits == 8) ? 256 : 0)), + (int) rint (matrix.m[0][3])); + g_print (" %d, %d, %d, %d,\n", + (int) rint (matrix.m[1][0] - ((bits == 8) ? 256 : 0)), + (int) rint (matrix.m[1][1]), + (int) rint (matrix.m[1][2]), (int) rint (matrix.m[1][3])); + g_print (" %d, %d, %d, %d,\n", + (int) rint (matrix.m[2][0] - ((bits == 8) ? 256 : 0)), + (int) rint (matrix.m[2][1] - ((bits == 8) ? 512 : 0)), + (int) rint (matrix.m[2][2]), (int) rint (matrix.m[2][3])); + g_print ("};\n"); + } + } + } + + return 0; } diff --git a/ext/cog/gstcogcolorspace.c b/ext/cog/gstcogcolorspace.c index 697f424c3f..1663a848fd 100644 --- a/ext/cog/gstcogcolorspace.c +++ b/ext/cog/gstcogcolorspace.c @@ -57,6 +57,7 @@ struct _GstCogcolorspace GstBaseTransform base_transform; int quality; + CogColorMatrix color_matrix; }; struct _GstCogcolorspaceClass @@ -75,11 +76,13 @@ enum }; #define DEFAULT_QUALITY 5 +#define DEFAULT_COLOR_MATRIX COG_COLOR_MATRIX_UNKNOWN enum { PROP_0, - PROP_QUALITY + PROP_QUALITY, + PROP_COLOR_MATRIX }; static void gst_cogcolorspace_set_property (GObject * object, guint prop_id, @@ -119,31 +122,26 @@ static GstStaticPadTemplate gst_cogcolorspace_src_template = GST_BOILERPLATE (GstCogcolorspace, gst_cogcolorspace, GstBaseTransform, GST_TYPE_BASE_TRANSFORM); -#if 0 GType -gst_cogcolorspace_get_type (void) +gst_cog_color_matrix_get_type (void) { - static GType compress_type = 0; + static gsize id = 0; + static const GEnumValue values[] = { + {COG_COLOR_MATRIX_UNKNOWN, "unknown", + "Unknown color matrix (works like sdtv)"}, + {COG_COLOR_MATRIX_HDTV, "hdtv", "High Definition TV color matrix (BT.709)"}, + {COG_COLOR_MATRIX_SDTV, "sdtv", + "Standard Definition TV color matrix (BT.470)"}, + {0, NULL, NULL} + }; - if (!compress_type) { - static const GTypeInfo compress_info = { - sizeof (GstCogcolorspaceClass), - gst_cogcolorspace_base_init, - NULL, - gst_cogcolorspace_class_init, - NULL, - NULL, - sizeof (GstCogcolorspace), - 0, - gst_cogcolorspace_init, - }; - - compress_type = g_type_register_static (GST_TYPE_BASE_TRANSFORM, - "GstCogcolorspace", &compress_info, 0); + if (g_once_init_enter (&id)) { + GType tmp = g_enum_register_static ("CogColorMatrix", values); + g_once_init_leave (&id, tmp); } - return compress_type; + + return (GType) id; } -#endif static void gst_cogcolorspace_base_init (gpointer g_class) @@ -178,7 +176,12 @@ gst_cogcolorspace_class_init (GstCogcolorspaceClass * colorspace_class) g_object_class_install_property (gobject_class, PROP_QUALITY, g_param_spec_int ("quality", "Quality", "Quality", - 0, 10, DEFAULT_QUALITY, G_PARAM_READWRITE)); + 0, 10, DEFAULT_QUALITY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, PROP_COLOR_MATRIX, + g_param_spec_enum ("color-matrix", "Color Matrix", + "Color matrix for YCbCr <-> RGB conversion", + gst_cog_color_matrix_get_type (), + DEFAULT_COLOR_MATRIX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); base_transform_class->transform = gst_cogcolorspace_transform; base_transform_class->transform_caps = gst_cogcolorspace_transform_caps; @@ -194,6 +197,7 @@ gst_cogcolorspace_init (GstCogcolorspace * colorspace, GST_DEBUG ("gst_cogcolorspace_init"); colorspace->quality = DEFAULT_QUALITY; + colorspace->color_matrix = DEFAULT_COLOR_MATRIX; } static void @@ -212,6 +216,11 @@ gst_cogcolorspace_set_property (GObject * object, guint prop_id, colorspace->quality = g_value_get_int (value); GST_OBJECT_UNLOCK (colorspace); break; + case PROP_COLOR_MATRIX: + GST_OBJECT_LOCK (colorspace); + colorspace->color_matrix = g_value_get_enum (value); + GST_OBJECT_UNLOCK (colorspace); + break; default: break; } @@ -232,6 +241,11 @@ gst_cogcolorspace_get_property (GObject * object, guint prop_id, GValue * value, g_value_set_int (value, colorspace->quality); GST_OBJECT_UNLOCK (colorspace); break; + case PROP_COLOR_MATRIX: + GST_OBJECT_LOCK (colorspace); + g_value_set_enum (value, colorspace->color_matrix); + GST_OBJECT_UNLOCK (colorspace); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -430,7 +444,8 @@ gst_cogcolorspace_transform (GstBaseTransform * base_transform, if (gst_video_format_is_yuv (out_format) && gst_video_format_is_rgb (in_format)) { - frame = cog_virt_frame_new_color_matrix_RGB_to_YCbCr (frame); + frame = cog_virt_frame_new_color_matrix_RGB_to_YCbCr (frame, + compress->color_matrix); } frame = cog_virt_frame_new_subsample (frame, new_subsample); @@ -438,7 +453,7 @@ gst_cogcolorspace_transform (GstBaseTransform * base_transform, if (gst_video_format_is_rgb (out_format) && gst_video_format_is_yuv (in_format)) { frame = cog_virt_frame_new_color_matrix_YCbCr_to_RGB (frame, - (compress->quality > 5) ? 8 : 6); + compress->color_matrix, (compress->quality >= 5) ? 8 : 6); } switch (out_format) { diff --git a/ext/cog/gstlogoinsert.c b/ext/cog/gstlogoinsert.c index 52f79e0bc2..9eb9141722 100644 --- a/ext/cog/gstlogoinsert.c +++ b/ext/cog/gstlogoinsert.c @@ -265,7 +265,7 @@ gst_logoinsert_transform_ip (GstBaseTransform * base_transform, GstBuffer * buf) li->alpha_frame = cog_frame_realize (f); f = cog_virt_frame_new_unpack (cog_frame_ref (li->ayuv_frame)); - f = cog_virt_frame_new_color_matrix_RGB_to_YCbCr (f); + f = cog_virt_frame_new_color_matrix_RGB_to_YCbCr (f, COG_COLOR_MATRIX_SDTV); f = cog_virt_frame_new_subsample (f, frame->format); li->overlay_frame = cog_frame_realize (f); }