Reworked the colorspace converter and the scaler API.

Original commit message from CVS:
Reworked the colorspace converter and the scaler API.
Fixed some MMX bugs in the mpeg encoder.
This commit is contained in:
Wim Taymans 2000-06-12 21:27:19 +00:00
parent f179798efb
commit f037c7a742
10 changed files with 354 additions and 318 deletions

View file

@ -22,29 +22,32 @@
#include <gstcolorspace.h>
extern GstColorSpaceConverter gst_colorspace_rgb2rgb_get_converter(GstColorSpace srcspace,
GstColorSpace destspace);
extern GstColorSpaceConverter gst_colorspace_yuv2rgb_get_converter(GstColorSpace srcspace,
GstColorSpace destspace);
extern GstColorSpaceConverter gst_colorspace_rgb2yuv_get_converter(GstColorSpace srcspace,
GstColorSpace destspace);
extern GstColorSpaceConverter gst_colorspace_yuv2yuv_get_converter(GstColorSpace srcspace,
GstColorSpace destspace);
GstBuffer *gst_colorspace_convert(GstBuffer *src, GstColorSpace dest) {
switch (dest) {
default:
break;
}
extern GstColorSpaceConverter gst_colorspace_rgb2rgb_get_converter(GstColorSpace *space, GstColorSpaceType srcspace,
GstColorSpaceType destspace);
extern GstColorSpaceConverter gst_colorspace_yuv2rgb_get_converter(GstColorSpace *space, GstColorSpaceType srcspace,
GstColorSpaceType destspace);
extern GstColorSpaceConverter gst_colorspace_rgb2yuv_get_converter(GstColorSpace *space, GstColorSpaceType srcspace,
GstColorSpaceType destspace);
extern GstColorSpaceConverter gst_colorspace_yuv2yuv_get_converter(GstColorSpace *space, GstColorSpaceType srcspace,
GstColorSpaceType destspace);
return src;
}
GstColorSpace *gst_colorspace_new(int width, int height, GstColorSpaceType srcspace, GstColorSpaceType destspace, GdkVisual *destvisual)
{
GstColorSpaceConverter gst_colorspace_get_converter(GstColorSpace srcspace, GstColorSpace destspace) {
DEBUG("gst_colorspace: get converter\n");
GstColorSpace *new = g_malloc(sizeof(GstColorSpace));
new->width = width;
new->height = height;
new->srcspace = srcspace;
new->destspace = destspace;
new->visual = destvisual;
new->convert = NULL;
DEBUG("gst_colorspace: new\n");
if (GST_COLORSPACE_IS_RGB_TYPE(srcspace)) {
if (GST_COLORSPACE_IS_RGB_TYPE(destspace)) {
return gst_colorspace_rgb2rgb_get_converter(srcspace, destspace);
new->convert = gst_colorspace_rgb2rgb_get_converter(new, srcspace, destspace);
}
else {
//return gst_colorspace_rgb2yuv_get_converter(srcspace, destspace);
@ -52,12 +55,20 @@ GstColorSpaceConverter gst_colorspace_get_converter(GstColorSpace srcspace, GstC
}
else if (GST_COLORSPACE_IS_YUV_TYPE(srcspace)) {
if (GST_COLORSPACE_IS_RGB_TYPE(destspace)) {
return gst_colorspace_yuv2rgb_get_converter(srcspace, destspace);
new->convert = gst_colorspace_yuv2rgb_get_converter(new, srcspace, destspace);
}
else {
//return gst_colorspace_yuv2yuv_get_converter(srcspace, destspace);
}
}
g_print("gst_colorspace: conversion not implemented\n");
return NULL;
if (new->convert == NULL) {
g_print("gst_colorspace: conversion not implemented\n");
}
return new;
}
void gst_colorspace_destroy(GstColorSpace *space)
{
if (space->color_tables) g_free(space->color_tables);
g_free(space);
}

View file

@ -25,8 +25,9 @@
#include <gst/gstbuffer.h>
#include <gst/gstplugin.h>
typedef enum {
#include "yuv2rgb.h"
typedef enum {
#define GST_COLORSPACE_RGB_FIRST GST_COLORSPACE_RGB555
GST_COLORSPACE_RGB555,
GST_COLORSPACE_BGR555,
@ -45,15 +46,22 @@ typedef enum {
GST_COLORSPACE_YUV422P,
#define GST_COLORSPACE_YUV_LAST GST_COLORSPACE_YUV422P
} GstColorSpace;
} GstColorSpaceType;
typedef struct _GstColorSpaceParameters GstColorSpaceParameters;
typedef struct _GstColorSpace GstColorSpace;
typedef void (*GstColorSpaceConverter) (GstColorSpace *space, unsigned char *src, unsigned char *dest);
struct _GstColorSpaceParameters {
struct _GstColorSpace {
guint width;
guint height;
gchar *outbuf;
GstColorSpaceType srcspace;
GstColorSpaceType destspace;
GdkVisual *visual;
guint insize;
guint outsize;
/* private */
GstColorSpaceYUVTables *color_tables;
GstColorSpaceConverter convert;
};
@ -62,11 +70,7 @@ struct _GstColorSpaceParameters {
#define GST_COLORSPACE_IS_YUV_TYPE(type) ((type)>=GST_COLORSPACE_YUV_FIRST && \
(type)<=GST_COLORSPACE_YUV_LAST)
typedef GstBuffer * (*GstColorSpaceConverter) (GstBuffer *src, GstColorSpaceParameters *params);
GstColorSpaceConverter gst_colorspace_get_converter(GstColorSpace srcspace, GstColorSpace destspace);
/* convert a buffer to a new buffer in the given colorspace */
GstBuffer *gst_colorspace_convert(GstBuffer *buf, GstColorSpace destspace);
GstColorSpace *gst_colorspace_new(int width, int height, GstColorSpaceType srcspace, GstColorSpaceType destspace, GdkVisual *destvisual);
void gst_colorspace_destroy(GstColorSpace *space);
#endif /* __GST_COLORSPACE_H__ */

View file

@ -22,26 +22,32 @@
#include <gst/gst.h>
#include <gstcolorspace.h>
static GstBuffer *gst_colorspace_rgb24_to_bgr24(GstBuffer *src, GstColorSpaceParameters *params);
static GstBuffer *gst_colorspace_rgb_to_rgb_identity(GstBuffer *src, GstColorSpaceParameters *params);
static void gst_colorspace_rgb_to_rgb_identity(GstColorSpace *space, unsigned char *src, unsigned char *dest);
static void gst_colorspace_rgb24_to_bgr24(GstColorSpace *space, unsigned char *src, unsigned char *dest);
GstColorSpaceConverter gst_colorspace_rgb2rgb_get_converter(GstColorSpace src, GstColorSpace dest) {
GstColorSpaceConverter gst_colorspace_rgb2rgb_get_converter(GstColorSpace *space, GstColorSpaceType src, GstColorSpaceType dest) {
switch(src) {
case GST_COLORSPACE_RGB24:
space->insize = space->width*space->height*3;
switch(dest) {
case GST_COLORSPACE_RGB24:
space->outsize = space->width*space->height*3;
return gst_colorspace_rgb_to_rgb_identity;
case GST_COLORSPACE_BGR24:
space->outsize = space->width*space->height*3;
return gst_colorspace_rgb24_to_bgr24;
default:
break;
}
break;
case GST_COLORSPACE_BGR24:
space->insize = space->width*space->height*3;
switch(dest) {
case GST_COLORSPACE_RGB24:
space->outsize = space->width*space->height*3;
return gst_colorspace_rgb24_to_bgr24;
case GST_COLORSPACE_BGR24:
space->outsize = space->width*space->height*3;
return gst_colorspace_rgb_to_rgb_identity;
default:
break;
@ -54,35 +60,36 @@ GstColorSpaceConverter gst_colorspace_rgb2rgb_get_converter(GstColorSpace src, G
return NULL;
}
static GstBuffer *gst_colorspace_rgb_to_rgb_identity(GstBuffer *src, GstColorSpaceParameters *params) {
return src;
static void gst_colorspace_rgb_to_rgb_identity(GstColorSpace *space, unsigned char *src, unsigned char *dest)
{
memcpy(dest, src, space->outsize);
}
static GstBuffer *gst_colorspace_rgb24_to_bgr24(GstBuffer *src, GstColorSpaceParameters *params) {
static void gst_colorspace_rgb24_to_bgr24(GstColorSpace *space, unsigned char *src, unsigned char *dest)
{
gint size;
gchar temp;
gchar *data;
DEBUG("gst_colorspace_rgb24_to_bgr24 %d\n", GST_BUFFER_SIZE(src));
DEBUG("gst_colorspace_rgb24_to_bgr24\n");
size = GST_BUFFER_SIZE(src)/3;
size = space->outsize;
if (params != NULL && params->outbuf != NULL) {
data = params->outbuf;
DEBUG("gst_colorspace: to buffer %p\n", data);
if (src == dest) {
while (size--) {
temp = src[0];
src[0] = src[2];
src[2] = temp;
src+=3;
}
}
else {
data = GST_BUFFER_DATA(src);
while (size--) {
*dest++ = src[2];
*dest++ = src[1];
*dest++ = src[0];
src+=3;
}
}
while (size--) {
temp = data[0];
data[0] = data[2];
data[2] = temp;
data+=3;
}
DEBUG("gst_colorspace_rgb24_to_bgr24 end %d\n", GST_BUFFER_SIZE(src));
return src;
DEBUG("gst_colorspace_rgb24_to_bgr24 end\n");
}

View file

@ -32,13 +32,13 @@
#include "yuv2rgb.h"
static GstBuffer *gst_colorspace_yuv420P_to_rgb32(GstBuffer *src, GstColorSpaceParameters *params);
static GstBuffer *gst_colorspace_yuv420P_to_bgr32(GstBuffer *src, GstColorSpaceParameters *params);
static GstBuffer *gst_colorspace_yuv420P_to_bgr32_mmx(GstBuffer *src, GstColorSpaceParameters *params);
static GstBuffer *gst_colorspace_yuv420P_to_rgb24(GstBuffer *src, GstColorSpaceParameters *params);
static GstBuffer *gst_colorspace_yuv420P_to_bgr24(GstBuffer *src, GstColorSpaceParameters *params);
static GstBuffer *gst_colorspace_yuv420P_to_rgb16(GstBuffer *src, GstColorSpaceParameters *params);
static GstBuffer *gst_colorspace_yuv420P_to_bgr16_mmx(GstBuffer *src, GstColorSpaceParameters *params);
static void gst_colorspace_yuv420P_to_rgb32(GstColorSpace *space, unsigned char *src, unsigned char *dest);
static void gst_colorspace_yuv420P_to_bgr32(GstColorSpace *space, unsigned char *src, unsigned char *dest);
static void gst_colorspace_yuv420P_to_bgr32_mmx(GstColorSpace *space, unsigned char *src, unsigned char *dest);
static void gst_colorspace_yuv420P_to_rgb24(GstColorSpace *space, unsigned char *src, unsigned char *dest);
static void gst_colorspace_yuv420P_to_bgr24(GstColorSpace *space, unsigned char *src, unsigned char *dest);
static void gst_colorspace_yuv420P_to_rgb16(GstColorSpace *space, unsigned char *src, unsigned char *dest);
static void gst_colorspace_yuv420P_to_bgr16_mmx(GstColorSpace *space, unsigned char *src, unsigned char *dest);
static void gst_colorspace_yuv_to_rgb16(GstColorSpaceYUVTables *tables,
unsigned char *lum,
@ -76,25 +76,38 @@ static void gst_colorspace_yuv_to_bgr16_mmx(GstColorSpaceYUVTables *tables,
static GstColorSpaceYUVTables * gst_colorspace_init_yuv(long depth,
long red_mask, long green_mask, long blue_mask);
GstColorSpaceConverter gst_colorspace_yuv2rgb_get_converter(GstColorSpace src, GstColorSpace dest) {
DEBUG("gst_colorspace_yuv2rgb_get_converter %d\n", dest);
GstColorSpaceConverter gst_colorspace_yuv2rgb_get_converter(GstColorSpace *space, GstColorSpaceType src, GstColorSpaceType dest) {
DEBUG("gst_colorspace_yuv2rgb_get_converter %d %d\n", src, dest);
switch(src) {
case GST_COLORSPACE_YUV420P:
space->insize = space->width*space->height+space->width*space->height/2;
switch(dest) {
case GST_COLORSPACE_BGR32:
space->color_tables = gst_colorspace_init_yuv(32, 0xFF0000, 0x00FF00, 0x0000FF);
space->outsize = space->width*space->height*4;
//return gst_colorspace_yuv420P_to_bgr32;
return gst_colorspace_yuv420P_to_bgr32_mmx;
case GST_COLORSPACE_RGB32:
space->color_tables = gst_colorspace_init_yuv(32, 0x0000FF, 0x00FF00, 0xFF0000);
space->outsize = space->width*space->height*4;
return gst_colorspace_yuv420P_to_rgb32;
case GST_COLORSPACE_RGB24:
space->color_tables = gst_colorspace_init_yuv(24, 0x0000FF, 0x00FF00, 0xFF0000);
space->outsize = space->width*space->height*3;
return gst_colorspace_yuv420P_to_rgb24;
case GST_COLORSPACE_BGR24:
space->color_tables = gst_colorspace_init_yuv(24, 0xFF0000, 0x00FF00, 0x0000FF);
space->outsize = space->width*space->height*3;
return gst_colorspace_yuv420P_to_bgr24;
case GST_COLORSPACE_RGB555:
case GST_COLORSPACE_RGB565:
case GST_COLORSPACE_BGR555:
g_return_val_if_fail(space->visual != NULL, NULL);
space->color_tables = gst_colorspace_init_yuv(16, space->visual->red_mask, space->visual->green_mask, space->visual->blue_mask);
space->outsize = space->width*space->height*2;
return gst_colorspace_yuv420P_to_rgb16;
case GST_COLORSPACE_BGR565:
space->outsize = space->width*space->height*2;
return gst_colorspace_yuv420P_to_bgr16_mmx;
default:
break;
@ -107,221 +120,122 @@ GstColorSpaceConverter gst_colorspace_yuv2rgb_get_converter(GstColorSpace src, G
return NULL;
}
static GstBuffer *gst_colorspace_yuv420P_to_bgr32(GstBuffer *src, GstColorSpaceParameters *params) {
static GstColorSpaceYUVTables *color_tables = NULL;
static void gst_colorspace_yuv420P_to_bgr32(GstColorSpace *space, unsigned char *src, unsigned char *dest)
{
int size;
GstBuffer *buf = NULL;
guchar *out;
DEBUG("gst_colorspace_yuv420P_to_bgr32\n");
g_return_val_if_fail(params != NULL, NULL);
size = space->width * space->height;
if (color_tables == NULL) {
color_tables = gst_colorspace_init_yuv(32, 0xFF0000, 0x00FF00, 0x0000FF);
}
size = params->width * params->height;
if (params->outbuf == NULL) {
buf = gst_buffer_new();
out = GST_BUFFER_DATA(buf) = g_malloc(size * 4);
GST_BUFFER_SIZE(buf) = size * 4;
}
else out = params->outbuf;
gst_colorspace_yuv_to_rgb32(space->color_tables,
src, // Y component
src+size, // cr component
src+size+(size>>2), // cb component
dest,
space->height,
space->width);
gst_colorspace_yuv_to_rgb32(color_tables,
GST_BUFFER_DATA(src), // Y component
GST_BUFFER_DATA(src)+size, // cr component
GST_BUFFER_DATA(src)+size+(size>>2), // cb component
out,
params->height,
params->width);
if (buf) {
gst_buffer_unref(src);
return buf;
}
else return src;
}
static GstBuffer *gst_colorspace_yuv420P_to_rgb32(GstBuffer *src, GstColorSpaceParameters *params) {
static GstColorSpaceYUVTables *color_tables = NULL;
static void gst_colorspace_yuv420P_to_rgb32(GstColorSpace *space, unsigned char *src, unsigned char *dest)
{
int size;
GstBuffer *buf = NULL;
guchar *out;
DEBUG("gst_colorspace_yuv420P_to_rgb32\n");
g_return_val_if_fail(params != NULL, NULL);
if (color_tables == NULL) {
color_tables = gst_colorspace_init_yuv(32, 0x0000FF, 0x00FF00, 0xFF0000);
}
size = params->width * params->height;
if (params->outbuf == NULL) {
buf = gst_buffer_new();
out = GST_BUFFER_DATA(buf) = g_malloc(size * 4);
GST_BUFFER_SIZE(buf) = size * 4;
}
else out = params->outbuf;
size = space->width * space->height;
gst_colorspace_yuv_to_rgb32(color_tables,
GST_BUFFER_DATA(src), // Y component
GST_BUFFER_DATA(src)+size, // cr component
GST_BUFFER_DATA(src)+size+(size>>2), // cb component
out,
params->height,
params->width);
gst_colorspace_yuv_to_rgb32(space->color_tables,
src, // Y component
src+size, // cr component
src+size+(size>>2), // cb component
dest,
space->height,
space->width);
if (buf) {
gst_buffer_unref(src);
return buf;
}
else return src;
}
static GstBuffer *gst_colorspace_yuv420P_to_bgr24(GstBuffer *src, GstColorSpaceParameters *params) {
static GstColorSpaceYUVTables *color_tables = NULL;
static void gst_colorspace_yuv420P_to_bgr24(GstColorSpace *space, unsigned char *src, unsigned char *dest) {
int size;
GstBuffer *buf = NULL;
guchar *out;
DEBUG("gst_colorspace_yuv420P_to_bgr24\n");
g_return_val_if_fail(params != NULL, NULL);
size = space->width * space->height;
if (color_tables == NULL) {
color_tables = gst_colorspace_init_yuv(24, 0xFF0000, 0x00FF00, 0x0000FF);
}
size = params->width * params->height;
if (params->outbuf == NULL) {
buf = gst_buffer_new();
out = GST_BUFFER_DATA(buf) = g_malloc(size * 3);
GST_BUFFER_SIZE(buf) = size * 3;
}
else out = params->outbuf;
gst_colorspace_yuv_to_rgb24(color_tables,
GST_BUFFER_DATA(src), // Y component
GST_BUFFER_DATA(src)+size, // cr component
GST_BUFFER_DATA(src)+size+(size>>2), // cb component
out,
params->height,
params->width);
if (buf) {
gst_buffer_unref(src);
return buf;
}
else return src;
gst_colorspace_yuv_to_rgb24(space->color_tables,
src, // Y component
src+size, // cr component
src+size+(size>>2), // cb component
dest,
space->height,
space->width);
}
static GstBuffer *gst_colorspace_yuv420P_to_rgb24(GstBuffer *src, GstColorSpaceParameters *params) {
static GstColorSpaceYUVTables *color_tables = NULL;
static void gst_colorspace_yuv420P_to_rgb24(GstColorSpace *space, unsigned char *src, unsigned char *dest) {
int size;
GstBuffer *buf = NULL;
guchar *out;
DEBUG("gst_colorspace_yuv420P_to_rgb24\n");
g_return_val_if_fail(params != NULL, NULL);
size = space->width * space->height;
if (color_tables == NULL) {
color_tables = gst_colorspace_init_yuv(24, 0x0000FF, 0x00FF00, 0xFF0000);
}
size = params->width * params->height;
if (params->outbuf == NULL) {
buf = gst_buffer_new();
out = GST_BUFFER_DATA(buf) = g_malloc(size * 3);
GST_BUFFER_SIZE(buf) = size * 3;
}
else out = params->outbuf;
gst_colorspace_yuv_to_rgb24(space->color_tables,
src, // Y component
src+size, // cr component
src+size+(size>>2), // cb component
dest,
space->height,
space->width);
gst_colorspace_yuv_to_rgb24(color_tables,
GST_BUFFER_DATA(src), // Y component
GST_BUFFER_DATA(src)+size, // cr component
GST_BUFFER_DATA(src)+size+(size>>2), // cb component
out,
params->height,
params->width);
if (buf) {
gst_buffer_unref(src);
return buf;
}
else return src;
}
static GstBuffer *gst_colorspace_yuv420P_to_rgb16(GstBuffer *src, GstColorSpaceParameters *params) {
static GstColorSpaceYUVTables *color_tables = NULL;
static void gst_colorspace_yuv420P_to_rgb16(GstColorSpace *space, unsigned char *src, unsigned char *dest) {
int size;
DEBUG("gst_colorspace_yuv420P_to_rgb16\n");
g_return_val_if_fail(params != NULL, NULL);
g_return_val_if_fail(params->visual != NULL, NULL);
size = space->width * space->height;
if (color_tables == NULL) {
color_tables = gst_colorspace_init_yuv(16, params->visual->red_mask, params->visual->green_mask, params->visual->blue_mask);
}
size = params->width * params->height;
gst_colorspace_yuv_to_rgb16(space->color_tables,
src, // Y component
src+size, // cr component
src+size+(size>>2), // cb component
dest,
space->height,
space->width);
gst_colorspace_yuv_to_rgb16(color_tables,
GST_BUFFER_DATA(src), // Y component
GST_BUFFER_DATA(src)+size, // cr component
GST_BUFFER_DATA(src)+size+(size>>2), // cb component
params->outbuf,
params->height,
params->width);
return src;
}
#ifdef HAVE_LIBMMX
static mmx_t MMX16_redmask = (mmx_t)(long long)0xf800f800f800f800LL; //dd 07c00 7c00h, 07c007c00h
static mmx_t MMX16_grnmask = (mmx_t)(long long)0x07e007e007e007e0LL; //dd 003e0 03e0h, 003e003e0h
static GstBuffer *gst_colorspace_yuv420P_to_bgr32_mmx(GstBuffer *src, GstColorSpaceParameters *params) {
static void gst_colorspace_yuv420P_to_bgr32_mmx(GstColorSpace *space, unsigned char *src, unsigned char *dest) {
int size;
GstBuffer *buf = NULL;
guchar *out;
DEBUG("gst_colorspace_yuv420P_to_rgb32_mmx\n");
g_return_val_if_fail(params != NULL, NULL);
size = params->width * params->height;
if (params->outbuf == NULL) {
buf = gst_buffer_new();
out = GST_BUFFER_DATA(buf) = g_malloc(size * 4);
GST_BUFFER_SIZE(buf) = size * 4;
}
else out = params->outbuf;
size = space->width * space->height;
gst_colorspace_yuv_to_bgr32_mmx(NULL,
GST_BUFFER_DATA(src), // Y component
GST_BUFFER_DATA(src)+size, // cr component
GST_BUFFER_DATA(src)+size+(size>>2), // cb component
out,
params->height,
params->width);
src, // Y component
src+size, // cr component
src+size+(size>>2), // cb component
dest,
space->height,
space->width);
if (buf) {
gst_buffer_unref(src);
return buf;
}
else return src;
}
static GstBuffer *gst_colorspace_yuv420P_to_bgr16_mmx(GstBuffer *src, GstColorSpaceParameters *params) {
static void gst_colorspace_yuv420P_to_bgr16_mmx(GstColorSpace *space, unsigned char *src, unsigned char *dest) {
int size;
DEBUG("gst_colorspace_yuv420P_to_bgr16_mmx \n");
g_return_val_if_fail(params != NULL, NULL);
size = params->width * params->height;
size = space->width * space->height;
gst_colorspace_yuv_to_bgr16_mmx(NULL,
GST_BUFFER_DATA(src), // Y component
GST_BUFFER_DATA(src)+size, // cr component
GST_BUFFER_DATA(src)+size+(size>>2), // cb component
params->outbuf,
params->height,
params->width);
src, // Y component
src+size, // cr component
src+size+(size>>2), // cb component
dest,
space->height,
space->width);
DEBUG("gst_colorspace_yuv420P_to_bgr16_mmx done\n");
return src;
}
#endif

View file

@ -19,6 +19,9 @@
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef __YUV2RGB_H__
#define __YUV2RGB_H__
typedef struct _GstColorSpaceYUVTables GstColorSpaceYUVTables;
struct _GstColorSpaceYUVTables {
@ -61,4 +64,5 @@ struct _GstColorSpaceYUVTables {
? Min(127.0, ((x) * chromaCorrect)) \
: Max(-128.0, ((x) * chromaCorrect)))
#endif

View file

@ -9,7 +9,7 @@ libgstvideoscaleinclude_HEADERS = gstvideoscale.h
noinst_HEADERS = yuv2rgb.h
CFLAGS += -Wall -O2 -fomit-frame-pointer -funroll-all-loops -finline-functions -ffast-math
CFLAGS += -Wall -O2 -fomit-frame-pointer -funroll-all-loops -finline-functions -ffast-math
INCLUDES = $(GLIB_CFLAGS) $(GTK_CFLAGS) -I$(top_srcdir) -I$(top_srcdir)/include
LDADD = $(GLIB_LIBS) $(GTK_LIBS) $(top_srcdir)/gst/libgst.la

View file

@ -25,34 +25,70 @@
#include <gstvideoscale.h>
#include <gst/meta/videoraw.h>
static void gst_videoscale_scale_plane(unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh);
static void gst_videoscale_scale_plane_slow(unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh);
static void gst_videoscale_scale_yuv(GstVideoScale *scale, unsigned char *src, unsigned char *dest);
GstBuffer *gst_videoscale_scale(GstBuffer *src, int sw, int sh, int dw, int dh, int format) {
GstBuffer *outbuf;
char *source;
char *dest;
GstMeta *meta;
DEBUG("videoscale: scaling %dx%d to %dx%d\n", sw, sh, dw, dh);
/* scalers */
static void generate_rowbytes(unsigned char *copy_row, int src_w, int dst_w, int bpp);
static void gst_videoscale_scale_nearest(GstVideoScale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh);
static void gst_videoscale_scale_plane_slow(GstVideoScale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh);
source = GST_BUFFER_DATA(src);
/* filters */
static unsigned char gst_videoscale_bilinear(unsigned char *src, double x, double y, int sw, int sh);
static unsigned char gst_videoscale_bicubic(unsigned char *src, double x, double y, int sw, int sh);
outbuf = gst_buffer_new();
dest = GST_BUFFER_DATA(outbuf) = g_malloc((dw*dh*12)/8);
GST_BUFFER_SIZE(outbuf) = (dw*dh*12)/8;
GstVideoScale *gst_videoscale_new(int sw, int sh, int dw, int dh, int format, GstVideoScaleMethod method)
{
GstVideoScale *new = g_malloc(sizeof(GstVideoScale));
meta = gst_buffer_get_first_meta(src);
if (meta) {
((MetaVideoRaw *)meta)->width = dw;
((MetaVideoRaw *)meta)->height = dh;
new->source_width = sw;
new->source_height = sh;
new->dest_width = dw;
new->dest_height = dh;
new->format = format;
new->method = method;
gst_buffer_add_meta(outbuf, meta);
new->scale = gst_videoscale_scale_yuv;
switch (method) {
case GST_VIDEOSCALE_NEAREST:
generate_rowbytes(new->copy_row, sw, dw, 1);
new->scaler = gst_videoscale_scale_nearest;
DEBUG("videoscale: scaling method NEAREST\n");
break;
case GST_VIDEOSCALE_BILINEAR:
new->scaler = gst_videoscale_scale_plane_slow;
new->filter = gst_videoscale_bilinear;
break;
case GST_VIDEOSCALE_BICUBIC:
new->scaler = gst_videoscale_scale_plane_slow;
new->filter = gst_videoscale_bicubic;
break;
default:
g_print("videoscale: unsupported scaling method %d\n", method);
break;
}
gst_videoscale_scale_plane_slow(source, dest, sw, sh, dw, dh);
return new;
}
source += sw*sh;
void gst_videoscale_destroy(GstVideoScale *scale)
{
g_free(scale);
}
static void gst_videoscale_scale_yuv(GstVideoScale *scale, unsigned char *src, unsigned char *dest)
{
int sw = scale->source_width;
int sh = scale->source_height;
int dw = scale->dest_width;
int dh = scale->dest_height;
DEBUG("videoscale: scaling YUV420 %dx%d to %dx%d\n", sw, sh, dw, dh);
scale->scaler(scale, src, dest, sw, sh, dw, dh);
src += sw*sh;
dest += dw*dh;
dh = dh>>1;
@ -60,21 +96,17 @@ GstBuffer *gst_videoscale_scale(GstBuffer *src, int sw, int sh, int dw, int dh,
sh = sh>>1;
sw = sw>>1;
gst_videoscale_scale_plane_slow(source, dest, sw, sh, dw, dh);
scale->scaler(scale, src, dest, sw, sh, dw, dh);
source += sw*sh;
src += sw*sh;
dest += dw*dh;
gst_videoscale_scale_plane_slow(source, dest, sw, sh, dw, dh);
gst_buffer_unref(src);
return outbuf;
scale->scaler(scale, src, dest, sw, sh, dw, dh);
}
#define RC(x,y) *(src+(int)(x)+(int)((y)*sw))
static unsigned char gst_videoscale_bilinear(unsigned char *src, double x, double y, int sw) {
static unsigned char gst_videoscale_bilinear(unsigned char *src, double x, double y, int sw, int sh) {
int j=floor(x);
int k=floor(y);
double a=x-j;
@ -83,8 +115,10 @@ static unsigned char gst_videoscale_bilinear(unsigned char *src, double x, doubl
int color;
dest=(1-a)*(1-b)*RC(j,k)+
a*(1-b)*RC(j+1,k)+
b*(1-a)*RC(j,k+1)+
a*(1-b)*RC(j+1,k);
k = MIN(sh-1, k);
dest+= b*(1-a)*RC(j,k+1)+
a*b*RC(j+1,k+1);
color=rint(dest);
@ -127,7 +161,8 @@ static unsigned char gst_videoscale_bicubic(unsigned char *src, double x, double
return (unsigned char) color;
}
static void gst_videoscale_scale_plane_slow(unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh) {
static void gst_videoscale_scale_plane_slow(GstVideoScale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh)
{
double zoomx = ((double)dw)/(double)sw;
double zoomy = ((double)dh)/(double)sh;
double xr, yr;
@ -142,62 +177,93 @@ static void gst_videoscale_scale_plane_slow(unsigned char *src, unsigned char *d
*dest++ = RC(xr, yr);
}
else {
//*dest++ = gst_videoscale_bilinear(src, xr, yr, sw);
*dest++ = gst_videoscale_bicubic(src, xr, yr, sw, sh);
*dest++ = scale->filter(src, xr, yr, sw, sh);
//*dest++ = gst_videoscale_bicubic(src, xr, yr, sw, sh);
}
}
}
}
static void gst_videoscale_scale_plane(unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh) {
#define PREFIX16 0x66
#define STORE_BYTE 0xAA
#define STORE_WORD 0xAB
#define LOAD_BYTE 0xAC
#define LOAD_WORD 0xAD
#define RETURN 0xC3
int yinc = sh / dh;
int srcys = sh % dh;
int destys = dh;
int dy = 2 * (srcys - destys);
int incyE = 2 * srcys;
int incyNE = 2 * (srcys - destys);
int x, y;
static void generate_rowbytes(unsigned char *copy_row, int src_w, int dst_w, int bpp)
{
int i;
int pos, inc;
unsigned char *eip;
unsigned char load, store;
int xinc = sw / dw;
int srcxs = sw % dw;
int destxs = dw;
int incxE = 2 * srcxs;
int incxNE = 2 * (srcxs - destxs);
int dx;
unsigned char *sourcep;
int srcinc = 0;
int xskip, yskip =0;
DEBUG("videoscale: setup scaling %p\n", copy_row);
for (y = 0; y<dh; y++) {
dx = 2 * (srcxs - destxs);
sourcep = src + (srcinc*sw);
for (x = dw; x; x--) {
if (dx <= 0) {
dx += incxE;
xskip = 0;
}
else {
dx += incxNE;
xskip = 1;
sourcep++;
}
sourcep += xinc;
*dest++ = *sourcep;
}
if (dy <= 0) {
dy += incyE;
yskip = 0;
}
else {
dy += incyNE;
srcinc++;
yskip = 1;
}
srcinc += yinc;
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;
}
static void gst_videoscale_scale_nearest(GstVideoScale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh)
{
int pos, inc, y;
int u1, u2;
scale->temp = scale->copy_row;
DEBUG("videoscale: scaling nearest %p\n", scale->copy_row);
pos = 0x10000;
inc = (sh<<16)/dh;
for (y = dh; y; y--) {
while (pos >0x10000) {
src += sw;
pos-=0x10000;
}
__asm__ __volatile__ ("
movl %2, %%eax\n
call *%%eax
"
: "=&D" (u1), "=&S" (u2)
: "g" (scale->temp), "0" (dest), "1" (src)
: "memory" );
dest+= dw;
pos += inc;
}
DEBUG("videoscale: scaling nearest done %p\n", scale->copy_row);
}

View file

@ -21,10 +21,32 @@
#ifndef __GST_VIDEOSCALE_H__
#define __GST_VIDEOSCALE_H__
#include <gdk/gdk.h>
#include <gst/gstbuffer.h>
#include <gst/gstplugin.h>
#include <gst/gst.h>
GstBuffer *gst_videoscale_scale(GstBuffer *src, int sw, int sh, int dw, int dh, int format);
typedef enum {
GST_VIDEOSCALE_NEAREST,
GST_VIDEOSCALE_BILINEAR,
GST_VIDEOSCALE_BICUBIC
} GstVideoScaleMethod;
typedef struct _GstVideoScale GstVideoScale;
struct _GstVideoScale {
guint source_width;
guint source_height;
guint dest_width;
guint dest_height;
guint format;
GstVideoScaleMethod method;
/* private */
guchar copy_row[4096];
guchar *temp;
void (*scale) (GstVideoScale *scale, unsigned char *src, unsigned char *dest);
void (*scaler) (GstVideoScale *scale, unsigned char *src, unsigned char *dest, int sw, int sh, int dw, int dh);
unsigned char (*filter) (unsigned char *src, double x, double y, int sw, int sh);
};
GstVideoScale *gst_videoscale_new(int sw, int sh, int dw, int dh, int format, GstVideoScaleMethod method);
void gst_videoscale_destroy(GstVideoScale *scale);
#endif /* __GST_VIDEOSCALE_H__ */

View file

@ -14,7 +14,7 @@ void eof(GstSrc *src) {
}
void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) {
GstElement *parse_audio, *parse_video, *decode, *decode_video, *play, *show;
GstElement *parse_audio, *parse_video, *decode, *decode_video, *play, *videoscale, *show;
GstElement *audio_queue, *video_queue;
GstElement *audio_thread, *video_thread;
@ -71,12 +71,18 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) {
gst_plugin_load("mp1videoparse");
gst_plugin_load(VIDEO_DECODER);
gst_plugin_load("videoscale");
gst_plugin_load("videosink");
// construct internal pipeline elements
parse_video = gst_elementfactory_make("mp1videoparse","parse_video");
g_return_if_fail(parse_video != NULL);
decode_video = gst_elementfactory_make(VIDEO_DECODER,"decode_video");
g_return_if_fail(decode_video != NULL);
videoscale = gst_elementfactory_make("videoscale","videoscale");
g_return_if_fail(videoscale != NULL);
gtk_object_set(GTK_OBJECT(videoscale),"width",704, "height", 576,NULL);
show = gst_elementfactory_make("videosink","show");
g_return_if_fail(show != NULL);
//gtk_object_set(GTK_OBJECT(show),"width",640, "height", 480,NULL);
@ -91,6 +97,7 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) {
g_return_if_fail(video_thread != NULL);
gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(parse_video));
gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(decode_video));
gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(videoscale));
gst_bin_add(GST_BIN(video_thread),GST_ELEMENT(show));
// set up pad connections
@ -99,6 +106,8 @@ void new_pad_created(GstElement *parse,GstPad *pad,GstElement *pipeline) {
gst_pad_connect(gst_element_get_pad(parse_video,"src"),
gst_element_get_pad(decode_video,"sink"));
gst_pad_connect(gst_element_get_pad(decode_video,"src"),
// gst_element_get_pad(videoscale,"sink"));
//gst_pad_connect(gst_element_get_pad(videoscale,"src"),
gst_element_get_pad(show,"sink"));
// construct queue and connect everything in the main pipeline

View file

@ -139,18 +139,17 @@ void mp2tomp1(GstElement *parser,GstPad *pad, GstElement *pipeline) {
g_return_if_fail(decode_video != NULL);
videoscale = gst_elementfactory_make("videoscale","videoscale");
g_return_if_fail(videoscale != NULL);
g_return_if_fail(median != NULL);
gtk_object_set(GTK_OBJECT(videoscale),"width",352, "height", 240,NULL);
median = gst_elementfactory_make("median","median");
gtk_object_set(GTK_OBJECT(median),"filtersize",5,NULL);
g_return_if_fail(median != NULL);
gtk_object_set(GTK_OBJECT(median),"filtersize",9,NULL);
smooth = gst_elementfactory_make("smooth","smooth");
g_return_if_fail(smooth != NULL);
gtk_object_set(GTK_OBJECT(smooth),"filtersize",5,NULL);
gtk_object_set(GTK_OBJECT(smooth),"tolerance",9,NULL);
gtk_object_set(GTK_OBJECT(videoscale),"width",352, "height", 240,NULL);
encode = gst_elementfactory_make("mpeg2enc","encode");
gtk_object_set(GTK_OBJECT(encode),"frames_per_second",29.97,NULL);
g_return_if_fail(encode != NULL);
gtk_object_set(GTK_OBJECT(encode),"frames_per_second",29.97,NULL);
//encode = gst_elementfactory_make("mpeg1encoder","encode");
//gtk_object_set(GTK_OBJECT(show),"width",640, "height", 480,NULL);
@ -172,10 +171,10 @@ void mp2tomp1(GstElement *parser,GstPad *pad, GstElement *pipeline) {
gst_pad_connect(gst_element_get_pad(parse_video,"src"),
gst_element_get_pad(decode_video,"sink"));
gst_pad_connect(gst_element_get_pad(decode_video,"src"),
gst_element_get_pad(videoscale,"sink"));
gst_pad_connect(gst_element_get_pad(videoscale,"src"),
gst_element_get_pad(median,"sink"));
gst_pad_connect(gst_element_get_pad(median,"src"),
gst_element_get_pad(videoscale,"sink"));
gst_pad_connect(gst_element_get_pad(videoscale,"src"),
// gst_element_get_pad(smooth,"sink"));
//gst_pad_connect(gst_element_get_pad(smooth,"src"),
gst_element_get_pad(encode,"sink"));