#ifdef HAVE_CONFIG_H #include "config.h" #endif #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 #define GL_GLEXT_PROTOTYPES // VERY dangerous: #define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878 #include #include #include #include #include #include #include #include "gstglsink.h" typedef struct _GstGLImageConnection GstGLImageConnection; struct _GstGLImageConnection { GstImageConnection conn; Display *dpy; gint w, h; gint bpp; int ytex_id; int uvtex_id; int septex_id; unsigned char *m_memory; int m_bufslots[4]; }; #define TEX_XSIZE 1024 #define TEX_YSIZE 1024 #define YUVTEX_SIZE ((TEX_XSIZE * TEX_YSIZE) * 3 /2) #define AGP_BUFSLOTS 4 typedef struct _GstNvImage GstNvImage; struct _GstNvImage { GstImageData data; int slot; // < AGP_BUFSLOTS: allocated from AGP mem, otherwise from CPU mem GstGLImageConnection *conn; }; static GstGLImageInfo *gst_gl_nvimage_info (GstImageInfo * info); static GstGLImageConnection *gst_gl_nvimage_connection (GstImageConnection * conn); static gboolean gst_gl_nvimage_check_xvideo (); static GstCaps *gst_gl_nvimage_get_caps (GstImageInfo * info); static GstImageConnection *gst_gl_nvimage_set_caps (GstImageInfo * info, GstCaps * caps); static GstImageData *gst_gl_nvimage_get_image (GstImageInfo * info, GstImageConnection * conn); static void gst_gl_nvimage_put_image (GstImageInfo * info, GstImageData * image); static void gst_gl_nvimage_free_image (GstImageData * image); static void gst_gl_nvimage_open_conn (GstImageConnection * conn, GstImageInfo * info); static void gst_gl_nvimage_close_conn (GstImageConnection * conn, GstImageInfo * info); static void gst_gl_nvimage_free_conn (GstImageConnection * conn); GstImagePlugin * get_gl_nvimage_plugin (void) { static GstImagePlugin plugin = { gst_gl_nvimage_get_caps, gst_gl_nvimage_set_caps, gst_gl_nvimage_get_image, gst_gl_nvimage_put_image, gst_gl_nvimage_free_image }; return &plugin; } static GstGLImageInfo * gst_gl_nvimage_info (GstImageInfo * info) { if (info == NULL || info->id != GST_MAKE_FOURCC ('X', 'l', 'i', 'b')) { return NULL; } return (GstGLImageInfo *) info; } static GstGLImageConnection * gst_gl_nvimage_connection (GstImageConnection * conn) { if (conn == NULL || conn->free_conn != gst_gl_nvimage_free_conn) return NULL; return (GstGLImageConnection *) conn; } gboolean gst_gl_nvimage_check_xvideo () { int ver, rel, req, ev, err; #if 0 if (display == NULL) return FALSE; if (Success == XvQueryExtension (display, &ver, &rel, &req, &ev, &err)) return TRUE; #endif return FALSE; } static GstCaps * gst_gl_nvimage_get_caps (GstImageInfo * info) { gint i; int adaptors; int formats; GstCaps *caps = NULL; GstGLImageInfo *xinfo = gst_gl_nvimage_info (info); /* we don't handle these image information */ if (xinfo == NULL) return NULL; if (gst_gl_nvimage_check_xvideo () == FALSE) { g_warning ("GL_NVImage: Server has no NVidia extension support\n"); return NULL; } caps = gst_caps_append (caps, GST_CAPS_NEW ("xvimage_caps", "video/raw", "format", GST_PROPS_FOURCC (GST_MAKE_FOURCC ('Y', 'C', '1', '2')), "width", GST_PROPS_INT_RANGE (0, 1024), "height", GST_PROPS_INT_RANGE (0, 1024)) ); return caps; } static GstImageConnection * gst_gl_nvimage_set_caps (GstImageInfo * info, GstCaps * caps) { gint i, j = 0; int adaptors; int formats; GstGLImageConnection *conn; GstGLImageInfo *xinfo = gst_gl_nvimage_info (info); guint32 format; /* we don't handle these image information */ if (xinfo == NULL) return NULL; conn = g_new0 (GstGLImageConnection, 1); conn->conn.open_conn = gst_gl_nvimage_open_conn; conn->conn.close_conn = gst_gl_nvimage_close_conn; conn->conn.free_conn = gst_gl_nvimage_free_conn; gst_caps_get (caps, "width", &conn->w, "height", &conn->h, "format", &format, NULL); // maybe I should a bit more checking here, e.g. maximum size smaller than maximum texture extents if (format != GST_MAKE_FOURCC ('R', 'G', 'B', ' ')) { GST_DEBUG (GST_CAT_PLUGIN_INFO, "GL_NVImage: Format is invalid !\n"); return NULL; } if (0) //conn->port == (XvPortID) -1) { /* this happens if the plugin can't handle the caps, so no warning */ g_free (conn); return NULL; } GST_DEBUG (GST_CAT_PLUGIN_INFO, "GL_NVImage: caps %p are ok, creating image", caps); return (GstImageConnection *) conn; } static GstImageData * gst_gl_nvimage_get_image (GstImageInfo * info, GstImageConnection * conn) { GstNvImage *image; GstGLImageInfo *xinfo = gst_gl_nvimage_info (info); GstGLImageConnection *nvconn = gst_gl_nvimage_connection (conn); int slot = 0; /* checks */ if (xinfo == NULL) return NULL; if (nvconn == NULL) return NULL; // I should also check the current GLX context ! // Ah, Don't have to, I am guarantueed to always be in the same thread image = g_new0 (GstNvImage, 1); for (slot = 0; slot < AGP_BUFSLOTS; slot++) { if (!nvconn->m_bufslots[slot]) break; } image->data.size = nvconn->w * nvconn->h * 3 / 2; if (slot < AGP_BUFSLOTS) // found an AGP buffer slot { image->data.data = nvconn->m_memory + slot * YUVTEX_SIZE; image->slot = slot; // store for freeing nvconn->m_bufslots[slot] = 1; // it is now taken } else { g_warning ("Allocating from main memory !"); image->data.data = g_malloc (image->data.size); image->slot = AGP_BUFSLOTS; // no AGP slot } image->conn = nvconn; if (image->data.data == NULL) { g_warning ("GL_NvImage: data allocation failed!"); g_free (image); return NULL; } return (GstImageData *) image; } static void gst_gl_nvimage_put_image (GstImageInfo * info, GstImageData * image) { GstNvImage *im = (GstNvImage *) image; GstGLImageInfo *xinfo = gst_gl_nvimage_info (info); /* checks omitted for speed (and lazyness), do we need them? */ g_assert (xinfo != NULL); /* Upload the texture here */ g_warning ("PUTTING IMAGE - BROOOKEN"); // 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->ytex_id); glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, im->conn->w, im->conn->h, GL_RGBA, GL_UNSIGNED_BYTE, im->data.data); float xmax = (float) im->conn->w / TEX_XSIZE; float 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); } static void gst_gl_nvimage_free_image (GstImageData * image) { GstNvImage *im = (GstNvImage *) image; g_return_if_fail (im != NULL); GstGLImageConnection *nvconn = im->conn; if (im->slot < AGP_BUFSLOTS) { nvconn->m_bufslots[im->slot] = 0; } else g_free (im->data.data); g_free (im); } static void gst_gl_nvimage_open_conn (GstImageConnection * conn, GstImageInfo * info) { GstGLImageInfo *xinfo = gst_gl_nvimage_info (info); GstGLImageConnection *xconn = gst_gl_nvimage_connection (conn); unsigned char data_sep[2][2] = { {0, 255}, {0, 255} }; int slot; g_warning ("Opening NVidia Connection"); xconn->m_memory = (unsigned char *) glXAllocateMemoryNV (AGP_BUFSLOTS * YUVTEX_SIZE, 0, 1.0, 1.0); if (!xconn->m_memory) { printf ("Unable to acquire graphics card mem... will acquire in normal memory.\n"); for (slot = 0; slot < AGP_BUFSLOTS; slot++) xconn->m_bufslots[slot] = 1; } else { // maybe this fast writable memory, awfully slow to read from, though glPixelDataRangeNV (GL_WRITE_PIXEL_DATA_RANGE_NV, AGP_BUFSLOTS * YUVTEX_SIZE, xconn->m_memory); glEnableClientState (GL_WRITE_PIXEL_DATA_RANGE_NV); for (slot = 0; slot < AGP_BUFSLOTS; slot++) xconn->m_bufslots[slot] = 0; } glGenTextures (1, &xconn->ytex_id); glBindTexture (GL_TEXTURE_2D, xconn->ytex_id); glPixelStorei (GL_UNPACK_ALIGNMENT, 1); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 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_LUMINANCE8_ALPHA8, TEX_XSIZE, TEX_YSIZE, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL); glActiveTextureARB (GL_TEXTURE1_ARB); glGenTextures (1, &xconn->uvtex_id); glBindTexture (GL_TEXTURE_2D, xconn->uvtex_id); glPixelStorei (GL_UNPACK_ALIGNMENT, 1); glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE8_ALPHA8, TEX_XSIZE / 2, TEX_YSIZE / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 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_ADD); glActiveTextureARB (GL_TEXTURE2_ARB); glGenTextures (1, &xconn->septex_id); glBindTexture (GL_TEXTURE_2D, xconn->septex_id); glPixelStorei (GL_UNPACK_ALIGNMENT, 1); glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE8, 2, 2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, data_sep); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 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_ADD); glFlushPixelDataRangeNV (GL_WRITE_PIXEL_DATA_RANGE_NV); //glEnable(GL_TEXTURE_2D); glActiveTextureARB (GL_TEXTURE0_ARB); glEnable (GL_TEXTURE_2D); glActiveTextureARB (GL_TEXTURE1_ARB); glEnable (GL_TEXTURE_2D); glActiveTextureARB (GL_TEXTURE2_ARB); glEnable (GL_TEXTURE_2D); glActiveTextureARB (GL_TEXTURE0_ARB); } static void gst_gl_nvimage_close_conn (GstImageConnection * conn, GstImageInfo * info) { GstGLImageConnection *xconn = gst_gl_nvimage_connection (conn); GstGLImageInfo *xinfo = gst_gl_nvimage_info (info); // anything needed in here ? Oh, maybe drawing de-init, or something glDeleteTextures (1, &xconn->ytex_id); glDeleteTextures (1, &xconn->uvtex_id); glDeleteTextures (1, &xconn->septex_id); } static void gst_gl_nvimage_free_conn (GstImageConnection * conn) { GstGLImageConnection *nvconn = gst_gl_nvimage_connection (conn); g_free (nvconn); }