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.
This commit is contained in:
David Schleef 2003-04-22 07:32:50 +00:00
parent 9cd5e80245
commit 856cea1d53
4 changed files with 686 additions and 221 deletions

View file

@ -20,6 +20,7 @@
/*#define DEBUG_ENABLED */ /*#define DEBUG_ENABLED */
#include <gstvideoscale.h> #include <gstvideoscale.h>
#include <videoscale.h>
@ -48,28 +49,6 @@ enum {
/* FILL ME */ /* 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()) #define GST_TYPE_VIDEOSCALE_METHOD (gst_videoscale_method_get_type())
static GType static GType
gst_videoscale_method_get_type (void) 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_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
static void gst_videoscale_chain (GstPad *pad, GstBuffer *buf); static void gst_videoscale_chain (GstPad *pad, GstBuffer *buf);
static GstCaps * gst_videoscale_get_capslist(void);
static GstElementClass *parent_class = NULL; static GstElementClass *parent_class = NULL;
/*static guint gst_videoscale_signals[LAST_SIGNAL] = { 0 }; */ /*static guint gst_videoscale_signals[LAST_SIGNAL] = { 0 }; */
@ -146,70 +126,189 @@ gst_videoscale_class_init (GstVideoscaleClass *klass)
} }
/* static GstPadTemplate *
static GstPadNegotiateReturn gst_videoscale_src_template_factory(void)
videoscale_negotiate_src (GstPad *pad, GstCaps **caps, gpointer *data)
{ {
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){ caps = gst_caps_intersect(caps, gst_videoscale_get_capslist ());
return GST_PAD_NEGOTIATE_FAIL;
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", for(i=0;i<videoscale_n_formats;i++){
"video/raw", caps = videoscale_get_caps(videoscale_formats + i);
"format", GST_PROPS_FOURCC (videoscale->format), capslist = gst_caps_append(capslist, caps);
"width", GST_PROPS_INT (videoscale->targetwidth), }
"height", GST_PROPS_INT (videoscale->targetheight)
);
return GST_PAD_NEGOTIATE_AGREE; gst_caps_ref(capslist);
return capslist;
} }
static GstPadNegotiateReturn static GstCaps *
videoscale_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data) gst_videoscale_getcaps (GstPad *pad, GstCaps *caps)
{
GST_DEBUG(0,"videoscale_negotiate_sink");
if (*caps==NULL)
return GST_PAD_NEGOTIATE_FAIL;
return GST_PAD_NEGOTIATE_AGREE;
}
*/
static GstPadLinkReturn
gst_videoscale_sinkconnect (GstPad *pad, GstCaps *caps)
{ {
GstVideoscale *videoscale; GstVideoscale *videoscale;
GstCaps *capslist = NULL;
GstCaps *peercaps;
GstCaps *sizecaps;
int i;
GST_DEBUG(0,"gst_videoscale_sinkconnect"); GST_DEBUG(0,"gst_videoscale_src_link");
videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad));
/* get list of peer's caps */
if(pad == videoscale->srcpad){
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;i<videoscale_n_formats;i++){
GstCaps *fromcaps = videoscale_get_caps(videoscale_formats + i);
if(gst_caps_is_always_compatible(fromcaps, peercaps)){
capslist = gst_caps_append(capslist, fromcaps);
}
gst_caps_unref (fromcaps);
}
gst_caps_unref (peercaps);
sizecaps = GST_CAPS_NEW("videoscale_size","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 ());
gst_caps_unref (sizecaps);
return caps;
}
static GstPadLinkReturn
gst_videoscale_src_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)); videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad));
if (!GST_CAPS_IS_FIXED (caps)) { if (!GST_CAPS_IS_FIXED (caps)) {
return GST_PAD_LINK_DELAYED; return GST_PAD_LINK_DELAYED;
} }
gst_caps_get_fourcc_int (caps, "format", &videoscale->format); videoscale->format = videoscale_find_by_caps (caps);
gst_caps_get_int (caps, "width", &videoscale->width); gst_caps_get_int (caps, "width", &videoscale->to_width);
gst_caps_get_int (caps, "height", &videoscale->height); gst_caps_get_int (caps, "height", &videoscale->to_height);
gst_videoscale_setup(videoscale); gst_videoscale_setup(videoscale);
GST_DEBUG (0,"target size %d x %d",videoscale->targetwidth, GST_DEBUG(0,"width %d height %d",videoscale->to_width,videoscale->to_height);
videoscale->targetheight);
GST_DEBUG(0,"width %d",videoscale->targetwidth); peercaps = gst_caps_copy(caps);
return gst_pad_try_set_caps (videoscale->srcpad,
GST_CAPS_NEW ( gst_caps_set(peercaps, "width", GST_PROPS_INT_RANGE (0, G_MAXINT));
"videoscale_src", gst_caps_set(peercaps, "height", GST_PROPS_INT_RANGE (0, G_MAXINT));
"video/raw",
"format", GST_PROPS_FOURCC (videoscale->format), ret = gst_pad_try_set_caps (videoscale->srcpad, peercaps);
"width", GST_PROPS_INT (videoscale->targetwidth),
"height", GST_PROPS_INT (videoscale->targetheight) 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 static void
@ -217,19 +316,23 @@ gst_videoscale_init (GstVideoscale *videoscale)
{ {
GST_DEBUG(0,"gst_videoscale_init"); GST_DEBUG(0,"gst_videoscale_init");
videoscale->sinkpad = gst_pad_new_from_template ( videoscale->sinkpad = gst_pad_new_from_template (
GST_PAD_TEMPLATE_GET (sink_templ), "sink"); GST_PAD_TEMPLATE_GET (gst_videoscale_sink_template_factory),
/*gst_pad_set_negotiate_function(videoscale->sinkpad,videoscale_negotiate_sink); */ "sink");
gst_element_add_pad(GST_ELEMENT(videoscale),videoscale->sinkpad); gst_element_add_pad(GST_ELEMENT(videoscale),videoscale->sinkpad);
gst_pad_set_chain_function(videoscale->sinkpad,gst_videoscale_chain); 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 ( videoscale->srcpad = gst_pad_new_from_template (
GST_PAD_TEMPLATE_GET (src_templ), "src"); GST_PAD_TEMPLATE_GET (gst_videoscale_src_template_factory),
/*gst_pad_set_negotiate_function(videoscale->srcpad,videoscale_negotiate_src); */ "src");
gst_element_add_pad(GST_ELEMENT(videoscale),videoscale->srcpad); 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_NEAREST;
/*videoscale->method = GST_VIDEOSCALE_BILINEAR; */ /*videoscale->method = GST_VIDEOSCALE_BILINEAR; */
/*videoscale->method = GST_VIDEOSCALE_POINT_SAMPLE; */ /*videoscale->method = GST_VIDEOSCALE_POINT_SAMPLE; */
@ -251,35 +354,39 @@ gst_videoscale_chain (GstPad *pad, GstBuffer *buf)
g_return_if_fail (buf != NULL); g_return_if_fail (buf != NULL);
videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad)); videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad));
g_return_if_fail (videoscale->inited);
data = GST_BUFFER_DATA(buf); data = GST_BUFFER_DATA(buf);
size = GST_BUFFER_SIZE(buf); size = GST_BUFFER_SIZE(buf);
if(!videoscale->scale_cc){ if(videoscale->passthru){
gst_caps_get_int (gst_pad_get_caps(pad), "format", &videoscale->format); gst_pad_push(videoscale->srcpad, buf);
gst_videoscale_setup(videoscale); return;
} }
GST_DEBUG (0,"gst_videoscale_chain: got buffer of %ld bytes in '%s'",size, GST_DEBUG (0,"gst_videoscale_chain: got buffer of %ld bytes in '%s'",size,
GST_OBJECT_NAME (videoscale)); 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, size,
videoscale->width, videoscale->height, videoscale->from_width, videoscale->from_height,
videoscale->targetwidth, videoscale->targetheight, videoscale->to_width, videoscale->to_height,
videoscale->targetwidth*videoscale->targetheight + videoscale->targetwidth*videoscale->targetheight/2); size, videoscale->from_buf_size,
videoscale->to_buf_size);
g_return_if_fail (size == videoscale->from_buf_size);
if(videoscale->targetwidth==videoscale->width &&
videoscale->targetheight==videoscale->height){
gst_pad_push(videoscale->srcpad, buf);
}else{
outbuf = gst_buffer_new(); outbuf = gst_buffer_new();
/* XXX this is wrong for anything but I420 */ /* FIXME: handle bufferpools */
GST_BUFFER_SIZE(outbuf) = videoscale->targetwidth*videoscale->targetheight + GST_BUFFER_SIZE(outbuf) = videoscale->to_buf_size;
videoscale->targetwidth*videoscale->targetheight/2; GST_BUFFER_DATA(outbuf) = g_malloc (videoscale->to_buf_size);
GST_BUFFER_DATA(outbuf) = g_malloc (videoscale->targetwidth*videoscale->targetheight*2);
GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf); GST_BUFFER_TIMESTAMP(outbuf) = GST_BUFFER_TIMESTAMP(buf);
/*g_return_if_fail(videoscale->scale_cc != NULL); */ g_return_if_fail(videoscale->format);
videoscale->scale_cc(videoscale, data, GST_BUFFER_DATA(outbuf)); GST_DEBUG (0,"format %s",videoscale->format->fourcc);
g_return_if_fail(videoscale->format->scale);
videoscale->format->scale(videoscale, GST_BUFFER_DATA(outbuf), data);
GST_DEBUG (0,"gst_videoscale_chain: pushing buffer of %d bytes in '%s'",GST_BUFFER_SIZE(outbuf), GST_DEBUG (0,"gst_videoscale_chain: pushing buffer of %d bytes in '%s'",GST_BUFFER_SIZE(outbuf),
GST_OBJECT_NAME (videoscale)); GST_OBJECT_NAME (videoscale));
@ -287,7 +394,6 @@ GST_DEBUG(0,"size=%ld from=%dx%d to=%dx%d newsize=%d",
gst_pad_push(videoscale->srcpad, outbuf); gst_pad_push(videoscale->srcpad, outbuf);
gst_buffer_unref(buf); gst_buffer_unref(buf);
}
} }
static void 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"); GST_DEBUG(0,"gst_videoscale_set_property");
switch (prop_id) { switch (prop_id) {
case ARG_WIDTH: case ARG_WIDTH:
src->targetwidth = g_value_get_int (value); src->forced_width = g_value_get_int (value);
src->force_size = TRUE;
break; break;
case ARG_HEIGHT: case ARG_HEIGHT:
src->targetheight = g_value_get_int (value); src->forced_height = g_value_get_int (value);
src->force_size = TRUE;
break; break;
case ARG_METHOD: case ARG_METHOD:
src->method = g_value_get_enum (value); 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) { switch (prop_id) {
case ARG_WIDTH: case ARG_WIDTH:
g_value_set_int (value, src->targetwidth); g_value_set_int (value, src->forced_width);
break; break;
case ARG_HEIGHT: case ARG_HEIGHT:
g_value_set_int (value, src->targetheight); g_value_set_int (value, src->forced_height);
break; break;
case ARG_METHOD: case ARG_METHOD:
g_value_set_enum (value, src->method); g_value_set_enum (value, src->method);
@ -351,8 +459,8 @@ plugin_init (GModule *module, GstPlugin *plugin)
&videoscale_details); &videoscale_details);
g_return_val_if_fail(factory != NULL, FALSE); 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 (gst_videoscale_sink_template_factory));
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_src_template_factory));
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory)); gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));

View file

@ -57,21 +57,29 @@ struct _GstVideoscale {
GstPad *sinkpad,*srcpad; GstPad *sinkpad,*srcpad;
gboolean force_size;
gint forced_width;
gint forced_height;
/* video state */ /* video state */
guint32 format; gboolean inited;
gint width; struct videoscale_format_struct *format;
gint height; gint to_width;
gint targetwidth; gint to_height;
gint targetheight; gint from_width;
gint from_height;
gboolean passthru;
GstVideoScaleMethod method; GstVideoScaleMethod method;
guint scale_bytes;
/* private */ /* private */
gint from_buf_size;
gint to_buf_size;
#if 0
guchar *temp; 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 (*filter) (guchar *src, gdouble x, gdouble y, gint sw, gint sh);
guchar copy_row[8192]; guchar copy_row[8192];
#endif
}; };
struct _GstVideoscaleClass { struct _GstVideoscaleClass {

View file

@ -18,8 +18,11 @@
*/ */
#define DEBUG_ENABLED #define DEBUG_ENABLED
#include <gst/gst.h>
#include <stdlib.h> #include <stdlib.h>
#include <math.h> #include <math.h>
#include <videoscale.h>
#include <string.h>
#include "config.h" #include "config.h"
#include "gstvideoscale.h" #include "gstvideoscale.h"
@ -28,79 +31,152 @@
#include "videoscale_x86.h" #include "videoscale_x86.h"
#endif #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 */ /* 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); 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, static void gst_videoscale_scale_plane_slow (GstVideoscale *scale, unsigned char *src, unsigned char *dest,
int sw, int sh, int dw, int dh); int sw, int sh, int dw, int dh);
static void gst_videoscale_scale_point_sample (GstVideoscale *scale, unsigned char *src, unsigned char *dest, static void gst_videoscale_scale_point_sample (GstVideoscale *scale, unsigned char *src, unsigned char *dest,
int sw, int sh, int dw, int dh); int sw, int sh, int dw, int dh);
#endif
/* filters */ /* filters */
static unsigned char gst_videoscale_bilinear (unsigned char *src, double x, double y, int sw, int sh); 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); static unsigned char gst_videoscale_bicubic (unsigned char *src, double x, double y, int sw, int sh);
void static void gst_videoscale_planar411 (GstVideoscale *scale, unsigned char *dest, unsigned char *src);
gst_videoscale_setup (GstVideoscale *scale) 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) { unsigned int fourcc;
case GST_MAKE_FOURCC('I','4','2','0'): GstCaps *caps;
scale->scale_cc = gst_videoscale_scale_yuv;
scale->scale_bytes = 1; if(format->scale==NULL)
break; return NULL;
case GST_MAKE_FOURCC('R','G','B',' '):
scale->scale_cc = gst_videoscale_scale_rgb; fourcc = GST_MAKE_FOURCC(format->fourcc[0],format->fourcc[1],format->fourcc[2],format->fourcc[3]);
/* XXX */
/*scale->scale_bytes = gst_caps_get_int(scale->srcpad->caps,"bpp")/8; */ if(format->bpp){
break; caps = GST_CAPS_NEW ("videoscale", "video/raw",
default: "format", GST_PROPS_FOURCC (fourcc),
g_print("videoscale: unsupported video format %08x\n", scale->format); "depth", GST_PROPS_INT(format->bpp),
return; /* XXX */ "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) { return caps;
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 */
} }
static void struct videoscale_format_struct *
gst_videoscale_scale_rgb (GstVideoscale *scale, unsigned char *src, unsigned char *dest) videoscale_find_by_caps(GstCaps *caps)
{ {
int sw = scale->width; int i;
int sh = scale->height;
int dw = scale->targetwidth; GST_DEBUG (0,"finding %p",caps);
int dh = scale->targetheight;
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); GST_DEBUG (0,"videoscale: scaling RGB %dx%d to %dx%d", sw, sh, dw, dh);
switch (scale->scale_bytes) { 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); 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 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 sw = scale->from_width;
int sh = scale->height; int sh = scale->from_height;
int dw = scale->targetwidth; int dw = scale->to_width;
int dh = scale->targetheight; 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; src += sw*sh;
dest += dw*dh; dest += dw*dh;
@ -140,12 +217,85 @@ gst_videoscale_scale_yuv (GstVideoscale *scale, unsigned char *src, unsigned cha
sh = sh>>1; sh = sh>>1;
sw = sw>>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; src += sw*sh;
dest += dw*dh; 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)) #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; return (unsigned char) color;
} }
#if 0
static void static void
gst_videoscale_scale_plane_slow (GstVideoscale *scale, unsigned char *src, unsigned char *dest, gst_videoscale_scale_plane_slow (GstVideoscale *scale, unsigned char *src, unsigned char *dest,
int sw, int sh, int dw, int dh) 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 static void
gst_videoscale_scale_point_sample (GstVideoscale *scale, unsigned char *src, unsigned char *dest, gst_videoscale_scale_point_sample (GstVideoscale *scale, unsigned char *src, unsigned char *dest,
int sw, int sh, int dw, int dh) 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; ypos += yinc;
} }
} }
#endif
static void static void
gst_videoscale_scale_nearest (GstVideoscale *scale, gst_videoscale_scale_nearest (GstVideoscale *scale,
unsigned char *src,
unsigned char *dest, unsigned char *dest,
unsigned char *src,
int sw, int sh, int dw, int dh) int sw, int sh, int dw, int dh)
{ {
int ypos, yinc, y; int ypos, yinc, y;
int xpos, xinc, x; 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; ypos = 0x10000;
@ -316,41 +472,8 @@ gst_videoscale_scale_nearest (GstVideoscale *scale,
xpos = 0x10000; xpos = 0x10000;
switch (scale->scale_bytes) { srcp = src;
case 4: destp = dest;
{
guint32 *destp = (guint32 *)dest;
guint32 *srcp = (guint32 *)src;
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-- ) { for ( x=dw; x; x-- ) {
while ( xpos >= 0x10000L ) { while ( xpos >= 0x10000L ) {
@ -360,11 +483,191 @@ gst_videoscale_scale_nearest (GstVideoscale *scale,
*destp++ = *srcp; *destp++ = *srcp;
xpos += xinc; xpos += xinc;
} }
}
}
dest += dw; dest += dw;
ypos += yinc; ypos += yinc;
} }
} }
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;
}
}

View file

@ -0,0 +1,46 @@
/* GStreamer
* Copyright (C) <2003> David A. Schleef <ds@schleef.org>
*
* 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