Commit 20ef6b8c authored by Wim Taymans's avatar Wim Taymans

- reimplemented using organic masks, rendered with gouraud shaded triangles

Original commit message from CVS:
- reimplemented using organic masks, rendered with gouraud shaded triangles
- implemented more masks
- implemented adjustable border
parent cea94d91
common @ 2f0e1ecb
Subproject commit fa2e4df50fd965b1dbd3b35b87d914ff87362815
Subproject commit 2f0e1ecbfe7d27cf1b2215204958c95516db173d
This diff is collapsed.
......@@ -19,6 +19,7 @@
#include "gstmask.h"
#include "paint.h"
extern void _gst_barboxwipes_register (void);
......@@ -73,31 +74,23 @@ gst_mask_factory_new (gint type, gint bpp, gint width, gint height)
definition = gst_mask_find_definition (type);
if (definition) {
mask = definition->new_func (definition, bpp, width, height);
mask = g_new0 (GstMask, 1);
mask->type = definition->type;
mask->bpp = bpp;
mask->width = width;
mask->height = height;
mask->destroy_func = definition->destroy_func;
mask->user_data = definition->user_data;
mask->data = g_malloc (width * height * sizeof (guint32));
if (definition->draw_func)
definition->draw_func (mask);
}
return mask;
}
GstMask*
_gst_mask_default_new (GstMaskDefinition *definition,
gint bpp, gint width, gint height)
{
GstMask *mask;
mask = g_new0 (GstMask, 1);
mask->type = definition->type;
mask->bpp = bpp;
mask->width = width;
mask->height = height;
mask->update_func = definition->update_func;
mask->destroy_func = definition->destroy_func;
mask->data = g_malloc (width * height * (bpp+7)>>3);
return mask;
}
void
_gst_mask_default_destroy (GstMask *mask)
{
......@@ -119,6 +112,4 @@ gst_mask_update (GstMask *mask,
{
g_return_if_fail (mask != NULL);
if (mask->update_func)
mask->update_func (mask, position, duration);
}
......@@ -27,47 +27,37 @@
typedef struct _GstMask GstMask;
typedef struct _GstMaskDefinition GstMaskDefinition;
typedef GstMask* (*GstMaskNewFunc) (GstMaskDefinition *definition,
gint bpp, gint width, gint height);
typedef void (*GstMaskDrawFunc) (GstMask *mask);
typedef void (*GstMaskDestroyFunc) (GstMask *mask);
typedef void (*GstMaskUpdateFunc) (GstMask *mask,
GstClockTime position,
GstClockTime duration);
struct _GstMaskDefinition {
gint type;
gchar *short_name;
gchar *long_name;
GstMaskNewFunc new_func;
GstMaskDrawFunc draw_func;
GstMaskDestroyFunc destroy_func;
GstMaskUpdateFunc update_func;
gpointer user_data;
};
struct _GstMask {
gint type;
guint8 *data;
guint32 *data;
gpointer user_data;
gint width;
gint height;
gint bpp;
GstMaskUpdateFunc update_func;
GstMaskDestroyFunc destroy_func;
};
void _gst_mask_init (void);
void _gst_mask_register (GstMaskDefinition *definition);
GstMask* _gst_mask_default_new (GstMaskDefinition *definition,
gint bpp, gint width, gint height);
void _gst_mask_default_destroy (GstMask *mask);
const GList* gst_mask_get_definitions (void);
GstMask* gst_mask_factory_new (gint type, gint bpp, gint width, gint height);
void gst_mask_destroy (GstMask *mask);
void gst_mask_update (GstMask *mask,
GstClockTime position,
GstClockTime duration);
#endif /* __GST_MASK_H__ */
......@@ -79,6 +79,9 @@ enum {
enum {
ARG_0,
ARG_TYPE,
ARG_BORDER,
ARG_DEPTH,
ARG_FPS,
};
#define GST_TYPE_SMPTE_TRANSITION_TYPE (gst_smpte_transition_type_get_type())
......@@ -106,7 +109,8 @@ gst_smpte_transition_type_get_type (void)
i++;
}
smpte_transition_type = g_enum_register_static ("GstSMPTETransitionType", smpte_transitions);
smpte_transition_type =
g_enum_register_static ("GstSMPTETransitionType", smpte_transitions);
}
return smpte_transition_type;
}
......@@ -166,7 +170,15 @@ gst_smpte_class_init (GstSMPTEClass *klass)
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TYPE,
g_param_spec_enum ("type", "Type", "The type of transition to use",
GST_TYPE_SMPTE_TRANSITION_TYPE, 1, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_FPS,
g_param_spec_int ("fps", "FPS", "Frames per second if no input files are given",
1, 255, 1, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_BORDER,
g_param_spec_int ("border", "Border", "The border width of the transition",
0, G_MAXINT, 0, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEPTH,
g_param_spec_int ("depth", "Depth", "Depth of the mask in bits",
1, 24, 16, G_PARAM_READWRITE));
}
/* wht yel cya grn mag red blu blk -I Q */
......@@ -177,13 +189,35 @@ static int v_colors[] = { 128, 155, 0, 21, 235, 255, 107, 128, 128, 255 };
static void
fill_i420 (guint8 *data, gint width, gint height, gint color)
{
gint size = width * height, size4 = size >> 2;
guint8 *yp = data;
guint8 *up = data + width * height;
guint8 *vp = data + width * height + (width * height) / 4;
guint8 *up = data + size;
guint8 *vp = data + size + size4;
gst_smpte_paint_rect (yp, width, 0, 0, width, height, y_colors[color]);
gst_smpte_paint_rect (up, width/2, 0, 0, width/2, height/2, u_colors[color]);
gst_smpte_paint_rect (vp, width/2, 0, 0, width/2, height/2, v_colors[color]);
memset (yp, y_colors[color], size);
memset (up, u_colors[color], size4);
memset (vp, v_colors[color], size4);
}
static gboolean
gst_smpte_update_mask (GstSMPTE *smpte, gint type, gint depth, gint width, gint height)
{
GstMask *newmask;
newmask = gst_mask_factory_new (type, depth, width, height);
if (newmask) {
if (smpte->mask) {
gst_mask_destroy (smpte->mask);
}
smpte->mask = newmask;
smpte->type = type;
smpte->depth = depth;
smpte->width = width;
smpte->height = height;
return TRUE;
}
return FALSE;
}
static gboolean
......@@ -199,7 +233,7 @@ gst_smpte_sinkconnect (GstPad *pad, GstCaps *caps)
gst_caps_get_int (caps, "width", &smpte->width);
gst_caps_get_int (caps, "height", &smpte->height);
smpte->mask = gst_mask_factory_new (smpte->type, 8, smpte->width, smpte->height);
gst_smpte_update_mask (smpte, smpte->type, smpte->depth, smpte->width, smpte->height);
/* forward to the next plugin */
return gst_pad_try_set_caps(smpte->srcpad, gst_caps_copy_1(caps));
......@@ -229,35 +263,43 @@ gst_smpte_init (GstSMPTE *smpte)
smpte->duration = 64;
smpte->position = 0;
smpte->type = 1;
smpte->mask = gst_mask_factory_new (smpte->type, 8, smpte->width, smpte->height);
smpte->fps = 1;
smpte->border = 0;
smpte->depth = 16;
gst_smpte_update_mask (smpte, smpte->type, smpte->depth, smpte->width, smpte->height);
}
static void
gst_smpte_blend_i420 (guint8 *in1, guint8 *in2, guint8 *out, GstMask *mask,
gint width, gint height)
gint width, gint height, gint border, gint pos)
{
gint i, j;
guint8 *maskporig, *maskp;
guint32 *maskp;
gint value;
gint i;
gint min, max;
guint8 *in1u, *in1v, *in2u, *in2v, *outu, *outv;
guint8 value;
gint chromsize = (width * height) >> 2;
gint lumsize = width * height;
gint chromsize = lumsize >> 2;
if (border == 0) border++;
maskp = maskporig = mask->data;
min = pos - border;
max = pos;
in1u = in1 + lumsize; in1v = in1 + chromsize;
in2u = in2 + lumsize; in2v = in2 + chromsize;
outu = out + lumsize; outv = out + chromsize;
for (i = width * height; i; i--) {
maskp = mask->data;
for (i = lumsize; i; i--) {
value = *maskp++;
*out++ = ((*in2++ * value) + (*in1++ * (255 - value))) >> 8;
}
in1u = in1; in1v = in1 + chromsize;
in2u = in2; in2v = in2 + chromsize;
outu = out; outv = out + chromsize;
maskp = maskporig;
for (i = height/2; i; i--, maskp += width) {
for (j = width/2; j; j--, maskp += 2) {
value = *maskp;
*outu++ = ((*in2u++ * value) + (*in1u++ * (255 - value))) >> 8;
*outv++ = ((*in2v++ * value) + (*in1v++ * (255 - value))) >> 8;
value = ((CLAMP (value, min, max) - min) << 8) / border;
*out++ = ((*in1++ * value) + (*in2++ * (255 - value))) >> 8;
if (i % 4) {
*outu++ = ((*in1u++ * value) + (*in2u++ * (255 - value))) >> 8;
*outv++ = ((*in1v++ * value) + (*in2v++ * (255 - value))) >> 8;
}
}
}
......@@ -272,7 +314,7 @@ gst_smpte_loop (GstElement *element)
smpte = GST_SMPTE (element);
ts = smpte->position * GST_SECOND;
ts = smpte->position * GST_SECOND / smpte->fps;
if (GST_PAD_IS_USABLE (smpte->sinkpad1)) {
in1 = gst_pad_pull (smpte->sinkpad1);
......@@ -297,23 +339,26 @@ gst_smpte_loop (GstElement *element)
if (!GST_PAD_CAPS (smpte->srcpad)) {
if (!gst_pad_try_set_caps (smpte->srcpad,
GST_CAPS_NEW (
"smpte_srccaps",
"video/raw",
"format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')),
"width", GST_PROPS_INT (smpte->width),
"height", GST_PROPS_INT (smpte->height)
)))
GST_CAPS_NEW (
"smpte_srccaps",
"video/raw",
"format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')),
"width", GST_PROPS_INT (smpte->width),
"height", GST_PROPS_INT (smpte->height)
)))
{
gst_element_error (element, "cannot set caps");
return;
}
}
gst_mask_update (smpte->mask, smpte->position, smpte->duration);
gst_smpte_blend_i420 (GST_BUFFER_DATA (in1), GST_BUFFER_DATA (in2), GST_BUFFER_DATA (outbuf),
smpte->mask, smpte->width, smpte->height);
gst_smpte_blend_i420 (GST_BUFFER_DATA (in1),
GST_BUFFER_DATA (in2),
GST_BUFFER_DATA (outbuf),
smpte->mask, smpte->width, smpte->height,
smpte->border,
((1 << smpte->depth) + smpte->border) *
smpte->position / smpte->duration);
}
else {
outbuf = in2;
......@@ -342,17 +387,24 @@ gst_smpte_set_property (GObject *object, guint prop_id,
switch (prop_id) {
case ARG_TYPE:
{
GstMask *newmask;
gint type = g_value_get_enum (value);
newmask = gst_mask_factory_new (type, 8, smpte->width, smpte->height);
if (newmask) {
if (smpte->mask) {
gst_mask_destroy (smpte->mask);
}
smpte->mask = newmask;
smpte->type = type;
}
gst_smpte_update_mask (smpte, type, smpte->depth,
smpte->width, smpte->height);
break;
}
case ARG_FPS:
smpte->fps = g_value_get_int (value);
break;
case ARG_BORDER:
smpte->border = g_value_get_int (value);
break;
case ARG_DEPTH:
{
gint depth = g_value_get_int (value);
gst_smpte_update_mask (smpte, smpte->type, depth,
smpte->width, smpte->height);
break;
}
default:
......@@ -375,6 +427,15 @@ gst_smpte_get_property (GObject *object, guint prop_id,
g_value_set_enum (value, smpte->mask->type);
}
break;
case ARG_FPS:
g_value_set_int (value, smpte->fps);
break;
case ARG_BORDER:
g_value_set_int (value, smpte->border);
break;
case ARG_DEPTH:
g_value_set_int (value, smpte->depth);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
......@@ -391,9 +452,12 @@ plugin_init (GModule *module, GstPlugin *plugin)
&smpte_details);
g_return_val_if_fail(factory != NULL, FALSE);
gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (smpte_sink1_factory));
gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (smpte_sink2_factory));
gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (smpte_src_factory));
gst_element_factory_add_pad_template (factory,
GST_PAD_TEMPLATE_GET (smpte_sink1_factory));
gst_element_factory_add_pad_template (factory,
GST_PAD_TEMPLATE_GET (smpte_sink2_factory));
gst_element_factory_add_pad_template (factory,
GST_PAD_TEMPLATE_GET (smpte_src_factory));
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
......
......@@ -53,6 +53,9 @@ struct _GstSMPTE {
*sinkpad2;
gint type;
gint fps;
gint border;
gint depth;
GstMask *mask;
};
......
......@@ -20,32 +20,196 @@
#include "paint.h"
void
gst_smpte_paint_rect (guint8 *dest, gint stride, gint x, gint y, gint w, gint h, guint8 color)
{
guint8 *d = dest + stride * y + x;
gint i;
for (i = 0; i < h; i++) {
memset (d, color, w);
d += stride;
gst_smpte_paint_vbox (guint32 *dest, gint stride,
gint x0, gint y0, gint c0,
gint x1, gint y1, gint c1)
{
gint i, j;
gint width, height;
width = x1 - x0;
height = y1 - y0;
g_assert (width > 0);
g_assert (height > 0);
dest = dest + y0 * stride + x0;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
dest[j] = (c1 * j + c0 * (width - j)) / width;
}
dest += stride;
}
}
void
gst_smpte_paint_hbox (guint32 *dest, gint stride,
gint x0, gint y0, gint c0,
gint x1, gint y1, gint c1)
{
gint i, j;
gint width, height;
width = x1 - x0;
height = y1 - y0;
g_assert (width > 0);
g_assert (height > 0);
g_print ("vbox: %d %d %d %d %d %d\n", x0, y0, c0, x1, y1, c1);
dest = dest + y0 * stride + x0;
for (i = 0; i < height; i++) {
guint32 value = (c1 * i + c0 * (height - i)) / height;
for (j = 0; j < width; j++) {
*dest++ = value;
}
}
}
void
gst_smpte_paint_rect_s (guint8 *dest, gint stride, gint x, gint y, gint w, gint h, guint8 color)
{
guint8 *d = dest + stride * y + x;
gst_smpte_paint_rect16 (guint16 * dest, gint depth, gint w, gint h)
{
gint i, j;
gint border = 100;
for (i = 0; i < h; i++) {
if (w - border > 0) {
memset (d, color, w - border);
for (j = 0; j < w; j++) {
*dest++ = (guint16) ((double) (1 << depth) * j / w);
}
}
}
#define STEP_3D_LINE(dxabs,dyabs,dzabs,sdx,sdy,sdz,xr,yr,zr,px,py,pz) \
G_STMT_START { \
if (dxabs >= dyabs && dxabs >= dzabs) { \
yr += dyabs; \
zr += dzabs; \
if (yr >= dxabs) { \
py += sdy; \
yr -= dxabs; \
} \
if (zr >= dzabs) { \
pz += sdz; \
zr -= dxabs; \
} \
px += sdx; \
} else if (dyabs >= dxabs && dyabs >= dzabs) { \
xr += dxabs; \
zr += dzabs; \
if (xr >= dyabs) { \
px += sdx; \
xr -= dyabs; \
} \
if (zr >= dzabs) { \
pz += sdz; \
zr -= dyabs; \
} \
py += sdy; \
} else { \
yr += dyabs; \
xr += dxabs; \
if (yr >= dyabs) { \
py += sdy; \
yr -= dzabs; \
} \
if (xr >= dyabs) { \
px += sdx; \
xr -= dzabs; \
} \
pz += sdz; \
} \
} G_STMT_END
#define SWAP(a,b) \
G_STMT_START { \
typeof (a) tmp; \
tmp = (a); \
(a) = (b); \
(b) = (tmp); \
} G_STMT_END
#define SIGN(a) ((a) < 0 ? -1 : 1)
#define PREPARE_3D_LINE(x0,y0,z0,x1,y1,z1,dxabs,dyabs,dzabs,sdx,sdy,sdz,xr,yr,zr,px,py,pz)\
G_STMT_START { \
typeof (x0) dx, dy, dz; \
dx = x1 - x0; \
dy = y1 - y0; \
dz = z1 - z0; \
dxabs = abs (dx); \
dyabs = abs (dy); \
dzabs = abs (dz); \
sdx = SIGN (dx); \
sdy = SIGN (dy); \
sdz = SIGN (dz); \
xr = dxabs >> 1; \
yr = dyabs >> 1; \
zr = dzabs >> 1; \
px = x0; \
py = y0; \
pz = z0; \
} G_STMT_END
void
gst_smpte_paint_triangle_linear (guint32 *dest, gint stride,
gint x0, gint y0, gint c0,
gint x1, gint y1, gint c1, gint x2, gint y2, gint c2)
{
gint sdxl, sdyl, sdcl, dxlabs, dylabs, dclabs, xrl, yrl, crl, pxl, pyl, pcl;
gint sdxr, sdyr, sdcr, dxrabs, dyrabs, dcrabs, xrr, yrr, crr, pxr, pyr, pcr;
gint i, j, k, seg_start, seg_end;
if (y0 > y1) { SWAP (x0, x1); SWAP (y0, y1); SWAP (c0, c1); }
if (y0 > y2) { SWAP (x0, x2); SWAP (y0, y2); SWAP (c0, c2); }
if (y1 > y2) { SWAP (x1, x2); SWAP (y1, y2); SWAP (c1, c2); }
PREPARE_3D_LINE (x0,y0,c0,x2,y2,c2,
dxlabs,dylabs,dclabs,
sdxl, sdyl,sdcl,
xrl,yrl,crl,
pxl,pyl,pcl);
PREPARE_3D_LINE (x0,y0,c0,x1,y1,c1,
dxrabs,dyrabs,dcrabs,
sdxr, sdyr,sdcr,
xrr,yrr,crr,
pxr,pyr,pcr);
dest = dest + stride * y0;
seg_start = y0;
seg_end = y1;
/* do two passes */
for (k = 0; k < 2; k++) {
for (i = seg_start; i < seg_end; i++) {
gint s = pxl, e = pxr, sc = pcl, ec = pcr;
gint sign = SIGN (e - s);
e += sign;
for (j = s; j != e; j+=sign) {
dest[j] = (ec * (j - s) + sc * (e - j)) / (e - s);
}
while (pyr == i) {
STEP_3D_LINE (dxrabs, dyrabs, dcrabs, sdxr, sdyr, sdcr,
xrr, yrr, crr, pxr, pyr, pcr);
}
while (pyl == i) {
STEP_3D_LINE (dxlabs, dylabs, dclabs, sdxl, sdyl, sdcl,
xrl, yrl, crl, pxl, pyl, pcl);
}
dest += stride;
}
PREPARE_3D_LINE (x1,y1,c1,x2,y2,c2,
dxrabs,dyrabs,dcrabs,
sdxr, sdyr,sdcr,
xrr,yrr,crr,
pxr,pyr,pcr);
for (j = 0; j < border - w; j++) {
*(d+w+j) = (color*(border-j)/border);
}
d += stride;
seg_start = y1;
seg_end = y2;
}
}
......@@ -22,14 +22,20 @@
#include <glib.h>
void gst_smpte_paint_rect (guint8 *dest, gint stride,
gint x, gint y, gint w, gint h,
guint8 color);
void gst_smpte_paint_vbox (guint32 *dest, gint stride,
gint x0, gint y0, gint c0,
gint x1, gint y1, gint c1);
void gst_smpte_paint_hbox (guint32 *dest, gint stride,
gint x0, gint y0, gint c0,
gint x1, gint y1, gint c1);
void gst_smpte_paint_rect_s (guint8 *dest, gint stride,
gint x, gint y, gint w, gint h,
guint8 color);
void gst_smpte_paint_rect16 (guint16 *dest, gint depth, gint width, gint height);
void gst_smpte_paint_triangle_linear (guint32 *dest, gint stride,
gint x0, gint y0, gint c0,
gint x1, gint y1, gint c1,
gint x2, gint y2, gint c2);
#endif /* __GST_SMPTE_PAINT_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment