From 856cea1d53f079c016adc18ca552817d3fc15205 Mon Sep 17 00:00:00 2001 From: David Schleef Date: Tue, 22 Apr 2003 07:32:50 +0000 Subject: [PATCH] Rewrote much of videoscale. Now handles most common YUV formats as well as 32 and 24 bit RGB. Only handles "nearest... Original commit message from CVS: Rewrote much of videoscale. Now handles most common YUV formats as well as 32 and 24 bit RGB. Only handles "nearest" scaling. --- gst/videoscale/gstvideoscale.c | 312 +++++++++++++------- gst/videoscale/gstvideoscale.h | 24 +- gst/videoscale/videoscale.c | 525 ++++++++++++++++++++++++++------- gst/videoscale/videoscale.h | 46 +++ 4 files changed, 686 insertions(+), 221 deletions(-) create mode 100644 gst/videoscale/videoscale.h diff --git a/gst/videoscale/gstvideoscale.c b/gst/videoscale/gstvideoscale.c index 9171a40242..4eb2d70c01 100644 --- a/gst/videoscale/gstvideoscale.c +++ b/gst/videoscale/gstvideoscale.c @@ -20,6 +20,7 @@ /*#define DEBUG_ENABLED */ #include +#include @@ -48,28 +49,6 @@ enum { /* FILL ME */ }; -GST_PAD_TEMPLATE_FACTORY (sink_templ, - "sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_CAPS_NEW ( - "videoscale_caps", - "video/raw", - "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')) - ) -) - -GST_PAD_TEMPLATE_FACTORY (src_templ, - "src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_CAPS_NEW ( - "videoscale_caps", - "video/raw", - "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('I','4','2','0')) - ) -) - #define GST_TYPE_VIDEOSCALE_METHOD (gst_videoscale_method_get_type()) static GType gst_videoscale_method_get_type (void) @@ -95,6 +74,7 @@ static void gst_videoscale_set_property (GObject *object, guint prop_id, const static void gst_videoscale_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void gst_videoscale_chain (GstPad *pad, GstBuffer *buf); +static GstCaps * gst_videoscale_get_capslist(void); static GstElementClass *parent_class = NULL; /*static guint gst_videoscale_signals[LAST_SIGNAL] = { 0 }; */ @@ -146,70 +126,189 @@ gst_videoscale_class_init (GstVideoscaleClass *klass) } -/* -static GstPadNegotiateReturn -videoscale_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data) +static GstPadTemplate * +gst_videoscale_src_template_factory(void) { - GstVideoscale *videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad)); + static GstPadTemplate *templ = NULL; - GST_DEBUG(0,"videoscale_negotiate_src"); + if(!templ){ + GstCaps *caps = GST_CAPS_NEW("src","video/raw", + "width", GST_PROPS_INT_RANGE (0, G_MAXINT), + "height", GST_PROPS_INT_RANGE (0, G_MAXINT)); - if(*caps==NULL){ - return GST_PAD_NEGOTIATE_FAIL; + caps = gst_caps_intersect(caps, gst_videoscale_get_capslist ()); + + templ = GST_PAD_TEMPLATE_NEW("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps); + } + return templ; +} + +static GstPadTemplate * +gst_videoscale_sink_template_factory(void) +{ + static GstPadTemplate *templ = NULL; + + if(!templ){ + GstCaps *caps = GST_CAPS_NEW("sink","video/raw", + "width", GST_PROPS_INT_RANGE (0, G_MAXINT), + "height", GST_PROPS_INT_RANGE (0, G_MAXINT)); + + caps = gst_caps_intersect(caps, gst_videoscale_get_capslist ()); + + templ = GST_PAD_TEMPLATE_NEW("src", GST_PAD_SINK, GST_PAD_ALWAYS, caps); + } + return templ; +} + +static GstCaps * +gst_videoscale_get_capslist(void) +{ + static GstCaps *capslist = NULL; + GstCaps *caps; + int i; + + if (capslist){ + gst_caps_ref(capslist); + return capslist; } - *caps = GST_CAPS_NEW ( "videoscale_caps", - "video/raw", - "format", GST_PROPS_FOURCC (videoscale->format), - "width", GST_PROPS_INT (videoscale->targetwidth), - "height", GST_PROPS_INT (videoscale->targetheight) - ); + for(i=0;isrcpad){ + peercaps = gst_pad_get_allowed_caps (videoscale->sinkpad); + }else{ + peercaps = gst_pad_get_allowed_caps (videoscale->srcpad); + } + + /* FIXME videoscale doesn't allow passthru of video formats it + * doesn't understand. */ + /* Look through our list of caps and find those that match with + * the peer's formats. Create a list of them. */ + for(i=0;iformat); - gst_caps_get_int (caps, "width", &videoscale->width); - gst_caps_get_int (caps, "height", &videoscale->height); + videoscale->format = videoscale_find_by_caps (caps); + gst_caps_get_int (caps, "width", &videoscale->to_width); + gst_caps_get_int (caps, "height", &videoscale->to_height); gst_videoscale_setup(videoscale); - GST_DEBUG (0,"target size %d x %d",videoscale->targetwidth, - videoscale->targetheight); + GST_DEBUG(0,"width %d height %d",videoscale->to_width,videoscale->to_height); - GST_DEBUG(0,"width %d",videoscale->targetwidth); - return gst_pad_try_set_caps (videoscale->srcpad, - GST_CAPS_NEW ( - "videoscale_src", - "video/raw", - "format", GST_PROPS_FOURCC (videoscale->format), - "width", GST_PROPS_INT (videoscale->targetwidth), - "height", GST_PROPS_INT (videoscale->targetheight) - )); + peercaps = gst_caps_copy(caps); + + gst_caps_set(peercaps, "width", GST_PROPS_INT_RANGE (0, G_MAXINT)); + gst_caps_set(peercaps, "height", GST_PROPS_INT_RANGE (0, G_MAXINT)); + + ret = gst_pad_try_set_caps (videoscale->srcpad, peercaps); + + gst_caps_unref(peercaps); + + if(ret==GST_PAD_LINK_OK){ + caps = gst_pad_get_caps (videoscale->srcpad); + + gst_caps_get_int (caps, "width", &videoscale->from_width); + gst_caps_get_int (caps, "height", &videoscale->from_height); + gst_videoscale_setup(videoscale); + } + + return ret; +} + +static GstPadLinkReturn +gst_videoscale_sink_link (GstPad *pad, GstCaps *caps) +{ + GstVideoscale *videoscale; + GstPadLinkReturn ret; + GstCaps *peercaps; + + GST_DEBUG(0,"gst_videoscale_src_link"); + videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad)); + + if (!GST_CAPS_IS_FIXED (caps)) { + return GST_PAD_LINK_DELAYED; + } + + videoscale->format = videoscale_find_by_caps (caps); + gst_caps_get_int (caps, "width", &videoscale->from_width); + gst_caps_get_int (caps, "height", &videoscale->from_height); + + gst_videoscale_setup(videoscale); + + peercaps = gst_caps_copy(caps); + + if(videoscale->force_size){ + gst_caps_set(peercaps, "width", GST_PROPS_INT (videoscale->forced_width)); + gst_caps_set(peercaps, "height", GST_PROPS_INT (videoscale->forced_height)); + }else{ + gst_caps_set(peercaps, "width", GST_PROPS_INT_RANGE (0, G_MAXINT)); + gst_caps_set(peercaps, "height", GST_PROPS_INT_RANGE (0, G_MAXINT)); + } + + ret = gst_pad_try_set_caps (videoscale->srcpad, peercaps); + + gst_caps_unref(peercaps); + + if(ret==GST_PAD_LINK_OK){ + caps = gst_pad_get_caps (videoscale->srcpad); + + gst_caps_get_int (caps, "width", &videoscale->to_width); + gst_caps_get_int (caps, "height", &videoscale->to_height); + gst_videoscale_setup(videoscale); + } + + return ret; } static void @@ -217,19 +316,23 @@ gst_videoscale_init (GstVideoscale *videoscale) { GST_DEBUG(0,"gst_videoscale_init"); videoscale->sinkpad = gst_pad_new_from_template ( - GST_PAD_TEMPLATE_GET (sink_templ), "sink"); - /*gst_pad_set_negotiate_function(videoscale->sinkpad,videoscale_negotiate_sink); */ + GST_PAD_TEMPLATE_GET (gst_videoscale_sink_template_factory), + "sink"); gst_element_add_pad(GST_ELEMENT(videoscale),videoscale->sinkpad); gst_pad_set_chain_function(videoscale->sinkpad,gst_videoscale_chain); - gst_pad_set_link_function(videoscale->sinkpad,gst_videoscale_sinkconnect); + gst_pad_set_link_function(videoscale->sinkpad,gst_videoscale_sink_link); + gst_pad_set_getcaps_function(videoscale->sinkpad,gst_videoscale_getcaps); videoscale->srcpad = gst_pad_new_from_template ( - GST_PAD_TEMPLATE_GET (src_templ), "src"); - /*gst_pad_set_negotiate_function(videoscale->srcpad,videoscale_negotiate_src); */ + GST_PAD_TEMPLATE_GET (gst_videoscale_src_template_factory), + "src"); gst_element_add_pad(GST_ELEMENT(videoscale),videoscale->srcpad); + gst_pad_set_link_function(videoscale->srcpad,gst_videoscale_src_link); + gst_pad_set_getcaps_function(videoscale->srcpad,gst_videoscale_getcaps); + + videoscale->inited = FALSE; + videoscale->force_size = FALSE; - videoscale->targetwidth = -1; - videoscale->targetheight = -1; videoscale->method = GST_VIDEOSCALE_NEAREST; /*videoscale->method = GST_VIDEOSCALE_BILINEAR; */ /*videoscale->method = GST_VIDEOSCALE_POINT_SAMPLE; */ @@ -251,43 +354,46 @@ gst_videoscale_chain (GstPad *pad, GstBuffer *buf) g_return_if_fail (buf != NULL); videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad)); + g_return_if_fail (videoscale->inited); + data = GST_BUFFER_DATA(buf); size = GST_BUFFER_SIZE(buf); - if(!videoscale->scale_cc){ - gst_caps_get_int (gst_pad_get_caps(pad), "format", &videoscale->format); - gst_videoscale_setup(videoscale); + if(videoscale->passthru){ + gst_pad_push(videoscale->srcpad, buf); + return; } + GST_DEBUG (0,"gst_videoscale_chain: got buffer of %ld bytes in '%s'",size, GST_OBJECT_NAME (videoscale)); -GST_DEBUG(0,"size=%ld from=%dx%d to=%dx%d newsize=%d", + GST_DEBUG(0,"size=%ld from=%dx%d to=%dx%d fromsize=%ld (should be %d) tosize=%d", size, - videoscale->width, videoscale->height, - videoscale->targetwidth, videoscale->targetheight, - videoscale->targetwidth*videoscale->targetheight + videoscale->targetwidth*videoscale->targetheight/2); + videoscale->from_width, videoscale->from_height, + videoscale->to_width, videoscale->to_height, + size, videoscale->from_buf_size, + videoscale->to_buf_size); - if(videoscale->targetwidth==videoscale->width && - videoscale->targetheight==videoscale->height){ - gst_pad_push(videoscale->srcpad, buf); - }else{ - outbuf = gst_buffer_new(); - /* XXX this is wrong for anything but I420 */ - GST_BUFFER_SIZE(outbuf) = videoscale->targetwidth*videoscale->targetheight + - videoscale->targetwidth*videoscale->targetheight/2; - GST_BUFFER_DATA(outbuf) = g_malloc (videoscale->targetwidth*videoscale->targetheight*2); - GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf); + g_return_if_fail (size == videoscale->from_buf_size); - /*g_return_if_fail(videoscale->scale_cc != NULL); */ - videoscale->scale_cc(videoscale, data, GST_BUFFER_DATA(outbuf)); + outbuf = gst_buffer_new(); + /* FIXME: handle bufferpools */ + GST_BUFFER_SIZE(outbuf) = videoscale->to_buf_size; + GST_BUFFER_DATA(outbuf) = g_malloc (videoscale->to_buf_size); + GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf); - GST_DEBUG (0,"gst_videoscale_chain: pushing buffer of %d bytes in '%s'",GST_BUFFER_SIZE(outbuf), - GST_OBJECT_NAME (videoscale)); + g_return_if_fail(videoscale->format); + GST_DEBUG (0,"format %s",videoscale->format->fourcc); + g_return_if_fail(videoscale->format->scale); - gst_pad_push(videoscale->srcpad, outbuf); + videoscale->format->scale(videoscale, GST_BUFFER_DATA(outbuf), data); - gst_buffer_unref(buf); - } + GST_DEBUG (0,"gst_videoscale_chain: pushing buffer of %d bytes in '%s'",GST_BUFFER_SIZE(outbuf), + GST_OBJECT_NAME (videoscale)); + + gst_pad_push(videoscale->srcpad, outbuf); + + gst_buffer_unref(buf); } static void @@ -302,10 +408,12 @@ gst_videoscale_set_property (GObject *object, guint prop_id, const GValue *value GST_DEBUG(0,"gst_videoscale_set_property"); switch (prop_id) { case ARG_WIDTH: - src->targetwidth = g_value_get_int (value); + src->forced_width = g_value_get_int (value); + src->force_size = TRUE; break; case ARG_HEIGHT: - src->targetheight = g_value_get_int (value); + src->forced_height = g_value_get_int (value); + src->force_size = TRUE; break; case ARG_METHOD: src->method = g_value_get_enum (value); @@ -326,10 +434,10 @@ gst_videoscale_get_property (GObject *object, guint prop_id, GValue *value, GPar switch (prop_id) { case ARG_WIDTH: - g_value_set_int (value, src->targetwidth); + g_value_set_int (value, src->forced_width); break; case ARG_HEIGHT: - g_value_set_int (value, src->targetheight); + g_value_set_int (value, src->forced_height); break; case ARG_METHOD: g_value_set_enum (value, src->method); @@ -351,8 +459,8 @@ plugin_init (GModule *module, GstPlugin *plugin) &videoscale_details); g_return_val_if_fail(factory != NULL, FALSE); - gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (sink_templ)); - gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (src_templ)); + gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (gst_videoscale_sink_template_factory)); + gst_element_factory_add_pad_template (factory, GST_PAD_TEMPLATE_GET (gst_videoscale_src_template_factory)); gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); diff --git a/gst/videoscale/gstvideoscale.h b/gst/videoscale/gstvideoscale.h index c70baea186..56308fab06 100644 --- a/gst/videoscale/gstvideoscale.h +++ b/gst/videoscale/gstvideoscale.h @@ -57,21 +57,29 @@ struct _GstVideoscale { GstPad *sinkpad,*srcpad; + gboolean force_size; + gint forced_width; + gint forced_height; + /* video state */ - guint32 format; - gint width; - gint height; - gint targetwidth; - gint targetheight; + gboolean inited; + struct videoscale_format_struct *format; + gint to_width; + gint to_height; + gint from_width; + gint from_height; + gboolean passthru; + GstVideoScaleMethod method; - guint scale_bytes; /* private */ + gint from_buf_size; + gint to_buf_size; +#if 0 guchar *temp; - void (*scale_cc) (GstVideoscale *scale, guchar *src, guchar *dest); - void (*scaler) (GstVideoscale *scale, guchar *src, guchar *dest,int,int,int,int); guchar (*filter) (guchar *src, gdouble x, gdouble y, gint sw, gint sh); guchar copy_row[8192]; +#endif }; struct _GstVideoscaleClass { diff --git a/gst/videoscale/videoscale.c b/gst/videoscale/videoscale.c index 9e5e909131..db9ad4c1ea 100644 --- a/gst/videoscale/videoscale.c +++ b/gst/videoscale/videoscale.c @@ -18,8 +18,11 @@ */ #define DEBUG_ENABLED +#include #include #include +#include +#include #include "config.h" #include "gstvideoscale.h" @@ -28,79 +31,152 @@ #include "videoscale_x86.h" #endif -static void gst_videoscale_scale_yuv (GstVideoscale *scale, unsigned char *src, unsigned char *dest); -static void gst_videoscale_scale_rgb (GstVideoscale *scale, unsigned char *src, unsigned char *dest); - /* scalers */ -static void gst_videoscale_scale_nearest (GstVideoscale *scale, unsigned char *src, unsigned char *dest, +static void gst_videoscale_scale_nearest (GstVideoscale *scale, unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh); +#if 0 static void gst_videoscale_scale_plane_slow (GstVideoscale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh); static void gst_videoscale_scale_point_sample (GstVideoscale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh); +#endif /* 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); -void -gst_videoscale_setup (GstVideoscale *scale) +static void gst_videoscale_planar411 (GstVideoscale *scale, unsigned char *dest, unsigned char *src); +static void gst_videoscale_planar400 (GstVideoscale *scale, unsigned char *dest, unsigned char *src); +static void gst_videoscale_packed422 (GstVideoscale *scale, unsigned char *dest, unsigned char *src); +static void gst_videoscale_packed422rev (GstVideoscale *scale, unsigned char *dest, unsigned char *src); +static void gst_videoscale_32bit (GstVideoscale *scale, unsigned char *dest, unsigned char *src); +static void gst_videoscale_24bit (GstVideoscale *scale, unsigned char *dest, unsigned char *src); + +static void gst_videoscale_scale_nearest_str2 (GstVideoscale *scale, + unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh); +static void gst_videoscale_scale_nearest_str4 (GstVideoscale *scale, + unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh); +static void gst_videoscale_scale_nearest_32bit (GstVideoscale *scale, + unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh); +static void gst_videoscale_scale_nearest_24bit (GstVideoscale *scale, + unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh); + +struct videoscale_format_struct videoscale_formats[] = { + /* packed */ + { "YUY2", 16, gst_videoscale_packed422, }, + { "UYVY", 16, gst_videoscale_packed422rev, }, + { "Y422", 16, gst_videoscale_packed422rev, }, + { "UYNV", 16, gst_videoscale_packed422rev, }, + { "YVYU", 16, gst_videoscale_packed422, }, + /* planar */ + { "YV12", 12, gst_videoscale_planar411, }, + { "I420", 12, gst_videoscale_planar411, }, + { "IYUV", 12, gst_videoscale_planar411, }, + { "Y800", 8, gst_videoscale_planar400, }, + { "Y8 ", 8, gst_videoscale_planar400, }, + /* RGB */ + { "RGB ", 32, gst_videoscale_32bit, 24, G_BIG_ENDIAN, 0x00ff0000, 0x0000ff00, 0x000000ff }, + { "RGB ", 32, gst_videoscale_32bit, 24, G_BIG_ENDIAN, 0x000000ff, 0x0000ff00, 0x00ff0000 }, + { "RGB ", 32, gst_videoscale_32bit, 24, G_BIG_ENDIAN, 0xff000000, 0x00ff0000, 0x0000ff00 }, + { "RGB ", 32, gst_videoscale_32bit, 24, G_BIG_ENDIAN, 0x0000ff00, 0x00ff0000, 0xff000000 }, + { "RGB ", 24, gst_videoscale_24bit, 24, G_BIG_ENDIAN, 0xff0000, 0x00ff00, 0x0000ff }, + { "RGB ", 24, gst_videoscale_24bit, 24, G_BIG_ENDIAN, 0x0000ff, 0x00ff00, 0xff0000 }, +}; + +int videoscale_n_formats = sizeof(videoscale_formats)/sizeof(videoscale_formats[0]); + +GstCaps * +videoscale_get_caps(struct videoscale_format_struct *format) { - switch (scale->format) { - case GST_MAKE_FOURCC('I','4','2','0'): - scale->scale_cc = gst_videoscale_scale_yuv; - scale->scale_bytes = 1; - break; - case GST_MAKE_FOURCC('R','G','B',' '): - scale->scale_cc = gst_videoscale_scale_rgb; - /* XXX */ - /*scale->scale_bytes = gst_caps_get_int(scale->srcpad->caps,"bpp")/8; */ - break; - default: - g_print("videoscale: unsupported video format %08x\n", scale->format); - return; /* XXX */ + unsigned int fourcc; + GstCaps *caps; + + if(format->scale==NULL) + return NULL; + + fourcc = GST_MAKE_FOURCC(format->fourcc[0],format->fourcc[1],format->fourcc[2],format->fourcc[3]); + + if(format->bpp){ + caps = GST_CAPS_NEW ("videoscale", "video/raw", + "format", GST_PROPS_FOURCC (fourcc), + "depth", GST_PROPS_INT(format->bpp), + "bpp", GST_PROPS_INT(format->depth), + "endianness", GST_PROPS_INT(format->endianness), + "red_mask", GST_PROPS_INT(format->red_mask), + "green_mask", GST_PROPS_INT(format->green_mask), + "blue_mask", GST_PROPS_INT(format->blue_mask)); + }else{ + caps = GST_CAPS_NEW ("videoscale", "video/raw", + "format", GST_PROPS_FOURCC (fourcc)); } - switch (scale->method) { - case GST_VIDEOSCALE_POINT_SAMPLE: - scale->scaler = gst_videoscale_scale_point_sample; - GST_DEBUG (0,"videoscale: scaling method POINT_SAMPLE"); - break; - case GST_VIDEOSCALE_NEAREST: -#ifdef HAVE_CPU_I386 - gst_videoscale_generate_rowbytes_x86 (scale->copy_row, scale->width, - scale->targetwidth, scale->scale_bytes); - scale->scaler = gst_videoscale_scale_nearest_x86; -#else - scale->scaler = gst_videoscale_scale_nearest; -#endif - GST_DEBUG (0,"videoscale: scaling method NEAREST"); - break; - case GST_VIDEOSCALE_BILINEAR: - scale->scaler = gst_videoscale_scale_plane_slow; - scale->filter = gst_videoscale_bilinear; - GST_DEBUG (0,"videoscale: scaling method BILINEAR"); - break; - case GST_VIDEOSCALE_BICUBIC: - scale->scaler = gst_videoscale_scale_plane_slow; - scale->filter = gst_videoscale_bicubic; - GST_DEBUG (0,"videoscale: scaling method BICUBIC"); - break; - default: - g_print("videoscale: unsupported scaling method %d\n", scale->method); - return; /* XXX */ - } - - return; /* XXX */ + return caps; } -static void -gst_videoscale_scale_rgb (GstVideoscale *scale, unsigned char *src, unsigned char *dest) +struct videoscale_format_struct * +videoscale_find_by_caps(GstCaps *caps) { - int sw = scale->width; - int sh = scale->height; - int dw = scale->targetwidth; - int dh = scale->targetheight; + int i; + + GST_DEBUG (0,"finding %p",caps); + + g_return_val_if_fail(caps != NULL, NULL); + + for (i = 0; i < videoscale_n_formats; i++){ + GstCaps *c; + + c = videoscale_get_caps(videoscale_formats + i); + if(c){ + if(gst_caps_is_always_compatible(caps, c)){ + gst_caps_unref(c); + return videoscale_formats + i; + } + gst_caps_unref(c); + } + } + + return NULL; +} + +void +gst_videoscale_setup (GstVideoscale *videoscale) +{ + GST_DEBUG (0,"format=%p \"%s\" from %dx%d to %dx%d", + videoscale->format, videoscale->format->fourcc, + videoscale->from_width, videoscale->from_height, + videoscale->to_width, videoscale->to_height); + + if(videoscale->to_width==0 || videoscale->to_height==0 || + videoscale->from_width==0 || videoscale->from_height==0){ + return; + } + + if(videoscale->to_width == videoscale->from_width && + videoscale->to_height == videoscale->from_height){ + GST_DEBUG (0,"videoscale: using passthru"); + videoscale->passthru = TRUE; + videoscale->inited = TRUE; + return; + } + + GST_DEBUG (0,"videoscale: scaling method POINT_SAMPLE"); + + videoscale->from_buf_size = (videoscale->from_width * videoscale->from_height + * videoscale->format->depth) / 8; + videoscale->to_buf_size = (videoscale->to_width * videoscale->to_height + * videoscale->format->depth) / 8; + + videoscale->inited = TRUE; +} + +#if 0 +static void +gst_videoscale_scale_rgb (GstVideoscale *scale, unsigned char *dest, unsigned char *src) +{ + int sw = scale->from_width; + int sh = scale->from_height; + int dw = scale->to_width; + int dh = scale->to_height; GST_DEBUG (0,"videoscale: scaling RGB %dx%d to %dx%d", sw, sh, dw, dh); switch (scale->scale_bytes) { @@ -117,20 +193,21 @@ gst_videoscale_scale_rgb (GstVideoscale *scale, unsigned char *src, unsigned cha } GST_DEBUG (0,"videoscale: %p %p", src, dest); - scale->scaler(scale, src, dest, sw, sh, dw, dh); + //scale->scaler(scale, src, dest, sw, sh, dw, dh); } +#endif static void -gst_videoscale_scale_yuv (GstVideoscale *scale, unsigned char *src, unsigned char *dest) +gst_videoscale_planar411 (GstVideoscale *scale, unsigned char *dest, unsigned char *src) { - int sw = scale->width; - int sh = scale->height; - int dw = scale->targetwidth; - int dh = scale->targetheight; + int sw = scale->from_width; + int sh = scale->from_height; + int dw = scale->to_width; + int dh = scale->to_height; - GST_DEBUG (0,"videoscale: scaling YUV420P %dx%d to %dx%d", sw, sh, dw, dh); + GST_DEBUG (0,"videoscale: scaling planar 4:1:1 %dx%d to %dx%d", sw, sh, dw, dh); - scale->scaler(scale, src, dest, sw, sh, dw, dh); + gst_videoscale_scale_nearest(scale, dest, src, sw, sh, dw, dh); src += sw*sh; dest += dw*dh; @@ -140,12 +217,85 @@ gst_videoscale_scale_yuv (GstVideoscale *scale, unsigned char *src, unsigned cha sh = sh>>1; sw = sw>>1; - scale->scaler(scale, src, dest, sw, sh, dw, dh); + gst_videoscale_scale_nearest(scale, dest, src, sw, sh, dw, dh); src += sw*sh; dest += dw*dh; - scale->scaler(scale, src, dest, sw, sh, dw, dh); + gst_videoscale_scale_nearest(scale, dest, src, sw, sh, dw, dh); +} + +static void +gst_videoscale_planar400 (GstVideoscale *scale, unsigned char *dest, unsigned char *src) +{ + int sw = scale->from_width; + int sh = scale->from_height; + int dw = scale->to_width; + int dh = scale->to_height; + + GST_DEBUG (0,"videoscale: scaling Y-only %dx%d to %dx%d", sw, sh, dw, dh); + + gst_videoscale_scale_nearest(scale, dest, src, sw, sh, dw, dh); +} + +static void +gst_videoscale_packed422 (GstVideoscale *scale, unsigned char *dest, unsigned char *src) +{ + int sw = scale->from_width; + int sh = scale->from_height; + int dw = scale->to_width; + int dh = scale->to_height; + + GST_DEBUG (0,"videoscale: scaling 4:2:2 %dx%d to %dx%d", sw, sh, dw, dh); + + gst_videoscale_scale_nearest_str2(scale, dest, src, sw, sh, dw, dh); + gst_videoscale_scale_nearest_str4(scale, dest+1, src+1, sw/2, sh, dw/2, dh); + gst_videoscale_scale_nearest_str4(scale, dest+3, src+3, sw/2, sh, dw/2, dh); + +} + +static void +gst_videoscale_packed422rev (GstVideoscale *scale, unsigned char *dest, unsigned char *src) +{ + int sw = scale->from_width; + int sh = scale->from_height; + int dw = scale->to_width; + int dh = scale->to_height; + + GST_DEBUG (0,"videoscale: scaling 4:2:2 %dx%d to %dx%d", sw, sh, dw, dh); + + gst_videoscale_scale_nearest_str2(scale, dest+1, src, sw, sh, dw, dh); + gst_videoscale_scale_nearest_str4(scale, dest, src+1, sw/2, sh, dw/2, dh); + gst_videoscale_scale_nearest_str4(scale, dest+2, src+3, sw/2, sh, dw/2, dh); + +} + +static void +gst_videoscale_32bit (GstVideoscale *scale, unsigned char *dest, unsigned char *src) +{ + int sw = scale->from_width; + int sh = scale->from_height; + int dw = scale->to_width; + int dh = scale->to_height; + + GST_DEBUG (0,"videoscale: scaling 32bit %dx%d to %dx%d", sw, sh, dw, dh); + + gst_videoscale_scale_nearest_32bit(scale, dest, src, sw, sh, dw, dh); + +} + +static void +gst_videoscale_24bit (GstVideoscale *scale, unsigned char *dest, unsigned char *src) +{ + int sw = scale->from_width; + int sh = scale->from_height; + int dw = scale->to_width; + int dh = scale->to_height; + + GST_DEBUG (0,"videoscale: scaling 24bit %dx%d to %dx%d", sw, sh, dw, dh); + + gst_videoscale_scale_nearest_24bit(scale, dest, src, sw, sh, dw, dh); + } #define RC(x,y) *(src+(int)(x)+(int)((y)*sw)) @@ -213,6 +363,7 @@ gst_videoscale_bicubic (unsigned char *src, double x, double y, int sw, int sh) return (unsigned char) color; } +#if 0 static void gst_videoscale_scale_plane_slow (GstVideoscale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh) @@ -242,7 +393,9 @@ gst_videoscale_scale_plane_slow (GstVideoscale *scale, unsigned char *src, unsig } } } +#endif +#if 0 static void gst_videoscale_scale_point_sample (GstVideoscale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh) @@ -290,17 +443,20 @@ gst_videoscale_scale_point_sample (GstVideoscale *scale, unsigned char *src, uns ypos += yinc; } } +#endif static void gst_videoscale_scale_nearest (GstVideoscale *scale, - unsigned char *src, unsigned char *dest, + unsigned char *src, int sw, int sh, int dw, int dh) { int ypos, yinc, y; int xpos, xinc, x; + guchar *destp = dest; + guchar *srcp = src; - GST_DEBUG (0, "videoscale: scaling nearest %p %p %d %d", src, dest, dw, scale->scale_bytes); + GST_DEBUG (0, "videoscale: scaling nearest %p %p %d", src, dest, dw); ypos = 0x10000; @@ -316,51 +472,16 @@ gst_videoscale_scale_nearest (GstVideoscale *scale, xpos = 0x10000; - switch (scale->scale_bytes) { - case 4: - { - guint32 *destp = (guint32 *)dest; - guint32 *srcp = (guint32 *)src; + srcp = src; + destp = dest; - for ( x=dw>>2; x; x-- ) { - while ( xpos >= 0x10000L ) { - srcp++; - xpos -= 0x10000L; - } - *destp++ = *srcp; - xpos += xinc; - } - break; - } - case 2: - { - guint16 *destp = (guint16 *)dest; - guint16 *srcp = (guint16 *)src; - - for ( x=dw>>1; x; x-- ) { - while ( xpos >= 0x10000L ) { - srcp++; - xpos -= 0x10000L; - } - *destp++ = *srcp; - xpos += xinc; - } - break; - } - case 1: - { - guchar *destp = dest; - guchar *srcp = src; - - for ( x=dw; x; x-- ) { - while ( xpos >= 0x10000L ) { - srcp++; - xpos -= 0x10000L; - } - *destp++ = *srcp; - xpos += xinc; - } + for ( x=dw; x; x-- ) { + while ( xpos >= 0x10000L ) { + srcp++; + xpos -= 0x10000L; } + *destp++ = *srcp; + xpos += xinc; } dest += dw; @@ -368,3 +489,185 @@ gst_videoscale_scale_nearest (GstVideoscale *scale, } } +static void +gst_videoscale_scale_nearest_str2 (GstVideoscale *scale, + unsigned char *dest, + unsigned char *src, + int sw, int sh, int dw, int dh) +{ + int ypos, yinc, y; + int xpos, xinc, x; + guchar *destp = dest; + guchar *srcp = src; + + GST_DEBUG (0, "videoscale: scaling nearest %p %p %d", src, dest, dw); + + + ypos = 0x10000; + yinc = (sh<<16)/dh; + xinc = (sw<<16)/dw; + + for (y = dh; y; y--) { + + while (ypos >0x10000) { + ypos-=0x10000; + src += sw*2; + } + + xpos = 0x10000; + + srcp = src; + destp = dest; + + for ( x=dw; x; x-- ) { + while ( xpos >= 0x10000L ) { + srcp+=2; + xpos -= 0x10000L; + } + *destp = *srcp; + destp+=2; + xpos += xinc; + } + dest += dw*2; + + ypos += yinc; + } +} + +static void +gst_videoscale_scale_nearest_str4 (GstVideoscale *scale, + unsigned char *dest, + unsigned char *src, + int sw, int sh, int dw, int dh) +{ + int ypos, yinc, y; + int xpos, xinc, x; + guchar *destp = dest; + guchar *srcp = src; + + GST_DEBUG (0, "videoscale: scaling nearest %p %p %d", src, dest, dw); + + + ypos = 0x10000; + yinc = (sh<<16)/dh; + xinc = (sw<<16)/dw; + + for (y = dh; y; y--) { + + while (ypos >0x10000) { + ypos-=0x10000; + src += sw*4; + } + + xpos = 0x10000; + + srcp = src; + destp = dest; + + for ( x=dw; x; x-- ) { + while ( xpos >= 0x10000L ) { + srcp+=4; + xpos -= 0x10000L; + } + *destp = *srcp; + destp+=4; + xpos += xinc; + } + dest += dw*4; + + ypos += yinc; + } +} + +static void +gst_videoscale_scale_nearest_32bit (GstVideoscale *scale, + unsigned char *dest, + unsigned char *src, + int sw, int sh, int dw, int dh) +{ + int ypos, yinc, y; + int xpos, xinc, x; + guchar *destp = dest; + guchar *srcp = src; + + GST_DEBUG (0, "videoscale: scaling nearest %p %p %d", src, dest, dw); + + + ypos = 0x10000; + yinc = (sh<<16)/dh; + xinc = (sw<<16)/dw; + + for (y = dh; y; y--) { + + while (ypos >0x10000) { + ypos-=0x10000; + src += sw*4; + } + + xpos = 0x10000; + + srcp = src; + destp = dest; + + for ( x=dw; x; x-- ) { + while ( xpos >= 0x10000L ) { + srcp+=4; + xpos -= 0x10000L; + } + *(guint32 *)destp = *(guint32 *)srcp; + destp+=4; + xpos += xinc; + } + dest += dw*4; + + ypos += yinc; + } +} + +static void +gst_videoscale_scale_nearest_24bit (GstVideoscale *scale, + unsigned char *dest, + unsigned char *src, + int sw, int sh, int dw, int dh) +{ + int ypos, yinc, y; + int xpos, xinc, x; + guchar *destp = dest; + guchar *srcp = src; + + GST_DEBUG (0, "videoscale: scaling nearest %p %p %d", src, dest, dw); + + + ypos = 0x10000; + yinc = (sh<<16)/dh; + xinc = (sw<<16)/dw; + + for (y = dh; y; y--) { + + while (ypos >0x10000) { + ypos-=0x10000; + src += sw*3; + } + + xpos = 0x10000; + + srcp = src; + destp = dest; + + for ( x=dw; x; x-- ) { + while ( xpos >= 0x10000L ) { + srcp+=3; + xpos -= 0x10000L; + } + destp[0] = srcp[0]; + destp[1] = srcp[1]; + destp[2] = srcp[2]; + destp+=3; + xpos += xinc; + } + dest += dw*3; + + ypos += yinc; + } +} + diff --git a/gst/videoscale/videoscale.h b/gst/videoscale/videoscale.h new file mode 100644 index 0000000000..1ebf35ad21 --- /dev/null +++ b/gst/videoscale/videoscale.h @@ -0,0 +1,46 @@ +/* GStreamer + * Copyright (C) <2003> David A. Schleef + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __VIDEOSCALE_H__ +#define __VIDEOSCALE_H__ + +#include "gstvideoscale.h" + +struct videoscale_format_struct { + char *fourcc; + int depth; + void (*scale)(GstVideoscale *,unsigned char *dest, unsigned char *src); + int bpp; + unsigned int endianness; + unsigned int red_mask; + unsigned int green_mask; + unsigned int blue_mask; +}; + +extern struct videoscale_format_struct videoscale_formats[]; +extern int videoscale_n_formats; + +GstCaps *videoscale_get_caps(struct videoscale_format_struct *format); + +struct videoscale_format_struct *videoscale_find_by_caps(GstCaps *caps); + + +#endif +