diff options
Diffstat (limited to 'sys/glsink/gstgl_rgbimage.c')
-rw-r--r-- | sys/glsink/gstgl_rgbimage.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/sys/glsink/gstgl_rgbimage.c b/sys/glsink/gstgl_rgbimage.c new file mode 100644 index 00000000..31ac16ae --- /dev/null +++ b/sys/glsink/gstgl_rgbimage.c @@ -0,0 +1,330 @@ +#include <gst/gst.h> + +/* gcc -ansi -pedantic on GNU/Linux causes warnings and errors + * unless this is defined: + * warning: #warning "Files using this header must be compiled with _SVID_SOURCE or _XOPEN_SOURCE" + */ +#ifndef _XOPEN_SOURCE +# define _XOPEN_SOURCE 1 +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <sys/types.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <GL/glx.h> +#include <GL/gl.h> +#include <GL/glu.h> + +#include "gstglsink.h" + +typedef struct _GstGLImageConnection GstGLImageConnection; + +// this contains everything to draw an image, including all necessary graphics card data. +struct _GstGLImageConnection { + GstImageConnection conn; + Display *dpy; // the Xlib drawing context + GLXContext ctx; // The GLX drawing context + gint w, h; + gint bpp; + + int rgbatex_id; + unsigned char *m_memory; +}; + +#define TEX_XSIZE 1024 +#define TEX_YSIZE 1024 + + +typedef struct _GstGLImage GstGLImage; +struct _GstGLImage +{ + GstImageData data; + GstGLImageConnection *conn; +}; + +static GstGLImageInfo * gst_gl_rgbimage_info (GstImageInfo *info); +static GstGLImageConnection * gst_gl_rgbimage_connection (GstImageConnection *conn); + +static GstCaps * gst_gl_rgbimage_get_caps (GstImageInfo *info); +static GstImageConnection * gst_gl_rgbimage_set_caps (GstImageInfo *info, GstCaps *caps); +static GstImageData * gst_gl_rgbimage_get_image (GstImageInfo *info, GstImageConnection *conn); +static void gst_gl_rgbimage_put_image (GstImageInfo *info, GstImageData *image); +static void gst_gl_rgbimage_free_image (GstImageData *image); +static void gst_gl_rgbimage_open_conn (GstImageConnection *conn, GstImageInfo *info); +static void gst_gl_rgbimage_close_conn (GstImageConnection *conn, GstImageInfo *info); +static void gst_gl_rgbimage_free_conn (GstImageConnection *conn); + +GstImagePlugin* get_gl_rgbimage_plugin(void) +{ + static GstImagePlugin plugin = { gst_gl_rgbimage_get_caps, + gst_gl_rgbimage_set_caps, + gst_gl_rgbimage_get_image, + gst_gl_rgbimage_put_image, + gst_gl_rgbimage_free_image}; + + return &plugin; +} + +static GstGLImageInfo * +gst_gl_rgbimage_info (GstImageInfo *info) +{ + if (info == NULL || info->id != GST_MAKE_FOURCC ('X', 'l', 'i', 'b')) + { + return NULL; + } + return (GstGLImageInfo *) info; +} + +static GstGLImageConnection * +gst_gl_rgbimage_connection (GstImageConnection *conn) +{ + if (conn == NULL || conn->free_conn != gst_gl_rgbimage_free_conn) + return NULL; + return (GstGLImageConnection *) conn; +} + +GstCaps * +gst_gl_rgbimage_get_caps (GstImageInfo *info) +{ + GstCaps *caps = NULL; + Visual *visual; + int xpad; + XWindowAttributes attrib; + XImage *ximage; + GstGLImageInfo *xinfo = gst_gl_rgbimage_info (info); + + /* we don't handle this image information */ + if (xinfo == NULL) return NULL; + + XGetWindowAttributes(xinfo->dpy, xinfo->win, &attrib); + + visual = attrib.visual; + if (attrib.depth <= 8) + xpad = 8; + else if (attrib.depth <= 16) + xpad = 16; + else + xpad = 32; + + // create a temporary image + ximage = XCreateImage (xinfo->dpy, visual, attrib.depth, ZPixmap, 0, NULL, + 100, 100, xpad, (attrib.depth + 7) / 8 * 100); + if (ximage != NULL) { + caps = + GST_CAPS_NEW ( + "forcing Video RGB", + "video/raw", + "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("RGB ")), + "bpp", GST_PROPS_INT(32), + "depth", GST_PROPS_INT(24), + "red_mask", GST_PROPS_INT(0xff), + "green_mask", GST_PROPS_INT(0xff00), + "blue_mask", GST_PROPS_INT(0xff0000), + "endianness", GST_PROPS_INT(G_LITTLE_ENDIAN), /*= 1234/4321 (INT) <- endianness */ + + "width", GST_PROPS_INT_RANGE (0, TEX_XSIZE), /* can't have videos larger than TEX_SIZE */ + "height", GST_PROPS_INT_RANGE (0, TEX_YSIZE) + ); + XDestroyImage (ximage); + } + + GST_DEBUG (GST_CAT_PLUGIN_INFO, "GL_RGBImage: returning caps at %p", caps); + return caps; +} + +static GstImageConnection * +gst_gl_rgbimage_set_caps (GstImageInfo *info, GstCaps *caps) +{ + GstGLImageConnection *new = NULL; + Visual *visual; + XWindowAttributes attrib; + GstGLImageInfo *xinfo = gst_gl_rgbimage_info (info); + guint32 format; + gint depth; + gint endianness; + gint red_mask, green_mask, blue_mask; + gint width, height, bpp; + + /* check if this is the right image info */ + if (xinfo == NULL) return NULL; + + XGetWindowAttributes(xinfo->dpy, xinfo->win, &attrib); + + visual = attrib.visual; + + gst_caps_get (caps, + "format", &format, + "depth", &depth, + "endianness", &endianness, + "red_mask", &red_mask, + "green_mask", &green_mask, + "blue_mask", &blue_mask, + "width", &width, + "height", &height, + "bpp", &bpp, + NULL); + + /* check if the caps are ok */ + if (format != GST_MAKE_FOURCC ('R', 'G', 'B', ' ')) return NULL; + /* if (gst_caps_get_int (caps, "bpp") != ???) return NULL; */ + //if (depth != attrib.depth) return NULL; + //if (endianness != ((ImageByteOrder (xinfo->dpy) == LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN)) return NULL; + //if (red_mask != visual->red_mask) return NULL; + //if (green_mask != visual->green_mask) return NULL; + //if (blue_mask != visual->blue_mask) return NULL; + GST_DEBUG (GST_CAT_PLUGIN_INFO, "GL_RGBImage: caps %p are ok, creating image", caps); + + new = g_new (GstGLImageConnection, 1); + new->conn.open_conn = gst_gl_rgbimage_open_conn; + new->conn.close_conn = gst_gl_rgbimage_close_conn; + new->conn.free_conn = gst_gl_rgbimage_free_conn; + new->dpy = xinfo->dpy; + new->ctx = xinfo->ctx; + new->w = width; + new->h = height; + new->bpp = bpp; + + return (GstImageConnection *) new; +} + +static GstImageData * +gst_gl_rgbimage_get_image (GstImageInfo *info, GstImageConnection *conn) +{ + GstGLImage *image; + XWindowAttributes attrib; + GstGLImageInfo *xinfo = gst_gl_rgbimage_info (info); + GstGLImageConnection *xconn = gst_gl_rgbimage_connection (conn); + + image = g_new (GstGLImage, 1); + + /* checks */ + if (xinfo == NULL) return NULL; + if (xconn == NULL) return NULL; + if (xinfo->dpy != xconn->dpy) + { + g_warning ("XImage: wrong x display specified in 'get_image'\n"); + return NULL; + } + + image->conn = xconn; + image->data.size = xconn->w * xconn->h * 4; + image->data.data = g_malloc(image->data.size); + if (image->data.data == NULL) + { + g_warning ("GL_RGBImage: data allocation failed!"); + g_free (image); + return NULL; + } + + return (GstImageData *) image; +} + + +static void +gst_gl_rgbimage_put_image (GstImageInfo *info, GstImageData *image) +{ + float xmax, ymax; + + GstGLImageInfo *xinfo = gst_gl_rgbimage_info (info); + GstGLImage *im = (GstGLImage *) image; + + g_assert (xinfo != NULL); + g_warning("PUTTING IMAGE"); + + // both upload the video, and redraw the screen + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + glEnable(GL_TEXTURE_2D); + + glPushMatrix(); + //glTranslatef(0,1,0); + glRotatef(xinfo->rotX-250,1,0,0); + glRotatef(xinfo->rotY,0,1,0); + int zoom = xinfo->zoom; + glScaled(zoom,zoom,zoom); + //Draws the surface rectangle + + glBindTexture(GL_TEXTURE_2D, im->conn->rgbatex_id); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, im->conn->w, im->conn->h, GL_RGBA, + GL_UNSIGNED_BYTE, im->data.data); + xmax = (float)im->conn->w/TEX_XSIZE; + ymax = (float)im->conn->h/TEX_YSIZE; + + glColor4f(1,1,1,1); + glBegin(GL_QUADS); + + glNormal3f(0, -1, 0); + + glTexCoord2f(xmax, 0); + glVertex3f(4,0,-4); + + glTexCoord2f(0, 0); + glVertex3f(-4,0,-4); + + glTexCoord2f(0, ymax); + glVertex3f(-4,0,4); + + glTexCoord2f(xmax, ymax); + glVertex3f(4,0,4); + + glEnd(); + + glPopMatrix(); + + glXSwapBuffers(xinfo->dpy, xinfo->win); +} + +void +gst_gl_rgbimage_free_image (GstImageData *image) +{ + GstGLImage *im = (GstGLImage *) image; + + g_warning ("gst_gl_rgbimage_free_image doesn't do anything yet -> freeing image\n"); + g_free (im->data.data); + g_free (im); +} + +/* Creates an OpenGL texture to upload the picture over */ +static void +gst_gl_rgbimage_open_conn (GstImageConnection *conn, GstImageInfo *info) +{ + g_warning("!!! Opening Connection !!!"); + + GstGLImageInfo *xinfo = gst_gl_rgbimage_info (info); + GstGLImageConnection *xconn = gst_gl_rgbimage_connection (conn); + + glGenTextures(1, &xconn->rgbatex_id); + glBindTexture(GL_TEXTURE_2D, xconn->rgbatex_id); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, TEX_XSIZE, TEX_YSIZE, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); +} + +/* Deletes the creates OpenGL textures */ +static void +gst_gl_rgbimage_close_conn (GstImageConnection *conn, GstImageInfo *info) +{ + GstGLImageConnection *xconn = gst_gl_rgbimage_connection (conn); + GstGLImageInfo *xinfo = gst_gl_rgbimage_info (info); + + glDeleteTextures(1, &xconn->rgbatex_id); + } + +static void +gst_gl_rgbimage_free_conn (GstImageConnection *conn) +{ + GstGLImageConnection *xconn = gst_gl_rgbimage_connection (conn); + + g_assert (xconn != NULL); + + g_free (xconn); +} + + |