summaryrefslogtreecommitdiffstats
path: root/sys/glsink/gstgl_rgbimage.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/glsink/gstgl_rgbimage.c')
-rw-r--r--sys/glsink/gstgl_rgbimage.c388
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);
+}
+
+