diff options
Diffstat (limited to 'sys/glsink/gstgl_rgbimage.c')
-rw-r--r-- | sys/glsink/gstgl_rgbimage.c | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/sys/glsink/gstgl_rgbimage.c b/sys/glsink/gstgl_rgbimage.c new file mode 100644 index 00000000..68a1329a --- /dev/null +++ b/sys/glsink/gstgl_rgbimage.c @@ -0,0 +1,388 @@ +#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 <string.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 <math.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/x-raw-rgb", + "format", GST_PROPS_FOURCC (GST_STR_FOURCC ("RGB ")), + "depth", GST_PROPS_INT(24), + "bpp", GST_PROPS_INT(24), + "red_mask", GST_PROPS_INT(0xff0000), + "green_mask", GST_PROPS_INT(0xff00), + "blue_mask", GST_PROPS_INT(0xff), + "endianness", GST_PROPS_INT(G_BIG_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 ("GL_RGBImage: returning caps at %p", caps); + return caps; +} + +static GstImageConnection * +gst_gl_rgbimage_set_caps (GstImageInfo *info, GstCaps *caps) +{ + g_warning("in set_caps !\n"); + + 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 ("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; + + int img_width = im->conn->w; + int img_height = im->conn->h; + + g_assert (xinfo != NULL); + + // both upload the video, and redraw the screen + glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef(0.0, 0.0, -25.0); + + glEnable(GL_TEXTURE_2D); + + if (xinfo->info.demo) + { + + glRotatef(180.0*sin(xinfo->rotX),1,0,0); + glRotatef(180.0*cos(xinfo->rotY),0,1,0); + + xinfo->rotX += 0.01; + xinfo->rotY -= 0.015; + float zoom = xinfo->zoom; + glScalef(zoom,zoom,zoom); + //glScalef(0.1,0.1,0.1); + + if (xinfo->zoom > 1.0) + xinfo->zoomdir = -0.01; + + if (xinfo->zoom < 0.5) + xinfo->zoomdir = 0.01; + + xinfo->zoom += xinfo->zoomdir; + } + + //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_RGB, + GL_UNSIGNED_BYTE, im->data.data); + xmax = (float)im->conn->w/TEX_XSIZE; + ymax = (float)im->conn->h/TEX_YSIZE; + + float aspect = img_width/(float)img_height; + float hor = 4 * aspect; + + glColor4f(1,1,1,1); + glBegin(GL_QUADS); + + glNormal3f(0, -1, 0); + + glTexCoord2f(xmax, 0); + glVertex3f(hor,4,0); + + glTexCoord2f(0, 0); + glVertex3f(-hor,4,0); + + glTexCoord2f(0, ymax); + glVertex3f(-hor,-4,0); + + glTexCoord2f(xmax, ymax); + glVertex3f(hor,-4,0); + glEnd(); + + if (xinfo->info.dumpvideo) + { + static int framenr = 0; + char capfilename[255]; + static guint8 *cap_image_data = NULL, *cap_image_data2 = NULL; + int i; + + // hmmmm, is this reentrant ?! + if (cap_image_data == NULL) + cap_image_data = (guint8 *)malloc(img_width * img_height * 3); + + if (cap_image_data2 == NULL) + cap_image_data2 = (guint8 *)malloc(img_width * img_height * 3); + + printf("Recording frame #%d\n", framenr); + glReadPixels(0,0,img_width,img_height,GL_RGB,GL_UNSIGNED_BYTE,cap_image_data); + // invert the pixels + for (i = 0; i < img_height; i++) + memcpy(cap_image_data2 + i * img_width * 3, cap_image_data + (img_height-1-i) * img_width * 3, img_width*3); + + sprintf(capfilename, "cap%04d.ppm", framenr); + FILE *outfile = fopen(capfilename, "wb"); + if (outfile != NULL) + { + fprintf(outfile, "P6\n"); + fprintf(outfile,"# created by raw_zb\n"); + fprintf(outfile,"%d %d\n",img_width,img_height); + fprintf(outfile,"255\n"); + fwrite(cap_image_data2, sizeof(char), img_width*img_height*3, outfile); + fclose(outfile); + } + framenr++; + } + + 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 RGB Connection; classic OpenGL 1.2 renderer."); + + //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); +} + + |