summaryrefslogtreecommitdiffstats
path: root/sys/glsink/gstgl_nvimage.c
diff options
context:
space:
mode:
authorGernot Ziegler <gz@lysator.liu.se>2003-10-27 11:27:32 +0000
committerGernot Ziegler <gz@lysator.liu.se>2003-10-27 11:27:32 +0000
commitbf156442acd3af570fae1bfe4cd1641ca704e09b (patch)
tree314a5ce58512a00c5e13c0bda5cba0443546d0a7 /sys/glsink/gstgl_nvimage.c
parentaf0b12d90106069017dcffcd46bfa056eb2dde9b (diff)
downloadgst-plugins-bad-bf156442acd3af570fae1bfe4cd1641ca704e09b.tar.gz
gst-plugins-bad-bf156442acd3af570fae1bfe4cd1641ca704e09b.tar.bz2
gst-plugins-bad-bf156442acd3af570fae1bfe4cd1641ca704e09b.zip
glsink files checked in
Original commit message from CVS: glsink files checked in
Diffstat (limited to 'sys/glsink/gstgl_nvimage.c')
-rw-r--r--sys/glsink/gstgl_nvimage.c388
1 files changed, 388 insertions, 0 deletions
diff --git a/sys/glsink/gstgl_nvimage.c b/sys/glsink/gstgl_nvimage.c
new file mode 100644
index 00000000..faa5224c
--- /dev/null
+++ b/sys/glsink/gstgl_nvimage.c
@@ -0,0 +1,388 @@
+#include "config.h"
+
+#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>
+
+#define GL_GLEXT_PROTOTYPES
+
+// VERY dangerous:
+#define GL_WRITE_PIXEL_DATA_RANGE_NV 0x8878
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <GL/glx.h>
+#include <GL/gl.h>
+#include <GL/glext.h>
+#include <GL/glu.h>
+#include <string.h>
+
+#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);
+
+ if (0) //conn->port == (XvPortID) -1)
+ {
+ /* this happens if the plugin can't handle the caps, so no warning */
+ g_free (conn);
+ return NULL;
+ }
+
+ 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 ! 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);
+}
+