#include /* 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 #include #include #include #include #include #include #include #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); }