cogcolorspace: implement color-matrix handling

This commit is contained in:
David Schleef 2010-03-14 18:56:06 -07:00
parent a37a68b7b7
commit 8272df7fb9
5 changed files with 199 additions and 47 deletions

View file

@ -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

View file

@ -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)
{

View file

@ -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);

View file

@ -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;
}

View file

@ -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) {