mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-17 12:55:53 +00:00
coloreffects: add ayuv support
Currently implemented switching from yuv to rgb, looking up rgb from the table in the usual way, getting back to yuv. With luma lookup presets (sepia, heat, xray) a color space conversion is saved directly looking up rgb for a given Y and converting to yuv. Probably this latter step can even be made faster precalculating a luma to yuv table in an outer loop. https://bugzilla.gnome.org/show_bug.cgi?id=625817
This commit is contained in:
parent
79c343bade
commit
74de641ca4
2 changed files with 175 additions and 45 deletions
|
@ -55,7 +55,8 @@ GST_BOILERPLATE (GstColorEffects, gst_color_effects, GstVideoFilter,
|
|||
GST_VIDEO_CAPS_ABGR ";" GST_VIDEO_CAPS_RGBA ";"\
|
||||
GST_VIDEO_CAPS_xRGB ";" GST_VIDEO_CAPS_RGBx ";"\
|
||||
GST_VIDEO_CAPS_xBGR ";" GST_VIDEO_CAPS_BGRx ";"\
|
||||
GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";"
|
||||
GST_VIDEO_CAPS_RGB ";" GST_VIDEO_CAPS_BGR ";" \
|
||||
GST_VIDEO_CAPS_YUV ("AYUV") ";"
|
||||
|
||||
static GstStaticPadTemplate gst_color_effects_src_template =
|
||||
GST_STATIC_PAD_TEMPLATE ("src",
|
||||
|
@ -251,58 +252,30 @@ static const guint8 xpro_table[768] =
|
|||
"\376\365\377\377\365\377\377\366\377\377\366\377\377\366\377\377\367\377"
|
||||
"\377\367\377\377\367\377\377\370";
|
||||
|
||||
static gboolean
|
||||
gst_color_effects_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
|
||||
GstCaps * outcaps)
|
||||
static const int cog_ycbcr_to_rgb_matrix_8bit_sdtv[] = {
|
||||
298, 0, 409, -57068,
|
||||
298, -100, -208, 34707,
|
||||
298, 516, 0, -70870,
|
||||
};
|
||||
|
||||
static const gint cog_rgb_to_ycbcr_matrix_8bit_sdtv[] = {
|
||||
66, 129, 25, 4096,
|
||||
-38, -74, 112, 32768,
|
||||
112, -94, -18, 32768,
|
||||
};
|
||||
|
||||
#define APPLY_MATRIX(m,o,v1,v2,v3) ((m[o*4] * v1 + m[o*4+1] * v2 + m[o*4+2] * v3 + m[o*4+3]) >> 8)
|
||||
|
||||
static void
|
||||
gst_color_effects_transform_rgb (GstColorEffects * filter, guint8 * data)
|
||||
{
|
||||
GstColorEffects *filter = GST_COLOR_EFFECTS (btrans);
|
||||
|
||||
GST_DEBUG_OBJECT (filter,
|
||||
"in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps);
|
||||
|
||||
if (!gst_video_format_parse_caps (incaps, &filter->format,
|
||||
&filter->width, &filter->height))
|
||||
goto invalid_caps;
|
||||
|
||||
GST_OBJECT_LOCK (filter);
|
||||
|
||||
filter->size =
|
||||
gst_video_format_get_size (filter->format, filter->width, filter->height);
|
||||
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
|
||||
return TRUE;
|
||||
|
||||
invalid_caps:
|
||||
GST_ERROR_OBJECT (filter, "Invalid caps: %" GST_PTR_FORMAT, incaps);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_color_effects_transform_ip (GstBaseTransform * trans, GstBuffer * out)
|
||||
{
|
||||
GstColorEffects *filter = GST_COLOR_EFFECTS (trans);
|
||||
guint8 *data;
|
||||
gint i, j;
|
||||
gint size;
|
||||
gint width, height;
|
||||
gint pixel_stride, row_stride, row_wrap;
|
||||
guint32 r, g, b;
|
||||
guint32 luma;
|
||||
gint offsets[3];
|
||||
|
||||
data = GST_BUFFER_DATA (out);
|
||||
size = GST_BUFFER_SIZE (out);
|
||||
|
||||
if (size != filter->size)
|
||||
goto wrong_size;
|
||||
|
||||
/* do nothing if there is no table ("none" preset) */
|
||||
if (filter->table == NULL)
|
||||
return GST_FLOW_OK;
|
||||
|
||||
GST_OBJECT_LOCK (filter);
|
||||
|
||||
/* videoformat fun copied from videobalance */
|
||||
|
||||
offsets[0] = gst_video_format_get_component_offset (filter->format, 0,
|
||||
|
@ -352,7 +325,159 @@ gst_color_effects_transform_ip (GstBaseTransform * trans, GstBuffer * out)
|
|||
}
|
||||
data += row_wrap;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_color_effects_transform_ayuv (GstColorEffects * filter, guint8 * data)
|
||||
{
|
||||
gint i, j;
|
||||
gint width, height;
|
||||
gint pixel_stride, row_stride, row_wrap;
|
||||
gint r, g, b;
|
||||
gint y, u, v;
|
||||
gint offsets[3];
|
||||
|
||||
/* videoformat fun copied from videobalance */
|
||||
|
||||
offsets[0] = gst_video_format_get_component_offset (filter->format, 0,
|
||||
filter->width, filter->height);
|
||||
offsets[1] = gst_video_format_get_component_offset (filter->format, 1,
|
||||
filter->width, filter->height);
|
||||
offsets[2] = gst_video_format_get_component_offset (filter->format, 2,
|
||||
filter->width, filter->height);
|
||||
|
||||
width =
|
||||
gst_video_format_get_component_width (filter->format, 0, filter->width);
|
||||
height =
|
||||
gst_video_format_get_component_height (filter->format, 0, filter->height);
|
||||
row_stride =
|
||||
gst_video_format_get_row_stride (filter->format, 0, filter->width);
|
||||
pixel_stride = gst_video_format_get_pixel_stride (filter->format, 0);
|
||||
row_wrap = row_stride - pixel_stride * width;
|
||||
|
||||
for (i = 0; i < height; i++) {
|
||||
for (j = 0; j < width; j++) {
|
||||
y = data[offsets[0]];
|
||||
u = data[offsets[1]];
|
||||
v = data[offsets[2]];
|
||||
|
||||
if (filter->map_luma) {
|
||||
/* map luma to lookup table */
|
||||
/* src.luma |-> table[luma].rgb */
|
||||
y *= 3;
|
||||
r = filter->table[y];
|
||||
g = filter->table[y + 1];
|
||||
b = filter->table[y + 2];
|
||||
|
||||
y = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 0, r, g, b);
|
||||
u = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 1, r, g, b);
|
||||
v = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 2, r, g, b);
|
||||
|
||||
data[offsets[0]] = CLAMP (y, 0, 255);
|
||||
data[offsets[1]] = CLAMP (u, 0, 255);
|
||||
data[offsets[2]] = CLAMP (v, 0, 255);
|
||||
} else {
|
||||
r = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 0, y, u, v);
|
||||
g = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 1, y, u, v);
|
||||
b = APPLY_MATRIX (cog_ycbcr_to_rgb_matrix_8bit_sdtv, 2, y, u, v);
|
||||
|
||||
r = CLAMP (r, 0, 255);
|
||||
g = CLAMP (g, 0, 255);
|
||||
b = CLAMP (b, 0, 255);
|
||||
|
||||
/* map each color component to the correspondent lut color */
|
||||
/* src.r |-> table[r].r */
|
||||
/* src.g |-> table[g].g */
|
||||
/* src.b |-> table[b].b */
|
||||
r = filter->table[r * 3];
|
||||
g = filter->table[g * 3 + 1];
|
||||
b = filter->table[b * 3 + 2];
|
||||
|
||||
y = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 0, r, g, b);
|
||||
u = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 1, r, g, b);
|
||||
v = APPLY_MATRIX (cog_rgb_to_ycbcr_matrix_8bit_sdtv, 2, r, g, b);
|
||||
|
||||
data[offsets[0]] = CLAMP (y, 0, 255);
|
||||
data[offsets[1]] = CLAMP (u, 0, 255);
|
||||
data[offsets[2]] = CLAMP (v, 0, 255);
|
||||
}
|
||||
data += pixel_stride;
|
||||
}
|
||||
data += row_wrap;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_color_effects_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
|
||||
GstCaps * outcaps)
|
||||
{
|
||||
GstColorEffects *filter = GST_COLOR_EFFECTS (btrans);
|
||||
|
||||
GST_DEBUG_OBJECT (filter,
|
||||
"in %" GST_PTR_FORMAT " out %" GST_PTR_FORMAT, incaps, outcaps);
|
||||
|
||||
filter->process = NULL;
|
||||
|
||||
if (!gst_video_format_parse_caps (incaps, &filter->format,
|
||||
&filter->width, &filter->height))
|
||||
goto invalid_caps;
|
||||
|
||||
GST_OBJECT_LOCK (filter);
|
||||
|
||||
filter->size =
|
||||
gst_video_format_get_size (filter->format, filter->width, filter->height);
|
||||
|
||||
switch (filter->format) {
|
||||
case GST_VIDEO_FORMAT_AYUV:
|
||||
filter->process = gst_color_effects_transform_ayuv;
|
||||
break;
|
||||
case GST_VIDEO_FORMAT_ARGB:
|
||||
case GST_VIDEO_FORMAT_ABGR:
|
||||
case GST_VIDEO_FORMAT_RGBA:
|
||||
case GST_VIDEO_FORMAT_BGRA:
|
||||
case GST_VIDEO_FORMAT_xRGB:
|
||||
case GST_VIDEO_FORMAT_xBGR:
|
||||
case GST_VIDEO_FORMAT_RGBx:
|
||||
case GST_VIDEO_FORMAT_BGRx:
|
||||
case GST_VIDEO_FORMAT_RGB:
|
||||
case GST_VIDEO_FORMAT_BGR:
|
||||
filter->process = gst_color_effects_transform_rgb;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
|
||||
return filter->process != NULL;
|
||||
|
||||
invalid_caps:
|
||||
GST_ERROR_OBJECT (filter, "Invalid caps: %" GST_PTR_FORMAT, incaps);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_color_effects_transform_ip (GstBaseTransform * trans, GstBuffer * out)
|
||||
{
|
||||
GstColorEffects *filter = GST_COLOR_EFFECTS (trans);
|
||||
guint8 *data;
|
||||
gint size;
|
||||
|
||||
if (!filter->process)
|
||||
goto not_negotiated;
|
||||
|
||||
data = GST_BUFFER_DATA (out);
|
||||
size = GST_BUFFER_SIZE (out);
|
||||
|
||||
if (size != filter->size)
|
||||
goto wrong_size;
|
||||
|
||||
/* do nothing if there is no table ("none" preset) */
|
||||
if (filter->table == NULL)
|
||||
return GST_FLOW_OK;
|
||||
|
||||
GST_OBJECT_LOCK (filter);
|
||||
filter->process (filter, data);
|
||||
GST_OBJECT_UNLOCK (filter);
|
||||
|
||||
return GST_FLOW_OK;
|
||||
|
@ -363,6 +488,9 @@ wrong_size:
|
|||
(NULL), ("Invalid buffer size %d, expected %d", size, filter->size));
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
not_negotiated:
|
||||
GST_ERROR_OBJECT (filter, "Not negotiated yet");
|
||||
return GST_FLOW_NOT_NEGOTIATED;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -76,6 +76,8 @@ struct _GstColorEffects
|
|||
gint width;
|
||||
gint height;
|
||||
gint size;
|
||||
|
||||
void (*process) (GstColorEffects *filter, guint8 *data);
|
||||
};
|
||||
|
||||
struct _GstColorEffectsClass
|
||||
|
|
Loading…
Reference in a new issue