shapewipe: Add support for ARGB video input/output

This commit is contained in:
Sebastian Dröge 2009-07-02 11:24:48 +02:00
parent cf2b2b017f
commit 8fade13db1
2 changed files with 158 additions and 120 deletions

View file

@ -93,10 +93,10 @@ enum
}; };
static GstStaticPadTemplate video_sink_pad_template = static GstStaticPadTemplate video_sink_pad_template =
GST_STATIC_PAD_TEMPLATE ("video_sink", GST_STATIC_PAD_TEMPLATE ("video_sink",
GST_PAD_SINK, GST_PAD_SINK,
GST_PAD_ALWAYS, GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV"))); GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") " ; " GST_VIDEO_CAPS_ARGB));
static GstStaticPadTemplate mask_sink_pad_template = static GstStaticPadTemplate mask_sink_pad_template =
GST_STATIC_PAD_TEMPLATE ("mask_sink", GST_STATIC_PAD_TEMPLATE ("mask_sink",
@ -112,8 +112,8 @@ static GstStaticPadTemplate mask_sink_pad_template =
"height = " GST_VIDEO_SIZE_RANGE ", " "framerate = 0/1")); "height = " GST_VIDEO_SIZE_RANGE ", " "framerate = 0/1"));
static GstStaticPadTemplate src_pad_template = static GstStaticPadTemplate src_pad_template =
GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV"))); GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV") " ; " GST_VIDEO_CAPS_ARGB));
GST_DEBUG_CATEGORY_STATIC (gst_shape_wipe_debug); GST_DEBUG_CATEGORY_STATIC (gst_shape_wipe_debug);
#define GST_CAT_DEFAULT gst_shape_wipe_debug #define GST_CAT_DEFAULT gst_shape_wipe_debug
@ -273,6 +273,7 @@ gst_shape_wipe_reset (GstShapeWipe * self)
g_cond_signal (self->mask_cond); g_cond_signal (self->mask_cond);
self->fmt = GST_VIDEO_FORMAT_UNKNOWN;
self->width = self->height = 0; self->width = self->height = 0;
self->mask_position = 0.0; self->mask_position = 0.0;
self->mask_border = 0.0; self->mask_border = 0.0;
@ -309,6 +310,7 @@ gst_shape_wipe_video_sink_setcaps (GstPad * pad, GstCaps * caps)
GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad)); GstShapeWipe *self = GST_SHAPE_WIPE (gst_pad_get_parent (pad));
gboolean ret = TRUE; gboolean ret = TRUE;
GstStructure *s; GstStructure *s;
GstVideoFormat fmt;
gint width, height; gint width, height;
gint fps_n, fps_d; gint fps_n, fps_d;
@ -316,13 +318,13 @@ gst_shape_wipe_video_sink_setcaps (GstPad * pad, GstCaps * caps)
s = gst_caps_get_structure (caps, 0); s = gst_caps_get_structure (caps, 0);
if (!gst_structure_get_int (s, "width", &width) || if (!gst_video_format_parse_caps (caps, &fmt, &width, &height) ||
!gst_structure_get_int (s, "height", &height) ||
!gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d)) { !gst_structure_get_fraction (s, "framerate", &fps_n, &fps_d)) {
ret = FALSE; ret = FALSE;
goto done; goto done;
} }
self->fmt = fmt;
if (self->width != width || self->height != height) { if (self->width != width || self->height != height) {
g_mutex_lock (self->mask_mutex); g_mutex_lock (self->mask_mutex);
self->width = width; self->width = width;
@ -402,13 +404,20 @@ gst_shape_wipe_video_sink_getcaps (GstPad * pad)
n = gst_caps_get_size (tmp); n = gst_caps_get_size (tmp);
tmp2 = gst_caps_new_empty ();
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
GstStructure *s = gst_caps_get_structure (tmp, i); GstStructure *s = gst_caps_get_structure (tmp, i);
GstStructure *c;
gst_structure_remove_fields (s, "bpp", "depth", "endianness", "framerate", gst_structure_remove_fields (s, "format", "bpp", "depth", "endianness",
"framerate", "red_mask", "green_mask", "blue_mask", "alpha_mask",
NULL); NULL);
gst_structure_set_name (s, "video/x-raw-yuv"); gst_structure_set_name (s, "video/x-raw-yuv");
c = gst_structure_copy (s);
gst_structure_set_name (c, "video/x-raw-rgb");
gst_caps_append_structure (tmp2, c);
} }
gst_caps_append (tmp, tmp2);
intersection = gst_caps_intersect (tmp, ret); intersection = gst_caps_intersect (tmp, ret);
gst_caps_unref (tmp); gst_caps_unref (tmp);
@ -498,7 +507,9 @@ gst_shape_wipe_mask_sink_getcaps (GstPad * pad)
GstStructure *t; GstStructure *t;
gst_structure_set_name (s, "video/x-raw-gray"); gst_structure_set_name (s, "video/x-raw-gray");
gst_structure_remove_fields (s, "format", "framerate", NULL); gst_structure_remove_fields (s, "format", "framerate", "bpp", "depth",
"endianness", "framerate", "red_mask", "green_mask", "blue_mask",
"alpha_mask", NULL);
if (self->width && self->height) if (self->width && self->height)
gst_structure_set (s, "width", G_TYPE_INT, self->width, "height", gst_structure_set (s, "width", G_TYPE_INT, self->width, "height",
@ -514,7 +525,7 @@ gst_shape_wipe_mask_sink_getcaps (GstPad * pad)
gst_caps_append_structure (tmp, t); gst_caps_append_structure (tmp, t);
} }
gst_caps_merge (ret, tmp); gst_caps_append (ret, tmp);
tmp = gst_pad_peer_get_caps (pad); tmp = gst_pad_peer_get_caps (pad);
if (tmp) { if (tmp) {
@ -591,13 +602,20 @@ gst_shape_wipe_src_getcaps (GstPad * pad)
tmp = intersection; tmp = intersection;
n = gst_caps_get_size (tmp); n = gst_caps_get_size (tmp);
tmp2 = gst_caps_new_empty ();
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
GstStructure *s = gst_caps_get_structure (tmp, i); GstStructure *s = gst_caps_get_structure (tmp, i);
GstStructure *c;
gst_structure_remove_fields (s, "bpp", "depth", "endianness", "framerate", gst_structure_remove_fields (s, "format", "bpp", "depth", "endianness",
"framerate", "red_mask", "green_mask", "blue_mask", "alpha_mask",
NULL); NULL);
gst_structure_set_name (s, "video/x-raw-yuv"); gst_structure_set_name (s, "video/x-raw-yuv");
c = gst_structure_copy (s);
gst_caps_append_structure (tmp2, c);
} }
gst_caps_append (tmp, tmp2);
intersection = gst_caps_intersect (tmp, ret); intersection = gst_caps_intersect (tmp, ret);
gst_caps_unref (tmp); gst_caps_unref (tmp);
@ -729,118 +747,128 @@ gst_shape_wipe_do_qos (GstShapeWipe * self, GstClockTime timestamp)
return TRUE; return TRUE;
} }
static GstFlowReturn #define CREATE_AYUV_FUNCTIONS(depth, scale) \
gst_shape_wipe_blend_16 (GstShapeWipe * self, GstBuffer * inbuf, static GstFlowReturn \
GstBuffer * maskbuf, GstBuffer * outbuf) gst_shape_wipe_blend_ayuv_##depth (GstShapeWipe * self, GstBuffer * inbuf, \
{ GstBuffer * maskbuf, GstBuffer * outbuf) \
const guint16 *mask = (const guint16 *) GST_BUFFER_DATA (maskbuf); { \
const guint8 *input = (const guint8 *) GST_BUFFER_DATA (inbuf); const guint##depth *mask = (const guint##depth *) GST_BUFFER_DATA (maskbuf); \
guint8 *output = (guint8 *) GST_BUFFER_DATA (outbuf); const guint8 *input = (const guint8 *) GST_BUFFER_DATA (inbuf); \
guint i, j; guint8 *output = (guint8 *) GST_BUFFER_DATA (outbuf); \
guint mask_increment = GST_ROUND_UP_2 (self->width) - self->width; guint i, j; \
gfloat position = self->mask_position; guint mask_increment = ((depth == 16) ? GST_ROUND_UP_2 (self->width) : \
gfloat low = position - (self->mask_border / 2.0f); GST_ROUND_UP_4 (self->width)) - self->width; \
gfloat high = position + (self->mask_border / 2.0f); gfloat position = self->mask_position; \
gfloat low = position - (self->mask_border / 2.0f); \
if (low < 0.0f) { gfloat high = position + (self->mask_border / 2.0f); \
high = 0.0f; \
low = 0.0f; if (low < 0.0f) { \
} high = 0.0f; \
low = 0.0f; \
if (high > 1.0f) { } \
low = 1.0f; \
high = 1.0f; if (high > 1.0f) { \
} low = 1.0f; \
high = 1.0f; \
for (i = 0; i < self->height; i++) { } \
for (j = 0; j < self->width; j++) { \
gfloat in = *mask / 65536.0f; for (i = 0; i < self->height; i++) { \
for (j = 0; j < self->width; j++) { \
if (in < low) { gfloat in = *mask / scale; \
output[0] = 0x00; /* A */ \
output[1] = 0x00; /* Y */ if (in < low) { \
output[2] = 0x80; /* U */ output[0] = 0x00; /* A */ \
output[3] = 0x80; /* V */ output[1] = 0x00; /* Y */ \
} else if (in >= high) { output[2] = 0x80; /* U */ \
output[0] = 0xff; /* A */ output[3] = 0x80; /* V */ \
output[1] = input[1]; /* Y */ } else if (in >= high) { \
output[2] = input[2]; /* U */ output[0] = 0xff; /* A */ \
output[3] = input[3]; /* V */ output[1] = input[1]; /* Y */ \
} else { output[2] = input[2]; /* U */ \
gfloat val = 255.0f * ((in - low) / (high - low)); output[3] = input[3]; /* V */ \
} else { \
output[0] = CLAMP (val, 0, 255); /* A */ gfloat val = 255.0f * ((in - low) / (high - low)); \
output[1] = input[1]; /* Y */ \
output[2] = input[2]; /* U */ output[0] = CLAMP (val, 0, 255); /* A */ \
output[3] = input[3]; /* V */ output[1] = input[1]; /* Y */ \
} output[2] = input[2]; /* U */ \
output[3] = input[3]; /* V */ \
mask++; } \
input += 4; \
output += 4; mask++; \
} input += 4; \
mask += mask_increment; output += 4; \
} } \
mask += mask_increment; \
return GST_FLOW_OK; } \
\
return GST_FLOW_OK; \
} }
static GstFlowReturn CREATE_AYUV_FUNCTIONS (16, 65536.0f);
gst_shape_wipe_blend_8 (GstShapeWipe * self, GstBuffer * inbuf, CREATE_AYUV_FUNCTIONS (8, 256.0f);
GstBuffer * maskbuf, GstBuffer * outbuf)
{
const guint8 *mask = (const guint8 *) GST_BUFFER_DATA (maskbuf);
const guint8 *input = (const guint8 *) GST_BUFFER_DATA (inbuf);
guint8 *output = (guint8 *) GST_BUFFER_DATA (outbuf);
guint i, j;
guint mask_increment = GST_ROUND_UP_4 (self->width) - self->width;
gfloat position = self->mask_position;
gfloat low = position - (self->mask_border / 2.0f);
gfloat high = position + (self->mask_border / 2.0f);
if (low < 0.0f) { #define CREATE_ARGB_FUNCTIONS(depth, scale) \
high = 0.0f; static GstFlowReturn \
low = 0.0f; gst_shape_wipe_blend_argb_##depth (GstShapeWipe * self, GstBuffer * inbuf, \
} GstBuffer * maskbuf, GstBuffer * outbuf) \
{ \
if (high > 1.0f) { const guint##depth *mask = (const guint##depth *) GST_BUFFER_DATA (maskbuf); \
low = 1.0f; const guint8 *input = (const guint8 *) GST_BUFFER_DATA (inbuf); \
high = 1.0f; guint8 *output = (guint8 *) GST_BUFFER_DATA (outbuf); \
} guint i, j; \
guint mask_increment = ((depth == 16) ? GST_ROUND_UP_2 (self->width) : \
for (i = 0; i < self->height; i++) { GST_ROUND_UP_4 (self->width)) - self->width; \
for (j = 0; j < self->width; j++) { gfloat position = self->mask_position; \
gfloat in = *mask / 256.0f; gfloat low = position - (self->mask_border / 2.0f); \
gfloat high = position + (self->mask_border / 2.0f); \
if (in < low) { \
output[0] = 0x00; /* A */ if (low < 0.0f) { \
output[1] = 0x00; /* Y */ high = 0.0f; \
output[2] = 0x80; /* U */ low = 0.0f; \
output[3] = 0x80; /* V */ } \
} else if (in >= high) { \
output[0] = 0xff; /* A */ if (high > 1.0f) { \
output[1] = input[1]; /* Y */ low = 1.0f; \
output[2] = input[2]; /* U */ high = 1.0f; \
output[3] = input[3]; /* V */ } \
} else { \
gfloat val = 255.0f * ((in - low) / (high - low)); for (i = 0; i < self->height; i++) { \
for (j = 0; j < self->width; j++) { \
output[0] = CLAMP (val, 0, 255); /* A */ gfloat in = *mask / scale; \
output[1] = input[1]; /* Y */ \
output[2] = input[2]; /* U */ if (in < low) { \
output[3] = input[3]; /* V */ output[0] = 0x00; /* A */ \
} output[1] = 0x00; /* R */ \
output[2] = 0x00; /* G */ \
mask++; output[3] = 0x00; /* B */ \
input += 4; } else if (in >= high) { \
output += 4; output[0] = 0xff; /* A */ \
} output[1] = input[1]; /* R */ \
mask += mask_increment; output[2] = input[2]; /* G */ \
} output[3] = input[3]; /* B */ \
} else { \
return GST_FLOW_OK; gfloat val = 255.0f * ((in - low) / (high - low)); \
\
output[0] = CLAMP (val, 0, 255); /* A */ \
output[1] = input[1]; /* R */ \
output[2] = input[2]; /* G */ \
output[3] = input[3]; /* B */ \
} \
\
mask++; \
input += 4; \
output += 4; \
} \
mask += mask_increment; \
} \
\
return GST_FLOW_OK; \
} }
CREATE_ARGB_FUNCTIONS (16, 65536.0f);
CREATE_ARGB_FUNCTIONS (8, 256.0f);
static GstFlowReturn static GstFlowReturn
gst_shape_wipe_video_sink_chain (GstPad * pad, GstBuffer * buffer) gst_shape_wipe_video_sink_chain (GstPad * pad, GstBuffer * buffer)
{ {
@ -850,6 +878,9 @@ gst_shape_wipe_video_sink_chain (GstPad * pad, GstBuffer * buffer)
GstClockTime timestamp; GstClockTime timestamp;
gboolean new_outbuf = FALSE; gboolean new_outbuf = FALSE;
if (G_UNLIKELY (self->fmt == GST_VIDEO_FORMAT_UNKNOWN))
return GST_FLOW_NOT_NEGOTIATED;
timestamp = GST_BUFFER_TIMESTAMP (buffer); timestamp = GST_BUFFER_TIMESTAMP (buffer);
timestamp = timestamp =
gst_segment_to_stream_time (&self->segment, GST_FORMAT_TIME, timestamp); gst_segment_to_stream_time (&self->segment, GST_FORMAT_TIME, timestamp);
@ -898,10 +929,16 @@ gst_shape_wipe_video_sink_chain (GstPad * pad, GstBuffer * buffer)
outbuf = buffer; outbuf = buffer;
} }
if (self->mask_bpp == 16) if (self->fmt == GST_VIDEO_FORMAT_AYUV && self->mask_bpp == 16)
ret = gst_shape_wipe_blend_16 (self, buffer, mask, outbuf); ret = gst_shape_wipe_blend_ayuv_16 (self, buffer, mask, outbuf);
else if (self->fmt == GST_VIDEO_FORMAT_AYUV)
ret = gst_shape_wipe_blend_ayuv_8 (self, buffer, mask, outbuf);
else if (self->fmt == GST_VIDEO_FORMAT_ARGB && self->mask_bpp == 16)
ret = gst_shape_wipe_blend_argb_16 (self, buffer, mask, outbuf);
else if (self->fmt == GST_VIDEO_FORMAT_ARGB)
ret = gst_shape_wipe_blend_argb_8 (self, buffer, mask, outbuf);
else else
ret = gst_shape_wipe_blend_8 (self, buffer, mask, outbuf); g_assert_not_reached ();
gst_buffer_unref (mask); gst_buffer_unref (mask);
if (new_outbuf) if (new_outbuf)

View file

@ -59,6 +59,7 @@ struct _GstShapeWipe
GCond *mask_cond; GCond *mask_cond;
gint mask_bpp; gint mask_bpp;
GstVideoFormat fmt;
gint width, height; gint width, height;
gdouble proportion; gdouble proportion;