mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 12:49:40 +00:00
videoconvert: refactor matrix setup
This commit is contained in:
parent
887d442da4
commit
ec4ca4773a
2 changed files with 157 additions and 207 deletions
|
@ -36,7 +36,7 @@ static void videoconvert_convert_generic (VideoConvert * convert,
|
|||
static void videoconvert_convert_matrix (VideoConvert * convert);
|
||||
static void videoconvert_convert_matrix16 (VideoConvert * convert);
|
||||
static gboolean videoconvert_convert_lookup_fastpath (VideoConvert * convert);
|
||||
static void videoconvert_convert_compute_matrix (VideoConvert * convert);
|
||||
static gboolean videoconvert_convert_compute_matrix (VideoConvert * convert);
|
||||
static void videoconvert_dither_none (VideoConvert * convert, int j);
|
||||
static void videoconvert_dither_verterr (VideoConvert * convert, int j);
|
||||
static void videoconvert_dither_halftone (VideoConvert * convert, int j);
|
||||
|
@ -56,7 +56,8 @@ videoconvert_convert_new (GstVideoInfo * in_info, GstVideoInfo * out_info)
|
|||
|
||||
if (!videoconvert_convert_lookup_fastpath (convert)) {
|
||||
convert->convert = videoconvert_convert_generic;
|
||||
videoconvert_convert_compute_matrix (convert);
|
||||
if (!videoconvert_convert_compute_matrix (convert))
|
||||
goto no_convert;
|
||||
}
|
||||
|
||||
convert->width = GST_VIDEO_INFO_WIDTH (in_info);
|
||||
|
@ -90,6 +91,13 @@ videoconvert_convert_new (GstVideoInfo * in_info, GstVideoInfo * out_info)
|
|||
palette[i++] = 0xff000000;
|
||||
}
|
||||
return convert;
|
||||
|
||||
/* ERRORS */
|
||||
no_convert:
|
||||
{
|
||||
videoconvert_convert_free (convert);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -186,128 +194,144 @@ matrix_identity (VideoConvert * convert)
|
|||
}
|
||||
|
||||
static void
|
||||
get_offset_scale (const GstVideoFormatInfo * finfo, GstVideoColorRange range,
|
||||
gint depth, gint offset[4], gint scale[4])
|
||||
{
|
||||
gint minL, minC, baseL, baseC, maxL, maxC;
|
||||
|
||||
if (depth < 8)
|
||||
depth = 8;
|
||||
|
||||
switch (range) {
|
||||
default:
|
||||
case GST_VIDEO_COLOR_RANGE_0_255:
|
||||
minL = minC = 0;
|
||||
baseL = 0;
|
||||
baseC = 128 << (depth - 8);
|
||||
maxL = (1 << depth) - 1;
|
||||
maxC = (1 << depth) - 1;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_RANGE_16_235:
|
||||
minL = 16 << (depth - 8);
|
||||
minC = 16 << (depth - 8);
|
||||
baseL = minL;
|
||||
baseC = 128 << (depth - 8);
|
||||
maxL = 235 << (depth - 8);
|
||||
maxC = 240 << (depth - 8);
|
||||
break;
|
||||
}
|
||||
|
||||
if (GST_VIDEO_FORMAT_INFO_IS_YUV (finfo)) {
|
||||
offset[0] = 0;
|
||||
offset[1] = baseL;
|
||||
offset[2] = offset[3] = baseC;
|
||||
scale[0] = 0;
|
||||
scale[1] = maxL - minL;
|
||||
scale[2] = scale[3] = maxC - minC;
|
||||
} else if (GST_VIDEO_FORMAT_INFO_IS_RGB (finfo)) {
|
||||
offset[0] = 0;
|
||||
offset[1] = offset[2] = offset[3] = baseL;
|
||||
scale[0] = 0;
|
||||
scale[1] = scale[2] = scale[3] = maxL - minL;
|
||||
} else if (GST_VIDEO_FORMAT_INFO_IS_GRAY (finfo)) {
|
||||
offset[0] = offset[2] = offset[3] = 0;
|
||||
offset[1] = baseL;
|
||||
scale[0] = scale[2] = scale[3] = 0;
|
||||
scale[1] = maxL - minL;
|
||||
} else {
|
||||
offset[0] = offset[1] = offset[2] = offset[3] = 0;
|
||||
scale[0] = scale[1] = scale[2] = scale[3] = (maxL - minL);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
get_Kr_Kb (GstVideoColorMatrix matrix, gdouble * Kr, gdouble * Kb)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
|
||||
switch (matrix) {
|
||||
/* RGB */
|
||||
default:
|
||||
case GST_VIDEO_COLOR_MATRIX_RGB:
|
||||
res = FALSE;
|
||||
break;
|
||||
/* YUV */
|
||||
case GST_VIDEO_COLOR_MATRIX_FCC:
|
||||
*Kr = 0.30;
|
||||
*Kb = 0.11;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_BT709:
|
||||
*Kr = 0.2126;
|
||||
*Kb = 0.0722;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_BT601:
|
||||
*Kr = 0.2990;
|
||||
*Kb = 0.1140;
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
|
||||
*Kr = 0.212;
|
||||
*Kb = 0.087;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
videoconvert_convert_compute_matrix (VideoConvert * convert)
|
||||
{
|
||||
GstVideoInfo *in_info, *out_info;
|
||||
ColorMatrix dst;
|
||||
gint i, j;
|
||||
const GstVideoFormatInfo *sfinfo, *dfinfo;
|
||||
gboolean use_16;
|
||||
gint in_bits, out_bits;
|
||||
gint depth;
|
||||
gint offset[4], scale[4];
|
||||
gdouble Kr, Kb;
|
||||
|
||||
in_info = &convert->in_info;
|
||||
out_info = &convert->out_info;
|
||||
|
||||
sfinfo = in_info->finfo;
|
||||
dfinfo = out_info->finfo;
|
||||
|
||||
if (sfinfo->unpack_func == NULL)
|
||||
goto no_unpack_func;
|
||||
|
||||
if (dfinfo->pack_func == NULL)
|
||||
goto no_pack_func;
|
||||
|
||||
convert->in_bits =
|
||||
GST_VIDEO_FORMAT_INFO_DEPTH (gst_video_format_get_info
|
||||
(sfinfo->unpack_format), 0);
|
||||
convert->out_bits =
|
||||
GST_VIDEO_FORMAT_INFO_DEPTH (gst_video_format_get_info
|
||||
(dfinfo->unpack_format), 0);
|
||||
|
||||
if (in_info->colorimetry.range == out_info->colorimetry.range &&
|
||||
in_info->colorimetry.matrix == out_info->colorimetry.matrix) {
|
||||
GST_DEBUG ("using identity color transform");
|
||||
convert->matrix = matrix_identity;
|
||||
convert->matrix16 = matrix_identity;
|
||||
return;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
sfinfo = in_info->finfo;
|
||||
dfinfo = out_info->finfo;
|
||||
|
||||
in_bits =
|
||||
GST_VIDEO_FORMAT_INFO_DEPTH (gst_video_format_get_info
|
||||
(sfinfo->unpack_format), 0);
|
||||
out_bits =
|
||||
GST_VIDEO_FORMAT_INFO_DEPTH (gst_video_format_get_info
|
||||
(dfinfo->unpack_format), 0);
|
||||
|
||||
if (in_bits == 16 || out_bits == 16)
|
||||
use_16 = TRUE;
|
||||
if (convert->in_bits == 16 || convert->out_bits == 16)
|
||||
depth = 16;
|
||||
else
|
||||
use_16 = FALSE;
|
||||
depth = 8;
|
||||
|
||||
color_matrix_set_identity (&dst);
|
||||
|
||||
/* 1, bring color components to [0..1.0] range */
|
||||
switch (in_info->colorimetry.range) {
|
||||
case GST_VIDEO_COLOR_RANGE_0_255:
|
||||
switch (in_info->finfo->unpack_format) {
|
||||
case GST_VIDEO_FORMAT_AYUV:
|
||||
case GST_VIDEO_FORMAT_AYUV64:
|
||||
GST_DEBUG ("using 0-255 input range YUV");
|
||||
if (use_16) {
|
||||
color_matrix_offset_components (&dst, 0, -32768, -32768);
|
||||
color_matrix_scale_components (&dst, (1 / 65535.0), (1 / 65535.0),
|
||||
(1 / 65535.0));
|
||||
} else {
|
||||
color_matrix_offset_components (&dst, 0, -128, -128);
|
||||
color_matrix_scale_components (&dst, (1 / 255.0), (1 / 255.0),
|
||||
(1 / 255.0));
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
case GST_VIDEO_FORMAT_ARGB64:
|
||||
GST_DEBUG ("using 0-255 input range RGB");
|
||||
if (use_16)
|
||||
color_matrix_scale_components (&dst, (1 / 65535.0), (1 / 65535.0),
|
||||
(1 / 65535.0));
|
||||
else
|
||||
color_matrix_scale_components (&dst, (1 / 255.0), (1 / 255.0),
|
||||
(1 / 255.0));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
case GST_VIDEO_COLOR_RANGE_16_235:
|
||||
/* offset ans scale required to get input video black to (0.,0.,0.) */
|
||||
switch (in_info->finfo->unpack_format) {
|
||||
case GST_VIDEO_FORMAT_AYUV:
|
||||
case GST_VIDEO_FORMAT_AYUV64:
|
||||
GST_DEBUG ("using 16-235 input range YUV");
|
||||
if (use_16) {
|
||||
color_matrix_offset_components (&dst, -4096, -32768, -32768);
|
||||
color_matrix_scale_components (&dst, (1 / 56064.0), (1 / 57344.0),
|
||||
(1 / 57344.0));
|
||||
} else {
|
||||
color_matrix_offset_components (&dst, -16, -128, -128);
|
||||
color_matrix_scale_components (&dst, (1 / 219.0), (1 / 224.0),
|
||||
(1 / 224.0));
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
case GST_VIDEO_FORMAT_ARGB64:
|
||||
GST_DEBUG ("using 16-235 input range RGB");
|
||||
if (use_16) {
|
||||
color_matrix_offset_components (&dst, -4096, -4096, -4096);
|
||||
color_matrix_scale_components (&dst, (1 / 56064.0), (1 / 56064.0),
|
||||
(1 / 56064.0));
|
||||
} else {
|
||||
color_matrix_offset_components (&dst, -16, -16, -16);
|
||||
color_matrix_scale_components (&dst, (1 / 219.0), (1 / 219.0),
|
||||
(1 / 219.0));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
get_offset_scale (sfinfo, in_info->colorimetry.range, depth, offset, scale);
|
||||
|
||||
color_matrix_offset_components (&dst, -offset[1], -offset[2], -offset[3]);
|
||||
color_matrix_scale_components (&dst, 1 / ((float) scale[1]),
|
||||
1 / ((float) scale[2]), 1 / ((float) scale[3]));
|
||||
|
||||
/* 2. bring components to R'G'B' space */
|
||||
switch (in_info->colorimetry.matrix) {
|
||||
case GST_VIDEO_COLOR_MATRIX_RGB:
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_FCC:
|
||||
color_matrix_YCbCr_to_RGB (&dst, 0.30, 0.11);
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_BT709:
|
||||
color_matrix_YCbCr_to_RGB (&dst, 0.2126, 0.0722);
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_BT601:
|
||||
color_matrix_YCbCr_to_RGB (&dst, 0.2990, 0.1140);
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
|
||||
color_matrix_YCbCr_to_RGB (&dst, 0.212, 0.087);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (get_Kr_Kb (in_info->colorimetry.matrix, &Kr, &Kb))
|
||||
color_matrix_YCbCr_to_RGB (&dst, Kr, Kb);
|
||||
|
||||
/* 3. inverse transfer function. R'G'B' to linear RGB */
|
||||
|
||||
/* 4. from RGB to XYZ using the primaries */
|
||||
|
@ -317,87 +341,15 @@ videoconvert_convert_compute_matrix (VideoConvert * convert)
|
|||
/* 6. transfer function. linear RGB to R'G'B' */
|
||||
|
||||
/* 7. bring components to YCbCr space */
|
||||
switch (out_info->colorimetry.matrix) {
|
||||
case GST_VIDEO_COLOR_MATRIX_RGB:
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_FCC:
|
||||
color_matrix_RGB_to_YCbCr (&dst, 0.30, 0.11);
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_BT709:
|
||||
color_matrix_RGB_to_YCbCr (&dst, 0.2126, 0.0722);
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_BT601:
|
||||
color_matrix_RGB_to_YCbCr (&dst, 0.2990, 0.1140);
|
||||
break;
|
||||
case GST_VIDEO_COLOR_MATRIX_SMPTE240M:
|
||||
color_matrix_RGB_to_YCbCr (&dst, 0.212, 0.087);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (get_Kr_Kb (out_info->colorimetry.matrix, &Kr, &Kb))
|
||||
color_matrix_RGB_to_YCbCr (&dst, Kr, Kb);
|
||||
|
||||
/* 8, bring color components to nominal range */
|
||||
switch (out_info->colorimetry.range) {
|
||||
case GST_VIDEO_COLOR_RANGE_0_255:
|
||||
switch (out_info->finfo->unpack_format) {
|
||||
case GST_VIDEO_FORMAT_AYUV:
|
||||
case GST_VIDEO_FORMAT_AYUV64:
|
||||
GST_DEBUG ("using 0-255 output range YUV");
|
||||
if (use_16) {
|
||||
color_matrix_scale_components (&dst, 65535.0, 65535.0, 65535.0);
|
||||
color_matrix_offset_components (&dst, 0, 32768, 32768);
|
||||
} else {
|
||||
color_matrix_scale_components (&dst, 255.0, 255.0, 255.0);
|
||||
color_matrix_offset_components (&dst, 0, 128, 128);
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
case GST_VIDEO_FORMAT_ARGB64:
|
||||
GST_DEBUG ("using 0-255 output range RGB");
|
||||
if (use_16)
|
||||
color_matrix_scale_components (&dst, 65535.0, 65535.0, 65535.0);
|
||||
else
|
||||
color_matrix_scale_components (&dst, 255.0, 255.0, 255.0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
GST_DEBUG ("using 0-255 output range");
|
||||
if (use_16)
|
||||
color_matrix_scale_components (&dst, 65535.0, 65535.0, 65535.0);
|
||||
else
|
||||
color_matrix_scale_components (&dst, 255.0, 255.0, 255.0);
|
||||
break;
|
||||
case GST_VIDEO_COLOR_RANGE_16_235:
|
||||
default:
|
||||
switch (out_info->finfo->unpack_format) {
|
||||
case GST_VIDEO_FORMAT_AYUV:
|
||||
case GST_VIDEO_FORMAT_AYUV64:
|
||||
GST_DEBUG ("using 16-235 output range YUV");
|
||||
if (use_16) {
|
||||
color_matrix_scale_components (&dst, 56064.0, 57344.0, 57344.0);
|
||||
color_matrix_offset_components (&dst, 4096, 32768, 32768);
|
||||
} else {
|
||||
color_matrix_scale_components (&dst, 219.0, 224.0, 224.0);
|
||||
color_matrix_offset_components (&dst, 16, 128, 128);
|
||||
}
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
case GST_VIDEO_FORMAT_ARGB64:
|
||||
GST_DEBUG ("using 16-235 output range RGB");
|
||||
if (use_16) {
|
||||
color_matrix_scale_components (&dst, 56064.0, 56064.0, 56064.0);
|
||||
color_matrix_offset_components (&dst, 4096, 4096, 4096);
|
||||
} else {
|
||||
color_matrix_scale_components (&dst, 219.0, 219.0, 219.0);
|
||||
color_matrix_offset_components (&dst, 16, 16, 16);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
get_offset_scale (dfinfo, out_info->colorimetry.range, depth, offset, scale);
|
||||
color_matrix_scale_components (&dst, (float) scale[1], (float) scale[2],
|
||||
(float) scale[3]);
|
||||
color_matrix_offset_components (&dst, offset[1], offset[2], offset[3]);
|
||||
|
||||
/* because we're doing 8-bit matrix coefficients */
|
||||
color_matrix_scale_components (&dst, 256.0, 256.0, 256.0);
|
||||
|
||||
|
@ -416,6 +368,22 @@ videoconvert_convert_compute_matrix (VideoConvert * convert)
|
|||
|
||||
convert->matrix = videoconvert_convert_matrix;
|
||||
convert->matrix16 = videoconvert_convert_matrix16;
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS */
|
||||
no_unpack_func:
|
||||
{
|
||||
GST_ERROR ("no unpack_func for format %s",
|
||||
gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (in_info)));
|
||||
return FALSE;
|
||||
}
|
||||
no_pack_func:
|
||||
{
|
||||
GST_ERROR ("no pack_func for format %s",
|
||||
gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (out_info)));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -479,57 +447,37 @@ videoconvert_convert_generic (VideoConvert * convert, GstVideoFrame * dest,
|
|||
const GstVideoFrame * src)
|
||||
{
|
||||
int i, j;
|
||||
const GstVideoFormatInfo *sfinfo, *dfinfo;
|
||||
gint width, height;
|
||||
guint src_bits, dest_bits;
|
||||
|
||||
sfinfo = src->info.finfo;
|
||||
dfinfo = dest->info.finfo;
|
||||
|
||||
src_bits =
|
||||
GST_VIDEO_FORMAT_INFO_DEPTH (gst_video_format_get_info
|
||||
(sfinfo->unpack_format), 0);
|
||||
dest_bits =
|
||||
GST_VIDEO_FORMAT_INFO_DEPTH (gst_video_format_get_info
|
||||
(dfinfo->unpack_format), 0);
|
||||
guint in_bits, out_bits;
|
||||
|
||||
height = convert->height;
|
||||
width = convert->width;
|
||||
|
||||
if (sfinfo->unpack_func == NULL) {
|
||||
GST_ERROR ("no unpack_func for format %s",
|
||||
gst_video_format_to_string (GST_VIDEO_FRAME_FORMAT (src)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (dfinfo->pack_func == NULL) {
|
||||
GST_ERROR ("no pack_func for format %s",
|
||||
gst_video_format_to_string (GST_VIDEO_FRAME_FORMAT (dest)));
|
||||
return;
|
||||
}
|
||||
in_bits = convert->in_bits;
|
||||
out_bits = convert->out_bits;
|
||||
|
||||
for (j = 0; j < height; j++) {
|
||||
if (src_bits == 16) {
|
||||
if (in_bits == 16) {
|
||||
UNPACK_FRAME (src, convert->tmpline16, j, width);
|
||||
} else {
|
||||
UNPACK_FRAME (src, convert->tmpline, j, width);
|
||||
|
||||
if (dest_bits == 16)
|
||||
if (out_bits == 16)
|
||||
for (i = 0; i < width * 4; i++)
|
||||
convert->tmpline16[i] = TO_16 (convert->tmpline[i]);
|
||||
}
|
||||
|
||||
if (dest_bits == 16 || src_bits == 16) {
|
||||
if (out_bits == 16 || in_bits == 16) {
|
||||
convert->matrix16 (convert);
|
||||
convert->dither16 (convert, j);
|
||||
} else {
|
||||
convert->matrix (convert);
|
||||
}
|
||||
|
||||
if (dest_bits == 16) {
|
||||
if (out_bits == 16) {
|
||||
PACK_FRAME (dest, convert->tmpline16, j, width);
|
||||
} else {
|
||||
if (src_bits == 16)
|
||||
if (in_bits == 16)
|
||||
for (i = 0; i < width * 4; i++)
|
||||
convert->tmpline[i] = convert->tmpline16[i] >> 8;
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@ struct _VideoConvert {
|
|||
gint width;
|
||||
gint height;
|
||||
|
||||
gint in_bits;
|
||||
gint out_bits;
|
||||
gint cmatrix[4][4];
|
||||
|
||||
guint32 *palette;
|
||||
|
|
Loading…
Reference in a new issue