diff --git a/ext/cog/cog.orc b/ext/cog/cog.orc index 4a7c14f3a2..fa8d2d43a6 100644 --- a/ext/cog/cog.orc +++ b/ext/cog/cog.orc @@ -363,6 +363,39 @@ addw t3, t3, t1 convsuswb d1, t3 +.function orc_matrix3_100_offset_u8 +.dest 1 d1 uint8_t +.source 1 s1 uint8_t +.source 1 s2 uint8_t +.source 1 s3 uint8_t +.param 2 p1 +.param 2 p2 +.param 2 p3 +.param 2 p4 +.param 2 p5 +#.param 2 p6 +.temp 2 t1 +.temp 2 t2 +.temp 2 t3 +#.temp 2 t3 +#.temp 2 t4 + +convubw t3, s1 +mullw t1, t3, p1 +convubw t2, s2 +mullw t2, t2, p2 +addw t1, t1, t2 +convubw t2, s3 +mullw t2, t2, p3 +addw t1, t1, t2 +addw t1, t1, p4 +shrsw t1, t1, p5 +#addw t1, t1, p6 +addw t1, t1, t3 +convsuswb d1, t1 + + + .function orc_matrix3_000_u8 .dest 1 d1 uint8_t .source 1 s1 uint8_t diff --git a/ext/cog/cogvirtframe.c b/ext/cog/cogvirtframe.c index edaa5934d3..f8b3cef906 100644 --- a/ext/cog/cogvirtframe.c +++ b/ext/cog/cogvirtframe.c @@ -139,9 +139,11 @@ cog_virt_frame_get_line (CogFrame * frame, int component, int i) } if (i < frame->cache_offset[component]) { - g_warning ("cache failure: %d outside [%d,%d]", i, - frame->cache_offset[component], - frame->cache_offset[component] + COG_FRAME_CACHE_SIZE - 1); + if (i != 0) { + g_warning ("cache failure: %d outside [%d,%d]", i, + frame->cache_offset[component], + frame->cache_offset[component] + COG_FRAME_CACHE_SIZE - 1); + } frame->cache_offset[component] = i; for (j = 0; j < COG_FRAME_CACHE_SIZE; j++) { @@ -1470,6 +1472,72 @@ cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf, return virt_frame; } +static const int cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit[] = { + 256, -30, -53, 10600, + 0, 261, 29, -4367, + 0, 19, 262, -3289, +}; + +static const int cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit[] = { + 256, 25, 49, -9536, + 0, 253, -28, 3958, + 0, -19, 252, 2918, +}; + + +static void +color_matrix_YCbCr_to_YCbCr (CogFrame * frame, void *_dest, int component, + int i) +{ + uint8_t *dest = _dest; + 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); + src3 = cog_virt_frame_get_line (frame->virt_frame1, 2, i); + + switch (component) { + case 0: + orc_matrix3_100_offset_u8 (dest, src1, src2, src3, + matrix[0] - 256, matrix[1], matrix[2], matrix[3], 8, frame->width); + break; + case 1: + orc_matrix3_000_u8 (dest, src1, src2, src3, + matrix[4], matrix[5], matrix[6], matrix[7], 8, frame->width); + break; + case 2: + orc_matrix3_000_u8 (dest, src1, src2, src3, + matrix[8], matrix[9], matrix[10], matrix[11], 8, frame->width); + break; + default: + break; + } + +} + +CogFrame * +cog_virt_frame_new_color_matrix_YCbCr_to_YCbCr (CogFrame * vf, + CogColorMatrix in_color_matrix, CogColorMatrix out_color_matrix, int bits) +{ + CogFrame *virt_frame; + + virt_frame = cog_frame_new_virtual (NULL, COG_FRAME_FORMAT_U8_444, + vf->width, vf->height); + virt_frame->virt_frame1 = vf; + virt_frame->render_line = color_matrix_YCbCr_to_YCbCr; + if (in_color_matrix == COG_COLOR_MATRIX_HDTV) { + virt_frame->virt_priv2 = (void *) cog_ycbcr_hdtv_to_ycbcr_sdtv_matrix_8bit; + } else { + virt_frame->virt_priv2 = (void *) cog_ycbcr_sdtv_to_ycbcr_hdtv_matrix_8bit; + } + + return virt_frame; +} + + static void convert_444_422 (CogFrame * frame, void *_dest, int component, int i) { diff --git a/ext/cog/cogvirtframe.h b/ext/cog/cogvirtframe.h index dfe405a5b4..2054e9586f 100644 --- a/ext/cog/cogvirtframe.h +++ b/ext/cog/cogvirtframe.h @@ -29,6 +29,9 @@ 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, CogColorMatrix color_matrix, int coefficient_bits); CogFrame * cog_virt_frame_new_color_matrix_RGB_to_YCbCr (CogFrame * vf, CogColorMatrix color_matrix, int coefficient_bits); +CogFrame * cog_virt_frame_new_color_matrix_YCbCr_to_YCbCr (CogFrame * vf, + CogColorMatrix in_color_matrix, CogColorMatrix out_color_matrix, + int bits); CogFrame *cog_virt_frame_new_subsample (CogFrame *vf, CogFrameFormat format, int n_taps); CogFrame * cog_virt_frame_new_convert_u8 (CogFrame *vf); diff --git a/ext/cog/generate_tables.c b/ext/cog/generate_tables.c index 224e5693ba..ca6e0f8534 100644 --- a/ext/cog/generate_tables.c +++ b/ext/cog/generate_tables.c @@ -180,6 +180,60 @@ main (int argc, char *argv[]) } } + { + int cm, bits; + + for (cm = 0; cm < 2; cm++) { + for (bits = 8; bits <= 8; bits += 1) { + + ColorMatrix matrix; + + 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, RGB -> YCbCr */ + if (cm) { + color_matrix_YCbCr_to_RGB (&matrix, 0.2126, 0.0722); /* HD */ + color_matrix_RGB_to_YCbCr (&matrix, 0.2990, 0.1140); /* SD */ + } else { + color_matrix_YCbCr_to_RGB (&matrix, 0.2990, 0.1140); /* SD */ + color_matrix_RGB_to_YCbCr (&matrix, 0.2126, 0.0722); /* HD */ + } + + /* + * We are now in YCbCr space + */ + + color_matrix_scale_components (&matrix, 219.0, 224.0, 224.0); + + color_matrix_offset_components (&matrix, 16, 128, 128); + + /* 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_%s_to_ycbcr_%s_matrix_%dbit[] = {\n", + cm ? "hdtv" : "sdtv", cm ? "sdtv" : "hdtv", bits); + g_print (" %d, %d, %d, %d,\n", (int) rint (matrix.m[0][0]), + (int) rint (matrix.m[0][1]), (int) rint (matrix.m[0][2]), + (int) rint (matrix.m[0][3])); + g_print (" %d, %d, %d, %d,\n", (int) rint (matrix.m[1][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]), + (int) rint (matrix.m[2][1]), (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 b2b7c1514e..5f9d38ea8b 100644 --- a/ext/cog/gstcogcolorspace.c +++ b/ext/cog/gstcogcolorspace.c @@ -57,7 +57,6 @@ struct _GstCogcolorspace GstBaseTransform base_transform; int quality; - CogColorMatrix color_matrix; }; struct _GstCogcolorspaceClass @@ -76,13 +75,11 @@ enum }; #define DEFAULT_QUALITY 5 -#define DEFAULT_COLOR_MATRIX COG_COLOR_MATRIX_UNKNOWN enum { PROP_0, - PROP_QUALITY, - PROP_COLOR_MATRIX + PROP_QUALITY }; static void gst_cogcolorspace_set_property (GObject * object, guint prop_id, @@ -122,27 +119,6 @@ static GstStaticPadTemplate gst_cogcolorspace_src_template = GST_BOILERPLATE (GstCogcolorspace, gst_cogcolorspace, GstBaseTransform, GST_TYPE_BASE_TRANSFORM); -GType -gst_cog_color_matrix_get_type (void) -{ - 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 (g_once_init_enter (&id)) { - GType tmp = g_enum_register_static ("CogColorMatrix", values); - g_once_init_leave (&id, tmp); - } - - return (GType) id; -} - static void gst_cogcolorspace_base_init (gpointer g_class) { @@ -177,11 +153,6 @@ 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 | 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; @@ -197,7 +168,6 @@ gst_cogcolorspace_init (GstCogcolorspace * colorspace, GST_DEBUG ("gst_cogcolorspace_init"); colorspace->quality = DEFAULT_QUALITY; - colorspace->color_matrix = DEFAULT_COLOR_MATRIX; } static void @@ -216,11 +186,6 @@ 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; } @@ -241,11 +206,6 @@ 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; @@ -314,6 +274,7 @@ gst_cogcolorspace_caps_remove_format_info (GstCaps * caps) gst_structure_remove_field (structure, "blue_mask"); gst_structure_remove_field (structure, "alpha_mask"); gst_structure_remove_field (structure, "palette_data"); + gst_structure_remove_field (structure, "color-matrix"); } gst_caps_do_simplify (caps); @@ -385,6 +346,25 @@ gst_cogcolorspace_get_unit_size (GstBaseTransform * base_transform, return TRUE; } +static CogColorMatrix +gst_cogcolorspace_caps_get_color_matrix (GstCaps * caps) +{ + const char *s; + + s = gst_video_parse_caps_color_matrix (caps); + + if (s == NULL) + return COG_COLOR_MATRIX_SDTV; + + if (strcmp (s, "sdtv") == 0) { + return COG_COLOR_MATRIX_SDTV; + } else if (strcmp (s, "hdtv") == 0) { + return COG_COLOR_MATRIX_HDTV; + } + + return COG_COLOR_MATRIX_SDTV; +} + static GstFlowReturn gst_cogcolorspace_transform (GstBaseTransform * base_transform, GstBuffer * inbuf, GstBuffer * outbuf) @@ -397,17 +377,22 @@ gst_cogcolorspace_transform (GstBaseTransform * base_transform, uint32_t out_format; CogFrameFormat new_subsample; gboolean ret; + CogColorMatrix in_color_matrix; + CogColorMatrix out_color_matrix; g_return_val_if_fail (GST_IS_COGCOLORSPACE (base_transform), GST_FLOW_ERROR); compress = GST_COGCOLORSPACE (base_transform); ret = gst_video_format_parse_caps (inbuf->caps, &in_format, &width, &height); - ret |= + ret &= gst_video_format_parse_caps (outbuf->caps, &out_format, &width, &height); if (!ret) { return GST_FLOW_ERROR; } + in_color_matrix = gst_cogcolorspace_caps_get_color_matrix (inbuf->caps); + out_color_matrix = gst_cogcolorspace_caps_get_color_matrix (outbuf->caps); + frame = gst_cog_buffer_wrap (gst_buffer_ref (inbuf), in_format, width, height); out_frame = gst_cog_buffer_wrap (gst_buffer_ref (outbuf), @@ -445,7 +430,16 @@ 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, - compress->color_matrix, 8); + out_color_matrix, 8); + } + + if (gst_video_format_is_yuv (out_format) && + gst_video_format_is_yuv (in_format) && + in_color_matrix != out_color_matrix) { + frame = cog_virt_frame_new_subsample (frame, COG_FRAME_FORMAT_U8_444, + (compress->quality >= 5) ? 8 : 6); + frame = cog_virt_frame_new_color_matrix_YCbCr_to_YCbCr (frame, + in_color_matrix, out_color_matrix, 8); } frame = cog_virt_frame_new_subsample (frame, new_subsample, @@ -454,7 +448,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->color_matrix, (compress->quality >= 5) ? 8 : 6); + in_color_matrix, (compress->quality >= 5) ? 8 : 6); } switch (out_format) {