From 4063477460a43777d38d96eceaada011c486b61a Mon Sep 17 00:00:00 2001 From: Andy Wingo Date: Fri, 1 Jul 2005 16:55:43 +0000 Subject: [PATCH] gst/videoscale: Merge David's work from 0.8 branch. Changes to come later. Original commit message from CVS: 2005-07-01 Andy Wingo * gst/videoscale: Merge David's work from 0.8 branch. Changes to come later. --- ChangeLog | 5 + gst/videoscale/Makefile.am | 16 +- gst/videoscale/gstvideoscale.c | 316 +++++++++-- gst/videoscale/gstvideoscale.h | 8 +- gst/videoscale/videoscale.c | 920 -------------------------------- gst/videoscale/videoscale.h | 46 -- gst/videoscale/videoscale_x86.c | 85 --- gst/videoscale/videoscale_x86.h | 30 -- gst/videoscale/vs_image.c | 854 +++++++++++++++++++++++++++++ gst/videoscale/vs_image.h | 82 +++ gst/videoscale/vs_scanline.c | 630 ++++++++++++++++++++++ gst/videoscale/vs_scanline.h | 73 +++ 12 files changed, 1925 insertions(+), 1140 deletions(-) delete mode 100644 gst/videoscale/videoscale.c delete mode 100644 gst/videoscale/videoscale.h delete mode 100644 gst/videoscale/videoscale_x86.c delete mode 100644 gst/videoscale/videoscale_x86.h create mode 100644 gst/videoscale/vs_image.c create mode 100644 gst/videoscale/vs_image.h create mode 100644 gst/videoscale/vs_scanline.c create mode 100644 gst/videoscale/vs_scanline.h diff --git a/ChangeLog b/ChangeLog index 96361cf153..ac7e2773e0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2005-07-01 Andy Wingo + + * gst/videoscale: Merge David's work from 0.8 branch. Changes to + come later. + 2005-06-30 Thomas Vander Stichele * configure.ac: diff --git a/gst/videoscale/Makefile.am b/gst/videoscale/Makefile.am index ce8c696aad..271a1dcd1b 100644 --- a/gst/videoscale/Makefile.am +++ b/gst/videoscale/Makefile.am @@ -2,10 +2,16 @@ plugin_LTLIBRARIES = libgstvideoscale.la libgstvideoscale_la_SOURCES = \ - gstvideoscale.c \ - videoscale.c -libgstvideoscale_la_CFLAGS = $(GST_CFLAGS) -libgstvideoscale_la_LIBADD = + gstvideoscale.c \ + vs_image.c \ + vs_scanline.c + +libgstvideoscale_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS) +libgstvideoscale_la_LIBADD = $(GST_BASE_LIBS) libgstvideoscale_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = gstvideoscale.h videoscale_x86.h videoscale.h +noinst_HEADERS = \ + gstvideoscale.h \ + vs_image.h \ + vs_scanline.h + diff --git a/gst/videoscale/gstvideoscale.c b/gst/videoscale/gstvideoscale.c index b45872630b..54d7189c5b 100644 --- a/gst/videoscale/gstvideoscale.c +++ b/gst/videoscale/gstvideoscale.c @@ -22,8 +22,11 @@ #include "config.h" #endif #include "gstvideoscale.h" -#include "videoscale.h" +#include +#include + +#include "vs_image.h" /* debug variable definition */ GST_DEBUG_CATEGORY (videoscale_debug); @@ -49,6 +52,43 @@ enum /* FILL ME */ }; +static GstStaticCaps gst_videoscale_format_caps[] = { + GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBx), + GST_STATIC_CAPS (GST_VIDEO_CAPS_xRGB), + GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx), + GST_STATIC_CAPS (GST_VIDEO_CAPS_xBGR), + GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB), + GST_STATIC_CAPS (GST_VIDEO_CAPS_BGR), + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("AYUV")), + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YUY2")), + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YVYU")), + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("UYVY")), + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("Y800")), + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("I420")), + GST_STATIC_CAPS (GST_VIDEO_CAPS_YUV ("YV12")), + GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB_16), + GST_STATIC_CAPS (GST_VIDEO_CAPS_RGB_15) +}; + +enum +{ + GST_VIDEOSCALE_RGBx = 0, + GST_VIDEOSCALE_xRGB, + GST_VIDEOSCALE_BGRx, + GST_VIDEOSCALE_xBGR, + GST_VIDEOSCALE_RGB, + GST_VIDEOSCALE_BGR, + GST_VIDEOSCALE_AYUV, + GST_VIDEOSCALE_YUY2, + GST_VIDEOSCALE_YVYU, + GST_VIDEOSCALE_UYVY, + GST_VIDEOSCALE_Y, + GST_VIDEOSCALE_I420, + GST_VIDEOSCALE_YV12, + GST_VIDEOSCALE_RGB565, + GST_VIDEOSCALE_RGB555 +}; + #define GST_TYPE_VIDEOSCALE_METHOD (gst_videoscale_method_get_type()) static GType gst_videoscale_method_get_type (void) @@ -72,16 +112,19 @@ gst_videoscale_method_get_type (void) static GstCaps * gst_videoscale_get_capslist (void) { - GstCaps *caps; - int i; + static GstCaps *caps; - caps = gst_caps_new_empty (); - for (i = 0; i < videoscale_n_formats; i++) { - gst_caps_append_structure (caps, - videoscale_get_structure (videoscale_formats + i)); + if (caps == NULL) { + int i; + + caps = gst_caps_new_empty (); + for (i = 0; i < G_N_ELEMENTS (gst_videoscale_format_caps); i++) { + gst_caps_append (caps, + gst_caps_copy (gst_static_caps_get (&gst_videoscale_format_caps[i]))); + } } - return caps; + return gst_caps_copy (caps); } static GstPadTemplate * @@ -194,8 +237,8 @@ gst_videoscale_getcaps (GstPad * pad) GstStructure *structure = gst_caps_get_structure (caps, i); gst_structure_set (structure, - "width", GST_TYPE_INT_RANGE, 16, G_MAXINT, - "height", GST_TYPE_INT_RANGE, 16, G_MAXINT, NULL); + "width", GST_TYPE_INT_RANGE, 16, 4096, + "height", GST_TYPE_INT_RANGE, 16, 4096, NULL); gst_structure_remove_field (structure, "pixel-aspect-ratio"); } @@ -203,6 +246,24 @@ gst_videoscale_getcaps (GstPad * pad) return caps; } +static int +gst_videoscale_get_format (const GstCaps * caps) +{ + int i; + GstCaps *icaps; + + for (i = 0; i < G_N_ELEMENTS (gst_videoscale_format_caps); i++) { + icaps = gst_caps_intersect (caps, + gst_static_caps_get (&gst_videoscale_format_caps[i])); + if (!gst_caps_is_empty (icaps)) { + gst_caps_free (icaps); + return i; + } + gst_caps_free (icaps); + } + + return -1; +} static GstPadLinkReturn gst_videoscale_link (GstPad * pad, const GstCaps * caps) @@ -212,7 +273,7 @@ gst_videoscale_link (GstPad * pad, const GstCaps * caps) GstPad *otherpad; GstCaps *othercaps, *newcaps; GstStructure *otherstructure, *structure, *newstructure; - struct videoscale_format_struct *format; + int format; int height = 0, width = 0, newwidth, newheight; const GValue *par = NULL, *otherpar; @@ -227,9 +288,9 @@ gst_videoscale_link (GstPad * pad, const GstCaps * caps) ret &= gst_structure_get_int (structure, "height", &height); par = gst_structure_get_value (structure, "pixel-aspect-ratio"); - format = videoscale_find_by_structure (structure); + format = gst_videoscale_get_format (caps); - if (!ret || format == NULL) + if (!ret || format == -1) return GST_PAD_LINK_REFUSED; GST_DEBUG_OBJECT (videoscale, @@ -240,6 +301,7 @@ gst_videoscale_link (GstPad * pad, const GstCaps * caps) if (GST_PAD_LINK_SUCCESSFUL (ret)) { /* cool, we can use passthru */ GST_DEBUG_OBJECT (videoscale, "passthru works"); + GST_FLAG_SET (videoscale, GST_ELEMENT_WORK_IN_PLACE); videoscale->passthru = TRUE; newwidth = width; @@ -248,6 +310,8 @@ gst_videoscale_link (GstPad * pad, const GstCaps * caps) goto beach; } + GST_FLAG_UNSET (videoscale, GST_ELEMENT_WORK_IN_PLACE); + /* no passthru, so try to convert */ GST_DEBUG_OBJECT (videoscale, "no passthru"); @@ -343,7 +407,6 @@ beach: videoscale->to_height = newheight; } videoscale->format = format; - gst_videoscale_setup (videoscale); GST_DEBUG_OBJECT (videoscale, "work completed"); @@ -473,8 +536,6 @@ gst_videoscale_init (GstVideoscale * videoscale) gst_pad_set_getcaps_function (videoscale->srcpad, gst_videoscale_getcaps); gst_pad_set_fixate_function (videoscale->srcpad, gst_videoscale_src_fixate); - videoscale->inited = FALSE; - videoscale->method = GST_VIDEOSCALE_NEAREST; /*videoscale->method = GST_VIDEOSCALE_BILINEAR; */ /*videoscale->method = GST_VIDEOSCALE_POINT_SAMPLE; */ @@ -486,29 +547,22 @@ gst_videoscale_handle_src_event (GstPad * pad, GstEvent * event) GstVideoscale *videoscale; double a; GstStructure *structure; - GstEvent *new_event; videoscale = GST_VIDEOSCALE (gst_pad_get_parent (pad)); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_NAVIGATION: - structure = gst_structure_copy (event->event_data.structure.structure); - if (gst_structure_get_double (event->event_data.structure.structure, - "pointer_x", &a)) { + event = GST_EVENT (gst_data_copy_on_write (GST_DATA (event))); + structure = event->event_data.structure.structure; + if (gst_structure_get_double (structure, "pointer_x", &a)) { gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, a * videoscale->from_width / videoscale->to_width, NULL); } - if (gst_structure_get_double (event->event_data.structure.structure, - "pointer_y", &a)) { + if (gst_structure_get_double (structure, "pointer_y", &a)) { gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, a * videoscale->from_height / videoscale->to_height, NULL); } - gst_event_unref (event); - new_event = gst_event_new (GST_EVENT_NAVIGATION); - GST_DEBUG_OBJECT (videoscale, "creating new NAVIGATION event %p", - new_event); - new_event->event_data.structure.structure = structure; - return gst_pad_event_default (pad, new_event); + return gst_pad_event_default (pad, event); break; default: GST_DEBUG_OBJECT (videoscale, "passing on non-NAVIGATION event %p", @@ -518,51 +572,219 @@ gst_videoscale_handle_src_event (GstPad * pad, GstEvent * event) } } +#define ROUND_UP_2(x) (((x)+1)&~1) +#define ROUND_UP_4(x) (((x)+3)&~3) +#define ROUND_UP_8(x) (((x)+7)&~7) + static void gst_videoscale_chain (GstPad * pad, GstData * _data) { GstBuffer *buf = GST_BUFFER (_data); GstVideoscale *videoscale; - guchar *data; gulong size; GstBuffer *outbuf; - + VSImage dest; + VSImage src; + VSImage dest_u; + VSImage src_u; + VSImage dest_v; + VSImage src_v; + guint8 *tmpbuf; g_return_if_fail (pad != NULL); g_return_if_fail (GST_IS_PAD (pad)); 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->passthru) { - GST_LOG_OBJECT (videoscale, "passing through buffer of %ld bytes", size); gst_pad_push (videoscale->srcpad, GST_DATA (buf)); return; } GST_LOG_OBJECT (videoscale, - "buffersize=%ld from=%dx%d to=%dx%d fromsize=%ld tosize=%ld", - size, videoscale->from_width, videoscale->from_height, - videoscale->to_width, videoscale->to_height, - videoscale->from_buf_size, videoscale->to_buf_size); + "from=%dx%d to=%dx%d", + videoscale->from_width, videoscale->from_height, + videoscale->to_width, videoscale->to_height); - g_return_if_fail (size == videoscale->from_buf_size); + src.pixels = GST_BUFFER_DATA (buf); + src.width = videoscale->from_width; + src.height = videoscale->from_height; + + dest.width = videoscale->to_width; + dest.height = videoscale->to_height; + + switch (videoscale->format) { + case GST_VIDEOSCALE_RGBx: + case GST_VIDEOSCALE_xRGB: + case GST_VIDEOSCALE_BGRx: + case GST_VIDEOSCALE_xBGR: + case GST_VIDEOSCALE_AYUV: + src.stride = videoscale->from_width * 4; + dest.stride = videoscale->to_width * 4; + size = dest.stride * dest.height; + break; + case GST_VIDEOSCALE_RGB: + case GST_VIDEOSCALE_BGR: + src.stride = ROUND_UP_4 (videoscale->from_width * 3); + dest.stride = ROUND_UP_4 (videoscale->to_width * 3); + size = dest.stride * dest.height; + break; + case GST_VIDEOSCALE_YUY2: + case GST_VIDEOSCALE_YVYU: + case GST_VIDEOSCALE_UYVY: + src.stride = ROUND_UP_4 (videoscale->from_width * 2); + dest.stride = ROUND_UP_4 (videoscale->to_width * 2); + size = dest.stride * dest.height; + break; + case GST_VIDEOSCALE_Y: + src.stride = ROUND_UP_4 (videoscale->from_width); + dest.stride = ROUND_UP_4 (videoscale->to_width); + size = dest.stride * dest.height; + break; + case GST_VIDEOSCALE_I420: + case GST_VIDEOSCALE_YV12: + src.stride = ROUND_UP_4 (videoscale->from_width); + dest.stride = ROUND_UP_4 (videoscale->to_width); + + src_u.pixels = src.pixels + ROUND_UP_2 (src.height) * src.stride; + src_u.height = ROUND_UP_2 (src.height) / 2; + src_u.width = ROUND_UP_2 (src.width) / 2; + src_u.stride = ROUND_UP_4 (src.stride / 2); + + dest_u.height = ROUND_UP_2 (dest.height) / 2; + dest_u.width = ROUND_UP_2 (dest.width) / 2; + dest_u.stride = ROUND_UP_4 (dest.stride / 2); + + memcpy (&src_v, &src_u, sizeof (src_v)); + src_v.pixels = src_u.pixels + src_u.height * src_u.stride; + + memcpy (&dest_v, &dest_u, sizeof (dest_v)); + + size = dest.stride * ROUND_UP_2 (dest.height) + + 2 * dest_u.stride * dest_u.height; + break; + case GST_VIDEOSCALE_RGB565: + src.stride = ROUND_UP_4 (videoscale->from_width * 2); + dest.stride = ROUND_UP_4 (videoscale->to_width * 2); + size = dest.stride * dest.height; + break; + case GST_VIDEOSCALE_RGB555: + src.stride = ROUND_UP_4 (videoscale->from_width * 2); + dest.stride = ROUND_UP_4 (videoscale->to_width * 2); + size = dest.stride * dest.height; + break; + default: + g_warning ("don't know how to scale"); + gst_buffer_unref (buf); + return; + } outbuf = gst_pad_alloc_buffer (videoscale->srcpad, - GST_BUFFER_OFFSET_NONE, videoscale->to_buf_size); - + GST_BUFFER_OFFSET_NONE, size); gst_buffer_stamp (outbuf, buf); - g_return_if_fail (videoscale->format); - GST_LOG_OBJECT (videoscale, "format " GST_FOURCC_FORMAT, - GST_FOURCC_ARGS (videoscale->format->fourcc)); - g_return_if_fail (videoscale->format->scale); + dest.pixels = GST_BUFFER_DATA (outbuf); + switch (videoscale->format) { + case GST_VIDEOSCALE_I420: + case GST_VIDEOSCALE_YV12: + dest_u.pixels = dest.pixels + ROUND_UP_2 (dest.height) * dest.stride; + dest_v.pixels = dest_u.pixels + dest_u.height * dest_u.stride; + break; + default: + break; + } - videoscale->format->scale (videoscale, GST_BUFFER_DATA (outbuf), data); + tmpbuf = g_malloc (dest.stride * 2); + + switch (videoscale->method) { + case GST_VIDEOSCALE_NEAREST: + switch (videoscale->format) { + case GST_VIDEOSCALE_RGBx: + case GST_VIDEOSCALE_xRGB: + case GST_VIDEOSCALE_BGRx: + case GST_VIDEOSCALE_xBGR: + case GST_VIDEOSCALE_AYUV: + vs_image_scale_nearest_RGBA (&dest, &src, tmpbuf); + break; + case GST_VIDEOSCALE_RGB: + case GST_VIDEOSCALE_BGR: + vs_image_scale_nearest_RGB (&dest, &src, tmpbuf); + break; + case GST_VIDEOSCALE_YUY2: + case GST_VIDEOSCALE_YVYU: + vs_image_scale_nearest_YUYV (&dest, &src, tmpbuf); + break; + case GST_VIDEOSCALE_UYVY: + vs_image_scale_nearest_UYVY (&dest, &src, tmpbuf); + break; + case GST_VIDEOSCALE_Y: + vs_image_scale_nearest_Y (&dest, &src, tmpbuf); + break; + case GST_VIDEOSCALE_I420: + case GST_VIDEOSCALE_YV12: + vs_image_scale_nearest_Y (&dest, &src, tmpbuf); + vs_image_scale_nearest_Y (&dest_u, &src_u, tmpbuf); + vs_image_scale_nearest_Y (&dest_v, &src_v, tmpbuf); + break; + case GST_VIDEOSCALE_RGB565: + vs_image_scale_nearest_RGB565 (&dest, &src, tmpbuf); + break; + case GST_VIDEOSCALE_RGB555: + vs_image_scale_nearest_RGB555 (&dest, &src, tmpbuf); + break; + default: + g_warning ("don't know how to scale"); + } + break; + case GST_VIDEOSCALE_BILINEAR: + case GST_VIDEOSCALE_BICUBIC: + switch (videoscale->format) { + case GST_VIDEOSCALE_RGBx: + case GST_VIDEOSCALE_xRGB: + case GST_VIDEOSCALE_BGRx: + case GST_VIDEOSCALE_xBGR: + case GST_VIDEOSCALE_AYUV: + vs_image_scale_linear_RGBA (&dest, &src, tmpbuf); + break; + case GST_VIDEOSCALE_RGB: + case GST_VIDEOSCALE_BGR: + vs_image_scale_linear_RGB (&dest, &src, tmpbuf); + break; + case GST_VIDEOSCALE_YUY2: + case GST_VIDEOSCALE_YVYU: + vs_image_scale_linear_YUYV (&dest, &src, tmpbuf); + break; + case GST_VIDEOSCALE_UYVY: + vs_image_scale_linear_UYVY (&dest, &src, tmpbuf); + break; + case GST_VIDEOSCALE_Y: + vs_image_scale_linear_Y (&dest, &src, tmpbuf); + break; + case GST_VIDEOSCALE_I420: + case GST_VIDEOSCALE_YV12: + vs_image_scale_linear_Y (&dest, &src, tmpbuf); + //memset (dest_u.pixels, 128, dest_u.stride * dest_u.height); + //memset (dest_v.pixels, 128, dest_v.stride * dest_v.height); + vs_image_scale_linear_Y (&dest_u, &src_u, tmpbuf); + vs_image_scale_linear_Y (&dest_v, &src_v, tmpbuf); + break; + case GST_VIDEOSCALE_RGB565: + vs_image_scale_linear_RGB565 (&dest, &src, tmpbuf); + break; + case GST_VIDEOSCALE_RGB555: + vs_image_scale_linear_RGB555 (&dest, &src, tmpbuf); + break; + default: + g_warning ("don't know how to scale"); + } + break; + default: + g_assert_not_reached (); + break; + } + + g_free (tmpbuf); GST_LOG_OBJECT (videoscale, "pushing buffer of %d bytes", GST_BUFFER_SIZE (outbuf)); diff --git a/gst/videoscale/gstvideoscale.h b/gst/videoscale/gstvideoscale.h index bed396f858..ca7563c9e2 100644 --- a/gst/videoscale/gstvideoscale.h +++ b/gst/videoscale/gstvideoscale.h @@ -61,7 +61,7 @@ struct _GstVideoscale { /* video state */ gboolean inited; - struct videoscale_format_struct *format; + int format; gint to_width; gint to_height; gint from_width; @@ -74,13 +74,7 @@ struct _GstVideoscale { GstVideoScaleMethod method; /* private */ - gint from_buf_size; gint to_buf_size; -#if 0 - guchar *temp; - 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 deleted file mode 100644 index 7e6decf20c..0000000000 --- a/gst/videoscale/videoscale.c +++ /dev/null @@ -1,920 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * 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. - */ - -#define DEBUG_ENABLED -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include "videoscale.h" -#include - -#include "gstvideoscale.h" -#undef HAVE_CPU_I386 -#ifdef HAVE_CPU_I386 -#include "videoscale_x86.h" -#endif - -#define ROUND_UP_2(x) (((x) + 1) & ~1) -#define ROUND_UP_4(x) (((x) + 3) & ~3) -#define ROUND_UP_8(x) (((x) + 7) & ~7) - -/* scalers */ -#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); - -/* 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); -#endif -static int -gst_videoscale_get_size (struct videoscale_format_struct *format, int width, - int height); - -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_16bit (GstVideoscale * scale, unsigned char *dest, - unsigned char *src); - -static void gst_videoscale_scale_nearest_str1 (GstVideoscale * scale, - unsigned char *dest, unsigned char *src, int sw, int sh, int ss, int dw, - int dh, int ds); -static void gst_videoscale_scale_nearest_str2 (GstVideoscale * scale, - unsigned char *dest, unsigned char *src, int sw, int sh, int ss, int dw, - int dh, int ds); -static void gst_videoscale_scale_nearest_str4 (GstVideoscale * scale, - unsigned char *dest, unsigned char *src, int sw, int sh, int ss, int dw, - int dh, int ds); -static void gst_videoscale_scale_nearest_16bit (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); -static void gst_videoscale_scale_nearest_32bit (GstVideoscale * scale, - unsigned char *dest, unsigned char *src, int sw, int sh, int dw, int dh); - -#define fourcc_YUY2 GST_MAKE_FOURCC('Y','U','Y','2') -#define fourcc_UYVY GST_MAKE_FOURCC('U','Y','V','Y') -#define fourcc_Y422 GST_MAKE_FOURCC('Y','4','2','2') -#define fourcc_UYNV GST_MAKE_FOURCC('U','Y','N','V') -#define fourcc_YVYU GST_MAKE_FOURCC('Y','V','Y','U') -#define fourcc_YV12 GST_MAKE_FOURCC('Y','V','1','2') -#define fourcc_I420 GST_MAKE_FOURCC('I','4','2','0') -#define fourcc_Y800 GST_MAKE_FOURCC('Y','8','0','0') -#define fourcc_RGB_ GST_MAKE_FOURCC('R','G','B',' ') - -struct videoscale_format_struct videoscale_formats[] = { - /* packed */ - {fourcc_YUY2, 16, gst_videoscale_packed422,}, - {fourcc_UYVY, 16, gst_videoscale_packed422rev,}, - {fourcc_Y422, 16, gst_videoscale_packed422rev,}, - {fourcc_UYNV, 16, gst_videoscale_packed422rev,}, - {fourcc_YVYU, 16, gst_videoscale_packed422,}, - /* planar */ - {fourcc_YV12, 12, gst_videoscale_planar411,}, - {fourcc_I420, 12, gst_videoscale_planar411,}, - {fourcc_Y800, 8, gst_videoscale_planar400,}, - /* RGB */ - {fourcc_RGB_, 32, gst_videoscale_32bit, 24, G_BIG_ENDIAN, 0x00ff0000, - 0x0000ff00, 0x000000ff}, - {fourcc_RGB_, 32, gst_videoscale_32bit, 24, G_BIG_ENDIAN, 0x000000ff, - 0x0000ff00, 0x00ff0000}, - {fourcc_RGB_, 32, gst_videoscale_32bit, 24, G_BIG_ENDIAN, 0xff000000, - 0x00ff0000, 0x0000ff00}, - {fourcc_RGB_, 32, gst_videoscale_32bit, 24, G_BIG_ENDIAN, 0x0000ff00, - 0x00ff0000, 0xff000000}, - {fourcc_RGB_, 24, gst_videoscale_24bit, 24, G_BIG_ENDIAN, 0xff0000, 0x00ff00, - 0x0000ff}, - {fourcc_RGB_, 24, gst_videoscale_24bit, 24, G_BIG_ENDIAN, 0x0000ff, 0x00ff00, - 0xff0000}, - {fourcc_RGB_, 16, gst_videoscale_16bit, 16, G_BYTE_ORDER, 0xf800, 0x07e0, - 0x001f}, - {fourcc_RGB_, 16, gst_videoscale_16bit, 15, G_BYTE_ORDER, 0x7c00, 0x03e0, - 0x001f}, -}; - -int videoscale_n_formats = - sizeof (videoscale_formats) / sizeof (videoscale_formats[0]); - -GstStructure * -videoscale_get_structure (struct videoscale_format_struct *format) -{ - GstStructure *structure; - - if (format->scale == NULL) - return NULL; - - if (format->depth) { - structure = gst_structure_new ("video/x-raw-rgb", - "depth", G_TYPE_INT, format->depth, - "bpp", G_TYPE_INT, format->bpp, - "endianness", G_TYPE_INT, format->endianness, - "red_mask", G_TYPE_INT, format->red_mask, - "green_mask", G_TYPE_INT, format->green_mask, - "blue_mask", G_TYPE_INT, format->blue_mask, NULL); - } else { - structure = gst_structure_new ("video/x-raw-yuv", - "format", GST_TYPE_FOURCC, format->fourcc, NULL); - } - - gst_structure_set (structure, - "width", GST_TYPE_INT_RANGE, 16, G_MAXINT, - "height", GST_TYPE_INT_RANGE, 16, G_MAXINT, - "framerate", GST_TYPE_DOUBLE_RANGE, 0.0, G_MAXDOUBLE, NULL); - - return structure; -} - -struct videoscale_format_struct * -videoscale_find_by_structure (GstStructure * structure) -{ - int i; - gboolean ret; - struct videoscale_format_struct *format; - char *str; - - str = gst_structure_to_string (structure); - GST_DEBUG ("finding %s", str); - g_free (str); - - g_return_val_if_fail (structure != NULL, NULL); - - if (strcmp (gst_structure_get_name (structure), "video/x-raw-yuv") == 0) { - unsigned int fourcc; - - ret = gst_structure_get_fourcc (structure, "format", &fourcc); - if (!ret) - return NULL; - for (i = 0; i < videoscale_n_formats; i++) { - format = videoscale_formats + i; - if (format->depth == 0 && format->fourcc == fourcc) { - return format; - } - } - } else { - int bpp; - int depth; - int endianness; - int red_mask; - int green_mask; - int blue_mask; - - ret = gst_structure_get_int (structure, "bpp", &bpp); - ret &= gst_structure_get_int (structure, "depth", &depth); - ret &= gst_structure_get_int (structure, "endianness", &endianness); - ret &= gst_structure_get_int (structure, "red_mask", &red_mask); - ret &= gst_structure_get_int (structure, "green_mask", &green_mask); - ret &= gst_structure_get_int (structure, "blue_mask", &blue_mask); - if (!ret) - return NULL; - for (i = 0; i < videoscale_n_formats; i++) { - format = videoscale_formats + i; - if (format->bpp == bpp && format->depth == depth && - format->endianness == endianness && format->red_mask == red_mask && - format->green_mask == green_mask && format->blue_mask == blue_mask) { - return format; - } - } - } - - return NULL; -} - -void -gst_videoscale_setup (GstVideoscale * videoscale) -{ - g_return_if_fail (GST_IS_VIDEOSCALE (videoscale)); - g_return_if_fail (videoscale->format != NULL); - - GST_DEBUG_OBJECT (videoscale, "format=%p " GST_FOURCC_FORMAT - " from %dx%d to %dx%d, %d bpp", - videoscale->format, - GST_FOURCC_ARGS (videoscale->format->fourcc), - videoscale->from_width, videoscale->from_height, - videoscale->to_width, videoscale->to_height, videoscale->format->bpp); - - if (videoscale->to_width == 0 || videoscale->to_height == 0 || - videoscale->from_width == 0 || videoscale->from_height == 0) { - g_critical ("bad sizes %dx%d %dx%d", - videoscale->from_width, videoscale->from_height, - videoscale->to_width, videoscale->to_height); - return; - } - - if (videoscale->to_width == videoscale->from_width && - videoscale->to_height == videoscale->from_height) { - GST_DEBUG_OBJECT (videoscale, "using passthru"); - videoscale->passthru = TRUE; - videoscale->inited = TRUE; - return; - } - - GST_DEBUG_OBJECT (videoscale, "scaling method POINT_SAMPLE"); - - videoscale->from_buf_size = gst_videoscale_get_size (videoscale->format, - videoscale->from_width, videoscale->from_height); - videoscale->to_buf_size = gst_videoscale_get_size (videoscale->format, - videoscale->to_width, videoscale->to_height); - - videoscale->passthru = FALSE; - 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_LOG_OBJECT (scale, "scaling RGB %dx%d to %dx%d", sw, sh, dw, dh); - - switch (scale->scale_bytes) { - case 2: - dw = ((dw + 1) & ~1) << 1; - sw = sw << 1; - break; - case 4: - dw = ((dw + 2) & ~3) << 2; - sw = sw << 2; - break; - default: - break; - } - - GST_LOG_OBJECT (scale, "%p %p", src, dest); - //scale->scaler(scale, src, dest, sw, sh, dw, dh); -} -#endif -/* calculate the total size needed for an image in the given format - * of the given width and height, taking stride into account */ -static int -gst_videoscale_get_size (struct videoscale_format_struct *format, int width, - int height) -{ - int stride = 0; - int ustride = 0, vstride = 0; - int size = 0; - - /* FIXME: we should get from and to strides from caps. For now we conform - * to videotestsrc's idea of it, which is to round w * bytespp to nearest - * multiple of 4 */ - - switch (format->fourcc) { - case fourcc_RGB_: - stride = ROUND_UP_4 (width * ROUND_UP_4 (format->bpp)) / 8; - size = stride * height; - break; - case fourcc_YUY2: - case fourcc_UYVY: - case fourcc_YVYU: - stride = ROUND_UP_2 (width) * 2; - size = stride * height; - break; - case fourcc_I420: - case fourcc_YV12: - stride = ROUND_UP_4 (width); - ustride = ROUND_UP_8 (width) / 2; - vstride = ROUND_UP_8 (stride) / 2; - size = stride * ROUND_UP_2 (height) + ustride * ROUND_UP_2 (height) / 2 + - vstride * ROUND_UP_2 (height) / 2; - break; - case fourcc_Y422: - case fourcc_UYNV: - case fourcc_Y800: - g_warning ("unhandled known YUV fourcc"); - break; - default: - g_warning ("unhandled unknown fourcc"); - break; - } - GST_LOG ("image size for %dx%d in " GST_FOURCC_FORMAT " is %d bytes", - width, height, GST_FOURCC_ARGS (format->fourcc), size); - return size; -} - -static void -gst_videoscale_planar411 (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; - int ss, ds; /* strides */ - - GST_LOG_OBJECT (scale, "scaling planar 4:1:1 %dx%d to %dx%d", sw, sh, dw, dh); - - /* Y */ - - ss = ROUND_UP_4 (sw); - ds = ROUND_UP_4 (dw); - - gst_videoscale_scale_nearest_str1 (scale, dest, src, sw, sh, ss, dw, dh, ds); - - src += ss * sh; - dest += ds * dh; - - /* Cb and Cr are 2x2, so divide widths and heights in half */ - - /* we want to round up, so we add 1 before shifting */ - dh = (dh + 1) >> 1; - dw = (dw + 1) >> 1; - sh = (sh + 1) >> 1; - sw = (sw + 1) >> 1; - - ss = ROUND_UP_4 (sw); - ds = ROUND_UP_4 (dw); - - gst_videoscale_scale_nearest_str1 (scale, dest, src, sw, sh, ss, dw, dh, ds); - - src += ss * sh; - dest += ds * dh; - - gst_videoscale_scale_nearest_str1 (scale, dest, src, sw, sh, ss, dw, dh, ds); -} - -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; - int ss, ds; /* strides */ - - GST_LOG_OBJECT (scale, "scaling Y-only %dx%d to %dx%d", sw, sh, dw, dh); - - ss = ROUND_UP_4 (sw); - ds = ROUND_UP_4 (dw); - gst_videoscale_scale_nearest_str1 (scale, dest, src, sw, sh, ss, dw, dh, ds); -} - -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; - int ss, ds; /* strides */ - - GST_LOG_OBJECT (scale, "scaling 4:2:2 %dx%d to %dx%d", sw, sh, dw, dh); - - /* Y */ - ss = ROUND_UP_4 (sw * 2); - ds = ROUND_UP_4 (dw * 2); - gst_videoscale_scale_nearest_str2 (scale, dest, src, sw, sh, ss, dw, dh, ds); - - /* Cb and Cr */ - gst_videoscale_scale_nearest_str4 (scale, dest + 1, src + 1, sw / 2, sh, ss, - dw / 2, dh, ds); - gst_videoscale_scale_nearest_str4 (scale, dest + 3, src + 3, sw / 2, sh, ss, - dw / 2, dh, ds); -} - -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; - int ss, ds; /* strides */ - - GST_LOG_OBJECT (scale, "scaling 4:2:2 %dx%d to %dx%d", sw, sh, dw, dh); - - /* Y */ - ss = ROUND_UP_4 (sw * 2); - ds = ROUND_UP_4 (dw * 2); - gst_videoscale_scale_nearest_str2 (scale, dest + 1, src + 1, sw, sh, ss, dw, - dh, ds); - - /* Cb and Cr */ - gst_videoscale_scale_nearest_str4 (scale, dest, src, sw / 2, sh, ss, - dw / 2, dh, ds); - gst_videoscale_scale_nearest_str4 (scale, dest + 2, src + 2, sw / 2, sh, ss, - dw / 2, dh, ds); -} - -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_LOG_OBJECT (scale, "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_LOG_OBJECT (scale, "scaling 24bit %dx%d to %dx%d", sw, sh, dw, dh); - - gst_videoscale_scale_nearest_24bit (scale, dest, src, sw, sh, dw, dh); - -} - -static void -gst_videoscale_16bit (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_LOG_OBJECT (scale, "scaling 16bit %dx%d to %dx%d", sw, sh, dw, dh); - - gst_videoscale_scale_nearest_16bit (scale, dest, src, sw, sh, dw, dh); - -} - -#if 0 -#define RC(x,y) *(src+(int)(x)+(int)((y)*sw)) - -static unsigned char -gst_videoscale_bilinear (unsigned char *src, double x, double y, int sw, int sh) -{ - int j = floor (x); - int k = floor (y); - double a = x - j; - double b = y - k; - double dest; - int color; - - GST_LOG_OBJECT (scale, "scaling bilinear %f %f %dx%d", x, y, sw, sh); - - dest = (1 - a) * (1 - b) * RC (j, k) + a * (1 - b) * RC (j + 1, k); - - k = MIN (sh - 1, k); - dest += b * (1 - a) * RC (j, k + 1) + a * b * RC (j + 1, k + 1); - - color = rint (dest); - if (color < 0) - color = abs (color); /* cannot have negative values ! */ - /*if (color<0) color=0; // cannot have negative values ! */ - if (color > 255) - color = 255; - - return (unsigned char) color; -} - -static unsigned char -gst_videoscale_bicubic (unsigned char *src, double x, double y, int sw, int sh) -{ - int j = floor (x); - int k = floor (y), k2; - double a = x - j; - double b = y - k; - double dest; - int color; - double t1, t2, t3, t4; - double a1, a2, a3, a4; - - GST_LOG_OBJECT (scale, "scaling bicubic %dx%d", sw, sh); - - a1 = -a * (1 - a) * (1 - a); - a2 = (1 - 2 * a * a + a * a * a); - a3 = a * (1 + a - a * a); - a4 = a * a * (1 - a); - - k2 = MAX (0, k - 1); - t1 = a1 * RC (j - 1, k2) + a2 * RC (j, k2) + a3 * RC (j + 1, - k2) - a4 * RC (j + 2, k2); - t2 = a1 * RC (j - 1, k) + a2 * RC (j, k) + a3 * RC (j + 1, - k) - a4 * RC (j + 2, k); - k2 = MIN (sh, k + 1); - t3 = a1 * RC (j - 1, k2) + a2 * RC (j, k2) + a3 * RC (j + 1, - k2) - a4 * RC (j + 2, k2); - k2 = MIN (sh, k + 2); - t4 = a1 * RC (j - 1, k2) + a2 * RC (j, k2) + a3 * RC (j + 1, - k2) - a4 * RC (j + 2, k2); - - dest = - -b * (1 - b) * (1 - b) * t1 + (1 - 2 * b * b + b * b * b) * t2 + b * (1 + - b - b * b) * t3 + b * b * (b - 1) * t4; - - color = rint (dest); - if (color < 0) - color = abs (color); /* cannot have negative values ! */ - if (color > 255) - color = 255; - - return (unsigned char) color; -} - -static void -gst_videoscale_scale_plane_slow (GstVideoscale * scale, unsigned char *src, - unsigned char *dest, int sw, int sh, int dw, int dh) -{ - double zoomx = ((double) dw) / (double) sw; - double zoomy = ((double) dh) / (double) sh; - double xr, yr; - int x, y; - - GST_LOG_OBJECT (scale, "scale plane slow %dx%d %dx%d %g %g %p %p", sw, sh, - dw, dh, zoomx, zoomy, src, dest); - - for (y = 0; y < dh; y++) { - yr = ((double) y) / zoomy; - for (x = 0; x < dw; x++) { - xr = ((double) x) / zoomx; - - GST_LOG_OBJECT (scale, "scale plane slow %g %g %p", xr, yr, - (src + (int) (x) + (int) ((y) * sw))); - - if (floor (xr) == xr && floor (yr) == yr) { - GST_LOG_OBJECT (scale, "scale plane %g %g %p %p", xr, yr, - (src + (int) (x) + (int) ((y) * sw)), dest); - *dest++ = RC (xr, yr); - } else { - *dest++ = scale->filter (src, xr, yr, sw, sh); - /**dest++ = gst_videoscale_bicubic(src, xr, yr, sw, sh); */ - } - } - } -} -#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) -{ - int ypos, yinc, y; - int xpos, xinc, x; - int sum, xcount, ycount, loop; - unsigned char *srcp, *srcp2; - - GST_LOG_OBJECT (scale, "scaling nearest point sample %p %p %d", src, dest, - dw); - - ypos = 0x10000; - yinc = (sh << 16) / dh; - xinc = (sw << 16) / dw; - - for (y = dh; y; y--) { - - ycount = 1; - srcp = src; - while (ypos > 0x10000) { - ycount++; - ypos -= 0x10000; - src += sw; - } - - xpos = 0x10000; - for (x = dw; x; x--) { - xcount = 0; - sum = 0; - while (xpos >= 0x10000L) { - loop = ycount; - srcp2 = srcp; - while (loop--) { - sum += *srcp2; - srcp2 += sw; - } - srcp++; - xcount++; - xpos -= 0x10000L; - } - *dest++ = sum / (xcount * ycount); - xpos += xinc; - } - - ypos += yinc; - } -} -#endif - -static void -gst_videoscale_scale_nearest_str1 (GstVideoscale * scale, - unsigned char *dest, unsigned char *src, int sw, int sh, int ss, - int dw, int dh, int ds) -{ - int ypos, yinc, y; - int xpos, xinc, x; - guchar *destp; - guchar *srcp; - - GST_LOG_OBJECT (scale, "scaling nearest from %p to %p with dest width %d", - src, dest, dw); - - ypos = 0; - yinc = (sh << 16) / dh; - xinc = (sw << 16) / dw; - - for (y = dh; y; y--) { - if (ypos >= 0x10000) { - src += (ypos >> 16) * ss; - ypos &= 0xffff; - } - - xpos = 0; - - srcp = src; - destp = dest; - - for (x = dw; x; x--) { - if (xpos >= 0x10000) { - srcp += (xpos >> 16); - xpos &= 0xffff; - } - *destp++ = *srcp; - xpos += xinc; - } - dest += ds; - - ypos += yinc; - } -} - -static void -gst_videoscale_scale_nearest_str2 (GstVideoscale * scale, - unsigned char *dest, unsigned char *src, int sw, int sh, int ss, - int dw, int dh, int ds) -{ - int ypos, yinc, y; - int xpos, xinc, x; - guchar *destp; - guchar *srcp; - - GST_LOG_OBJECT (scale, "scaling nearest from %p to %p with dest width %d", - src, dest, dw); - - ypos = 0; - yinc = (sh << 16) / dh; - xinc = (sw << 16) / dw; - - for (y = dh; y; y--) { - - if (ypos >= 0x10000) { - src += (ypos >> 16) * ss; - ypos &= 0xffff; - } - - xpos = 0; - - srcp = src; - destp = dest; - - for (x = dw; x; x--) { - if (xpos >= 0x10000) { - srcp += (xpos >> 16) * 2; - xpos &= 0xffff; - } - *destp = *srcp; - destp += 2; - xpos += xinc; - } - dest += ds; - - ypos += yinc; - } -} - -static void -gst_videoscale_scale_nearest_str4 (GstVideoscale * scale, - unsigned char *dest, unsigned char *src, int sw, int sh, int ss, - int dw, int dh, int ds) -{ - int ypos, yinc, y; - int xpos, xinc, x; - guchar *destp; - guchar *srcp; - - GST_LOG_OBJECT (scale, "scaling nearest from %p to %p with dest width %d", - src, dest, dw); - - ypos = 0; - yinc = (sh << 16) / dh; - xinc = (sw << 16) / dw; - - for (y = dh; y; y--) { - - if (ypos >= 0x10000) { - src += (ypos >> 16) * ss; - ypos &= 0xffff; - } - - xpos = 0; - - srcp = src; - destp = dest; - - for (x = dw; x; x--) { - if (xpos >= 0x10000) { - srcp += (xpos >> 16) * 4; - xpos &= 0xffff; - } - *destp = *srcp; - destp += 4; - xpos += xinc; - } - dest += ds; - - ypos += yinc; - } -} - -static void -gst_videoscale_scale_nearest_16bit (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; - guchar *srcp; - int ss, ds; /* row strides in bytes */ - - GST_LOG_OBJECT (scale, "scaling nearest from %p to %p, destination width %d", - src, dest, dw); - - /* FIXME: strides should be gotten from caps; for now we do it Just Like - videotestsrc, which means round off to next multiple of 4 bytes */ - ss = sw * 2; - if (sw % 2 == 1) - ss += 2; - ds = dw * 2; - if (dw % 2 == 1) - ds += 2; - - ypos = 0; - yinc = (sh << 16) / dh; /* 16 bit fixed point arithmetic */ - xinc = (sw << 16) / dw; - - /* go over all destination lines */ - for (y = dh; y; y--) { /* faster than 0 .. dh */ - - if (ypos >= 0x10000) { /* ypos >= 1 ? */ - src += (ypos >> 16) * ss; /* go down round(ypos) src lines */ - ypos &= 0xffff; /* ypos %= 1 */ - } - - xpos = 0; - - srcp = src; - destp = dest; - - /* go over all destination pixels for each line */ - for (x = dw; x; x--) { - if (xpos >= 0x10000) { /* xpos >= 1 ? */ - srcp += (xpos >> 16) * 2; /* go right round(xpos) src pixels */ - xpos &= 0xffff; /* xpos %= 1 */ - } - destp[0] = srcp[0]; - destp[1] = srcp[1]; - destp += 2; /* go right one destination pixel */ - xpos += xinc; - } - dest += ds; /* go down one destination line */ - - 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; - guchar *srcp; - int ss, ds; /* row strides in bytes */ - - GST_LOG_OBJECT (scale, "scaling nearest %p %p %d", src, dest, dw); - - /* FIXME: strides should be gotten from caps; for now we do it Just Like - videotestsrc, which means round off to next multiple of 4 bytes */ - ss = ROUND_UP_4 (sw * 3); - ds = ROUND_UP_4 (dw * 3); - - ypos = 0; - yinc = (sh << 16) / dh; - xinc = (sw << 16) / dw; - - for (y = dh; y; y--) { - - if (ypos >= 0x10000) { - src += (ypos >> 16) * ss; - ypos &= 0xffff; - } - - xpos = 0; - - srcp = src; - destp = dest; - - for (x = dw; x; x--) { - if (xpos >= 0x10000) { - srcp += (xpos >> 16) * 3; - xpos &= 0xffff; - } - destp[0] = srcp[0]; - destp[1] = srcp[1]; - destp[2] = srcp[2]; - destp += 3; - xpos += xinc; - } - dest += ds; - - 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; - guchar *srcp; - - GST_LOG_OBJECT (scale, "scaling nearest %p %p %d", src, dest, dw); - - /* given how videoscale rounds off stride to nearest multiple of 4, - * we don't have stride issues for 32 bit */ - ypos = 0; - yinc = (sh << 16) / dh; - xinc = (sw << 16) / dw; - - for (y = dh; y; y--) { - - if (ypos >= 0x10000) { - src += (ypos >> 16) * sw * 4; - ypos &= 0xffff; - } - - xpos = 0; - - srcp = src; - destp = dest; - - for (x = dw; x; x--) { - if (xpos >= 0x10000) { - srcp += (xpos >> 16) * 4; - xpos &= 0xffff; - } - *(guint32 *) destp = *(guint32 *) srcp; - destp += 4; - xpos += xinc; - } - dest += dw * 4; - - ypos += yinc; - } -} diff --git a/gst/videoscale/videoscale.h b/gst/videoscale/videoscale.h deleted file mode 100644 index dd7f5e11b1..0000000000 --- a/gst/videoscale/videoscale.h +++ /dev/null @@ -1,46 +0,0 @@ -/* 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 { - unsigned int fourcc; - int bpp; - void (*scale)(GstVideoscale *,unsigned char *dest, unsigned char *src); - int depth; - 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; - -GstStructure *videoscale_get_structure(struct videoscale_format_struct *format); - -struct videoscale_format_struct *videoscale_find_by_structure (GstStructure *structure); - - -#endif - diff --git a/gst/videoscale/videoscale_x86.c b/gst/videoscale/videoscale_x86.c deleted file mode 100644 index f2c7ef0b58..0000000000 --- a/gst/videoscale/videoscale_x86.c +++ /dev/null @@ -1,85 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * 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. - */ - -/*#define DEBUG_ENABLED */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "gstvideoscale.h" - -/* scalers */ -void gst_videoscale_generate_rowbytes_x86 (unsigned char *copy_row, int src_w, - int dst_w, int bpp); -void gst_videoscale_scale_nearest_x86 (GstVideoscale * scale, - unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh); - -#define PREFIX16 0x66 -#define STORE_BYTE 0xAA -#define STORE_WORD 0xAB -#define LOAD_BYTE 0xAC -#define LOAD_WORD 0xAD -#define RETURN 0xC3 - -void -gst_videoscale_generate_rowbytes_x86 (unsigned char *copy_row, int src_w, - int dst_w, int bpp) -{ - int i; - int pos, inc; - unsigned char *eip; - unsigned char load, store; - - GST_DEBUG ("videoscale: setup scaling %p", copy_row); - - switch (bpp) { - case 1: - load = LOAD_BYTE; - store = STORE_BYTE; - break; - case 2: - case 4: - load = LOAD_WORD; - store = STORE_WORD; - break; - default: - return; - } - pos = 0x10000; - inc = (src_w << 16) / dst_w; - eip = copy_row; - for (i = 0; i < dst_w; ++i) { - while (pos >= 0x10000L) { - if (bpp == 2) { - *eip++ = PREFIX16; - } - *eip++ = load; - pos -= 0x10000L; - } - if (bpp == 2) { - *eip++ = PREFIX16; - } - *eip++ = store; - pos += inc; - } - *eip++ = RETURN; - GST_DEBUG ("scaler start/end %p %p %p", copy_row, eip, - (void *) (eip - copy_row)); -} diff --git a/gst/videoscale/videoscale_x86.h b/gst/videoscale/videoscale_x86.h deleted file mode 100644 index 56f7150b16..0000000000 --- a/gst/videoscale/videoscale_x86.h +++ /dev/null @@ -1,30 +0,0 @@ -/* GStreamer - * Copyright (C) <1999> Erik Walthinsen - * - * 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 __GST_VIDEOSCALE__X86_H__ -#define __GST_VIDEOSCALE__X86_H__ - - -/* scalers */ -void gst_videoscale_generate_rowbytes_x86 (unsigned char *copy_row, int src_w, int dst_w, int bpp); -void gst_videoscale_scale_nearest_x86 (GstVideoscale *scale, - unsigned char *src, unsigned char *dest, - int sw, int sh, int dw, int dh); -#endif /* __GST_VIDEOSCALE__X86_H__ */ diff --git a/gst/videoscale/vs_image.c b/gst/videoscale/vs_image.c new file mode 100644 index 0000000000..2efe40f416 --- /dev/null +++ b/gst/videoscale/vs_image.c @@ -0,0 +1,854 @@ +/* + * Image Scaling Functions + * Copyright (c) 2005 David A. Schleef + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "vs_scanline.h" +#include "vs_image.h" + +#define ROUND_UP_2(x) (((x)+1)&~1) +#define ROUND_UP_4(x) (((x)+3)&~3) +#define ROUND_UP_8(x) (((x)+7)&~7) + +void +vs_image_scale_nearest_RGBA (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + int i; + int j; + int x; + int xacc; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + acc = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + xacc = 0; + vs_scanline_resample_nearest_RGBA (dest->pixels + i * dest->stride, + src->pixels + j * src->stride, dest->width, &xacc, x_increment); + + acc += y_increment; + } +} + +void +vs_image_scale_linear_RGBA (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + guint8 *tmp1; + guint8 *tmp2; + int y1; + int y2; + int i; + int j; + int x; + int dest_size; + int xacc; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + dest_size = dest->width * 4; + + tmp1 = tmpbuf; + tmp2 = tmpbuf + dest_size; + + acc = 0; + xacc = 0; + y2 = -1; + vs_scanline_resample_linear_RGBA (tmp1, src->pixels, dest->width, &xacc, + x_increment); + y1 = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + if (x == 0) { + if (j == y1) { + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } else if (j == y2) { + memcpy (dest->pixels + i * dest->stride, tmp2, dest_size); + } else { + xacc = 0; + vs_scanline_resample_linear_RGBA (tmp1, src->pixels + j * src->stride, + dest->width, &xacc, x_increment); + y1 = j; + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } + } else { + if (j == y1) { + if (j + 1 != y2) { + xacc = 0; + vs_scanline_resample_linear_RGBA (tmp2, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y2 = j + 1; + } + vs_scanline_merge_linear_RGBA (dest->pixels + i * dest->stride, + tmp1, tmp2, dest->width, x); + } else if (j == y2) { + if (j + 1 != y1) { + xacc = 0; + vs_scanline_resample_linear_RGBA (tmp1, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y1 = j + 1; + } + vs_scanline_merge_linear_RGBA (dest->pixels + i * dest->stride, + tmp2, tmp1, dest->width, x); + } else { + xacc = 0; + vs_scanline_resample_linear_RGBA (tmp1, src->pixels + j * src->stride, + dest->width, &xacc, x_increment); + y1 = j; + xacc = 0; + vs_scanline_resample_linear_RGBA (tmp2, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y2 = (j + 1); + vs_scanline_merge_linear_RGBA (dest->pixels + i * dest->stride, + tmp1, tmp2, dest->width, x); + } + } + + acc += y_increment; + } +} + + +void +vs_image_scale_nearest_RGB (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + int i; + int j; + int x; + int xacc; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + acc = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + xacc = 0; + vs_scanline_resample_nearest_RGB (dest->pixels + i * dest->stride, + src->pixels + j * src->stride, dest->width, &xacc, x_increment); + + acc += y_increment; + } +} + +void +vs_image_scale_linear_RGB (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + guint8 *tmp1; + guint8 *tmp2; + int y1; + int y2; + int i; + int j; + int x; + int dest_size; + int xacc; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + dest_size = dest->width * 3; + + tmp1 = tmpbuf; + tmp2 = tmpbuf + dest_size; + + acc = 0; + xacc = 0; + y2 = -1; + vs_scanline_resample_linear_RGB (tmp1, src->pixels, dest->width, &xacc, + x_increment); + y1 = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + if (x == 0) { + if (j == y1) { + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } else if (j == y2) { + memcpy (dest->pixels + i * dest->stride, tmp2, dest_size); + } else { + xacc = 0; + vs_scanline_resample_linear_RGB (tmp1, src->pixels + j * src->stride, + dest->width, &xacc, x_increment); + y1 = j; + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } + } else { + if (j == y1) { + if (j + 1 != y2) { + xacc = 0; + vs_scanline_resample_linear_RGB (tmp2, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y2 = j + 1; + } + vs_scanline_merge_linear_RGB (dest->pixels + i * dest->stride, + tmp1, tmp2, dest->width, x); + } else if (j == y2) { + if (j + 1 != y1) { + xacc = 0; + vs_scanline_resample_linear_RGB (tmp1, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y1 = j + 1; + } + vs_scanline_merge_linear_RGB (dest->pixels + i * dest->stride, + tmp2, tmp1, dest->width, x); + } else { + xacc = 0; + vs_scanline_resample_linear_RGB (tmp1, src->pixels + j * src->stride, + dest->width, &xacc, x_increment); + y1 = j; + xacc = 0; + vs_scanline_resample_linear_RGB (tmp2, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y2 = (j + 1); + vs_scanline_merge_linear_RGB (dest->pixels + i * dest->stride, + tmp1, tmp2, dest->width, x); + } + } + + acc += y_increment; + } +} + +/* YUYV */ + +void +vs_image_scale_nearest_YUYV (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + int i; + int j; + int x; + int xacc; + int n_quads; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + n_quads = ROUND_UP_2 (dest->width); + acc = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + xacc = 0; + vs_scanline_resample_nearest_YUYV (dest->pixels + i * dest->stride, + src->pixels + j * src->stride, n_quads, &xacc, x_increment); + + acc += y_increment; + } +} + +void +vs_image_scale_linear_YUYV (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + guint8 *tmp1; + guint8 *tmp2; + int y1; + int y2; + int i; + int j; + int x; + int dest_size; + int n_quads; + int xacc; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + dest_size = ROUND_UP_4 (dest->width * 2); + n_quads = ROUND_UP_2 (dest->width) / 2; + + tmp1 = tmpbuf; + tmp2 = tmpbuf + dest_size; + + acc = 0; + xacc = 0; + y2 = -1; + vs_scanline_resample_linear_YUYV (tmp1, src->pixels, n_quads, &xacc, + x_increment); + y1 = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + if (x == 0) { + if (j == y1) { + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } else if (j == y2) { + memcpy (dest->pixels + i * dest->stride, tmp2, dest_size); + } else { + xacc = 0; + vs_scanline_resample_linear_YUYV (tmp1, src->pixels + j * src->stride, + n_quads, &xacc, x_increment); + y1 = j; + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } + } else { + if (j == y1) { + if (j + 1 != y2) { + xacc = 0; + vs_scanline_resample_linear_YUYV (tmp2, + src->pixels + (j + 1) * src->stride, n_quads, &xacc, x_increment); + y2 = j + 1; + } + vs_scanline_merge_linear_YUYV (dest->pixels + i * dest->stride, + tmp1, tmp2, n_quads, x); + } else if (j == y2) { + if (j + 1 != y1) { + xacc = 0; + vs_scanline_resample_linear_YUYV (tmp1, + src->pixels + (j + 1) * src->stride, n_quads, &xacc, x_increment); + y1 = j + 1; + } + vs_scanline_merge_linear_YUYV (dest->pixels + i * dest->stride, + tmp2, tmp1, n_quads, x); + } else { + xacc = 0; + vs_scanline_resample_linear_YUYV (tmp1, src->pixels + j * src->stride, + n_quads, &xacc, x_increment); + y1 = j; + xacc = 0; + vs_scanline_resample_linear_YUYV (tmp2, + src->pixels + (j + 1) * src->stride, n_quads, &xacc, x_increment); + y2 = (j + 1); + vs_scanline_merge_linear_YUYV (dest->pixels + i * dest->stride, + tmp1, tmp2, n_quads, x); + } + } + + acc += y_increment; + } +} + +/* UYVY */ + +void +vs_image_scale_nearest_UYVY (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + int i; + int j; + int x; + int xacc; + int n_quads; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + n_quads = (dest->width + 1) / 2; + acc = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + xacc = 0; + vs_scanline_resample_nearest_UYVY (dest->pixels + i * dest->stride, + src->pixels + j * src->stride, n_quads, &xacc, x_increment); + + acc += y_increment; + } +} + +void +vs_image_scale_linear_UYVY (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + guint8 *tmp1; + guint8 *tmp2; + int y1; + int y2; + int i; + int j; + int x; + int dest_size; + int n_quads; + int xacc; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + dest_size = ROUND_UP_4 (dest->width * 2); + n_quads = ROUND_UP_2 (dest->width) / 2; + + tmp1 = tmpbuf; + tmp2 = tmpbuf + dest_size; + + acc = 0; + xacc = 0; + y2 = -1; + vs_scanline_resample_linear_UYVY (tmp1, src->pixels, n_quads, &xacc, + x_increment); + y1 = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + if (x == 0) { + if (j == y1) { + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } else if (j == y2) { + memcpy (dest->pixels + i * dest->stride, tmp2, dest_size); + } else { + xacc = 0; + vs_scanline_resample_linear_UYVY (tmp1, src->pixels + j * src->stride, + n_quads, &xacc, x_increment); + y1 = j; + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } + } else { + if (j == y1) { + if (j + 1 != y2) { + xacc = 0; + vs_scanline_resample_linear_UYVY (tmp2, + src->pixels + (j + 1) * src->stride, n_quads, &xacc, x_increment); + y2 = j + 1; + } + vs_scanline_merge_linear_UYVY (dest->pixels + i * dest->stride, + tmp1, tmp2, n_quads, x); + } else if (j == y2) { + if (j + 1 != y1) { + xacc = 0; + vs_scanline_resample_linear_UYVY (tmp1, + src->pixels + (j + 1) * src->stride, n_quads, &xacc, x_increment); + y1 = j + 1; + } + vs_scanline_merge_linear_UYVY (dest->pixels + i * dest->stride, + tmp2, tmp1, n_quads, x); + } else { + xacc = 0; + vs_scanline_resample_linear_UYVY (tmp1, src->pixels + j * src->stride, + n_quads, &xacc, x_increment); + y1 = j; + xacc = 0; + vs_scanline_resample_linear_UYVY (tmp2, + src->pixels + (j + 1) * src->stride, n_quads, &xacc, x_increment); + y2 = (j + 1); + vs_scanline_merge_linear_UYVY (dest->pixels + i * dest->stride, + tmp1, tmp2, n_quads, x); + } + } + + acc += y_increment; + } +} + +/* greyscale */ + +void +vs_image_scale_nearest_Y (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + int i; + int j; + int x; + int xacc; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + acc = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + xacc = 0; + vs_scanline_resample_nearest_Y (dest->pixels + i * dest->stride, + src->pixels + j * src->stride, dest->width, &xacc, x_increment); + + acc += y_increment; + } +} + +void +vs_image_scale_linear_Y (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + guint8 *tmp1; + guint8 *tmp2; + int y1; + int y2; + int i; + int j; + int x; + int dest_size; + int xacc; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + dest_size = dest->width; + + tmp1 = tmpbuf; + tmp2 = tmpbuf + dest_size; + + acc = 0; + xacc = 0; + y2 = -1; + vs_scanline_resample_linear_Y (tmp1, src->pixels, dest->width, &xacc, + x_increment); + y1 = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + if (x == 0) { + if (j == y1) { + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } else if (j == y2) { + memcpy (dest->pixels + i * dest->stride, tmp2, dest_size); + } else { + xacc = 0; + vs_scanline_resample_linear_Y (tmp1, src->pixels + j * src->stride, + dest->width, &xacc, x_increment); + y1 = j; + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } + } else { + if (j == y1) { + if (j + 1 != y2) { + xacc = 0; + vs_scanline_resample_linear_Y (tmp2, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y2 = j + 1; + } + vs_scanline_merge_linear_Y (dest->pixels + i * dest->stride, + tmp1, tmp2, dest->width, x); + } else if (j == y2) { + if (j + 1 != y1) { + xacc = 0; + vs_scanline_resample_linear_Y (tmp1, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y1 = j + 1; + } + vs_scanline_merge_linear_Y (dest->pixels + i * dest->stride, + tmp2, tmp1, dest->width, x); + } else { + xacc = 0; + vs_scanline_resample_linear_Y (tmp1, src->pixels + j * src->stride, + dest->width, &xacc, x_increment); + y1 = j; + xacc = 0; + vs_scanline_resample_linear_Y (tmp2, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y2 = (j + 1); + vs_scanline_merge_linear_Y (dest->pixels + i * dest->stride, + tmp1, tmp2, dest->width, x); + } + } + + acc += y_increment; + } +} + +/* RGB565 */ + +void +vs_image_scale_nearest_RGB565 (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + int i; + int j; + int x; + int xacc; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + acc = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + xacc = 0; + vs_scanline_resample_nearest_RGB565 (dest->pixels + i * dest->stride, + src->pixels + j * src->stride, dest->width, &xacc, x_increment); + + acc += y_increment; + } +} + +void +vs_image_scale_linear_RGB565 (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + guint8 *tmp1; + guint8 *tmp2; + int y1; + int y2; + int i; + int j; + int x; + int dest_size; + int xacc; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + dest_size = dest->width * 2; + + tmp1 = tmpbuf; + tmp2 = tmpbuf + dest_size; + + acc = 0; + xacc = 0; + y2 = -1; + vs_scanline_resample_linear_RGB565 (tmp1, src->pixels, dest->width, &xacc, + x_increment); + y1 = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + if (x == 0) { + if (j == y1) { + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } else if (j == y2) { + memcpy (dest->pixels + i * dest->stride, tmp2, dest_size); + } else { + xacc = 0; + vs_scanline_resample_linear_RGB565 (tmp1, src->pixels + j * src->stride, + dest->width, &xacc, x_increment); + y1 = j; + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } + } else { + if (j == y1) { + if (j + 1 != y2) { + xacc = 0; + vs_scanline_resample_linear_RGB565 (tmp2, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y2 = j + 1; + } + vs_scanline_merge_linear_RGB565 (dest->pixels + i * dest->stride, + tmp1, tmp2, dest->width, x); + } else if (j == y2) { + if (j + 1 != y1) { + xacc = 0; + vs_scanline_resample_linear_RGB565 (tmp1, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y1 = j + 1; + } + vs_scanline_merge_linear_RGB565 (dest->pixels + i * dest->stride, + tmp2, tmp1, dest->width, x); + } else { + xacc = 0; + vs_scanline_resample_linear_RGB565 (tmp1, src->pixels + j * src->stride, + dest->width, &xacc, x_increment); + y1 = j; + xacc = 0; + vs_scanline_resample_linear_RGB565 (tmp2, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y2 = (j + 1); + vs_scanline_merge_linear_RGB565 (dest->pixels + i * dest->stride, + tmp1, tmp2, dest->width, x); + } + } + + acc += y_increment; + } +} + +/* RGB555 */ + +void +vs_image_scale_nearest_RGB555 (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + int i; + int j; + int x; + int xacc; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + acc = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + xacc = 0; + vs_scanline_resample_nearest_RGB555 (dest->pixels + i * dest->stride, + src->pixels + j * src->stride, dest->width, &xacc, x_increment); + + acc += y_increment; + } +} + +void +vs_image_scale_linear_RGB555 (const VSImage * dest, const VSImage * src, + guint8 * tmpbuf) +{ + int acc; + int y_increment; + int x_increment; + guint8 *tmp1; + guint8 *tmp2; + int y1; + int y2; + int i; + int j; + int x; + int dest_size; + int xacc; + + y_increment = ((src->height - 1) << 16) / (dest->height - 1); + x_increment = ((src->width - 1) << 16) / (dest->width - 1); + + dest_size = dest->width * 2; + + tmp1 = tmpbuf; + tmp2 = tmpbuf + dest_size; + + acc = 0; + xacc = 0; + y2 = -1; + vs_scanline_resample_linear_RGB555 (tmp1, src->pixels, dest->width, &xacc, + x_increment); + y1 = 0; + for (i = 0; i < dest->height; i++) { + j = acc >> 16; + x = acc & 0xffff; + + if (x == 0) { + if (j == y1) { + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } else if (j == y2) { + memcpy (dest->pixels + i * dest->stride, tmp2, dest_size); + } else { + xacc = 0; + vs_scanline_resample_linear_RGB555 (tmp1, src->pixels + j * src->stride, + dest->width, &xacc, x_increment); + y1 = j; + memcpy (dest->pixels + i * dest->stride, tmp1, dest_size); + } + } else { + if (j == y1) { + if (j + 1 != y2) { + xacc = 0; + vs_scanline_resample_linear_RGB555 (tmp2, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y2 = j + 1; + } + vs_scanline_merge_linear_RGB555 (dest->pixels + i * dest->stride, + tmp1, tmp2, dest->width, x); + } else if (j == y2) { + if (j + 1 != y1) { + xacc = 0; + vs_scanline_resample_linear_RGB555 (tmp1, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y1 = j + 1; + } + vs_scanline_merge_linear_RGB555 (dest->pixels + i * dest->stride, + tmp2, tmp1, dest->width, x); + } else { + xacc = 0; + vs_scanline_resample_linear_RGB555 (tmp1, src->pixels + j * src->stride, + dest->width, &xacc, x_increment); + y1 = j; + xacc = 0; + vs_scanline_resample_linear_RGB555 (tmp2, + src->pixels + (j + 1) * src->stride, dest->width, &xacc, + x_increment); + y2 = (j + 1); + vs_scanline_merge_linear_RGB555 (dest->pixels + i * dest->stride, + tmp1, tmp2, dest->width, x); + } + } + + acc += y_increment; + } +} diff --git a/gst/videoscale/vs_image.h b/gst/videoscale/vs_image.h new file mode 100644 index 0000000000..9a90e8281c --- /dev/null +++ b/gst/videoscale/vs_image.h @@ -0,0 +1,82 @@ +/* + * Image Scaling Functions + * Copyright (c) 2005 David A. Schleef + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __VS_IMAGE_H__ +#define __VS_IMAGE_H__ + +#include + +G_BEGIN_DECLS + +typedef struct _VSImage VSImage; + +struct _VSImage { + guint8 *pixels; + int width; + int height; + int stride; +}; + +void vs_image_scale_nearest_RGBA (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); +void vs_image_scale_linear_RGBA (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); + +void vs_image_scale_nearest_RGB (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); +void vs_image_scale_linear_RGB (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); + +void vs_image_scale_nearest_YUYV (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); +void vs_image_scale_linear_YUYV (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); + +void vs_image_scale_nearest_UYVY (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); +void vs_image_scale_linear_UYVY (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); + +void vs_image_scale_nearest_Y (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); +void vs_image_scale_linear_Y (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); + +void vs_image_scale_nearest_RGB565 (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); +void vs_image_scale_linear_RGB565 (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); + +void vs_image_scale_nearest_RGB555 (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); +void vs_image_scale_linear_RGB555 (const VSImage *dest, const VSImage *src, + guint8 *tmpbuf); + +G_END_DECLS + +#endif + diff --git a/gst/videoscale/vs_scanline.c b/gst/videoscale/vs_scanline.c new file mode 100644 index 0000000000..a2dc724bf0 --- /dev/null +++ b/gst/videoscale/vs_scanline.c @@ -0,0 +1,630 @@ +/* + * Image Scaling Functions + * Copyright (c) 2005 David A. Schleef + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "vs_scanline.h" + +#include + +/* greyscale, i.e., single componenet */ + +void +vs_scanline_downsample_Y (guint8 * dest, guint8 * src, int n) +{ + int i; + + for (i = 0; i < n; i++) { + dest[i] = (src[i * 2] + src[i * 2 + 1]) / 2; + } +} + +void +vs_scanline_resample_nearest_Y (guint8 * dest, guint8 * src, int n, + int *accumulator, int increment) +{ + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i] = (x < 32768) ? src[j] : src[j + 1]; + + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_resample_linear_Y (guint8 * dest, guint8 * src, int n, + int *accumulator, int increment) +{ + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i] = (src[j] * (65536 - x) + src[j + 1] * x) >> 16; + + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_merge_linear_Y (guint8 * dest, guint8 * src1, guint8 * src2, + int n, int x) +{ + int i; + + for (i = 0; i < n; i++) { + dest[i] = (src1[i] * (65536 - x) + src2[i] * x) >> 16; + } +} + + +/* RGBA */ + +void +vs_scanline_downsample_RGBA (guint8 * dest, guint8 * src, int n) +{ + int i; + + for (i = 0; i < n; i++) { + dest[i * 4 + 0] = (src[i * 8 + 0] + src[i * 8 + 4]) / 2; + dest[i * 4 + 1] = (src[i * 8 + 1] + src[i * 8 + 5]) / 2; + dest[i * 4 + 2] = (src[i * 8 + 2] + src[i * 8 + 6]) / 2; + dest[i * 4 + 3] = (src[i * 8 + 3] + src[i * 8 + 7]) / 2; + } +} + +void +vs_scanline_resample_nearest_RGBA (guint8 * dest, guint8 * src, int n, + int *accumulator, int increment) +{ + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i * 4 + 0] = (x < 32768) ? src[j * 4 + 0] : src[j * 4 + 4]; + dest[i * 4 + 1] = (x < 32768) ? src[j * 4 + 1] : src[j * 4 + 5]; + dest[i * 4 + 2] = (x < 32768) ? src[j * 4 + 2] : src[j * 4 + 6]; + dest[i * 4 + 3] = (x < 32768) ? src[j * 4 + 3] : src[j * 4 + 7]; + + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_resample_linear_RGBA (guint8 * dest, guint8 * src, int n, + int *accumulator, int increment) +{ + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i * 4 + 0] = (src[j * 4 + 0] * (65536 - x) + src[j * 4 + 4] * x) >> 16; + dest[i * 4 + 1] = (src[j * 4 + 1] * (65536 - x) + src[j * 4 + 5] * x) >> 16; + dest[i * 4 + 2] = (src[j * 4 + 2] * (65536 - x) + src[j * 4 + 6] * x) >> 16; + dest[i * 4 + 3] = (src[j * 4 + 3] * (65536 - x) + src[j * 4 + 7] * x) >> 16; + + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_merge_linear_RGBA (guint8 * dest, guint8 * src1, guint8 * src2, + int n, int x) +{ + int i; + + for (i = 0; i < n; i++) { + dest[i * 4 + 0] = + (src1[i * 4 + 0] * (65536 - x) + src2[i * 4 + 0] * x) >> 16; + dest[i * 4 + 1] = + (src1[i * 4 + 1] * (65536 - x) + src2[i * 4 + 1] * x) >> 16; + dest[i * 4 + 2] = + (src1[i * 4 + 2] * (65536 - x) + src2[i * 4 + 2] * x) >> 16; + dest[i * 4 + 3] = + (src1[i * 4 + 3] * (65536 - x) + src2[i * 4 + 3] * x) >> 16; + } +} + + +/* RGB */ + +void +vs_scanline_downsample_RGB (guint8 * dest, guint8 * src, int n) +{ + int i; + + for (i = 0; i < n; i++) { + dest[i * 3 + 0] = (src[i * 6 + 0] + src[i * 6 + 3]) / 2; + dest[i * 3 + 1] = (src[i * 6 + 1] + src[i * 6 + 4]) / 2; + dest[i * 3 + 2] = (src[i * 6 + 2] + src[i * 6 + 5]) / 2; + } +} + +void +vs_scanline_resample_nearest_RGB (guint8 * dest, guint8 * src, int n, + int *accumulator, int increment) +{ + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i * 3 + 0] = (x < 32768) ? src[j * 3 + 0] : src[j * 3 + 3]; + dest[i * 3 + 1] = (x < 32768) ? src[j * 3 + 1] : src[j * 3 + 4]; + dest[i * 3 + 2] = (x < 32768) ? src[j * 3 + 2] : src[j * 3 + 5]; + + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_resample_linear_RGB (guint8 * dest, guint8 * src, int n, + int *accumulator, int increment) +{ + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i * 3 + 0] = (src[j * 3 + 0] * (65536 - x) + src[j * 3 + 3] * x) >> 16; + dest[i * 3 + 1] = (src[j * 3 + 1] * (65536 - x) + src[j * 3 + 4] * x) >> 16; + dest[i * 3 + 2] = (src[j * 3 + 2] * (65536 - x) + src[j * 3 + 5] * x) >> 16; + + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_merge_linear_RGB (guint8 * dest, guint8 * src1, guint8 * src2, + int n, int x) +{ + int i; + + for (i = 0; i < n; i++) { + dest[i * 3 + 0] = + (src1[i * 3 + 0] * (65536 - x) + src2[i * 3 + 3] * x) >> 16; + dest[i * 3 + 1] = + (src1[i * 3 + 1] * (65536 - x) + src2[i * 3 + 4] * x) >> 16; + dest[i * 3 + 2] = + (src1[i * 3 + 2] * (65536 - x) + src2[i * 3 + 5] * x) >> 16; + } +} + + +/* YUYV */ + +/* n is the number of bi-pixels */ +/* increment is per Y pixel */ + +void +vs_scanline_downsample_YUYV (guint8 * dest, guint8 * src, int n) +{ + int i; + + for (i = 0; i < n; i++) { + dest[i * 4 + 0] = (src[i * 8 + 0] + src[i * 8 + 2]) / 2; + dest[i * 4 + 1] = (src[i * 8 + 1] + src[i * 8 + 5]) / 2; + dest[i * 4 + 2] = (src[i * 8 + 4] + src[i * 8 + 6]) / 2; + dest[i * 4 + 3] = (src[i * 8 + 3] + src[i * 8 + 7]) / 2; + } +} + +void +vs_scanline_resample_nearest_YUYV (guint8 * dest, guint8 * src, int n, + int *accumulator, int increment) +{ + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i * 4 + 0] = (x < 32768) ? src[j * 2 + 0] : src[j * 2 + 2]; + + j = acc >> 17; + x = acc & 0x1ffff; + dest[i * 4 + 1] = (x < 65536) ? src[j * 4 + 1] : src[j * 4 + 5]; + dest[i * 4 + 3] = (x < 65536) ? src[j * 4 + 3] : src[j * 4 + 7]; + + acc += increment; + + j = acc >> 16; + x = acc & 0xffff; + dest[i * 4 + 2] = (x < 32768) ? src[j * 2 + 0] : src[j * 2 + 2]; + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_resample_linear_YUYV (guint8 * dest, guint8 * src, int n, + int *accumulator, int increment) +{ + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i * 4 + 0] = (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16; + + j = acc >> 17; + x = acc & 0x1ffff; + dest[i * 4 + 1] = + (src[j * 4 + 1] * (131072 - x) + src[j * 4 + 5] * x) >> 17; + dest[i * 4 + 3] = + (src[j * 4 + 3] * (131072 - x) + src[j * 4 + 7] * x) >> 17; + + acc += increment; + + j = acc >> 16; + x = acc & 0xffff; + dest[i * 4 + 2] = (src[j * 2 + 0] * (65536 - x) + src[j * 2 + 2] * x) >> 16; + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_merge_linear_YUYV (guint8 * dest, guint8 * src1, guint8 * src2, + int n, int x) +{ + int i; + + for (i = 0; i < n; i++) { + dest[i * 4 + 0] = + (src1[i * 4 + 0] * (65536 - x) + src2[i * 4 + 0] * x) >> 16; + dest[i * 4 + 1] = + (src1[i * 4 + 1] * (65536 - x) + src2[i * 4 + 1] * x) >> 16; + dest[i * 4 + 2] = + (src1[i * 4 + 2] * (65536 - x) + src2[i * 4 + 2] * x) >> 16; + dest[i * 4 + 3] = + (src1[i * 4 + 3] * (65536 - x) + src2[i * 4 + 3] * x) >> 16; + } +} + + +/* UYVY */ + +/* n is the number of bi-pixels */ +/* increment is per Y pixel */ + +void +vs_scanline_downsample_UYVY (guint8 * dest, guint8 * src, int n) +{ + int i; + + for (i = 0; i < n; i++) { + dest[i * 4 + 0] = (src[i * 8 + 0] + src[i * 8 + 4]) / 2; + dest[i * 4 + 1] = (src[i * 8 + 1] + src[i * 8 + 3]) / 2; + dest[i * 4 + 2] = (src[i * 8 + 2] + src[i * 8 + 6]) / 2; + dest[i * 4 + 3] = (src[i * 8 + 5] + src[i * 8 + 7]) / 2; + } +} + +void +vs_scanline_resample_nearest_UYVY (guint8 * dest, guint8 * src, int n, + int *accumulator, int increment) +{ + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i * 4 + 1] = (x < 32768) ? src[j * 2 + 1] : src[j * 2 + 3]; + + j = acc >> 17; + x = acc & 0x1ffff; + dest[i * 4 + 0] = (x < 65536) ? src[j * 4 + 0] : src[j * 4 + 4]; + dest[i * 4 + 2] = (x < 65536) ? src[j * 4 + 2] : src[j * 4 + 6]; + + acc += increment; + + j = acc >> 16; + x = acc & 0xffff; + dest[i * 4 + 3] = (x < 32768) ? src[j * 2 + 1] : src[j * 2 + 3]; + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_resample_linear_UYVY (guint8 * dest, guint8 * src, int n, + int *accumulator, int increment) +{ + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i * 4 + 1] = (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16; + + j = acc >> 17; + x = acc & 0x1ffff; + dest[i * 4 + 0] = + (src[j * 4 + 0] * (131072 - x) + src[j * 4 + 4] * x) >> 17; + dest[i * 4 + 2] = + (src[j * 4 + 2] * (131072 - x) + src[j * 4 + 6] * x) >> 17; + + acc += increment; + + j = acc >> 16; + x = acc & 0xffff; + dest[i * 4 + 3] = (src[j * 2 + 1] * (65536 - x) + src[j * 2 + 3] * x) >> 16; + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_merge_linear_UYVY (guint8 * dest, guint8 * src1, guint8 * src2, + int n, int x) +{ + int i; + + for (i = 0; i < n; i++) { + dest[i * 4 + 0] = + (src1[i * 4 + 0] * (65536 - x) + src2[i * 4 + 0] * x) >> 16; + dest[i * 4 + 1] = + (src1[i * 4 + 1] * (65536 - x) + src2[i * 4 + 1] * x) >> 16; + dest[i * 4 + 2] = + (src1[i * 4 + 2] * (65536 - x) + src2[i * 4 + 2] * x) >> 16; + dest[i * 4 + 3] = + (src1[i * 4 + 3] * (65536 - x) + src2[i * 4 + 3] * x) >> 16; + } +} + + +/* RGB565 */ + +/* note that src and dest are guint16, and thus endian dependent */ + +#define RGB565_R(x) (((x)&0xf800)>>8 | ((x)&0xf800)>>13) +#define RGB565_G(x) (((x)&0x07e0)>>3 | ((x)&0x07e0)>>9) +#define RGB565_B(x) (((x)&0x001f)<<3 | ((x)&0x001f)>>2) + +#define RGB565(r,g,b) \ + ((((r)<<8)&0xf800) | (((g)<<3)&0x07e0) | (((b)>>3)&0x001f)) + + +void +vs_scanline_downsample_RGB565 (guint8 * dest_u8, guint8 * src_u8, int n) +{ + guint16 *dest = (guint16 *) dest_u8; + guint16 *src = (guint16 *) src_u8; + int i; + + for (i = 0; i < n; i++) { + dest[i] = RGB565 ( + (RGB565_R (src[i * 2]) + RGB565_R (src[i * 2 + 1])) / 2, + (RGB565_G (src[i * 2]) + RGB565_G (src[i * 2 + 1])) / 2, + (RGB565_B (src[i * 2]) + RGB565_B (src[i * 2 + 1])) / 2); + } +} + +void +vs_scanline_resample_nearest_RGB565 (guint8 * dest_u8, guint8 * src_u8, int n, + int *accumulator, int increment) +{ + guint16 *dest = (guint16 *) dest_u8; + guint16 *src = (guint16 *) src_u8; + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i] = (x < 32768) ? src[j] : src[j + 1]; + + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_resample_linear_RGB565 (guint8 * dest_u8, guint8 * src_u8, int n, + int *accumulator, int increment) +{ + guint16 *dest = (guint16 *) dest_u8; + guint16 *src = (guint16 *) src_u8; + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i] = RGB565 ( + (RGB565_R (src[j]) * (65536 - x) + RGB565_R (src[j + 1]) * x) >> 16, + (RGB565_G (src[j]) * (65536 - x) + RGB565_G (src[j + 1]) * x) >> 16, + (RGB565_B (src[j]) * (65536 - x) + RGB565_B (src[j + 1]) * x) >> 16); + + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_merge_linear_RGB565 (guint8 * dest_u8, guint8 * src1_u8, + guint8 * src2_u8, int n, int x) +{ + guint16 *dest = (guint16 *) dest_u8; + guint16 *src1 = (guint16 *) src1_u8; + guint16 *src2 = (guint16 *) src2_u8; + int i; + + for (i = 0; i < n; i++) { + dest[i] = RGB565 ( + (RGB565_R (src1[i]) * (65536 - x) + RGB565_R (src2[i]) * x) >> 16, + (RGB565_G (src1[i]) * (65536 - x) + RGB565_G (src2[i]) * x) >> 16, + (RGB565_B (src1[i]) * (65536 - x) + RGB565_B (src2[i]) * x) >> 16); + } +} + + +/* RGB555 */ + +/* note that src and dest are guint16, and thus endian dependent */ + +#define RGB555_R(x) (((x)&0x7c00)>>8 | ((x)&0x7c00)>>13) +#define RGB555_G(x) (((x)&0x03e0)>>3 | ((x)&0x03e0)>>9) +#define RGB555_B(x) (((x)&0x001f)<<3 | ((x)&0x001f)>>2) + +#define RGB555(r,g,b) \ + ((((r)<<7)&0x7c00) | (((g)<<3)&0x03e0) | (((b)>>3)&0x001f)) + + +void +vs_scanline_downsample_RGB555 (guint8 * dest_u8, guint8 * src_u8, int n) +{ + guint16 *dest = (guint16 *) dest_u8; + guint16 *src = (guint16 *) src_u8; + int i; + + for (i = 0; i < n; i++) { + dest[i] = RGB555 ( + (RGB555_R (src[i * 2]) + RGB555_R (src[i * 2 + 1])) / 2, + (RGB555_G (src[i * 2]) + RGB555_G (src[i * 2 + 1])) / 2, + (RGB555_B (src[i * 2]) + RGB555_B (src[i * 2 + 1])) / 2); + } +} + +void +vs_scanline_resample_nearest_RGB555 (guint8 * dest_u8, guint8 * src_u8, int n, + int *accumulator, int increment) +{ + guint16 *dest = (guint16 *) dest_u8; + guint16 *src = (guint16 *) src_u8; + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i] = (x < 32768) ? src[j] : src[j + 1]; + + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_resample_linear_RGB555 (guint8 * dest_u8, guint8 * src_u8, int n, + int *accumulator, int increment) +{ + guint16 *dest = (guint16 *) dest_u8; + guint16 *src = (guint16 *) src_u8; + int acc = *accumulator; + int i; + int j; + int x; + + for (i = 0; i < n; i++) { + j = acc >> 16; + x = acc & 0xffff; + dest[i] = RGB555 ( + (RGB555_R (src[j]) * (65536 - x) + RGB555_R (src[j + 1]) * x) >> 16, + (RGB555_G (src[j]) * (65536 - x) + RGB555_G (src[j + 1]) * x) >> 16, + (RGB555_B (src[j]) * (65536 - x) + RGB555_B (src[j + 1]) * x) >> 16); + + acc += increment; + } + + *accumulator = acc; +} + +void +vs_scanline_merge_linear_RGB555 (guint8 * dest_u8, guint8 * src1_u8, + guint8 * src2_u8, int n, int x) +{ + guint16 *dest = (guint16 *) dest_u8; + guint16 *src1 = (guint16 *) src1_u8; + guint16 *src2 = (guint16 *) src2_u8; + int i; + + for (i = 0; i < n; i++) { + dest[i] = RGB555 ( + (RGB555_R (src1[i]) * (65536 - x) + RGB555_R (src2[i]) * x) >> 16, + (RGB555_G (src1[i]) * (65536 - x) + RGB555_G (src2[i]) * x) >> 16, + (RGB555_B (src1[i]) * (65536 - x) + RGB555_B (src2[i]) * x) >> 16); + } +} diff --git a/gst/videoscale/vs_scanline.h b/gst/videoscale/vs_scanline.h new file mode 100644 index 0000000000..30b6c033df --- /dev/null +++ b/gst/videoscale/vs_scanline.h @@ -0,0 +1,73 @@ +/* + * Image Scaling Functions + * Copyright (c) 2005 David A. Schleef + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __VS_SCANLINE_H__ +#define __VS_SCANLINE_H__ + +#include + +G_BEGIN_DECLS + +void vs_scanline_downsample_Y (guint8 *dest, guint8 *src, int n); +void vs_scanline_resample_nearest_Y (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_resample_linear_Y (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_merge_linear_Y (guint8 *dest, guint8 *src1, guint8 *src2, int n, int x); + +void vs_scanline_downsample_RGBA (guint8 *dest, guint8 *src, int n); +void vs_scanline_resample_nearest_RGBA (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_resample_linear_RGBA (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_merge_linear_RGBA (guint8 *dest, guint8 *src1, guint8 *src2, int n, int x); + +void vs_scanline_downsample_RGB (guint8 *dest, guint8 *src, int n); +void vs_scanline_resample_nearest_RGB (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_resample_linear_RGB (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_merge_linear_RGB (guint8 *dest, guint8 *src1, guint8 *src2, int n, int x); + +void vs_scanline_downsample_YUYV (guint8 *dest, guint8 *src, int n); +void vs_scanline_resample_nearest_YUYV (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_resample_linear_YUYV (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_merge_linear_YUYV (guint8 *dest, guint8 *src1, guint8 *src2, int n, int x); + +void vs_scanline_downsample_UYVY (guint8 *dest, guint8 *src, int n); +void vs_scanline_resample_nearest_UYVY (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_resample_linear_UYVY (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_merge_linear_UYVY (guint8 *dest, guint8 *src1, guint8 *src2, int n, int x); + +void vs_scanline_downsample_RGB565 (guint8 *dest, guint8 *src, int n); +void vs_scanline_resample_nearest_RGB565 (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_resample_linear_RGB565 (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_merge_linear_RGB565 (guint8 *dest, guint8 *src1, guint8 *src2, int n, int x); + +void vs_scanline_downsample_RGB555 (guint8 *dest, guint8 *src, int n); +void vs_scanline_resample_nearest_RGB555 (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_resample_linear_RGB555 (guint8 *dest, guint8 *src, int n, int *accumulator, int increment); +void vs_scanline_merge_linear_RGB555 (guint8 *dest, guint8 *src1, guint8 *src2, int n, int x); + +G_END_DECLS + +#endif +