Rewrote much of videoscale. Now handles most common YUV formats as well as 32 and...
authorDavid Schleef <ds@schleef.org>
Tue, 22 Apr 2003 07:32:50 +0000 (07:32 +0000)
committerDavid Schleef <ds@schleef.org>
Tue, 22 Apr 2003 07:32:50 +0000 (07:32 +0000)
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
gst/videoscale/gstvideoscale.h
gst/videoscale/videoscale.c
gst/videoscale/videoscale.h [new file with mode: 0644]

index 9171a40..4eb2d70 100644 (file)
@@ -20,6 +20,7 @@
 
 /*#define DEBUG_ENABLED */
 #include <gstvideoscale.h>
+#include <videoscale.h>
 
 
 
@@ -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)
+{
+  static GstPadTemplate *templ = NULL;
+
+  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));
+
+    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)
 {
-  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("sink","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_SINK, GST_PAD_ALWAYS, caps);
   }
+  return templ;
+}
 
-  *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)
-                   );
+static GstCaps *
+gst_videoscale_get_capslist(void)
+{
+  static GstCaps *capslist = NULL;
+  GstCaps *caps;
+  int i;
+
+  if (capslist){
+    gst_caps_ref(capslist);
+    return capslist;
+  }
 
-  return GST_PAD_NEGOTIATE_AGREE;
+  for(i=0;i<videoscale_n_formats;i++){
+    caps = videoscale_get_caps(videoscale_formats + i);
+    capslist = gst_caps_append(capslist, caps);
+  }
+
+  gst_caps_ref(capslist);
+  return capslist;
 }
 
-static GstPadNegotiateReturn
-videoscale_negotiate_sink (GstPad *pad, GstCaps **caps, gpointer *data)
+static GstCaps *
+gst_videoscale_getcaps (GstPad *pad, GstCaps *caps)
 {
-  GST_DEBUG(0,"videoscale_negotiate_sink");
+  GstVideoscale *videoscale;
+  GstCaps *capslist = NULL;
+  GstCaps *peercaps;
+  GstCaps *sizecaps;
+  int i;
 
-  if (*caps==NULL)
-    return GST_PAD_NEGOTIATE_FAIL;
+  GST_DEBUG(0,"gst_videoscale_src_link");
+  videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad));
   
-  return GST_PAD_NEGOTIATE_AGREE;
+  /* 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_sinkconnect (GstPad *pad, GstCaps *caps)
+gst_videoscale_src_link (GstPad *pad, GstCaps *caps)
 {
   GstVideoscale *videoscale;
+  GstPadLinkReturn ret;
+  GstCaps *peercaps;
 
-  GST_DEBUG(0,"gst_videoscale_sinkconnect");
+  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;
   }
 
-  gst_caps_get_fourcc_int (caps, "format", &videoscale->format);
-  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",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)
-                   ));
+  GST_DEBUG(0,"width %d height %d",videoscale->to_width,videoscale->to_height);
+
+  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));
 
index c70baea..56308fa 100644 (file)
@@ -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 {
index 9e5e909..db9ad4c 100644 (file)
  */
 
 #define DEBUG_ENABLED
+#include <gst/gst.h>
 #include <stdlib.h>
 #include <math.h>
+#include <videoscale.h>
+#include <string.h>
 
 #include "config.h"
 #include "gstvideoscale.h"
 #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);
 
+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)
+{
+  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));
+  }
+
+  return caps;
+}
+
+struct videoscale_format_struct *
+videoscale_find_by_caps(GstCaps *caps)
+{
+  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 *scale)
+gst_videoscale_setup (GstVideoscale *videoscale)
 {
-  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 */
+  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;
   }
 
-  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 */
+  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;
   }
 
-  return; /* XXX */
+  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 *src, unsigned char *dest)
+gst_videoscale_scale_rgb (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 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,53 +472,200 @@ gst_videoscale_scale_nearest (GstVideoscale *scale,
 
     xpos = 0x10000;
 
-    switch (scale->scale_bytes) {
-      case 4:
-      {
-        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;
+    srcp = src;
+    destp = dest;
+
+    for ( x=dw; x; x-- ) {
+      while ( xpos >= 0x10000L ) {
+        srcp++;
+        xpos -= 0x10000L;
       }
-      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;
+      *destp++ = *srcp;
+      xpos += xinc;
+    }
+    dest += dw;
+
+    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;
       }
-      case 1:
-      {
-        guchar *destp = dest;
-        guchar *srcp = src;
-
-        for ( x=dw; x; x-- ) {
-          while ( xpos >= 0x10000L ) {
-           srcp++;
-            xpos -= 0x10000L;
-          }
-         *destp++ = *srcp;
-          xpos += xinc;
-        }
+      *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;
+    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 (file)
index 0000000..1ebf35a
--- /dev/null
@@ -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
+