diff --git a/gst-libs/gst/gl/gstglbuffer.c b/gst-libs/gst/gl/gstglbuffer.c index 048ad9937d..e3e9df6ba3 100644 --- a/gst-libs/gst/gl/gstglbuffer.c +++ b/gst-libs/gst/gl/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); + 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_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); - 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; + GstGLBuffer *buffer; + int comp; - GST_DEBUG ("uploading %p %dx%d", data, buffer->width, buffer->height); + g_return_val_if_fail (width > 0, NULL); + g_return_val_if_fail (height > 0, NULL); + g_return_val_if_fail (data != NULL, NULL); + + GST_DEBUG ("uploading %p %dx%d", data, width, height); + + buffer = (GstGLBuffer *) gst_mini_object_new (GST_TYPE_GL_BUFFER); + buffer->display = g_object_ref (display); + buffer->width = width; + buffer->height = height; gst_gl_display_lock (buffer->display); + glGenTextures (1, &buffer->texture); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, buffer->texture); - switch (buffer->type) { - case GST_GL_BUFFER_XIMAGE: - { - XImage *image; - Visual *visual; - int depth; - int bpp; - - visual = DefaultVisual (display, 0); - depth = 32; - bpp = 32; - - image = XCreateImage (display, visual, depth, ZPixmap, 0, NULL, - buffer->width, buffer->height, bpp, 0); - GST_DEBUG ("image %p", image); - image->data = data; - - XPutImage (display, buffer->pixmap, buffer->gc, - image, 0, 0, 0, 0, buffer->width, buffer->height); - - XDestroyImage (image); + 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_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_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_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; + gst_gl_display_lock (buffer->display); - image = XGetImage (buffer->display->display, buffer->pixmap, - 0, 0, buffer->width, buffer->height, 0xffffffff, ZPixmap); + glGenFramebuffersEXT (1, &fbo); + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo); - memcpy (data, image->data, buffer->width * buffer->height * 4); + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, buffer->texture, 0); - XDestroyImage (image); - break; - } - case GST_GL_BUFFER_RBO: - { - unsigned int fbo; + glDrawBuffer (GL_COLOR_ATTACHMENT1_EXT); + glReadBuffer (GL_COLOR_ATTACHMENT1_EXT); - glGenFramebuffersEXT (1, &fbo); - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo); + g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) == + GL_FRAMEBUFFER_COMPLETE_EXT); - glFramebufferRenderbufferEXT (GL_FRAMEBUFFER_EXT, - GL_COLOR_ATTACHMENT1_EXT, GL_RENDERBUFFER_EXT, buffer->rbo); + /* 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); - glDrawBuffer (GL_COLOR_ATTACHMENT1_EXT); - glReadBuffer (GL_COLOR_ATTACHMENT1_EXT); + glReadPixels (0, 0, buffer->width, buffer->height, GL_RGBA, + GL_UNSIGNED_BYTE, data); - 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); - - break; - } - case GST_GL_BUFFER_TEXTURE: - { - unsigned int fbo; - - glGenFramebuffersEXT (1, &fbo); - glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo); - - 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); - - g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) == - GL_FRAMEBUFFER_COMPLETE_EXT); - - 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/gst-libs/gst/gl/gstglbuffer.h b/gst-libs/gst/gl/gstglbuffer.h index e24b70f072..1d29aebf36 100644 --- a/gst-libs/gst/gl/gstglbuffer.h +++ b/gst-libs/gst/gl/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/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c index 4378c04dea..6d93c8896e 100644 --- a/gst-libs/gst/gl/gstgldisplay.c +++ b/gst-libs/gst/gl/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/gst/gl/BUGS b/gst/gl/BUGS new file mode 100644 index 0000000000..795d3525f0 --- /dev/null +++ b/gst/gl/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/gst/gl/Makefile.am b/gst/gl/Makefile.am index b4f72c9272..6cb9dd10b6 100644 --- a/gst/gl/Makefile.am +++ b/gst/gl/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/gst/gl/color_matrix.c b/gst/gl/color_matrix.c new file mode 100644 index 0000000000..255184f759 --- /dev/null +++ b/gst/gl/color_matrix.c @@ -0,0 +1,243 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include + +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/gst/gl/gstglconvert.c b/gst/gl/gstglconvert.c new file mode 100644 index 0000000000..57daec5a5b --- /dev/null +++ b/gst/gl/gstglconvert.c @@ -0,0 +1,253 @@ +/* + * GStreamer + * Copyright (C) 2007 David Schleef + * + * 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 +#include +#include +#include +#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 "); + +#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/gst/gl/gstglfilter.c b/gst/gl/gstglfilter.c index d5c3f60e5b..3efa396b7f 100644 --- a/gst/gl/gstglfilter.c +++ b/gst/gl/gstglfilter.c @@ -25,46 +25,12 @@ #include #include #include +#include #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 "); #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/gst/gl/gstglfilter.h b/gst/gl/gstglfilter.h new file mode 100644 index 0000000000..01b915f544 --- /dev/null +++ b/gst/gl/gstglfilter.h @@ -0,0 +1,68 @@ +/* + * GStreamer + * Copyright (C) 2007 David Schleef + * + * 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 +#include +#include + +#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/gst/gl/gstglfilterexample.c b/gst/gl/gstglfilterexample.c new file mode 100644 index 0000000000..6a513b33d6 --- /dev/null +++ b/gst/gl/gstglfilterexample.c @@ -0,0 +1,243 @@ +/* + * GStreamer + * Copyright (C) 2007 David Schleef + * + * 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 +#include +#include +#include +#include "glextensions.h" +#include + +#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 "); + +#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/gst/gl/gstgltestsrc.c b/gst/gl/gstgltestsrc.c index 66d32f6081..a5e544a6c6 100644 --- a/gst/gl/gstgltestsrc.c +++ b/gst/gl/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/gst/gl/gstglupload.c b/gst/gl/gstglupload.c index 90f7dc2e98..3b5cbc5fa5 100644 --- a/gst/gl/gstglupload.c +++ b/gst/gl/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/gst/gl/gstopengl.c b/gst/gl/gstopengl.c index d44ed9f20b..7acbe1fdc7 100644 --- a/gst/gl/gstopengl.c +++ b/gst/gl/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",