diff --git a/libs/colorspace/gstcolorspace.c b/libs/colorspace/gstcolorspace.c index aa9e2ac9ad..058bc133e1 100644 --- a/libs/colorspace/gstcolorspace.c +++ b/libs/colorspace/gstcolorspace.c @@ -22,29 +22,32 @@ #include -extern GstColorSpaceConverter gst_colorspace_rgb2rgb_get_converter(GstColorSpace srcspace, - GstColorSpace destspace); -extern GstColorSpaceConverter gst_colorspace_yuv2rgb_get_converter(GstColorSpace srcspace, - GstColorSpace destspace); -extern GstColorSpaceConverter gst_colorspace_rgb2yuv_get_converter(GstColorSpace srcspace, - GstColorSpace destspace); -extern GstColorSpaceConverter gst_colorspace_yuv2yuv_get_converter(GstColorSpace srcspace, - GstColorSpace destspace); -GstBuffer *gst_colorspace_convert(GstBuffer *src, GstColorSpace dest) { - switch (dest) { - default: - break; - } +extern GstColorSpaceConverter gst_colorspace_rgb2rgb_get_converter(GstColorSpace *space, GstColorSpaceType srcspace, + GstColorSpaceType destspace); +extern GstColorSpaceConverter gst_colorspace_yuv2rgb_get_converter(GstColorSpace *space, GstColorSpaceType srcspace, + GstColorSpaceType destspace); +extern GstColorSpaceConverter gst_colorspace_rgb2yuv_get_converter(GstColorSpace *space, GstColorSpaceType srcspace, + GstColorSpaceType destspace); +extern GstColorSpaceConverter gst_colorspace_yuv2yuv_get_converter(GstColorSpace *space, GstColorSpaceType srcspace, + GstColorSpaceType destspace); - return src; -} +GstColorSpace *gst_colorspace_new(int width, int height, GstColorSpaceType srcspace, GstColorSpaceType destspace, GdkVisual *destvisual) +{ -GstColorSpaceConverter gst_colorspace_get_converter(GstColorSpace srcspace, GstColorSpace destspace) { - DEBUG("gst_colorspace: get converter\n"); + GstColorSpace *new = g_malloc(sizeof(GstColorSpace)); + + new->width = width; + new->height = height; + new->srcspace = srcspace; + new->destspace = destspace; + new->visual = destvisual; + new->convert = NULL; + + DEBUG("gst_colorspace: new\n"); if (GST_COLORSPACE_IS_RGB_TYPE(srcspace)) { if (GST_COLORSPACE_IS_RGB_TYPE(destspace)) { - return gst_colorspace_rgb2rgb_get_converter(srcspace, destspace); + new->convert = gst_colorspace_rgb2rgb_get_converter(new, srcspace, destspace); } else { //return gst_colorspace_rgb2yuv_get_converter(srcspace, destspace); @@ -52,12 +55,20 @@ GstColorSpaceConverter gst_colorspace_get_converter(GstColorSpace srcspace, GstC } else if (GST_COLORSPACE_IS_YUV_TYPE(srcspace)) { if (GST_COLORSPACE_IS_RGB_TYPE(destspace)) { - return gst_colorspace_yuv2rgb_get_converter(srcspace, destspace); + new->convert = gst_colorspace_yuv2rgb_get_converter(new, srcspace, destspace); } else { //return gst_colorspace_yuv2yuv_get_converter(srcspace, destspace); } } - g_print("gst_colorspace: conversion not implemented\n"); - return NULL; + if (new->convert == NULL) { + g_print("gst_colorspace: conversion not implemented\n"); + } + return new; +} + +void gst_colorspace_destroy(GstColorSpace *space) +{ + if (space->color_tables) g_free(space->color_tables); + g_free(space); } diff --git a/libs/colorspace/gstcolorspace.h b/libs/colorspace/gstcolorspace.h index 50024333c5..01ee2fe2a0 100644 --- a/libs/colorspace/gstcolorspace.h +++ b/libs/colorspace/gstcolorspace.h @@ -25,8 +25,9 @@ #include #include -typedef enum { +#include "yuv2rgb.h" +typedef enum { #define GST_COLORSPACE_RGB_FIRST GST_COLORSPACE_RGB555 GST_COLORSPACE_RGB555, GST_COLORSPACE_BGR555, @@ -45,15 +46,22 @@ typedef enum { GST_COLORSPACE_YUV422P, #define GST_COLORSPACE_YUV_LAST GST_COLORSPACE_YUV422P -} GstColorSpace; +} GstColorSpaceType; -typedef struct _GstColorSpaceParameters GstColorSpaceParameters; +typedef struct _GstColorSpace GstColorSpace; +typedef void (*GstColorSpaceConverter) (GstColorSpace *space, unsigned char *src, unsigned char *dest); -struct _GstColorSpaceParameters { +struct _GstColorSpace { guint width; guint height; - gchar *outbuf; + GstColorSpaceType srcspace; + GstColorSpaceType destspace; GdkVisual *visual; + guint insize; + guint outsize; + /* private */ + GstColorSpaceYUVTables *color_tables; + GstColorSpaceConverter convert; }; @@ -62,11 +70,7 @@ struct _GstColorSpaceParameters { #define GST_COLORSPACE_IS_YUV_TYPE(type) ((type)>=GST_COLORSPACE_YUV_FIRST && \ (type)<=GST_COLORSPACE_YUV_LAST) -typedef GstBuffer * (*GstColorSpaceConverter) (GstBuffer *src, GstColorSpaceParameters *params); - -GstColorSpaceConverter gst_colorspace_get_converter(GstColorSpace srcspace, GstColorSpace destspace); - -/* convert a buffer to a new buffer in the given colorspace */ -GstBuffer *gst_colorspace_convert(GstBuffer *buf, GstColorSpace destspace); +GstColorSpace *gst_colorspace_new(int width, int height, GstColorSpaceType srcspace, GstColorSpaceType destspace, GdkVisual *destvisual); +void gst_colorspace_destroy(GstColorSpace *space); #endif /* __GST_COLORSPACE_H__ */ diff --git a/libs/colorspace/rgb2rgb.c b/libs/colorspace/rgb2rgb.c index b9c605f8e3..892e30ada0 100644 --- a/libs/colorspace/rgb2rgb.c +++ b/libs/colorspace/rgb2rgb.c @@ -22,26 +22,32 @@ #include #include -static GstBuffer *gst_colorspace_rgb24_to_bgr24(GstBuffer *src, GstColorSpaceParameters *params); -static GstBuffer *gst_colorspace_rgb_to_rgb_identity(GstBuffer *src, GstColorSpaceParameters *params); +static void gst_colorspace_rgb_to_rgb_identity(GstColorSpace *space, unsigned char *src, unsigned char *dest); +static void gst_colorspace_rgb24_to_bgr24(GstColorSpace *space, unsigned char *src, unsigned char *dest); -GstColorSpaceConverter gst_colorspace_rgb2rgb_get_converter(GstColorSpace src, GstColorSpace dest) { +GstColorSpaceConverter gst_colorspace_rgb2rgb_get_converter(GstColorSpace *space, GstColorSpaceType src, GstColorSpaceType dest) { switch(src) { case GST_COLORSPACE_RGB24: + space->insize = space->width*space->height*3; switch(dest) { case GST_COLORSPACE_RGB24: + space->outsize = space->width*space->height*3; return gst_colorspace_rgb_to_rgb_identity; case GST_COLORSPACE_BGR24: + space->outsize = space->width*space->height*3; return gst_colorspace_rgb24_to_bgr24; default: break; } break; case GST_COLORSPACE_BGR24: + space->insize = space->width*space->height*3; switch(dest) { case GST_COLORSPACE_RGB24: + space->outsize = space->width*space->height*3; return gst_colorspace_rgb24_to_bgr24; case GST_COLORSPACE_BGR24: + space->outsize = space->width*space->height*3; return gst_colorspace_rgb_to_rgb_identity; default: break; @@ -54,35 +60,36 @@ GstColorSpaceConverter gst_colorspace_rgb2rgb_get_converter(GstColorSpace src, G return NULL; } -static GstBuffer *gst_colorspace_rgb_to_rgb_identity(GstBuffer *src, GstColorSpaceParameters *params) { - return src; +static void gst_colorspace_rgb_to_rgb_identity(GstColorSpace *space, unsigned char *src, unsigned char *dest) +{ + memcpy(dest, src, space->outsize); } -static GstBuffer *gst_colorspace_rgb24_to_bgr24(GstBuffer *src, GstColorSpaceParameters *params) { +static void gst_colorspace_rgb24_to_bgr24(GstColorSpace *space, unsigned char *src, unsigned char *dest) +{ gint size; gchar temp; - gchar *data; - DEBUG("gst_colorspace_rgb24_to_bgr24 %d\n", GST_BUFFER_SIZE(src)); + DEBUG("gst_colorspace_rgb24_to_bgr24\n"); - size = GST_BUFFER_SIZE(src)/3; + size = space->outsize; - if (params != NULL && params->outbuf != NULL) { - data = params->outbuf; - DEBUG("gst_colorspace: to buffer %p\n", data); + if (src == dest) { + while (size--) { + temp = src[0]; + src[0] = src[2]; + src[2] = temp; + src+=3; + } } else { - data = GST_BUFFER_DATA(src); + while (size--) { + *dest++ = src[2]; + *dest++ = src[1]; + *dest++ = src[0]; + src+=3; + } } - - while (size--) { - temp = data[0]; - data[0] = data[2]; - data[2] = temp; - data+=3; - } - DEBUG("gst_colorspace_rgb24_to_bgr24 end %d\n", GST_BUFFER_SIZE(src)); - - return src; + DEBUG("gst_colorspace_rgb24_to_bgr24 end\n"); } diff --git a/libs/colorspace/yuv2rgb.c b/libs/colorspace/yuv2rgb.c index 5d584f57a6..b65bbd46ff 100644 --- a/libs/colorspace/yuv2rgb.c +++ b/libs/colorspace/yuv2rgb.c @@ -32,13 +32,13 @@ #include "yuv2rgb.h" -static GstBuffer *gst_colorspace_yuv420P_to_rgb32(GstBuffer *src, GstColorSpaceParameters *params); -static GstBuffer *gst_colorspace_yuv420P_to_bgr32(GstBuffer *src, GstColorSpaceParameters *params); -static GstBuffer *gst_colorspace_yuv420P_to_bgr32_mmx(GstBuffer *src, GstColorSpaceParameters *params); -static GstBuffer *gst_colorspace_yuv420P_to_rgb24(GstBuffer *src, GstColorSpaceParameters *params); -static GstBuffer *gst_colorspace_yuv420P_to_bgr24(GstBuffer *src, GstColorSpaceParameters *params); -static GstBuffer *gst_colorspace_yuv420P_to_rgb16(GstBuffer *src, GstColorSpaceParameters *params); -static GstBuffer *gst_colorspace_yuv420P_to_bgr16_mmx(GstBuffer *src, GstColorSpaceParameters *params); +static void gst_colorspace_yuv420P_to_rgb32(GstColorSpace *space, unsigned char *src, unsigned char *dest); +static void gst_colorspace_yuv420P_to_bgr32(GstColorSpace *space, unsigned char *src, unsigned char *dest); +static void gst_colorspace_yuv420P_to_bgr32_mmx(GstColorSpace *space, unsigned char *src, unsigned char *dest); +static void gst_colorspace_yuv420P_to_rgb24(GstColorSpace *space, unsigned char *src, unsigned char *dest); +static void gst_colorspace_yuv420P_to_bgr24(GstColorSpace *space, unsigned char *src, unsigned char *dest); +static void gst_colorspace_yuv420P_to_rgb16(GstColorSpace *space, unsigned char *src, unsigned char *dest); +static void gst_colorspace_yuv420P_to_bgr16_mmx(GstColorSpace *space, unsigned char *src, unsigned char *dest); static void gst_colorspace_yuv_to_rgb16(GstColorSpaceYUVTables *tables, unsigned char *lum, @@ -76,25 +76,38 @@ static void gst_colorspace_yuv_to_bgr16_mmx(GstColorSpaceYUVTables *tables, static GstColorSpaceYUVTables * gst_colorspace_init_yuv(long depth, long red_mask, long green_mask, long blue_mask); -GstColorSpaceConverter gst_colorspace_yuv2rgb_get_converter(GstColorSpace src, GstColorSpace dest) { - DEBUG("gst_colorspace_yuv2rgb_get_converter %d\n", dest); +GstColorSpaceConverter gst_colorspace_yuv2rgb_get_converter(GstColorSpace *space, GstColorSpaceType src, GstColorSpaceType dest) { + DEBUG("gst_colorspace_yuv2rgb_get_converter %d %d\n", src, dest); switch(src) { case GST_COLORSPACE_YUV420P: + space->insize = space->width*space->height+space->width*space->height/2; switch(dest) { case GST_COLORSPACE_BGR32: + space->color_tables = gst_colorspace_init_yuv(32, 0xFF0000, 0x00FF00, 0x0000FF); + space->outsize = space->width*space->height*4; //return gst_colorspace_yuv420P_to_bgr32; return gst_colorspace_yuv420P_to_bgr32_mmx; case GST_COLORSPACE_RGB32: + space->color_tables = gst_colorspace_init_yuv(32, 0x0000FF, 0x00FF00, 0xFF0000); + space->outsize = space->width*space->height*4; return gst_colorspace_yuv420P_to_rgb32; case GST_COLORSPACE_RGB24: + space->color_tables = gst_colorspace_init_yuv(24, 0x0000FF, 0x00FF00, 0xFF0000); + space->outsize = space->width*space->height*3; return gst_colorspace_yuv420P_to_rgb24; case GST_COLORSPACE_BGR24: + space->color_tables = gst_colorspace_init_yuv(24, 0xFF0000, 0x00FF00, 0x0000FF); + space->outsize = space->width*space->height*3; return gst_colorspace_yuv420P_to_bgr24; case GST_COLORSPACE_RGB555: case GST_COLORSPACE_RGB565: case GST_COLORSPACE_BGR555: + g_return_val_if_fail(space->visual != NULL, NULL); + space->color_tables = gst_colorspace_init_yuv(16, space->visual->red_mask, space->visual->green_mask, space->visual->blue_mask); + space->outsize = space->width*space->height*2; return gst_colorspace_yuv420P_to_rgb16; case GST_COLORSPACE_BGR565: + space->outsize = space->width*space->height*2; return gst_colorspace_yuv420P_to_bgr16_mmx; default: break; @@ -107,221 +120,122 @@ GstColorSpaceConverter gst_colorspace_yuv2rgb_get_converter(GstColorSpace src, G return NULL; } -static GstBuffer *gst_colorspace_yuv420P_to_bgr32(GstBuffer *src, GstColorSpaceParameters *params) { - static GstColorSpaceYUVTables *color_tables = NULL; +static void gst_colorspace_yuv420P_to_bgr32(GstColorSpace *space, unsigned char *src, unsigned char *dest) +{ int size; - GstBuffer *buf = NULL; - guchar *out; DEBUG("gst_colorspace_yuv420P_to_bgr32\n"); - g_return_val_if_fail(params != NULL, NULL); + size = space->width * space->height; - if (color_tables == NULL) { - color_tables = gst_colorspace_init_yuv(32, 0xFF0000, 0x00FF00, 0x0000FF); - } - size = params->width * params->height; - if (params->outbuf == NULL) { - buf = gst_buffer_new(); - out = GST_BUFFER_DATA(buf) = g_malloc(size * 4); - GST_BUFFER_SIZE(buf) = size * 4; - } - else out = params->outbuf; + gst_colorspace_yuv_to_rgb32(space->color_tables, + src, // Y component + src+size, // cr component + src+size+(size>>2), // cb component + dest, + space->height, + space->width); - gst_colorspace_yuv_to_rgb32(color_tables, - GST_BUFFER_DATA(src), // Y component - GST_BUFFER_DATA(src)+size, // cr component - GST_BUFFER_DATA(src)+size+(size>>2), // cb component - out, - params->height, - params->width); - - if (buf) { - gst_buffer_unref(src); - return buf; - } - else return src; } -static GstBuffer *gst_colorspace_yuv420P_to_rgb32(GstBuffer *src, GstColorSpaceParameters *params) { - static GstColorSpaceYUVTables *color_tables = NULL; +static void gst_colorspace_yuv420P_to_rgb32(GstColorSpace *space, unsigned char *src, unsigned char *dest) +{ int size; - GstBuffer *buf = NULL; - guchar *out; DEBUG("gst_colorspace_yuv420P_to_rgb32\n"); - g_return_val_if_fail(params != NULL, NULL); - if (color_tables == NULL) { - color_tables = gst_colorspace_init_yuv(32, 0x0000FF, 0x00FF00, 0xFF0000); - } - size = params->width * params->height; - if (params->outbuf == NULL) { - buf = gst_buffer_new(); - out = GST_BUFFER_DATA(buf) = g_malloc(size * 4); - GST_BUFFER_SIZE(buf) = size * 4; - } - else out = params->outbuf; + size = space->width * space->height; - gst_colorspace_yuv_to_rgb32(color_tables, - GST_BUFFER_DATA(src), // Y component - GST_BUFFER_DATA(src)+size, // cr component - GST_BUFFER_DATA(src)+size+(size>>2), // cb component - out, - params->height, - params->width); + gst_colorspace_yuv_to_rgb32(space->color_tables, + src, // Y component + src+size, // cr component + src+size+(size>>2), // cb component + dest, + space->height, + space->width); - if (buf) { - gst_buffer_unref(src); - return buf; - } - else return src; } -static GstBuffer *gst_colorspace_yuv420P_to_bgr24(GstBuffer *src, GstColorSpaceParameters *params) { - static GstColorSpaceYUVTables *color_tables = NULL; +static void gst_colorspace_yuv420P_to_bgr24(GstColorSpace *space, unsigned char *src, unsigned char *dest) { int size; - GstBuffer *buf = NULL; - guchar *out; DEBUG("gst_colorspace_yuv420P_to_bgr24\n"); - g_return_val_if_fail(params != NULL, NULL); + size = space->width * space->height; - if (color_tables == NULL) { - color_tables = gst_colorspace_init_yuv(24, 0xFF0000, 0x00FF00, 0x0000FF); - } - size = params->width * params->height; - if (params->outbuf == NULL) { - buf = gst_buffer_new(); - out = GST_BUFFER_DATA(buf) = g_malloc(size * 3); - GST_BUFFER_SIZE(buf) = size * 3; - } - else out = params->outbuf; - - gst_colorspace_yuv_to_rgb24(color_tables, - GST_BUFFER_DATA(src), // Y component - GST_BUFFER_DATA(src)+size, // cr component - GST_BUFFER_DATA(src)+size+(size>>2), // cb component - out, - params->height, - params->width); - if (buf) { - gst_buffer_unref(src); - return buf; - } - else return src; + gst_colorspace_yuv_to_rgb24(space->color_tables, + src, // Y component + src+size, // cr component + src+size+(size>>2), // cb component + dest, + space->height, + space->width); } -static GstBuffer *gst_colorspace_yuv420P_to_rgb24(GstBuffer *src, GstColorSpaceParameters *params) { - static GstColorSpaceYUVTables *color_tables = NULL; +static void gst_colorspace_yuv420P_to_rgb24(GstColorSpace *space, unsigned char *src, unsigned char *dest) { int size; - GstBuffer *buf = NULL; - guchar *out; DEBUG("gst_colorspace_yuv420P_to_rgb24\n"); - g_return_val_if_fail(params != NULL, NULL); + size = space->width * space->height; - if (color_tables == NULL) { - color_tables = gst_colorspace_init_yuv(24, 0x0000FF, 0x00FF00, 0xFF0000); - } - size = params->width * params->height; - if (params->outbuf == NULL) { - buf = gst_buffer_new(); - out = GST_BUFFER_DATA(buf) = g_malloc(size * 3); - GST_BUFFER_SIZE(buf) = size * 3; - } - else out = params->outbuf; + gst_colorspace_yuv_to_rgb24(space->color_tables, + src, // Y component + src+size, // cr component + src+size+(size>>2), // cb component + dest, + space->height, + space->width); - gst_colorspace_yuv_to_rgb24(color_tables, - GST_BUFFER_DATA(src), // Y component - GST_BUFFER_DATA(src)+size, // cr component - GST_BUFFER_DATA(src)+size+(size>>2), // cb component - out, - params->height, - params->width); - - if (buf) { - gst_buffer_unref(src); - return buf; - } - else return src; } -static GstBuffer *gst_colorspace_yuv420P_to_rgb16(GstBuffer *src, GstColorSpaceParameters *params) { - static GstColorSpaceYUVTables *color_tables = NULL; +static void gst_colorspace_yuv420P_to_rgb16(GstColorSpace *space, unsigned char *src, unsigned char *dest) { int size; DEBUG("gst_colorspace_yuv420P_to_rgb16\n"); - g_return_val_if_fail(params != NULL, NULL); - g_return_val_if_fail(params->visual != NULL, NULL); + size = space->width * space->height; - if (color_tables == NULL) { - color_tables = gst_colorspace_init_yuv(16, params->visual->red_mask, params->visual->green_mask, params->visual->blue_mask); - } - size = params->width * params->height; + gst_colorspace_yuv_to_rgb16(space->color_tables, + src, // Y component + src+size, // cr component + src+size+(size>>2), // cb component + dest, + space->height, + space->width); - gst_colorspace_yuv_to_rgb16(color_tables, - GST_BUFFER_DATA(src), // Y component - GST_BUFFER_DATA(src)+size, // cr component - GST_BUFFER_DATA(src)+size+(size>>2), // cb component - params->outbuf, - params->height, - params->width); - - return src; } #ifdef HAVE_LIBMMX static mmx_t MMX16_redmask = (mmx_t)(long long)0xf800f800f800f800LL; //dd 07c00 7c00h, 07c007c00h static mmx_t MMX16_grnmask = (mmx_t)(long long)0x07e007e007e007e0LL; //dd 003e0 03e0h, 003e003e0h -static GstBuffer *gst_colorspace_yuv420P_to_bgr32_mmx(GstBuffer *src, GstColorSpaceParameters *params) { +static void gst_colorspace_yuv420P_to_bgr32_mmx(GstColorSpace *space, unsigned char *src, unsigned char *dest) { int size; - GstBuffer *buf = NULL; - guchar *out; DEBUG("gst_colorspace_yuv420P_to_rgb32_mmx\n"); - g_return_val_if_fail(params != NULL, NULL); - - size = params->width * params->height; - if (params->outbuf == NULL) { - buf = gst_buffer_new(); - out = GST_BUFFER_DATA(buf) = g_malloc(size * 4); - GST_BUFFER_SIZE(buf) = size * 4; - } - else out = params->outbuf; + size = space->width * space->height; gst_colorspace_yuv_to_bgr32_mmx(NULL, - GST_BUFFER_DATA(src), // Y component - GST_BUFFER_DATA(src)+size, // cr component - GST_BUFFER_DATA(src)+size+(size>>2), // cb component - out, - params->height, - params->width); + src, // Y component + src+size, // cr component + src+size+(size>>2), // cb component + dest, + space->height, + space->width); - if (buf) { - gst_buffer_unref(src); - return buf; - } - else return src; } -static GstBuffer *gst_colorspace_yuv420P_to_bgr16_mmx(GstBuffer *src, GstColorSpaceParameters *params) { +static void gst_colorspace_yuv420P_to_bgr16_mmx(GstColorSpace *space, unsigned char *src, unsigned char *dest) { int size; DEBUG("gst_colorspace_yuv420P_to_bgr16_mmx \n"); - g_return_val_if_fail(params != NULL, NULL); - - size = params->width * params->height; + size = space->width * space->height; gst_colorspace_yuv_to_bgr16_mmx(NULL, - GST_BUFFER_DATA(src), // Y component - GST_BUFFER_DATA(src)+size, // cr component - GST_BUFFER_DATA(src)+size+(size>>2), // cb component - params->outbuf, - params->height, - params->width); + src, // Y component + src+size, // cr component + src+size+(size>>2), // cb component + dest, + space->height, + space->width); DEBUG("gst_colorspace_yuv420P_to_bgr16_mmx done\n"); - return src; } #endif diff --git a/libs/colorspace/yuv2rgb.h b/libs/colorspace/yuv2rgb.h index 59e6fc255e..e0e8772701 100644 --- a/libs/colorspace/yuv2rgb.h +++ b/libs/colorspace/yuv2rgb.h @@ -19,6 +19,9 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ +#ifndef __YUV2RGB_H__ +#define __YUV2RGB_H__ + typedef struct _GstColorSpaceYUVTables GstColorSpaceYUVTables; struct _GstColorSpaceYUVTables { @@ -61,4 +64,5 @@ struct _GstColorSpaceYUVTables { ? Min(127.0, ((x) * chromaCorrect)) \ : Max(-128.0, ((x) * chromaCorrect))) +#endif diff --git a/libs/videoscale/Makefile.am b/libs/videoscale/Makefile.am index c82bc4df62..19b0920134 100644 --- a/libs/videoscale/Makefile.am +++ b/libs/videoscale/Makefile.am @@ -9,7 +9,7 @@ libgstvideoscaleinclude_HEADERS = gstvideoscale.h noinst_HEADERS = yuv2rgb.h -CFLAGS += -Wall -O2 -fomit-frame-pointer -funroll-all-loops -finline-functions -ffast-math +CFLAGS += -Wall -O2 -fomit-frame-pointer -funroll-all-loops -finline-functions -ffast-math INCLUDES = $(GLIB_CFLAGS) $(GTK_CFLAGS) -I$(top_srcdir) -I$(top_srcdir)/include LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_srcdir)/gst/libgst.la diff --git a/libs/videoscale/gstvideoscale.c b/libs/videoscale/gstvideoscale.c index a3dd08c2aa..cca2eac8de 100644 --- a/libs/videoscale/gstvideoscale.c +++ b/libs/videoscale/gstvideoscale.c @@ -25,34 +25,70 @@ #include #include -static void gst_videoscale_scale_plane(unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh); -static void gst_videoscale_scale_plane_slow(unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh); +static void gst_videoscale_scale_yuv(GstVideoScale *scale, unsigned char *src, unsigned char *dest); -GstBuffer *gst_videoscale_scale(GstBuffer *src, int sw, int sh, int dw, int dh, int format) { - GstBuffer *outbuf; - char *source; - char *dest; - GstMeta *meta; - - DEBUG("videoscale: scaling %dx%d to %dx%d\n", sw, sh, dw, dh); +/* scalers */ +static void generate_rowbytes(unsigned char *copy_row, int src_w, int dst_w, int bpp); +static void gst_videoscale_scale_nearest(GstVideoScale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh); +static void gst_videoscale_scale_plane_slow(GstVideoScale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh); - source = GST_BUFFER_DATA(src); +/* filters */ +static unsigned char gst_videoscale_bilinear(unsigned char *src, double x, double y, int sw, int sh); +static unsigned char gst_videoscale_bicubic(unsigned char *src, double x, double y, int sw, int sh); - outbuf = gst_buffer_new(); - dest = GST_BUFFER_DATA(outbuf) = g_malloc((dw*dh*12)/8); - GST_BUFFER_SIZE(outbuf) = (dw*dh*12)/8; +GstVideoScale *gst_videoscale_new(int sw, int sh, int dw, int dh, int format, GstVideoScaleMethod method) +{ + GstVideoScale *new = g_malloc(sizeof(GstVideoScale)); - meta = gst_buffer_get_first_meta(src); - if (meta) { - ((MetaVideoRaw *)meta)->width = dw; - ((MetaVideoRaw *)meta)->height = dh; + new->source_width = sw; + new->source_height = sh; + new->dest_width = dw; + new->dest_height = dh; + new->format = format; + new->method = method; - gst_buffer_add_meta(outbuf, meta); + + new->scale = gst_videoscale_scale_yuv; + + switch (method) { + case GST_VIDEOSCALE_NEAREST: + generate_rowbytes(new->copy_row, sw, dw, 1); + new->scaler = gst_videoscale_scale_nearest; + DEBUG("videoscale: scaling method NEAREST\n"); + break; + case GST_VIDEOSCALE_BILINEAR: + new->scaler = gst_videoscale_scale_plane_slow; + new->filter = gst_videoscale_bilinear; + break; + case GST_VIDEOSCALE_BICUBIC: + new->scaler = gst_videoscale_scale_plane_slow; + new->filter = gst_videoscale_bicubic; + break; + default: + g_print("videoscale: unsupported scaling method %d\n", method); + break; } - gst_videoscale_scale_plane_slow(source, dest, sw, sh, dw, dh); + return new; +} - source += sw*sh; +void gst_videoscale_destroy(GstVideoScale *scale) +{ + g_free(scale); +} + +static void gst_videoscale_scale_yuv(GstVideoScale *scale, unsigned char *src, unsigned char *dest) +{ + int sw = scale->source_width; + int sh = scale->source_height; + int dw = scale->dest_width; + int dh = scale->dest_height; + + DEBUG("videoscale: scaling YUV420 %dx%d to %dx%d\n", sw, sh, dw, dh); + + scale->scaler(scale, src, dest, sw, sh, dw, dh); + + src += sw*sh; dest += dw*dh; dh = dh>>1; @@ -60,21 +96,17 @@ GstBuffer *gst_videoscale_scale(GstBuffer *src, int sw, int sh, int dw, int dh, sh = sh>>1; sw = sw>>1; - gst_videoscale_scale_plane_slow(source, dest, sw, sh, dw, dh); + scale->scaler(scale, src, dest, sw, sh, dw, dh); - source += sw*sh; + src += sw*sh; dest += dw*dh; - gst_videoscale_scale_plane_slow(source, dest, sw, sh, dw, dh); - - gst_buffer_unref(src); - - return outbuf; + scale->scaler(scale, src, dest, sw, sh, dw, dh); } #define RC(x,y) *(src+(int)(x)+(int)((y)*sw)) -static unsigned char gst_videoscale_bilinear(unsigned char *src, double x, double y, int sw) { +static unsigned char gst_videoscale_bilinear(unsigned char *src, double x, double y, int sw, int sh) { int j=floor(x); int k=floor(y); double a=x-j; @@ -83,8 +115,10 @@ static unsigned char gst_videoscale_bilinear(unsigned char *src, double x, doubl int color; dest=(1-a)*(1-b)*RC(j,k)+ - a*(1-b)*RC(j+1,k)+ - b*(1-a)*RC(j,k+1)+ + a*(1-b)*RC(j+1,k); + + k = MIN(sh-1, k); + dest+= b*(1-a)*RC(j,k+1)+ a*b*RC(j+1,k+1); color=rint(dest); @@ -127,7 +161,8 @@ static unsigned char gst_videoscale_bicubic(unsigned char *src, double x, double return (unsigned char) color; } -static void gst_videoscale_scale_plane_slow(unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh) { +static void gst_videoscale_scale_plane_slow(GstVideoScale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh) +{ double zoomx = ((double)dw)/(double)sw; double zoomy = ((double)dh)/(double)sh; double xr, yr; @@ -142,62 +177,93 @@ static void gst_videoscale_scale_plane_slow(unsigned char *src, unsigned char *d *dest++ = RC(xr, yr); } else { - //*dest++ = gst_videoscale_bilinear(src, xr, yr, sw); - *dest++ = gst_videoscale_bicubic(src, xr, yr, sw, sh); + *dest++ = scale->filter(src, xr, yr, sw, sh); + //*dest++ = gst_videoscale_bicubic(src, xr, yr, sw, sh); } } } } -static void gst_videoscale_scale_plane(unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh) { +#define PREFIX16 0x66 +#define STORE_BYTE 0xAA +#define STORE_WORD 0xAB +#define LOAD_BYTE 0xAC +#define LOAD_WORD 0xAD +#define RETURN 0xC3 - int yinc = sh / dh; - int srcys = sh % dh; - int destys = dh; - int dy = 2 * (srcys - destys); - int incyE = 2 * srcys; - int incyNE = 2 * (srcys - destys); - int x, y; +static void generate_rowbytes(unsigned char *copy_row, int src_w, int dst_w, int bpp) +{ + int i; + int pos, inc; + unsigned char *eip; + unsigned char load, store; - int xinc = sw / dw; - int srcxs = sw % dw; - int destxs = dw; - int incxE = 2 * srcxs; - int incxNE = 2 * (srcxs - destxs); - int dx; - unsigned char *sourcep; - int srcinc = 0; - int xskip, yskip =0; + DEBUG("videoscale: setup scaling %p\n", copy_row); - for (y = 0; y= 0x10000L ) { + if ( bpp == 2 ) { + *eip++ = PREFIX16; + } + *eip++ = load; + pos -= 0x10000L; + } + if ( bpp == 2 ) { + *eip++ = PREFIX16; + } + *eip++ = store; + pos += inc; + } + *eip++ = RETURN; +} + + +static void gst_videoscale_scale_nearest(GstVideoScale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh) +{ + int pos, inc, y; + int u1, u2; + + scale->temp = scale->copy_row; + + DEBUG("videoscale: scaling nearest %p\n", scale->copy_row); + + pos = 0x10000; + inc = (sh<<16)/dh; + + for (y = dh; y; y--) { + + while (pos >0x10000) { + src += sw; + pos-=0x10000; + } + __asm__ __volatile__ (" + movl %2, %%eax\n + call *%%eax + " + : "=&D" (u1), "=&S" (u2) + : "g" (scale->temp), "0" (dest), "1" (src) + : "memory" ); + + dest+= dw; + + pos += inc; + } + DEBUG("videoscale: scaling nearest done %p\n", scale->copy_row); } diff --git a/libs/videoscale/gstvideoscale.h b/libs/videoscale/gstvideoscale.h index 064c5756eb..a96d67b7c4 100644 --- a/libs/videoscale/gstvideoscale.h +++ b/libs/videoscale/gstvideoscale.h @@ -21,10 +21,32 @@ #ifndef __GST_VIDEOSCALE_H__ #define __GST_VIDEOSCALE_H__ -#include -#include -#include +#include -GstBuffer *gst_videoscale_scale(GstBuffer *src, int sw, int sh, int dw, int dh, int format); +typedef enum { + GST_VIDEOSCALE_NEAREST, + GST_VIDEOSCALE_BILINEAR, + GST_VIDEOSCALE_BICUBIC +} GstVideoScaleMethod; + +typedef struct _GstVideoScale GstVideoScale; + +struct _GstVideoScale { + guint source_width; + guint source_height; + guint dest_width; + guint dest_height; + guint format; + GstVideoScaleMethod method; + /* private */ + guchar copy_row[4096]; + guchar *temp; + void (*scale) (GstVideoScale *scale, unsigned char *src, unsigned char *dest); + void (*scaler) (GstVideoScale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh); + unsigned char (*filter) (unsigned char *src, double x, double y, int sw, int sh); +}; + +GstVideoScale *gst_videoscale_new(int sw, int sh, int dw, int dh, int format, GstVideoScaleMethod method); +void gst_videoscale_destroy(GstVideoScale *scale); #endif /* __GST_VIDEOSCALE_H__ */ diff --git a/test/mp1parse.c b/test/mp1parse.c index 06f5743daa..5670b389e8 100644 --- a/test/mp1parse.c +++ b/test/mp1parse.c @@ -14,7 +14,7 @@ void eof(GstSrc *src) { } void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) { - GstElement *parse_audio, *parse_video, *decode, *decode_video, *play, *show; + GstElement *parse_audio, *parse_video, *decode, *decode_video, *play, *videoscale, *show; GstElement *audio_queue, *video_queue; GstElement *audio_thread, *video_thread; @@ -71,12 +71,18 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) { gst_plugin_load("mp1videoparse"); gst_plugin_load(VIDEO_DECODER); + gst_plugin_load("videoscale"); gst_plugin_load("videosink"); // construct internal pipeline elements parse_video = gst_elementfactory_make("mp1videoparse","parse_video"); g_return_if_fail(parse_video != NULL); decode_video = gst_elementfactory_make(VIDEO_DECODER,"decode_video"); g_return_if_fail(decode_video != NULL); + videoscale = gst_elementfactory_make("videoscale","videoscale"); + g_return_if_fail(videoscale != NULL); + gtk_object_set(GTK_OBJECT(videoscale),"width",704, "height", 576,NULL); + + show = gst_elementfactory_make("videosink","show"); g_return_if_fail(show != NULL); //gtk_object_set(GTK_OBJECT(show),"width",640, "height", 480,NULL); @@ -91,6 +97,7 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) { g_return_if_fail(video_thread != NULL); gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(parse_video)); gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(decode_video)); + gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(videoscale)); gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(show)); // set up pad connections @@ -99,6 +106,8 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) { gst_pad_connect(gst_element_get_pad(parse_video,"src"), gst_element_get_pad(decode_video,"sink")); gst_pad_connect(gst_element_get_pad(decode_video,"src"), + // gst_element_get_pad(videoscale,"sink")); + //gst_pad_connect(gst_element_get_pad(videoscale,"src"), gst_element_get_pad(show,"sink")); // construct queue and connect everything in the main pipeline diff --git a/test/mp2tomp1.c b/test/mp2tomp1.c index dce23984bc..70e4bb729d 100644 --- a/test/mp2tomp1.c +++ b/test/mp2tomp1.c @@ -139,18 +139,17 @@ void mp2tomp1(GstElement *parser,GstPad *pad, GstElement *pipeline) { g_return_if_fail(decode_video != NULL); videoscale = gst_elementfactory_make("videoscale","videoscale"); g_return_if_fail(videoscale != NULL); - g_return_if_fail(median != NULL); + gtk_object_set(GTK_OBJECT(videoscale),"width",352, "height", 240,NULL); median = gst_elementfactory_make("median","median"); - gtk_object_set(GTK_OBJECT(median),"filtersize",5,NULL); + g_return_if_fail(median != NULL); + gtk_object_set(GTK_OBJECT(median),"filtersize",9,NULL); smooth = gst_elementfactory_make("smooth","smooth"); g_return_if_fail(smooth != NULL); gtk_object_set(GTK_OBJECT(smooth),"filtersize",5,NULL); gtk_object_set(GTK_OBJECT(smooth),"tolerance",9,NULL); - - gtk_object_set(GTK_OBJECT(videoscale),"width",352, "height", 240,NULL); encode = gst_elementfactory_make("mpeg2enc","encode"); - gtk_object_set(GTK_OBJECT(encode),"frames_per_second",29.97,NULL); g_return_if_fail(encode != NULL); + gtk_object_set(GTK_OBJECT(encode),"frames_per_second",29.97,NULL); //encode = gst_elementfactory_make("mpeg1encoder","encode"); //gtk_object_set(GTK_OBJECT(show),"width",640, "height", 480,NULL); @@ -172,10 +171,10 @@ void mp2tomp1(GstElement *parser,GstPad *pad, GstElement *pipeline) { gst_pad_connect(gst_element_get_pad(parse_video,"src"), gst_element_get_pad(decode_video,"sink")); gst_pad_connect(gst_element_get_pad(decode_video,"src"), - gst_element_get_pad(videoscale,"sink")); - gst_pad_connect(gst_element_get_pad(videoscale,"src"), gst_element_get_pad(median,"sink")); gst_pad_connect(gst_element_get_pad(median,"src"), + gst_element_get_pad(videoscale,"sink")); + gst_pad_connect(gst_element_get_pad(videoscale,"src"), // gst_element_get_pad(smooth,"sink")); //gst_pad_connect(gst_element_get_pad(smooth,"src"), gst_element_get_pad(encode,"sink"));