summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/glsink/BUGS19
-rw-r--r--sys/glsink/Makefile.am12
-rw-r--r--sys/glsink/color_matrix.c243
-rw-r--r--sys/glsink/gstglbuffer.c319
-rw-r--r--sys/glsink/gstglbuffer.h28
-rw-r--r--sys/glsink/gstglconvert.c253
-rw-r--r--sys/glsink/gstgldisplay.c2
-rw-r--r--sys/glsink/gstglfilter.c134
-rw-r--r--sys/glsink/gstglfilter.h68
-rw-r--r--sys/glsink/gstglfilterexample.c243
-rw-r--r--sys/glsink/gstgltestsrc.c8
-rw-r--r--sys/glsink/gstglupload.c29
-rw-r--r--sys/glsink/gstopengl.c11
13 files changed, 1059 insertions, 310 deletions
diff --git a/sys/glsink/BUGS b/sys/glsink/BUGS
new file mode 100644
index 00000000..795d3525
--- /dev/null
+++ b/sys/glsink/BUGS
@@ -0,0 +1,19 @@
+
+known issues:
+
+ - negotiation is shite. I don't want to know about any failed
+ negotiations or failed prerolls.
+
+ - teardown sometimes fails.
+
+ - sharing a GL context among a bunch of elements that stomp all
+ over it is potential fail.
+
+
+intel driver:
+
+ - rendering to texture ignores the color matrix. This causes any
+ YUV->RGB conversion to fail.
+
+ - YUY2 and UYVY conversions in the driver use the wrong matrix.
+
diff --git a/sys/glsink/Makefile.am b/sys/glsink/Makefile.am
index b4f72c92..6cb9dd10 100644
--- a/sys/glsink/Makefile.am
+++ b/sys/glsink/Makefile.am
@@ -1,6 +1,11 @@
plugin_LTLIBRARIES = libgstglimagesink.la
+noinst_PROGRAMS = color_matrix
+
+AM_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)
+AM_LIBS = $(GST_BASE_LIBS)
+
libgstglimagesink_la_SOURCES = \
glimagesink.c \
gstgldisplay.c \
@@ -11,7 +16,9 @@ libgstglimagesink_la_SOURCES = \
gstgldownload.c \
gstgltestsrc.c \
gltestsrc.c \
- gstglfilter.c
+ gstglfilter.c \
+ gstglfilterexample.c \
+ gstglconvert.c
libgstglimagesink_la_CFLAGS = $(GST_CFLAGS) $(X_CFLAGS) $(GST_BASE_CFLAGS) \
$(GST_PLUGINS_BASE_CFLAGS)
libgstglimagesink_la_LIBADD = $(X_LIBS) $(XSHM_LIBS) -lGL \
@@ -25,4 +32,5 @@ noinst_HEADERS = \
glextensions.h \
gstgltestsrc.h \
gltestsrc.h \
- gstglbuffer.h
+ gstglbuffer.h \
+ gstglfilter.h
diff --git a/sys/glsink/color_matrix.c b/sys/glsink/color_matrix.c
new file mode 100644
index 00000000..255184f7
--- /dev/null
+++ b/sys/glsink/color_matrix.c
@@ -0,0 +1,243 @@
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdio.h>
+#include <string.h>
+
+typedef struct
+{
+ double comp[3];
+} Color;
+
+typedef struct
+{
+ Color pre_offset;
+ double matrix[3][3];
+ Color post_offset;
+} ColorMatrix;
+
+
+/* convert uint8 RGB values to float */
+ColorMatrix rgb255_to_rgb = {
+ {{0, 0, 0}},
+ {{(1 / 255.0), 0, 0},
+ {0, (1 / 255.0), 0},
+ {0, 0, (1 / 255.0)}},
+ {{0, 0, 0}}
+};
+ColorMatrix rgb_to_rgb255;
+
+/* convert uint8 YUV values to float as per ITU-R.601
+ * technically, Y, Cr, Cb to E_Y, E_C_B, E_C_R */
+ColorMatrix ycbcr601_to_yuv = {
+ {{-16, -128, -128}},
+ {{(1 / 219.0), 0, 0},
+ {0, (1 / 224.0), 0},
+ {0, 0, (1 / 224.0)}},
+ {{0, 0, 0}}
+};
+ColorMatrix yuv_to_ycbcr601;
+
+/* convert RGB to YUV as per ITU-R.601
+ * technically, E_R, E_G, E_B to E_Y, E_C_B, E_C_R */
+ColorMatrix rgb_to_yuv = {
+ {{0, 0, 0}},
+ {{0.299, 0.587, 0.114},
+ {0.500, -0.419, -0.081},
+ {-0.169, -0.331, 0.500}},
+ {{0, 0, 0}}
+};
+ColorMatrix yuv_to_rgb;
+
+ColorMatrix compress = {
+ {{0, 0, 0}},
+ {{0.50, 0, 0},
+ {0, 0.5, 0},
+ {0, 0, 0.500}},
+ {{0.25, 0.25, 0.25}}
+};
+
+/* red mask */
+ColorMatrix red_mask = {
+ {{0, 0, 0}},
+ {{1, 1, 1},
+ {0, 0, 0},
+ {0, 0, 0}},
+ {{0, 0, 0}}
+};
+
+double colors[][3] = {
+ {0, 0, 0},
+ {255, 0, 0},
+ {0, 255, 0},
+ {0, 0, 255}
+};
+
+
+void
+color_dump (const double *a)
+{
+ printf (" %g, %g, %g\n", a[0], a[1], a[2]);
+}
+
+void
+color_matrix_dump (ColorMatrix * m)
+{
+ printf ("pre: %g, %g, %g\n",
+ m->pre_offset.comp[0], m->pre_offset.comp[1], m->pre_offset.comp[2]);
+ printf (" %g, %g, %g\n", m->matrix[0][0], m->matrix[0][1], m->matrix[0][2]);
+ printf (" %g, %g, %g\n", m->matrix[1][0], m->matrix[1][1], m->matrix[1][2]);
+ printf (" %g, %g, %g\n", m->matrix[2][0], m->matrix[2][1], m->matrix[2][2]);
+ printf ("post: %g, %g, %g\n",
+ m->post_offset.comp[0], m->post_offset.comp[1], m->post_offset.comp[2]);
+}
+
+void
+color_matrix_apply_color (Color * a, const ColorMatrix * b)
+{
+ Color d;
+ int i;
+
+ a->comp[0] += b->pre_offset.comp[0];
+ a->comp[1] += b->pre_offset.comp[1];
+ a->comp[2] += b->pre_offset.comp[2];
+
+ for (i = 0; i < 3; i++) {
+ d.comp[i] = a->comp[0] * b->matrix[i][0];
+ d.comp[i] += a->comp[1] * b->matrix[i][1];
+ d.comp[i] += a->comp[2] * b->matrix[i][2];
+ }
+
+ d.comp[0] += b->post_offset.comp[0];
+ d.comp[1] += b->post_offset.comp[1];
+ d.comp[2] += b->post_offset.comp[2];
+
+ *a = d;
+}
+
+void
+color_matrix_init (ColorMatrix * a)
+{
+ memset (a, 0, sizeof (*a));
+ a->matrix[0][0] = 1.0;
+ a->matrix[1][1] = 1.0;
+ a->matrix[2][2] = 1.0;
+}
+
+void
+color_matrix_apply (ColorMatrix * a, ColorMatrix * b)
+{
+ ColorMatrix d;
+ int i, j;
+
+ d.pre_offset = a->pre_offset;
+
+ d.post_offset = a->post_offset;
+ color_matrix_apply_color (&d.post_offset, b);
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ d.matrix[i][j] =
+ a->matrix[i][0] * b->matrix[0][j] +
+ a->matrix[i][1] * b->matrix[1][j] + a->matrix[i][2] * b->matrix[2][j];
+ }
+ }
+
+ *a = d;
+}
+
+void
+color_matrix_invert (ColorMatrix * a, ColorMatrix * b)
+{
+ int i, j;
+ double det;
+
+ a->post_offset.comp[0] = -b->pre_offset.comp[0];
+ a->post_offset.comp[1] = -b->pre_offset.comp[1];
+ a->post_offset.comp[2] = -b->pre_offset.comp[2];
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ a->matrix[j][i] =
+ b->matrix[(i + 1) % 3][(j + 1) % 3] * b->matrix[(i + 2) % 3][(j +
+ 2) % 3] - b->matrix[(i + 1) % 3][(j + 2) % 3] * b->matrix[(i +
+ 2) % 3][(j + 1) % 3];
+ }
+ }
+
+ det = a->matrix[0][0] * b->matrix[0][0];
+ det += a->matrix[0][1] * b->matrix[1][0];
+ det += a->matrix[0][2] * b->matrix[2][0];
+
+ for (j = 0; j < 3; j++) {
+ for (i = 0; i < 3; i++) {
+ a->matrix[j][i] /= det;
+ }
+ }
+
+ a->pre_offset.comp[0] = -b->post_offset.comp[0];
+ a->pre_offset.comp[1] = -b->post_offset.comp[1];
+ a->pre_offset.comp[2] = -b->post_offset.comp[2];
+}
+
+void
+init (void)
+{
+ color_matrix_invert (&yuv_to_rgb, &rgb_to_yuv);
+ color_matrix_invert (&yuv_to_ycbcr601, &ycbcr601_to_yuv);
+ color_matrix_invert (&rgb_to_rgb255, &rgb255_to_rgb);
+#if 0
+ color_matrix_dump (&yuv_to_rgb);
+ color_matrix_dump (&yuv_to_ycbcr601);
+ color_matrix_dump (&rgb_to_rgb255);
+#endif
+}
+
+int
+main (int argc, char *argv[])
+{
+ ColorMatrix want;
+ ColorMatrix actual;
+ ColorMatrix actual_inv;
+ ColorMatrix a;
+
+ init ();
+
+#if 0
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ double color[3];
+
+ printf ("%d:\n", i);
+
+ color_copy (color, colors[i]);
+ color_matrix_apply_color (color, &rgb255_to_rgb);
+ color_matrix_apply_color (color, &rgb_to_yuv);
+ color_dump (color);
+ }
+#endif
+
+ color_matrix_init (&want);
+ color_matrix_apply (&want, &ycbcr601_to_yuv);
+ color_matrix_apply (&want, &yuv_to_rgb);
+ color_matrix_apply (&want, &compress);
+ color_matrix_apply (&want, &compress);
+ //color_matrix_apply (&want, &compress);
+
+ color_matrix_init (&actual);
+ color_matrix_apply (&actual, &rgb255_to_rgb);
+
+ /* calc X such that actual * X = want */
+
+ color_matrix_invert (&actual_inv, &actual);
+
+ a = actual_inv;
+ color_matrix_apply (&a, &want);
+
+ color_matrix_dump (&a);
+
+
+ return 0;
+}
diff --git a/sys/glsink/gstglbuffer.c b/sys/glsink/gstglbuffer.c
index 048ad993..e3e9df6b 100644
--- a/sys/glsink/gstglbuffer.c
+++ b/sys/glsink/gstglbuffer.c
@@ -18,22 +18,14 @@ gst_gl_buffer_finalize (GstGLBuffer * buffer)
{
gst_gl_display_lock (buffer->display);
- switch (buffer->type) {
- case GST_GL_BUFFER_XIMAGE:
- GST_DEBUG ("freeing pixmap %ld", buffer->pixmap);
- XFreeGC (buffer->display->display, buffer->gc);
- XFreePixmap (buffer->display->display, buffer->pixmap);
- break;
- case GST_GL_BUFFER_RBO:
- glDeleteRenderbuffersEXT (1, &buffer->rbo);
- break;
- case GST_GL_BUFFER_TEXTURE:
- glDeleteTextures (1, &buffer->texture);
- break;
- default:
- g_assert_not_reached ();
- break;
+ glDeleteTextures (1, &buffer->texture);
+ if (buffer->texture_u) {
+ glDeleteTextures (1, &buffer->texture_u);
+ }
+ if (buffer->texture_v) {
+ glDeleteTextures (1, &buffer->texture_v);
}
+
gst_gl_display_unlock (buffer->display);
g_object_unref (buffer->display);
@@ -85,215 +77,194 @@ gst_gl_buffer_get_type (void)
GstGLBuffer *
-gst_gl_buffer_new (GstGLDisplay * display, GstVideoFormat format,
+gst_gl_buffer_new (GstGLDisplay * display, GstGLBufferFormat format,
int width, int height)
{
GstGLBuffer *buffer;
- XGCValues values = { 0 };
- g_return_val_if_fail (format == GST_VIDEO_FORMAT_RGBx, NULL);
g_return_val_if_fail (width > 0, NULL);
g_return_val_if_fail (height > 0, NULL);
buffer = (GstGLBuffer *) gst_mini_object_new (GST_TYPE_GL_BUFFER);
buffer->display = g_object_ref (display);
- buffer->type = GST_GL_BUFFER_TEXTURE;
-
buffer->width = width;
buffer->height = height;
- switch (buffer->type) {
- case GST_GL_BUFFER_XIMAGE:
- {
- buffer->pixmap = XCreatePixmap (display->display,
- DefaultRootWindow (display->display), width, height, 32);
- XSync (display->display, False);
-
- buffer->gc = XCreateGC (display->display, buffer->pixmap, 0, &values);
-
- GST_DEBUG ("new pixmap %dx%d xid %ld", width, height, buffer->pixmap);
- break;
- }
- case GST_GL_BUFFER_RBO:
- {
- GLuint fbo;
-
- gst_gl_display_lock (buffer->display);
-
- glGenFramebuffersEXT (1, &fbo);
- glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo);
-
- glGenRenderbuffersEXT (1, &buffer->rbo);
- glBindRenderbufferEXT (GL_RENDERBUFFER_EXT, buffer->rbo);
-
- glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT,
- GL_COLOR_ATTACHMENT1_EXT, GL_RENDERBUFFER_EXT, buffer->rbo);
- glRenderbufferStorageEXT (GL_RENDERBUFFER_EXT, GL_RGB,
- buffer->width, buffer->height);
-
- glDrawBuffer (GL_COLOR_ATTACHMENT1_EXT);
- glReadBuffer (GL_COLOR_ATTACHMENT1_EXT);
- g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) ==
- GL_FRAMEBUFFER_COMPLETE_EXT);
-
- glDeleteFramebuffersEXT (1, &fbo);
-
- gst_gl_display_unlock (buffer->display);
+ gst_gl_display_lock (buffer->display);
+ glGenTextures (1, &buffer->texture);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture);
+ switch (format) {
+ case GST_GL_BUFFER_FORMAT_RGBA:
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+ buffer->width, buffer->height, 0, GL_RGBA, GL_FLOAT, NULL);
break;
- }
- case GST_GL_BUFFER_TEXTURE:
+ case GST_GL_BUFFER_FORMAT_RGB:
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB,
+ buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
break;
default:
- g_assert_not_reached ();
+ g_warning ("GL buffer format not handled");
}
+ gst_gl_display_unlock (buffer->display);
+
return buffer;
}
-void
-gst_gl_buffer_upload (GstGLBuffer * buffer, void *data)
+GstGLBuffer *
+gst_gl_buffer_new_from_data (GstGLDisplay * display, GstVideoFormat format,
+ int width, int height, void *data)
{
- Display *display = buffer->display->display;
-
- GST_DEBUG ("uploading %p %dx%d", data, buffer->width, buffer->height);
-
- gst_gl_display_lock (buffer->display);
-
- switch (buffer->type) {
- case GST_GL_BUFFER_XIMAGE:
- {
- XImage *image;
- Visual *visual;
- int depth;
- int bpp;
+ GstGLBuffer *buffer;
+ int comp;
- visual = DefaultVisual (display, 0);
- depth = 32;
- bpp = 32;
+ g_return_val_if_fail (width > 0, NULL);
+ g_return_val_if_fail (height > 0, NULL);
+ g_return_val_if_fail (data != NULL, NULL);
- image = XCreateImage (display, visual, depth, ZPixmap, 0, NULL,
- buffer->width, buffer->height, bpp, 0);
- GST_DEBUG ("image %p", image);
- image->data = data;
+ GST_DEBUG ("uploading %p %dx%d", data, width, height);
- XPutImage (display, buffer->pixmap, buffer->gc,
- image, 0, 0, 0, 0, buffer->width, buffer->height);
+ buffer = (GstGLBuffer *) gst_mini_object_new (GST_TYPE_GL_BUFFER);
+ buffer->display = g_object_ref (display);
+ buffer->width = width;
+ buffer->height = height;
- XDestroyImage (image);
+ gst_gl_display_lock (buffer->display);
+ glGenTextures (1, &buffer->texture);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture);
+
+ switch (format) {
+ case GST_VIDEO_FORMAT_RGBx:
+ buffer->format = GST_GL_BUFFER_FORMAT_RGB;
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+ buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
break;
- }
- case GST_GL_BUFFER_RBO:
- {
- unsigned int fbo;
-
- g_assert (glIsRenderbufferEXT (buffer->rbo));
-
- glGenFramebuffersEXT (1, &fbo);
- glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo);
-
- glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT,
- GL_COLOR_ATTACHMENT1_EXT, GL_RENDERBUFFER_EXT, buffer->rbo);
-
- glDrawBuffer (GL_COLOR_ATTACHMENT1_EXT);
- glReadBuffer (GL_COLOR_ATTACHMENT1_EXT);
-
- g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) ==
- GL_FRAMEBUFFER_COMPLETE_EXT);
-
- gst_gl_display_check_error (buffer->display, __LINE__);
- glWindowPos2iARB (0, 0);
- glDrawPixels (buffer->width, buffer->height, GL_RGB,
- GL_UNSIGNED_BYTE, data);
-
- glDeleteFramebuffersEXT (1, &fbo);
-
- g_assert (glIsRenderbufferEXT (buffer->rbo));
-
+ case GST_VIDEO_FORMAT_BGRx:
+ buffer->format = GST_GL_BUFFER_FORMAT_RGB;
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+ buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
+ GL_BGRA, GL_UNSIGNED_BYTE, data);
+ break;
+ case GST_VIDEO_FORMAT_xRGB:
+ buffer->format = GST_GL_BUFFER_FORMAT_RGB;
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+ buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
+ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, data);
+ break;
+ case GST_VIDEO_FORMAT_xBGR:
+ buffer->format = GST_GL_BUFFER_FORMAT_RGB;
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+ buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
+ GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, data);
+ break;
+ case GST_VIDEO_FORMAT_YUY2:
+ buffer->format = GST_GL_BUFFER_FORMAT_YUYV;
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_YCBCR_MESA, width, height,
+ 0, GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_REV_MESA, NULL);
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
+ GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_REV_MESA, data);
break;
- }
- case GST_GL_BUFFER_TEXTURE:
- buffer->texture =
- gst_gl_display_upload_texture_rectangle (buffer->display,
- GST_VIDEO_FORMAT_RGBx, data, buffer->width, buffer->height);
+ case GST_VIDEO_FORMAT_UYVY:
+ buffer->format = GST_GL_BUFFER_FORMAT_YUYV;
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_YCBCR_MESA, width, height,
+ 0, GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_REV_MESA, NULL);
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
+ GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_MESA, data);
+ break;
+ case GST_VIDEO_FORMAT_AYUV:
+ buffer->format = GST_GL_BUFFER_FORMAT_RGB;
+ buffer->is_yuv = TRUE;
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+ buffer->width, buffer->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
+ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, data);
+ break;
+ case GST_VIDEO_FORMAT_I420:
+ case GST_VIDEO_FORMAT_YV12:
+ buffer->format = GST_GL_BUFFER_FORMAT_PLANAR420;
+ buffer->is_yuv = TRUE;
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE,
+ buffer->width, buffer->height,
+ 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
+
+ glGenTextures (1, &buffer->texture_u);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture_u);
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE,
+ GST_ROUND_UP_2 (buffer->width) / 2,
+ GST_ROUND_UP_2 (buffer->height) / 2,
+ 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
+ comp = (format == GST_VIDEO_FORMAT_I420) ? 1 : 2;
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0,
+ GST_ROUND_UP_2 (buffer->width) / 2,
+ GST_ROUND_UP_2 (buffer->height) / 2,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ (guint8 *) data +
+ gst_video_format_get_component_offset (format, comp, width, height));
+
+ glGenTextures (1, &buffer->texture_v);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture_v);
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE,
+ GST_ROUND_UP_2 (buffer->width) / 2,
+ GST_ROUND_UP_2 (buffer->height) / 2,
+ 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
+ comp = (format == GST_VIDEO_FORMAT_I420) ? 2 : 1;
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0,
+ GST_ROUND_UP_2 (buffer->width) / 2,
+ GST_ROUND_UP_2 (buffer->height) / 2,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ (guint8 *) data +
+ gst_video_format_get_component_offset (format, comp, width, height));
break;
default:
g_assert_not_reached ();
}
gst_gl_display_unlock (buffer->display);
+
+ return buffer;
}
void
gst_gl_buffer_download (GstGLBuffer * buffer, void *data)
{
- gst_gl_display_lock (buffer->display);
+ GLuint fbo;
GST_DEBUG ("downloading");
- switch (buffer->type) {
- case GST_GL_BUFFER_XIMAGE:
- {
- XImage *image;
-
- image = XGetImage (buffer->display->display, buffer->pixmap,
- 0, 0, buffer->width, buffer->height, 0xffffffff, ZPixmap);
-
- memcpy (data, image->data, buffer->width * buffer->height * 4);
-
- XDestroyImage (image);
- break;
- }
- case GST_GL_BUFFER_RBO:
- {
- unsigned int fbo;
-
- glGenFramebuffersEXT (1, &fbo);
- glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo);
-
- glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT,
- GL_COLOR_ATTACHMENT1_EXT, GL_RENDERBUFFER_EXT, buffer->rbo);
-
- glDrawBuffer (GL_COLOR_ATTACHMENT1_EXT);
- glReadBuffer (GL_COLOR_ATTACHMENT1_EXT);
-
- g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) ==
- GL_FRAMEBUFFER_COMPLETE_EXT);
-
- glReadPixels (0, 0, buffer->width, buffer->height / 2, GL_RGBA,
- GL_UNSIGNED_BYTE, data);
-
- glDeleteFramebuffersEXT (1, &fbo);
+ gst_gl_display_lock (buffer->display);
- break;
- }
- case GST_GL_BUFFER_TEXTURE:
- {
- unsigned int fbo;
+ glGenFramebuffersEXT (1, &fbo);
+ glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo);
- glGenFramebuffersEXT (1, &fbo);
- glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo);
+ glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
+ GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, buffer->texture, 0);
- glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
- GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB,
- buffer->texture, 0);
+ glDrawBuffer (GL_COLOR_ATTACHMENT1_EXT);
+ glReadBuffer (GL_COLOR_ATTACHMENT1_EXT);
- glDrawBuffer (GL_COLOR_ATTACHMENT1_EXT);
- glReadBuffer (GL_COLOR_ATTACHMENT1_EXT);
+ g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) ==
+ GL_FRAMEBUFFER_COMPLETE_EXT);
- g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) ==
- GL_FRAMEBUFFER_COMPLETE_EXT);
+ /* needs a reset function */
+ glMatrixMode (GL_COLOR);
+ glLoadIdentity ();
+ glPixelTransferf (GL_POST_COLOR_MATRIX_RED_BIAS, 0);
+ glPixelTransferf (GL_POST_COLOR_MATRIX_GREEN_BIAS, 0);
+ glPixelTransferf (GL_POST_COLOR_MATRIX_BLUE_BIAS, 0);
- glReadPixels (0, 0, buffer->width, buffer->height, GL_RGBA,
- GL_UNSIGNED_BYTE, data);
+ glReadPixels (0, 0, buffer->width, buffer->height, GL_RGBA,
+ GL_UNSIGNED_BYTE, data);
- glDeleteFramebuffersEXT (1, &fbo);
- }
- break;
- default:
- g_assert_not_reached ();
- }
+ glDeleteFramebuffersEXT (1, &fbo);
gst_gl_display_unlock (buffer->display);
}
diff --git a/sys/glsink/gstglbuffer.h b/sys/glsink/gstglbuffer.h
index e24b70f0..1d29aebf 100644
--- a/sys/glsink/gstglbuffer.h
+++ b/sys/glsink/gstglbuffer.h
@@ -14,24 +14,25 @@ typedef struct _GstGLBuffer GstGLBuffer;
#define GST_GL_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_GL_BUFFER, GstGLBuffer))
typedef enum {
- GST_GL_BUFFER_UNKNOWN,
- GST_GL_BUFFER_XIMAGE,
- GST_GL_BUFFER_RBO,
- GST_GL_BUFFER_TEXTURE
-} GstGLBufferType;
+ GST_GL_BUFFER_FORMAT_RGBA,
+ GST_GL_BUFFER_FORMAT_RGB,
+ GST_GL_BUFFER_FORMAT_YUYV,
+ GST_GL_BUFFER_FORMAT_PLANAR444,
+ GST_GL_BUFFER_FORMAT_PLANAR422,
+ GST_GL_BUFFER_FORMAT_PLANAR420
+} GstGLBufferFormat;
struct _GstGLBuffer {
GstBuffer buffer;
GstGLDisplay *display;
- GstGLBufferType type;
+ GstGLBufferFormat format;
+ gboolean is_yuv;
- XID pixmap;
- GC gc;
-
- GLuint rbo;
GLuint texture;
+ GLuint texture_u;
+ GLuint texture_v;
int width;
int height;
@@ -39,9 +40,10 @@ struct _GstGLBuffer {
GType gst_gl_buffer_get_type (void);
-GstGLBuffer * gst_gl_buffer_new (GstGLDisplay *display, GstVideoFormat format,
- int width, int height);
-void gst_gl_buffer_upload (GstGLBuffer *buffer, void *data);
+GstGLBuffer * gst_gl_buffer_new (GstGLDisplay *display,
+ GstGLBufferFormat format, int width, int height);
+GstGLBuffer * gst_gl_buffer_new_from_data (GstGLDisplay *display,
+ GstVideoFormat format, int width, int height, void *data);
void gst_gl_buffer_download (GstGLBuffer *buffer, void *data);
#endif
diff --git a/sys/glsink/gstglconvert.c b/sys/glsink/gstglconvert.c
new file mode 100644
index 00000000..57daec5a
--- /dev/null
+++ b/sys/glsink/gstglconvert.c
@@ -0,0 +1,253 @@
+/*
+ * GStreamer
+ * Copyright (C) 2007 David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gstglbuffer.h>
+#include <gstglfilter.h>
+#include "glextensions.h"
+
+#define GST_CAT_DEFAULT gst_gl_convert_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+#define GST_TYPE_GL_CONVERT (gst_gl_convert_get_type())
+#define GST_GL_CONVERT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_CONVERT,GstGLConvert))
+#define GST_IS_GL_CONVERT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_CONVERT))
+#define GST_GL_CONVERT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_CONVERT,GstGLConvertClass))
+#define GST_IS_GL_CONVERT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_CONVERT))
+#define GST_GL_CONVERT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_CONVERT,GstGLConvertClass))
+typedef struct _GstGLConvert GstGLConvert;
+typedef struct _GstGLConvertClass GstGLConvertClass;
+
+struct _GstGLConvert
+{
+ GstGLFilter filter;
+
+ /* < private > */
+
+};
+
+struct _GstGLConvertClass
+{
+ GstGLFilterClass filter_class;
+};
+
+static const GstElementDetails element_details = GST_ELEMENT_DETAILS ("FIXME",
+ "Filter/Effect",
+ "FIXME GL conversion filter",
+ "FIXME <fixme@fixme.com>");
+
+#if 0
+#define GST_GL_VIDEO_CAPS "video/x-raw-gl"
+
+static GstStaticPadTemplate gst_gl_convert_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_GL_VIDEO_CAPS)
+ );
+
+static GstStaticPadTemplate gst_gl_convert_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_GL_VIDEO_CAPS)
+ );
+#endif
+
+enum
+{
+ PROP_0
+};
+
+#define DEBUG_INIT(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_gl_convert_debug, "glconvert", 0, "glconvert element");
+
+GST_BOILERPLATE_FULL (GstGLConvert, gst_gl_convert, GstGLFilter,
+ GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_convert_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_gl_convert_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void gst_gl_convert_reset (GstGLConvert * filter);
+static gboolean gst_gl_convert_transform (GstGLFilter * filter,
+ GstGLBuffer * outbuf, GstGLBuffer * inbuf);
+static gboolean gst_gl_convert_start (GstGLFilter * _filter);
+static gboolean gst_gl_convert_stop (GstGLFilter * _filter);
+
+
+static void
+gst_gl_convert_base_init (gpointer klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_set_details (element_class, &element_details);
+
+#if 0
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_gl_convert_src_pad_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_gl_convert_sink_pad_template));
+#endif
+}
+
+static void
+gst_gl_convert_class_init (GstGLConvertClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gobject_class->set_property = gst_gl_convert_set_property;
+ gobject_class->get_property = gst_gl_convert_get_property;
+
+ GST_GL_FILTER_CLASS (klass)->transform = gst_gl_convert_transform;
+ GST_GL_FILTER_CLASS (klass)->start = gst_gl_convert_start;
+ GST_GL_FILTER_CLASS (klass)->stop = gst_gl_convert_stop;
+}
+
+static void
+gst_gl_convert_init (GstGLConvert * filter, GstGLConvertClass * klass)
+{
+ gst_gl_convert_reset (filter);
+}
+
+static void
+gst_gl_convert_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ //GstGLConvert *filter = GST_GL_CONVERT (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_gl_convert_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ //GstGLConvert *filter = GST_GL_CONVERT (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_gl_convert_reset (GstGLConvert * filter)
+{
+
+}
+
+static gboolean
+gst_gl_convert_start (GstGLFilter * _filter)
+{
+ //GstGLConvert *convert = GST_GL_CONVERT(_filter);
+
+ return TRUE;
+}
+
+static gboolean
+gst_gl_convert_stop (GstGLFilter * _filter)
+{
+ GstGLConvert *convert = GST_GL_CONVERT (_filter);
+
+ gst_gl_convert_reset (convert);
+
+ return TRUE;
+}
+
+static gboolean
+gst_gl_convert_transform (GstGLFilter * filter, GstGLBuffer * outbuf,
+ GstGLBuffer * inbuf)
+{
+ //GstGLConvert *convert = GST_GL_CONVERT(filter);
+
+ glDisable (GL_CULL_FACE);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ if (inbuf->is_yuv) {
+#ifdef GL_POST_COLOR_MATRIX_RED_BIAS
+ const double matrix[16] = {
+ 1.16438, 1.6321, -0.00107909, 0,
+ 1.13839, -0.813005, -0.39126, 0,
+ 1.13839, 0.00112726, 2.01741, 0,
+ 0, 0, 0, 1
+ };
+
+ GST_DEBUG ("applying YUV->RGB conversion");
+
+ glMatrixMode (GL_COLOR);
+ glLoadMatrixd (matrix);
+
+ /* same */
+ glPixelTransferf (GL_POST_COLOR_MATRIX_RED_BIAS, -0.873494);
+ glPixelTransferf (GL_POST_COLOR_MATRIX_GREEN_BIAS, 0.531435);
+ glPixelTransferf (GL_POST_COLOR_MATRIX_BLUE_BIAS, -1.08629);
+#else
+ g_assert_not_reached ();
+#endif
+ }
+
+ glColor4f (1, 0, 1, 1);
+
+ glBegin (GL_QUADS);
+ glNormal3f (0, 0, -1);
+ glTexCoord2f (inbuf->width, 0);
+ glVertex3f (1.0, -1.0, 0);
+ glTexCoord2f (0, 0);
+ glVertex3f (-1.0, -1.0, 0);
+ glTexCoord2f (0, inbuf->height);
+ glVertex3f (-1.0, 1.0, 0);
+ glTexCoord2f (inbuf->width, inbuf->height);
+ glVertex3f (1.0, 1.0, 0);
+ glEnd ();
+
+ if (inbuf->is_yuv) {
+#ifdef GL_POST_COLOR_MATRIX_RED_BIAS
+ glMatrixMode (GL_COLOR);
+ glLoadIdentity ();
+
+ glPixelTransferf (GL_POST_COLOR_MATRIX_RED_BIAS, 0);
+ glPixelTransferf (GL_POST_COLOR_MATRIX_GREEN_BIAS, 0);
+ glPixelTransferf (GL_POST_COLOR_MATRIX_BLUE_BIAS, 0);
+#else
+ g_assert_not_reached ();
+#endif
+ }
+
+ return TRUE;
+}
diff --git a/sys/glsink/gstgldisplay.c b/sys/glsink/gstgldisplay.c
index 4378c04d..6d93c889 100644
--- a/sys/glsink/gstgldisplay.c
+++ b/sys/glsink/gstgldisplay.c
@@ -430,8 +430,6 @@ draw_rect_texture (GstGLDisplay * display, GstVideoFormat type,
#ifdef GL_TEXTURE_RECTANGLE_ARB
glEnable (GL_TEXTURE_RECTANGLE_ARB);
- //glGenTextures (1, &texture);
- //glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture);
texture = gst_gl_display_upload_texture_rectangle (display, type,
data, width, height);
diff --git a/sys/glsink/gstglfilter.c b/sys/glsink/gstglfilter.c
index d5c3f60e..3efa396b 100644
--- a/sys/glsink/gstglfilter.c
+++ b/sys/glsink/gstglfilter.c
@@ -25,46 +25,12 @@
#include <gst/gst.h>
#include <gst/video/video.h>
#include <gstglbuffer.h>
+#include <gstglfilter.h>
#include "glextensions.h"
#define GST_CAT_DEFAULT gst_gl_filter_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
-#define GST_TYPE_GL_FILTER (gst_gl_filter_get_type())
-#define GST_GL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER,GstGLFilter))
-#define GST_IS_GL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER))
-#define GST_GL_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER,GstGLFilterClass))
-#define GST_IS_GL_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER))
-#define GST_GL_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER,GstGLFilterClass))
-typedef struct _GstGLFilter GstGLFilter;
-typedef struct _GstGLFilterClass GstGLFilterClass;
-
-typedef void (*GstGLFilterProcessFunc) (GstGLFilter *, guint8 *, guint);
-
-struct _GstGLFilter
-{
- GstElement element;
-
- GstPad *srcpad;
- GstPad *sinkpad;
-
- /* < private > */
-
- GstGLDisplay *display;
- GstVideoFormat format;
- int width;
- int height;
-};
-
-struct _GstGLFilterClass
-{
- GstElementClass element_class;
-};
-
-static const GstElementDetails element_details = GST_ELEMENT_DETAILS ("FIXME",
- "Filter/Effect",
- "FIXME example filter",
- "FIXME <fixme@fixme.com>");
#define GST_GL_VIDEO_CAPS "video/x-raw-gl"
@@ -82,11 +48,6 @@ GST_STATIC_PAD_TEMPLATE ("sink",
GST_STATIC_CAPS (GST_GL_VIDEO_CAPS)
);
-enum
-{
- PROP_0
-};
-
#define DEBUG_INIT(bla) \
GST_DEBUG_CATEGORY_INIT (gst_gl_filter_debug, "glfilter", 0, "glfilter element");
@@ -103,8 +64,8 @@ static void gst_gl_filter_reset (GstGLFilter * filter);
static GstStateChangeReturn
gst_gl_filter_change_state (GstElement * element, GstStateChange transition);
static gboolean gst_gl_filter_sink_setcaps (GstPad * pad, GstCaps * caps);
-static gboolean gst_gl_filter_transform (GstGLBuffer * outbuf,
- GstGLBuffer * inbuf);
+static gboolean gst_gl_filter_do_transform (GstGLFilter * filter,
+ GstGLBuffer * outbuf, GstGLBuffer * inbuf);
static void
@@ -112,8 +73,6 @@ gst_gl_filter_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
- gst_element_class_set_details (element_class, &element_details);
-
gst_element_class_add_pad_template (element_class,
gst_static_pad_template_get (&gst_gl_filter_src_pad_template));
gst_element_class_add_pad_template (element_class,
@@ -179,17 +138,26 @@ gst_gl_filter_reset (GstGLFilter * filter)
g_object_unref (filter->display);
filter->display = NULL;
}
- filter->format = GST_VIDEO_FORMAT_RGBx;
+ filter->format = GST_GL_BUFFER_FORMAT_RGB;
}
static gboolean
gst_gl_filter_start (GstGLFilter * filter)
{
+ GstGLFilterClass *filter_class;
gboolean ret;
- filter->format = GST_VIDEO_FORMAT_RGBx;
+ filter_class = GST_GL_FILTER_GET_CLASS (filter);
+
+ filter->format = GST_GL_BUFFER_FORMAT_RGB;
filter->display = gst_gl_display_new ();
ret = gst_gl_display_connect (filter->display, NULL);
+ if (!ret)
+ return FALSE;
+
+ if (filter_class->start) {
+ ret = filter_class->start (filter);
+ }
return ret;
}
@@ -197,8 +165,20 @@ gst_gl_filter_start (GstGLFilter * filter)
static gboolean
gst_gl_filter_stop (GstGLFilter * filter)
{
+ GstGLFilterClass *filter_class;
+ gboolean ret;
+
+ filter_class = GST_GL_FILTER_GET_CLASS (filter);
+
gst_gl_filter_reset (filter);
+ if (filter_class->stop) {
+ ret = filter_class->stop (filter);
+ }
+
+ g_object_unref (filter->display);
+ filter->display = NULL;
+
return TRUE;
}
@@ -218,7 +198,7 @@ gst_gl_filter_sink_setcaps (GstPad * pad, GstCaps * caps)
if (!ret)
return FALSE;
- GST_ERROR ("setcaps %d %d", filter->width, filter->height);
+ GST_DEBUG ("setcaps %d %d", filter->width, filter->height);
ret = gst_pad_set_caps (filter->srcpad, caps);
@@ -242,7 +222,7 @@ gst_gl_filter_chain (GstPad * pad, GstBuffer * buf)
GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS);
gst_buffer_set_caps (GST_BUFFER (outbuf), GST_PAD_CAPS (filter->srcpad));
- gst_gl_filter_transform (outbuf, inbuf);
+ gst_gl_filter_do_transform (filter, outbuf, inbuf);
gst_pad_push (filter->srcpad, GST_BUFFER (outbuf));
@@ -292,65 +272,21 @@ gst_gl_filter_change_state (GstElement * element, GstStateChange transition)
return ret;
}
-void
-dump_fbconfigs (Display * display)
-{
- GLXFBConfig *fbconfigs;
- int n;
- int i;
- int j;
- int ret;
- int value;
- struct
- {
- int attr;
- char *name;
- } list[] = {
- {
- GLX_DRAWABLE_TYPE, "drawable type"}, {
- GLX_BIND_TO_TEXTURE_TARGETS_EXT, "bind to texture targets"}, {
- GLX_BIND_TO_TEXTURE_RGBA_EXT, "bind to texture rgba"}, {
- GLX_MAX_PBUFFER_WIDTH, "max pbuffer width"}, {
- GLX_MAX_PBUFFER_HEIGHT, "max pbuffer height"}, {
- GLX_MAX_PBUFFER_PIXELS, "max pbuffer pixels"}, {
- GLX_RENDER_TYPE, "render type"}, {
- 0, 0}
- };
-
- g_print ("screen count: %d\n", ScreenCount (display));
-
- fbconfigs = glXGetFBConfigs (display, 0, &n);
- for (i = 0; i < n; i++) {
- g_print ("%d:\n", i);
- for (j = 0; list[j].attr; j++) {
- ret = glXGetFBConfigAttrib (display, fbconfigs[i], list[j].attr, &value);
- if (ret != Success) {
- g_print ("%s: failed\n", list[j].name);
- } else {
- g_print ("%s: %d\n", list[j].name, value);
- }
- }
- }
-
-}
-
static gboolean
-gst_gl_filter_transform (GstGLBuffer * outbuf, GstGLBuffer * inbuf)
+gst_gl_filter_do_transform (GstGLFilter * filter,
+ GstGLBuffer * outbuf, GstGLBuffer * inbuf)
{
GstGLDisplay *display = inbuf->display;
+ GstGLFilterClass *filter_class;
unsigned int fbo;
+ filter_class = GST_GL_FILTER_GET_CLASS (filter);
+
gst_gl_display_lock (display);
glGenFramebuffersEXT (1, &fbo);
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo);
- /* FIXME: This should be part of buffer creation */
- glGenTextures (1, &outbuf->texture);
- glBindTexture (GL_TEXTURE_RECTANGLE_ARB, outbuf->texture);
- glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
- outbuf->width, outbuf->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-
glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, outbuf->texture, 0);
@@ -379,6 +315,9 @@ gst_gl_filter_transform (GstGLBuffer * outbuf, GstGLBuffer * inbuf)
glEnable (GL_TEXTURE_RECTANGLE_ARB);
glBindTexture (GL_TEXTURE_RECTANGLE_ARB, inbuf->texture);
+ filter_class->transform (filter, outbuf, inbuf);
+
+#if 0
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
@@ -399,6 +338,7 @@ gst_gl_filter_transform (GstGLBuffer * outbuf, GstGLBuffer * inbuf)
glTexCoord2f (inbuf->width, inbuf->height);
glVertex3f (1.0, 1.0, 0);
glEnd ();
+#endif
glFlush ();
diff --git a/sys/glsink/gstglfilter.h b/sys/glsink/gstglfilter.h
new file mode 100644
index 00000000..01b915f5
--- /dev/null
+++ b/sys/glsink/gstglfilter.h
@@ -0,0 +1,68 @@
+/*
+ * GStreamer
+ * Copyright (C) 2007 David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _GST_GL_FILTER_H_
+#define _GST_GL_FILTER_H_
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gstglbuffer.h>
+
+#define GST_TYPE_GL_FILTER (gst_gl_filter_get_type())
+#define GST_GL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER,GstGLFilter))
+#define GST_IS_GL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER))
+#define GST_GL_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER,GstGLFilterClass))
+#define GST_IS_GL_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER))
+#define GST_GL_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER,GstGLFilterClass))
+typedef struct _GstGLFilter GstGLFilter;
+typedef struct _GstGLFilterClass GstGLFilterClass;
+
+typedef gboolean (*GstGLFilterProcessFunc) (GstGLFilter *filter,
+ GstGLBuffer *outbuf, GstGLBuffer *inbuf);
+typedef gboolean (*GstGLFilterStartFunc) (GstGLFilter *filter);
+typedef gboolean (*GstGLFilterStopFunc) (GstGLFilter *filter);
+
+struct _GstGLFilter
+{
+ GstElement element;
+
+ GstPad *srcpad;
+ GstPad *sinkpad;
+
+ /* < private > */
+
+ GstGLDisplay *display;
+ GstGLBufferFormat format;
+ int width;
+ int height;
+};
+
+struct _GstGLFilterClass
+{
+ GstElementClass element_class;
+ GstGLFilterProcessFunc transform;
+ GstGLFilterStartFunc start;
+ GstGLFilterStopFunc stop;
+};
+
+GType gst_gl_filter_get_type(void);
+
+#endif
+
diff --git a/sys/glsink/gstglfilterexample.c b/sys/glsink/gstglfilterexample.c
new file mode 100644
index 00000000..6a513b33
--- /dev/null
+++ b/sys/glsink/gstglfilterexample.c
@@ -0,0 +1,243 @@
+/*
+ * GStreamer
+ * Copyright (C) 2007 David Schleef <ds@schleef.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+#include <gstglbuffer.h>
+#include <gstglfilter.h>
+#include "glextensions.h"
+#include <string.h>
+
+#define GST_CAT_DEFAULT gst_gl_filter_example_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+#define GST_TYPE_GL_FILTER_EXAMPLE (gst_gl_filter_example_get_type())
+#define GST_GL_FILTER_EXAMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_EXAMPLE,GstGLFilterExample))
+#define GST_IS_GL_FILTER_EXAMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_EXAMPLE))
+#define GST_GL_FILTER_EXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_EXAMPLE,GstGLFilterExampleClass))
+#define GST_IS_GL_FILTER_EXAMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_EXAMPLE))
+#define GST_GL_FILTER_EXAMPLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_EXAMPLE,GstGLFilterExampleClass))
+typedef struct _GstGLFilterExample GstGLFilterExample;
+typedef struct _GstGLFilterExampleClass GstGLFilterExampleClass;
+
+struct _GstGLFilterExample
+{
+ GstGLFilter filter;
+
+ /* < private > */
+
+};
+
+struct _GstGLFilterExampleClass
+{
+ GstGLFilterClass filter_class;
+};
+
+static const GstElementDetails element_details = GST_ELEMENT_DETAILS ("FIXME",
+ "Filter/Effect",
+ "FIXME example filter",
+ "FIXME <fixme@fixme.com>");
+
+#if 0
+#define GST_GL_VIDEO_CAPS "video/x-raw-gl"
+
+static GstStaticPadTemplate gst_gl_filter_example_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_GL_VIDEO_CAPS)
+ );
+
+static GstStaticPadTemplate gst_gl_filter_example_sink_pad_template =
+GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_GL_VIDEO_CAPS)
+ );
+#endif
+
+enum
+{
+ PROP_0
+};
+
+#define DEBUG_INIT(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_gl_filter_example_debug, "glfilterexample", 0, "glfilterexample element");
+
+GST_BOILERPLATE_FULL (GstGLFilterExample, gst_gl_filter_example, GstGLFilter,
+ GST_TYPE_GL_FILTER, DEBUG_INIT);
+
+static void gst_gl_filter_example_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_gl_filter_example_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void gst_gl_filter_example_reset (GstGLFilterExample * filter);
+static gboolean gst_gl_filter_example_transform (GstGLFilter * filter,
+ GstGLBuffer * outbuf, GstGLBuffer * inbuf);
+static gboolean gst_gl_filter_example_start (GstGLFilter * filter);
+static gboolean gst_gl_filter_example_stop (GstGLFilter * filter);
+
+
+static void
+gst_gl_filter_example_base_init (gpointer klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ gst_element_class_set_details (element_class, &element_details);
+
+#if 0
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_gl_filter_example_src_pad_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_gl_filter_example_sink_pad_template));
+#endif
+}
+
+static void
+gst_gl_filter_example_class_init (GstGLFilterExampleClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gobject_class->set_property = gst_gl_filter_example_set_property;
+ gobject_class->get_property = gst_gl_filter_example_get_property;
+
+ GST_GL_FILTER_CLASS (klass)->transform = gst_gl_filter_example_transform;
+ GST_GL_FILTER_CLASS (klass)->start = gst_gl_filter_example_start;
+ GST_GL_FILTER_CLASS (klass)->stop = gst_gl_filter_example_stop;
+}
+
+static void
+gst_gl_filter_example_init (GstGLFilterExample * filter,
+ GstGLFilterExampleClass * klass)
+{
+ gst_gl_filter_example_reset (filter);
+}
+
+static void
+gst_gl_filter_example_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ //GstGLFilterExample *filter = GST_GL_FILTER_EXAMPLE (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_gl_filter_example_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ //GstGLFilterExample *filter = GST_GL_FILTER_EXAMPLE (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_gl_filter_example_reset (GstGLFilterExample * filter)
+{
+
+}
+
+static gboolean
+gst_gl_filter_example_start (GstGLFilter * _filter)
+{
+ //GstGLFilterExample *filter = GST_GL_FILTER_EXAMPLE(_filter);
+
+ return TRUE;
+}
+
+static gboolean
+gst_gl_filter_example_stop (GstGLFilter * _filter)
+{
+ GstGLFilterExample *filter = GST_GL_FILTER_EXAMPLE (_filter);
+
+ gst_gl_filter_example_reset (filter);
+ return TRUE;
+}
+
+static gboolean
+gst_gl_filter_example_transform (GstGLFilter * filter, GstGLBuffer * outbuf,
+ GstGLBuffer * inbuf)
+{
+ //GstGLFilterExample *example = GST_GL_FILTER_EXAMPLE(filter);
+
+ glDisable (GL_CULL_FACE);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+
+ glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ glColor4f (1, 0, 1, 1);
+
+#define GAIN 0.5
+ {
+ const double matrix[16] = {
+ 0, 0, 1.0, 0,
+ 0, 1.0, 0, 0,
+ 1.0, 0, 0, 0,
+ 0, 0, 0, 1
+ };
+
+ glMatrixMode (GL_COLOR);
+ glLoadMatrixd (matrix);
+ glPixelTransferf (GL_POST_COLOR_MATRIX_RED_BIAS, (1 - GAIN) / 2);
+ glPixelTransferf (GL_POST_COLOR_MATRIX_GREEN_BIAS, (1 - GAIN) / 2);
+ glPixelTransferf (GL_POST_COLOR_MATRIX_BLUE_BIAS, (1 - GAIN) / 2);
+ }
+
+ glBegin (GL_QUADS);
+ glNormal3f (0, 0, -1);
+ glTexCoord2f (inbuf->width, 0);
+ glVertex3f (0.9, -0.9, 0);
+ glTexCoord2f (0, 0);
+ glVertex3f (-1.0, -1.0, 0);
+ glTexCoord2f (0, inbuf->height);
+ glVertex3f (-1.0, 1.0, 0);
+ glTexCoord2f (inbuf->width, inbuf->height);
+ glVertex3f (1.0, 1.0, 0);
+ glEnd ();
+
+ glFlush ();
+
+ glMatrixMode (GL_COLOR);
+ glLoadIdentity ();
+ glPixelTransferf (GL_POST_COLOR_MATRIX_RED_SCALE, 1.0);
+ glPixelTransferf (GL_POST_COLOR_MATRIX_RED_BIAS, 0);
+ glPixelTransferf (GL_POST_COLOR_MATRIX_GREEN_BIAS, 0);
+ glPixelTransferf (GL_POST_COLOR_MATRIX_BLUE_BIAS, 0);
+
+ return TRUE;
+}
diff --git a/sys/glsink/gstgltestsrc.c b/sys/glsink/gstgltestsrc.c
index 66d32f60..a5e544a6 100644
--- a/sys/glsink/gstgltestsrc.c
+++ b/sys/glsink/gstgltestsrc.c
@@ -522,19 +522,13 @@ gst_gl_test_src_create (GstPushSrc * psrc, GstBuffer ** buffer)
GST_LOG_OBJECT (src, "creating buffer %dx%d image for frame %d",
src->width, src->height, (gint) src->n_frames);
- outbuf = gst_gl_buffer_new (src->display, GST_VIDEO_FORMAT_RGBx,
+ outbuf = gst_gl_buffer_new (src->display, GST_GL_BUFFER_FORMAT_RGB,
src->width, src->height);
gst_buffer_set_caps (GST_BUFFER (outbuf),
GST_PAD_CAPS (GST_BASE_SRC_PAD (psrc)));
gst_gl_display_lock (outbuf->display);
- /* FIXME: This should be part of buffer creation */
- glGenTextures (1, &outbuf->texture);
- glBindTexture (GL_TEXTURE_RECTANGLE_ARB, outbuf->texture);
- glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
- outbuf->width, outbuf->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-
glGenFramebuffersEXT (1, &fbo);
glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo);
diff --git a/sys/glsink/gstglupload.c b/sys/glsink/gstglupload.c
index 90f7dc2e..3b5cbc5f 100644
--- a/sys/glsink/gstglupload.c
+++ b/sys/glsink/gstglupload.c
@@ -50,7 +50,8 @@ struct _GstGLUpload
/* < private > */
GstGLDisplay *display;
- GstVideoFormat format;
+ GstVideoFormat video_format;
+ GstGLBufferFormat format;
int width;
int height;
@@ -77,10 +78,14 @@ GST_STATIC_PAD_TEMPLATE ("src",
);
static GstStaticPadTemplate gst_gl_upload_sink_pad_template =
-GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBx)
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBx ";"
+ GST_VIDEO_CAPS_BGRx ";"
+ GST_VIDEO_CAPS_xRGB ";"
+ GST_VIDEO_CAPS_xBGR ";"
+ GST_VIDEO_CAPS_YUV ("{ YUY2, UYVY, AYUV, YV12, I420 }"))
);
enum
@@ -178,7 +183,7 @@ gst_gl_upload_reset (GstGLUpload * upload)
g_object_unref (upload->display);
upload->display = NULL;
}
- upload->format = GST_VIDEO_FORMAT_RGBx;
+ upload->format = GST_GL_BUFFER_FORMAT_RGB;
upload->peek = FALSE;
}
@@ -187,7 +192,7 @@ gst_gl_upload_start (GstGLUpload * upload)
{
gboolean ret;
- upload->format = GST_VIDEO_FORMAT_RGBx;
+ upload->format = GST_GL_BUFFER_FORMAT_RGB;
upload->display = gst_gl_display_new ();
ret = gst_gl_display_connect (upload->display, NULL);
@@ -206,7 +211,7 @@ static gboolean
gst_gl_upload_sink_setcaps (GstPad * pad, GstCaps * caps)
{
GstGLUpload *upload;
- GstVideoFormat format;
+ GstVideoFormat video_format;
int height;
int width;
gboolean ret;
@@ -214,15 +219,15 @@ gst_gl_upload_sink_setcaps (GstPad * pad, GstCaps * caps)
upload = GST_GL_UPLOAD (gst_pad_get_parent (pad));
- ret = gst_video_format_parse_caps (caps, &format, &width, &height);
+ ret = gst_video_format_parse_caps (caps, &video_format, &width, &height);
if (!ret)
return FALSE;
- upload->format = format;
+ upload->video_format = video_format;
upload->width = width;
upload->height = height;
- GST_ERROR ("setcaps %d %d %d", format, width, height);
+ GST_DEBUG ("setcaps %d %d %d", video_format, width, height);
srccaps = gst_caps_new_simple ("video/x-raw-gl",
"width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
@@ -240,8 +245,9 @@ gst_gl_upload_chain (GstPad * pad, GstBuffer * buf)
upload = GST_GL_UPLOAD (gst_pad_get_parent (pad));
- outbuf = gst_gl_buffer_new (upload->display, upload->format,
- upload->width, upload->height);
+ outbuf = gst_gl_buffer_new_from_data (upload->display,
+ upload->video_format, upload->width, upload->height,
+ GST_BUFFER_DATA (buf));
gst_buffer_copy_metadata (GST_BUFFER (outbuf), buf,
GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS);
@@ -249,7 +255,6 @@ gst_gl_upload_chain (GstPad * pad, GstBuffer * buf)
GST_DEBUG ("uploading %p size %d", GST_BUFFER_DATA (buf),
GST_BUFFER_SIZE (buf));
- gst_gl_buffer_upload (outbuf, GST_BUFFER_DATA (buf));
gst_buffer_unref (buf);
if (upload->peek) {
diff --git a/sys/glsink/gstopengl.c b/sys/glsink/gstopengl.c
index d44ed9f2..7acbe1fd 100644
--- a/sys/glsink/gstopengl.c
+++ b/sys/glsink/gstopengl.c
@@ -34,7 +34,8 @@
GType gst_gl_upload_get_type (void);
GType gst_gl_download_get_type (void);
-GType gst_gl_filter_get_type (void);
+GType gst_gl_filter_example_get_type (void);
+GType gst_gl_convert_get_type (void);
GType gst_gl_test_src_get_type (void);
@@ -56,8 +57,12 @@ plugin_init (GstPlugin * plugin)
GST_RANK_NONE, gst_gl_download_get_type ())) {
return FALSE;
}
- if (!gst_element_register (plugin, "glfilter",
- GST_RANK_NONE, gst_gl_filter_get_type ())) {
+ if (!gst_element_register (plugin, "glfilterexample",
+ GST_RANK_NONE, gst_gl_filter_example_get_type ())) {
+ return FALSE;
+ }
+ if (!gst_element_register (plugin, "glconvert",
+ GST_RANK_NONE, gst_gl_convert_get_type ())) {
return FALSE;
}
if (!gst_element_register (plugin, "gltestsrc",