From bb4e1d10e99c206fdf0ca22a43ef20efa24236ef Mon Sep 17 00:00:00 2001 From: David Schleef Date: Fri, 21 Dec 2007 00:03:11 +0000 Subject: sys/glsink/: Switch to using framebuffer_objects instead of GLXPixmaps, because that's what my driver supports. Remo... Original commit message from CVS: * sys/glsink/Makefile.am: * sys/glsink/glextensions.c: * sys/glsink/glextensions.h: * sys/glsink/glimagesink.c: * sys/glsink/glimagesink.h: * sys/glsink/glvideo.c: * sys/glsink/glvideo.h: * sys/glsink/gstglbuffer.c: * sys/glsink/gstglbuffer.h: * sys/glsink/gstgldownload.c: * sys/glsink/gstglfilter.c: * sys/glsink/gstglupload.c: * sys/glsink/gstopengl.c: Switch to using framebuffer_objects instead of GLXPixmaps, because that's what my driver supports. Remove GLDrawable, since GstGLDisplay now has a default drawable and context. --- ChangeLog | 19 +++ sys/glsink/Makefile.am | 4 +- sys/glsink/glextensions.c | 57 +++++++ sys/glsink/glextensions.h | 24 +++ sys/glsink/glimagesink.c | 29 +--- sys/glsink/glimagesink.h | 1 - sys/glsink/glvideo.c | 285 ++++++++++++++++--------------- sys/glsink/glvideo.h | 62 ++++--- sys/glsink/gstglbuffer.c | 239 ++++++++++++++++++++++++++ sys/glsink/gstglbuffer.h | 47 +++++ sys/glsink/gstgldownload.c | 294 ++++++++++++++++++++++++++++++++ sys/glsink/gstglfilter.c | 416 +++++++++++++++++++++++++++++++++++++++++++++ sys/glsink/gstglupload.c | 112 +++++++++++- sys/glsink/gstopengl.c | 12 +- 14 files changed, 1413 insertions(+), 188 deletions(-) create mode 100644 sys/glsink/gstglbuffer.c create mode 100644 sys/glsink/gstglbuffer.h create mode 100644 sys/glsink/gstgldownload.c create mode 100644 sys/glsink/gstglfilter.c diff --git a/ChangeLog b/ChangeLog index 4d2dd09f..fa3d45ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2007-12-20 David Schleef + + * sys/glsink/Makefile.am: + * sys/glsink/glextensions.c: + * sys/glsink/glextensions.h: + * sys/glsink/glimagesink.c: + * sys/glsink/glimagesink.h: + * sys/glsink/glvideo.c: + * sys/glsink/glvideo.h: + * sys/glsink/gstglbuffer.c: + * sys/glsink/gstglbuffer.h: + * sys/glsink/gstgldownload.c: + * sys/glsink/gstglfilter.c: + * sys/glsink/gstglupload.c: + * sys/glsink/gstopengl.c: + Switch to using framebuffer_objects instead of GLXPixmaps, + because that's what my driver supports. Remove GLDrawable, + since GstGLDisplay now has a default drawable and context. + 2007-12-20 Tim-Philipp Müller * gst/equalizer/.cvsignore: diff --git a/sys/glsink/Makefile.am b/sys/glsink/Makefile.am index 43e60378..49d8ac4f 100644 --- a/sys/glsink/Makefile.am +++ b/sys/glsink/Makefile.am @@ -7,7 +7,9 @@ libgstglimagesink_la_SOURCES = \ gstopengl.c \ glextensions.c \ gstglbuffer.c \ - gstglupload.c + gstglupload.c \ + gstgldownload.c \ + gstglfilter.c libgstglimagesink_la_CFLAGS = $(GST_CFLAGS) $(X_CFLAGS) $(GST_BASE_CFLAGS) \ $(GST_PLUGINS_BASE_CFLAGS) libgstglimagesink_la_LIBADD = $(X_LIBS) $(XSHM_LIBS) -lGL \ diff --git a/sys/glsink/glextensions.c b/sys/glsink/glextensions.c index 31b862e3..6c48e8b2 100644 --- a/sys/glsink/glextensions.c +++ b/sys/glsink/glextensions.c @@ -122,3 +122,60 @@ DEFINE_FUNC_RET (glXWaitForSbcOML, Bool, DEFINE_FUNC_RET (glXSwapIntervalSGI, int, (int interval), (interval)); DEFINE_FUNC_RET (glXSwapIntervalMESA, int, (unsigned int interval), (interval)); + +#if 0 +DEFINE_FUNC (glBindFramebufferEXT, (int target, uint framebuffer), + (target, framebuffer)); + +DEFINE_FUNC (glDeleteRenderbuffersEXT, (int n, unsigned int *renderbuffers), + (n, renderbuffers)); +DEFINE_FUNC (glGenRenderbuffersEXT, (int n, unsigned int *renderbuffers), + (n, renderbuffers)); +DEFINE_FUNC (glRenderbufferStorageEXT, (int target, int internalformat, + int width, int height), (target, internalformat, width, height)); +DEFINE_FUNC (glBindRenderbufferEXT, (int target, unsigned int renderbuffer), + (target, renderbuffer)); +DEFINE_FUNC (glFramebufferRenderbufferEXT, + (int target, int attachment, int renderbuffertarget, + unsigned int renderbuffer), (target, attachment, renderbuffertarget, + renderbuffer)); +#endif + +/* EXT_framebuffer_object */ +DEFINE_FUNC_RET (glIsRenderbufferEXT, Bool, + (GLuint renderbuffer), (renderbuffer)); +DEFINE_FUNC (glBindRenderbufferEXT, + (GLenum target, GLuint renderbuffer), (target, renderbuffer)); +DEFINE_FUNC (glDeleteRenderbuffersEXT, + (GLsizei n, GLuint * renderbuffers), (n, renderbuffers)); +DEFINE_FUNC (glGenRenderbuffersEXT, + (GLsizei n, GLuint * renderbuffers), (n, renderbuffers)); +DEFINE_FUNC (glRenderbufferStorageEXT, + (GLenum target, GLenum internalformat, GLsizei width, GLsizei height), + (target, internalformat, width, height)); +DEFINE_FUNC (glGetRenderbufferParameterivEXT, + (GLenum target, GLenum pname, GLint * params), (target, pname, params)); +DEFINE_FUNC_RET (glIsFramebufferEXT, Bool, (GLuint framebuffer), (framebuffer)); +DEFINE_FUNC (glBindFramebufferEXT, + (GLenum target, GLuint framebuffer), (target, framebuffer)); +DEFINE_FUNC (glDeleteFramebuffersEXT, + (GLsizei n, GLuint * framebuffers), (n, framebuffers)); +DEFINE_FUNC (glGenFramebuffersEXT, + (GLsizei n, GLuint * framebuffers), (n, framebuffers)); +DEFINE_FUNC_RET (glCheckFramebufferStatusEXT, GLenum, + (GLenum target), (target)); +DEFINE_FUNC (glFramebufferTexture1DEXT, + (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, + GLint level), (target, attachment, textarget, texture, level)); +DEFINE_FUNC (glFramebufferTexture2DEXT, (GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level), (target, attachment, + textarget, texture, level)); +DEFINE_FUNC (glFramebufferTexture3DEXT, (GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level, GLint zoffset), (target, + attachment, textarget, texture, level, zoffset)); +DEFINE_FUNC (glFramebufferRenderbufferEXT, (GLenum target, GLenum attachment, + GLenum renderbuffertarget, GLuint renderbuffer), (target, attachment, + renderbuffertarget, renderbuffer)); +DEFINE_FUNC (glGetFramebufferAttachmentParameterivEXT, (GLenum target, + GLenum pname, GLint * params), (target, pname, params)); +DEFINE_FUNC (glGenerateMipmapEXT, (GLenum target), (target)); diff --git a/sys/glsink/glextensions.h b/sys/glsink/glextensions.h index fd3f8ea7..48161c49 100644 --- a/sys/glsink/glextensions.h +++ b/sys/glsink/glextensions.h @@ -29,6 +29,30 @@ Bool glXWaitForSbcOML (Display *, GLXDrawable, int64_t, int64_t *, int64_t *, in int glXSwapIntervalSGI (int); int glXSwapIntervalMESA (unsigned int); +/* EXT_framebuffer_object */ +Bool glIsRenderbufferEXT (GLuint renderbuffer); +void glBindRenderbufferEXT (GLenum target, GLuint renderbuffer); +void glDeleteRenderbuffersEXT (GLsizei n, GLuint *renderbuffers); +void glGenRenderbuffersEXT (GLsizei n, GLuint *renderbuffers); +void glRenderbufferStorageEXT (GLenum target, GLenum internalformat, + GLsizei width, GLsizei height); +void glGetRenderbufferParameterivEXT (GLenum target, GLenum pname, GLint *params); +Bool glIsFramebufferEXT (GLuint framebuffer); +void glBindFramebufferEXT (GLenum target, GLuint framebuffer); +void glDeleteFramebuffersEXT (GLsizei n, GLuint *framebuffers); +void glGenFramebuffersEXT (GLsizei n, GLuint *framebuffers); +GLenum glCheckFramebufferStatusEXT (GLenum target); +void glFramebufferTexture1DEXT (GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level); +void glFramebufferTexture2DEXT (GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level); +void glFramebufferTexture3DEXT (GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level, GLint zoffset); +void glFramebufferRenderbufferEXT (GLenum target, GLenum attachment, + GLenum renderbuffertarget, GLuint renderbuffer); +void glGetFramebufferAttachmentParameterivEXT (GLenum target, GLenum pname, + GLint *params); +void glGenerateMipmapEXT (GLenum target); #endif diff --git a/sys/glsink/glimagesink.c b/sys/glsink/glimagesink.c index 8df11e00..560a523f 100644 --- a/sys/glsink/glimagesink.c +++ b/sys/glsink/glimagesink.c @@ -282,27 +282,22 @@ static gboolean gst_glimage_sink_start (GstBaseSink * bsink) { GstGLImageSink *glimage_sink; + gboolean ret; GST_DEBUG ("start"); glimage_sink = GST_GLIMAGE_SINK (bsink); - glimage_sink->display = gst_gl_display_new (glimage_sink->display_name); - if (glimage_sink->display == NULL) { + glimage_sink->display = gst_gl_display_new (); + ret = gst_gl_display_connect (glimage_sink->display, + glimage_sink->display_name); + if (!ret) { GST_ERROR ("failed to open display"); return FALSE; } if (glimage_sink->window_id) { - glimage_sink->drawable = - gst_gl_drawable_new_from_window (glimage_sink->display, - glimage_sink->window_id); - } else { - glimage_sink->drawable = gst_gl_drawable_new_window (glimage_sink->display); - } - if (glimage_sink->drawable == NULL) { - GST_ERROR ("failed to create window"); - return FALSE; + gst_gl_display_set_window (glimage_sink->display, glimage_sink->window_id); } GST_DEBUG ("start done"); @@ -319,11 +314,9 @@ gst_glimage_sink_stop (GstBaseSink * bsink) glimage_sink = GST_GLIMAGE_SINK (bsink); - gst_gl_drawable_free (glimage_sink->drawable); - gst_gl_display_free (glimage_sink->display); + g_object_unref (glimage_sink->display); glimage_sink->display = NULL; - glimage_sink->drawable = NULL; return TRUE; } @@ -461,7 +454,7 @@ gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf) glimage_sink = GST_GLIMAGE_SINK (bsink); - gst_gl_drawable_draw_image (glimage_sink->drawable, + gst_gl_display_draw_image (glimage_sink->display, glimage_sink->type, GST_BUFFER_DATA (buf), GST_VIDEO_SINK_WIDTH (glimage_sink), GST_VIDEO_SINK_HEIGHT (glimage_sink)); @@ -495,11 +488,7 @@ gst_glimage_sink_set_xwindow_id (GstXOverlay * overlay, XID window_id) return; } glimage_sink->window_id = window_id; - if (glimage_sink->drawable) { - gst_gl_drawable_free (glimage_sink->drawable); - glimage_sink->drawable = - gst_gl_drawable_new_from_window (glimage_sink->display, window_id); - } + gst_gl_display_set_window (glimage_sink->display, glimage_sink->window_id); } static void diff --git a/sys/glsink/glimagesink.h b/sys/glsink/glimagesink.h index 9d8294b1..7eee7f3b 100644 --- a/sys/glsink/glimagesink.h +++ b/sys/glsink/glimagesink.h @@ -58,7 +58,6 @@ struct _GstGLImageSink int par_n, par_d; GstGLDisplay *display; - GstGLDrawable *drawable; GstGLImageType type; XID window_id; diff --git a/sys/glsink/glvideo.c b/sys/glsink/glvideo.c index 5b4e222d..f7328153 100644 --- a/sys/glsink/glvideo.c +++ b/sys/glsink/glvideo.c @@ -27,33 +27,115 @@ #include +static void gst_gl_display_finalize (GObject * object); +static void gst_gl_display_init_tmp_window (GstGLDisplay * display); -static gboolean gst_gl_display_check_features (GstGLDisplay * display); +GST_BOILERPLATE (GstGLDisplay, gst_gl_display, GObject, G_TYPE_OBJECT); + +static void +gst_gl_display_base_init (gpointer g_class) +{ + +} + +static void +gst_gl_display_class_init (GstGLDisplayClass * klass) +{ + G_OBJECT_CLASS (klass)->finalize = gst_gl_display_finalize; +} + +static void +gst_gl_display_init (GstGLDisplay * display, GstGLDisplayClass * klass) +{ + + display->lock = g_mutex_new (); +} + +static void +gst_gl_display_finalize (GObject * object) +{ + GstGLDisplay *display = GST_GL_DISPLAY (object); + + if (display->assigned_window == None) { + XDestroyWindow (display->display, display->window); + } + if (display->context) { + glXDestroyContext (display->display, display->context); + } + if (display->visinfo) { + XFree (display->visinfo); + } + if (display->display) { + XCloseDisplay (display->display); + } + + if (display->lock) { + g_mutex_free (display->lock); + } +} + +static gboolean gst_gl_display_check_features (GstGLDisplay * display); GstGLDisplay * -gst_gl_display_new (const char *display_name) +gst_gl_display_new (void) { - GstGLDisplay *display; - gboolean usable; + return g_object_new (GST_TYPE_GL_DISPLAY, NULL); +} - display = g_malloc0 (sizeof (GstGLDisplay)); +#define HANDLE_X_ERRORS +#ifdef HANDLE_X_ERRORS +static int +x_error_handler (Display * display, XErrorEvent * event) +{ + g_assert_not_reached (); +} +#endif + +gboolean +gst_gl_display_connect (GstGLDisplay * display, const char *display_name) +{ + gboolean usable; + XGCValues values; + XPixmapFormatValues *px_formats; + int n_formats; + int i; display->display = XOpenDisplay (display_name); if (display->display == NULL) { - g_free (display); - return NULL; + return FALSE; } +#ifdef HANDLE_X_ERRORS + XSynchronize (display->display, True); + XSetErrorHandler (x_error_handler); +#endif usable = gst_gl_display_check_features (display); if (!usable) { - g_free (display); - return NULL; + return FALSE; } - display->lock = g_mutex_new (); + display->screen = DefaultScreenOfDisplay (display->display); + display->screen_num = DefaultScreen (display->display); + display->visual = DefaultVisual (display->display, display->screen_num); + display->root = DefaultRootWindow (display->display); + display->white = XWhitePixel (display->display, display->screen_num); + display->black = XBlackPixel (display->display, display->screen_num); + display->depth = DefaultDepthOfScreen (display->screen); + + display->gc = XCreateGC (display->display, + DefaultRootWindow (display->display), 0, &values); + + px_formats = XListPixmapFormats (display->display, &n_formats); + for (i = 0; i < n_formats; i++) { + GST_DEBUG ("%d: depth %d bpp %d pad %d", i, + px_formats[i].depth, + px_formats[i].bits_per_pixel, px_formats[i].scanline_pad); + } + + gst_gl_display_init_tmp_window (display); - return display; + return TRUE; } static gboolean @@ -160,57 +242,30 @@ gst_gl_display_can_handle_type (GstGLDisplay * display, GstGLImageType type) } } -void -gst_gl_display_free (GstGLDisplay * display) -{ - /* sure hope nobody is using it as it's being freed */ - g_mutex_lock (display->lock); - g_mutex_unlock (display->lock); - - if (display->context) { - glXDestroyContext (display->display, display->context); - } - if (display->visinfo) { - XFree (display->visinfo); - } - if (display->display) { - XCloseDisplay (display->display); - } - - g_mutex_free (display->lock); - - g_free (display); -} - void gst_gl_display_lock (GstGLDisplay * display) { g_mutex_lock (display->lock); + glXMakeCurrent (display->display, display->window, display->context); } void gst_gl_display_unlock (GstGLDisplay * display) { + glXMakeCurrent (display->display, None, NULL); g_mutex_unlock (display->lock); } - -/* drawable */ - -GstGLDrawable * -gst_gl_drawable_new_window (GstGLDisplay * display) +static void +gst_gl_display_init_tmp_window (GstGLDisplay * display) { - GstGLDrawable *drawable; XSetWindowAttributes attr = { 0 }; int scrnum; int mask; Window root; Screen *screen; - drawable = g_malloc0 (sizeof (GstGLDrawable)); - - g_mutex_lock (display->lock); - drawable->display = display; + GST_ERROR ("creating temp window"); screen = XDefaultScreenOfDisplay (display->display); scrnum = XScreenNumberOfScreen (screen); @@ -229,114 +284,72 @@ gst_gl_drawable_new_window (GstGLDisplay * display) mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect; - drawable->window = XCreateWindow (display->display, + display->window = XCreateWindow (display->display, root, 0, 0, 100, 100, 0, display->visinfo->depth, InputOutput, display->visinfo->visual, mask, &attr); - XMapWindow (display->display, drawable->window); - drawable->destroy_on_free = TRUE; - - g_mutex_unlock (display->lock); - - return drawable; -} - -GstGLDrawable * -gst_gl_drawable_new_root_window (GstGLDisplay * display) -{ - GstGLDrawable *drawable; - int scrnum; - Screen *screen; - - drawable = g_malloc0 (sizeof (GstGLDrawable)); - - g_mutex_lock (display->lock); - drawable->display = display; - - screen = XDefaultScreenOfDisplay (display->display); - scrnum = XScreenNumberOfScreen (screen); - - drawable->window = XRootWindow (display->display, scrnum); - drawable->destroy_on_free = FALSE; - g_mutex_unlock (display->lock); - - return drawable; + XMapWindow (display->display, display->window); + XSync (display->display, FALSE); } -GstGLDrawable * -gst_gl_drawable_new_from_window (GstGLDisplay * display, Window window) +static void +gst_gl_display_destroy_tmp_window (GstGLDisplay * display) { - GstGLDrawable *drawable; - - drawable = g_malloc0 (sizeof (GstGLDrawable)); - - g_mutex_lock (display->lock); - drawable->display = display; - - drawable->window = window; - drawable->destroy_on_free = FALSE; - - g_mutex_unlock (display->lock); - return drawable; + XDestroyWindow (display->display, display->window); } void -gst_gl_drawable_free (GstGLDrawable * drawable) +gst_gl_display_set_window (GstGLDisplay * display, Window window) { + g_mutex_lock (display->lock); - g_mutex_lock (drawable->display->lock); - if (drawable->destroy_on_free) { - XDestroyWindow (drawable->display->display, drawable->window); + if (window != display->assigned_window) { + if (display->assigned_window == None) { + gst_gl_display_destroy_tmp_window (display); + } + display->assigned_window = window; + if (display->assigned_window == None) { + gst_gl_display_init_tmp_window (display); + } else { + display->window = window; + } } - g_mutex_unlock (drawable->display->lock); - - g_free (drawable); -} - -void -gst_gl_drawable_lock (GstGLDrawable * drawable) -{ - g_mutex_lock (drawable->display->lock); - glXMakeCurrent (drawable->display->display, drawable->window, - drawable->display->context); -} -void -gst_gl_drawable_unlock (GstGLDrawable * drawable) -{ - glXMakeCurrent (drawable->display->display, None, NULL); - g_mutex_unlock (drawable->display->lock); + g_mutex_unlock (display->lock); } void -gst_gl_drawable_update_attributes (GstGLDrawable * drawable) +gst_gl_display_update_attributes (GstGLDisplay * display) { XWindowAttributes attr; - XGetWindowAttributes (drawable->display->display, drawable->window, &attr); - drawable->win_width = attr.width; - drawable->win_height = attr.height; - + if (display->window != None) { + XGetWindowAttributes (display->display, display->window, &attr); + display->win_width = attr.width; + display->win_height = attr.height; + } else { + display->win_width = 0; + display->win_height = 0; + } } void -gst_gl_drawable_clear (GstGLDrawable * drawable) +gst_gl_display_clear (GstGLDisplay * display) { - - gst_gl_drawable_lock (drawable); + gst_gl_display_lock (display); glDepthFunc (GL_LESS); glEnable (GL_DEPTH_TEST); glClearColor (0.2, 0.2, 0.2, 1.0); - glViewport (0, 0, drawable->win_width, drawable->win_height); + glViewport (0, 0, display->win_width, display->win_height); - gst_gl_drawable_unlock (drawable); + gst_gl_display_unlock (display); } static void -draw_rect_texture (GstGLDrawable * drawable, GstGLImageType type, +draw_rect_texture (GstGLDisplay * display, GstGLImageType type, void *data, int width, int height) { GLuint texture; @@ -437,7 +450,7 @@ draw_rect_texture (GstGLDrawable * drawable, GstGLImageType type, } static void -draw_pow2_texture (GstGLDrawable * drawable, GstGLImageType type, +draw_pow2_texture (GstGLDisplay * display, GstGLImageType type, void *data, int width, int height) { int pow2_width; @@ -544,14 +557,14 @@ draw_pow2_texture (GstGLDrawable * drawable, GstGLImageType type, } void -gst_gl_drawable_draw_image (GstGLDrawable * drawable, GstGLImageType type, +gst_gl_display_draw_image (GstGLDisplay * display, GstGLImageType type, void *data, int width, int height) { g_return_if_fail (data != NULL); g_return_if_fail (width > 0); g_return_if_fail (height > 0); - gst_gl_drawable_lock (drawable); + gst_gl_display_lock (display); #if 0 /* Doesn't work */ @@ -561,9 +574,9 @@ gst_gl_drawable_draw_image (GstGLDrawable * drawable, GstGLImageType type, int64_t sbc = 1234; gboolean ret; - ret = glXGetSyncValuesOML (drawable->display->display, drawable->window, + ret = glXGetSyncValuesOML (display->display, display->window, &ust, &mst, &sbc); - GST_ERROR ("sync values %d %lld %lld %lld", ret, ust, mst, sbc); + GST_DEBUG ("sync values %d %lld %lld %lld", ret, ust, mst, sbc); } #endif @@ -574,16 +587,15 @@ gst_gl_drawable_draw_image (GstGLDrawable * drawable, GstGLImageType type, int32_t den = 1234; gboolean ret; - ret = glXGetMscRateOML (drawable->display->display, drawable->window, - &num, &den); - GST_ERROR ("rate %d %d %d", ret, num, den); + ret = glXGetMscRateOML (display->display, display->window, &num, &den); + GST_DEBUG ("rate %d %d %d", ret, num, den); } #endif - gst_gl_drawable_update_attributes (drawable); + gst_gl_display_update_attributes (display); - glXSwapIntervalSGI (1); - glViewport (0, 0, drawable->win_width, drawable->win_height); + //glXSwapIntervalSGI (1); + glViewport (0, 0, display->win_width, display->win_height); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -598,23 +610,22 @@ gst_gl_drawable_draw_image (GstGLDrawable * drawable, GstGLImageType type, glColor4f (1, 1, 1, 1); - if (drawable->display->have_texture_rectangle) { - draw_rect_texture (drawable, type, data, width, height); + if (display->have_texture_rectangle) { + draw_rect_texture (display, type, data, width, height); } else { - draw_pow2_texture (drawable, type, data, width, height); + draw_pow2_texture (display, type, data, width, height); } - glXSwapBuffers (drawable->display->display, drawable->window); + glXSwapBuffers (display->display, display->window); #if 0 /* Doesn't work */ { - ret = glXSwapBuffersMscOML (drawable->display->display, drawable->window, - 0, 1, 0); + ret = glXSwapBuffersMscOML (display->display, display->window, 0, 1, 0); if (ret == 0) { - GST_ERROR ("glXSwapBuffersMscOML failed"); + GST_DEBUG ("glXSwapBuffersMscOML failed"); } } #endif - gst_gl_drawable_unlock (drawable); + gst_gl_display_unlock (display); } diff --git a/sys/glsink/glvideo.h b/sys/glsink/glvideo.h index e1bdfe92..aef064e3 100644 --- a/sys/glsink/glvideo.h +++ b/sys/glsink/glvideo.h @@ -6,9 +6,6 @@ #include #include -typedef struct _GstGLDisplay GstGLDisplay; -typedef struct _GstGLDrawable GstGLDrawable; - typedef enum { GST_GL_IMAGE_TYPE_RGBx, GST_GL_IMAGE_TYPE_BGRx, @@ -19,54 +16,71 @@ typedef enum { GST_GL_IMAGE_TYPE_AYUV, } GstGLImageType; +typedef struct _GstGLDisplay GstGLDisplay; +typedef struct _GstGLDisplayClass GstGLDisplayClass; + +#define GST_TYPE_GL_DISPLAY \ + (gst_gl_display_get_type()) +#define GST_GL_DISPLAY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_DISPLAY,GstGLDisplay)) +#define GST_GL_DISPLAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GL_DISPLAY,GstGLDisplayClass)) +#define GST_IS_GL_DISPLAY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_DISPLAY)) +#define GST_IS_GL_DISPLAY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GL_DISPLAY)) + struct _GstGLDisplay { + GObject object; + Display *display; + GC gc; XVisualInfo *visinfo; GLXContext context; GMutex *lock; Screen *screen; - int scrnum; + int screen_num; + Visual *visual; Window root; + guint32 white; + guint32 black; + int depth; int max_texture_size; gboolean have_ycbcr_texture; gboolean have_texture_rectangle; gboolean have_color_matrix; -}; - -struct _GstGLDrawable { - GstGLDisplay *display; Window window; - - gboolean destroy_on_free; + Window assigned_window; int win_width; int win_height; + +}; + +struct _GstGLDisplayClass { + GObjectClass object_class; }; +GType gst_gl_display_get_type (void); + -GstGLDisplay *gst_gl_display_new (const char *display_name); +GstGLDisplay *gst_gl_display_new (void); +gboolean gst_gl_display_connect (GstGLDisplay *display, + const char *display_name); gboolean gst_gl_display_can_handle_type (GstGLDisplay *display, GstGLImageType type); -void gst_gl_display_free (GstGLDisplay *display); void gst_gl_display_lock (GstGLDisplay *display); void gst_gl_display_unlock (GstGLDisplay *display); - -/* drawable */ - -GstGLDrawable * gst_gl_drawable_new_window (GstGLDisplay *display); -GstGLDrawable * gst_gl_drawable_new_root_window (GstGLDisplay *display); -GstGLDrawable * gst_gl_drawable_new_from_window (GstGLDisplay *display, Window window); -void gst_gl_drawable_free (GstGLDrawable *drawable); -void gst_gl_drawable_lock (GstGLDrawable *drawable); -void gst_gl_drawable_unlock (GstGLDrawable *drawable); -void gst_gl_drawable_update_attributes (GstGLDrawable *drawable); -void gst_gl_drawable_clear (GstGLDrawable *drawable); -void gst_gl_drawable_draw_image (GstGLDrawable *drawable, GstGLImageType type, void *data, int width, int height); +void gst_gl_display_set_window (GstGLDisplay *display, Window window); +void gst_gl_display_update_attributes (GstGLDisplay *display); +void gst_gl_display_clear (GstGLDisplay *display); +void gst_gl_display_draw_image (GstGLDisplay * display, GstGLImageType type, + void *data, int width, int height); #endif diff --git a/sys/glsink/gstglbuffer.c b/sys/glsink/gstglbuffer.c new file mode 100644 index 00000000..04421ce7 --- /dev/null +++ b/sys/glsink/gstglbuffer.c @@ -0,0 +1,239 @@ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include "glextensions.h" + +#include + +static GObjectClass *gst_gl_buffer_parent_class; + +static void +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; + default: + g_assert_not_reached (); + break; + } + gst_gl_display_unlock (buffer->display); + g_object_unref (buffer->display); + + GST_MINI_OBJECT_CLASS (gst_gl_buffer_parent_class)-> + finalize (GST_MINI_OBJECT (buffer)); +} + +static void +gst_gl_buffer_init (GstGLBuffer * buffer, gpointer g_class) +{ + +} + +static void +gst_gl_buffer_class_init (gpointer g_class, gpointer class_data) +{ + GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class); + + gst_gl_buffer_parent_class = g_type_class_peek_parent (g_class); + + mini_object_class->finalize = (GstMiniObjectFinalizeFunction) + gst_gl_buffer_finalize; +} + + +GType +gst_gl_buffer_get_type (void) +{ + static GType _gst_gl_buffer_type; + + if (G_UNLIKELY (_gst_gl_buffer_type == 0)) { + static const GTypeInfo info = { + sizeof (GstBufferClass), + NULL, + NULL, + gst_gl_buffer_class_init, + NULL, + NULL, + sizeof (GstGLBuffer), + 0, + (GInstanceInitFunc) gst_gl_buffer_init, + NULL + }; + _gst_gl_buffer_type = g_type_register_static (GST_TYPE_BUFFER, + "GstGLBuffer", &info, 0); + } + return _gst_gl_buffer_type; +} + + +GstGLBuffer * +gst_gl_buffer_new (GstGLDisplay * display, GstVideoFormat format, + int width, int height) +{ + GstGLBuffer *buffer; + XGCValues values = { 0 }; + + g_return_val_if_fail (format == GST_VIDEO_FORMAT_BGRx, 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_RBO; + + 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: + { + gst_gl_display_lock (buffer->display); + + 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); + + + + gst_gl_display_unlock (buffer->display); + break; + } + default: + g_assert_not_reached (); + } + + return buffer; +} + +void +gst_gl_buffer_upload (GstGLBuffer * buffer, 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; + + 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); + 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); + //glWindowPos2iARB(0, 0); + glDrawPixels (buffer->width, buffer->height, GL_RGBA, + GL_UNSIGNED_BYTE, data); + + glDeleteFramebuffersEXT (1, &fbo); + + break; + } + default: + g_assert_not_reached (); + } + + gst_gl_display_unlock (buffer->display); +} + + +void +gst_gl_buffer_download (GstGLBuffer * buffer, void *data) +{ + gst_gl_display_lock (buffer->display); + + 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); + + glReadBuffer (GL_COLOR_ATTACHMENT1_EXT); + glReadPixels (0, 0, buffer->width, buffer->height, GL_RGBA, + GL_UNSIGNED_BYTE, data); + + glDeleteFramebuffersEXT (1, &fbo); + + break; + } + default: + g_assert_not_reached (); + } + + gst_gl_display_unlock (buffer->display); +} diff --git a/sys/glsink/gstglbuffer.h b/sys/glsink/gstglbuffer.h new file mode 100644 index 00000000..969f2161 --- /dev/null +++ b/sys/glsink/gstglbuffer.h @@ -0,0 +1,47 @@ + +#ifndef _GST_GL_BUFFER_H_ +#define _GST_GL_BUFFER_H_ + +#include +#include +#include +#include + +typedef struct _GstGLBuffer GstGLBuffer; + +#define GST_TYPE_GL_BUFFER (gst_gl_buffer_get_type()) + +#define GST_IS_GL_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_GL_BUFFER)) +#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 +} GstGLBufferType; + +struct _GstGLBuffer { + GstBuffer buffer; + + GstGLDisplay *display; + + GstGLBufferType type; + + XID pixmap; + GC gc; + + GLuint rbo; + + int width; + int height; +}; + +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); +void gst_gl_buffer_download (GstGLBuffer *buffer, void *data); + +#endif + diff --git a/sys/glsink/gstgldownload.c b/sys/glsink/gstgldownload.c new file mode 100644 index 00000000..55f9e759 --- /dev/null +++ b/sys/glsink/gstgldownload.c @@ -0,0 +1,294 @@ +/* + * 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 + +#define GST_CAT_DEFAULT gst_gl_download_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +#define GST_TYPE_GL_DOWNLOAD (gst_gl_download_get_type()) +#define GST_GL_DOWNLOAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_DOWNLOAD,GstGLDownload)) +#define GST_IS_GL_DOWNLOAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_DOWNLOAD)) +#define GST_GL_DOWNLOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_DOWNLOAD,GstGLDownloadClass)) +#define GST_IS_GL_DOWNLOAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_DOWNLOAD)) +#define GST_GL_DOWNLOAD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_DOWNLOAD,GstGLDownloadClass)) +typedef struct _GstGLDownload GstGLDownload; +typedef struct _GstGLDownloadClass GstGLDownloadClass; + +typedef void (*GstGLDownloadProcessFunc) (GstGLDownload *, guint8 *, guint); + +struct _GstGLDownload +{ + GstElement element; + + GstPad *srcpad; + GstPad *sinkpad; + + /* < private > */ + + GstGLDisplay *display; + GstVideoFormat format; + int width; + int height; +}; + +struct _GstGLDownloadClass +{ + 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" + +static GstStaticPadTemplate gst_gl_download_src_pad_template = +GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx) + ); + +static GstStaticPadTemplate gst_gl_download_sink_pad_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS (GST_GL_VIDEO_CAPS) + ); + +enum +{ + PROP_0 +}; + +#define DEBUG_INIT(bla) \ + GST_DEBUG_CATEGORY_INIT (gst_gl_download_debug, "gldownload", 0, "gldownload element"); + +GST_BOILERPLATE_FULL (GstGLDownload, gst_gl_download, GstElement, + GST_TYPE_ELEMENT, DEBUG_INIT); + +static void gst_gl_download_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_gl_download_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstFlowReturn gst_gl_download_chain (GstPad * pad, GstBuffer * buf); +static void gst_gl_download_reset (GstGLDownload * download); +static GstStateChangeReturn +gst_gl_download_change_state (GstElement * element, GstStateChange transition); +static gboolean gst_gl_download_sink_setcaps (GstPad * pad, GstCaps * caps); + + +static void +gst_gl_download_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_download_src_pad_template)); + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&gst_gl_download_sink_pad_template)); +} + +static void +gst_gl_download_class_init (GstGLDownloadClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + gobject_class->set_property = gst_gl_download_set_property; + gobject_class->get_property = gst_gl_download_get_property; + + GST_ELEMENT_CLASS (klass)->change_state = gst_gl_download_change_state; +} + +static void +gst_gl_download_init (GstGLDownload * download, GstGLDownloadClass * klass) +{ + gst_element_create_all_pads (GST_ELEMENT (download)); + + download->sinkpad = + gst_element_get_static_pad (GST_ELEMENT (download), "sink"); + download->srcpad = gst_element_get_static_pad (GST_ELEMENT (download), "src"); + + gst_pad_set_setcaps_function (download->sinkpad, + gst_gl_download_sink_setcaps); + gst_pad_set_chain_function (download->sinkpad, gst_gl_download_chain); + + gst_gl_download_reset (download); +} + +static void +gst_gl_download_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + //GstGLDownload *download = GST_GL_DOWNLOAD (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_gl_download_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + //GstGLDownload *download = GST_GL_DOWNLOAD (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_gl_download_reset (GstGLDownload * download) +{ + if (download->display) { + g_object_unref (download->display); + download->display = NULL; + } + download->format = GST_VIDEO_FORMAT_BGRx; +} + +static gboolean +gst_gl_download_start (GstGLDownload * download) +{ + gboolean ret; + + download->format = GST_VIDEO_FORMAT_BGRx; + download->display = gst_gl_display_new (); + ret = gst_gl_display_connect (download->display, NULL); + + return ret; +} + +static gboolean +gst_gl_download_stop (GstGLDownload * download) +{ + gst_gl_download_reset (download); + + return TRUE; +} + +static gboolean +gst_gl_download_sink_setcaps (GstPad * pad, GstCaps * caps) +{ + GstGLDownload *download; + gboolean ret; + GstStructure *structure; + GstCaps *srccaps; + + download = GST_GL_DOWNLOAD (gst_pad_get_parent (pad)); + + structure = gst_caps_get_structure (caps, 0); + + ret = gst_structure_get_int (structure, "width", &download->width); + ret &= gst_structure_get_int (structure, "height", &download->height); + if (!ret) + return FALSE; + + srccaps = gst_video_format_new_caps (download->format, + download->width, download->height, 30, 1, 1, 1); + ret = gst_pad_set_caps (download->srcpad, srccaps); + gst_caps_unref (srccaps); + + return ret; +} + +static GstFlowReturn +gst_gl_download_chain (GstPad * pad, GstBuffer * buf) +{ + GstGLDownload *download; + GstGLBuffer *inbuf = GST_GL_BUFFER (buf); + GstBuffer *outbuf; + + GST_ERROR ("got here"); + download = GST_GL_DOWNLOAD (gst_pad_get_parent (pad)); + + outbuf = gst_buffer_new_and_alloc (inbuf->width * inbuf->height * 4); + + gst_buffer_copy_metadata (GST_BUFFER (outbuf), buf, + GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS); + gst_buffer_set_caps (GST_BUFFER (outbuf), GST_PAD_CAPS (download->srcpad)); + + GST_ERROR ("downloading %p size %d", + GST_BUFFER_DATA (outbuf), GST_BUFFER_SIZE (outbuf)); + gst_gl_buffer_download (inbuf, GST_BUFFER_DATA (outbuf)); + + gst_pad_push (download->srcpad, GST_BUFFER (outbuf)); + + gst_object_unref (download); + return GST_FLOW_OK; +} + +static GstStateChangeReturn +gst_gl_download_change_state (GstElement * element, GstStateChange transition) +{ + GstGLDownload *download; + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + GST_DEBUG ("change state"); + + download = GST_GL_DOWNLOAD (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + gst_gl_download_start (download); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_gl_download_stop (download); + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return ret; +} diff --git a/sys/glsink/gstglfilter.c b/sys/glsink/gstglfilter.c new file mode 100644 index 00000000..c2b91f45 --- /dev/null +++ b/sys/glsink/gstglfilter.c @@ -0,0 +1,416 @@ +/* + * 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 + +#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" + +static GstStaticPadTemplate gst_gl_filter_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_sink_pad_template = +GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + 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"); + +GST_BOILERPLATE_FULL (GstGLFilter, gst_gl_filter, GstElement, + GST_TYPE_ELEMENT, DEBUG_INIT); + +static void gst_gl_filter_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_gl_filter_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static GstFlowReturn gst_gl_filter_chain (GstPad * pad, GstBuffer * buf); +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 void +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, + gst_static_pad_template_get (&gst_gl_filter_sink_pad_template)); +} + +static void +gst_gl_filter_class_init (GstGLFilterClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + gobject_class->set_property = gst_gl_filter_set_property; + gobject_class->get_property = gst_gl_filter_get_property; + + GST_ELEMENT_CLASS (klass)->change_state = gst_gl_filter_change_state; +} + +static void +gst_gl_filter_init (GstGLFilter * filter, GstGLFilterClass * klass) +{ + gst_element_create_all_pads (GST_ELEMENT (filter)); + + filter->sinkpad = gst_element_get_static_pad (GST_ELEMENT (filter), "sink"); + filter->srcpad = gst_element_get_static_pad (GST_ELEMENT (filter), "src"); + + gst_pad_set_setcaps_function (filter->sinkpad, gst_gl_filter_sink_setcaps); + gst_pad_set_chain_function (filter->sinkpad, gst_gl_filter_chain); + + gst_gl_filter_reset (filter); +} + +static void +gst_gl_filter_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + //GstGLFilter *filter = GST_GL_FILTER (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_gl_filter_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + //GstGLFilter *filter = GST_GL_FILTER (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_gl_filter_reset (GstGLFilter * filter) +{ + if (filter->display) { + g_object_unref (filter->display); + filter->display = NULL; + } + filter->format = GST_VIDEO_FORMAT_BGRx; +} + +static gboolean +gst_gl_filter_start (GstGLFilter * filter) +{ + gboolean ret; + + filter->format = GST_VIDEO_FORMAT_BGRx; + filter->display = gst_gl_display_new (); + ret = gst_gl_display_connect (filter->display, NULL); + + return ret; +} + +static gboolean +gst_gl_filter_stop (GstGLFilter * filter) +{ + gst_gl_filter_reset (filter); + + return TRUE; +} + +static gboolean +gst_gl_filter_sink_setcaps (GstPad * pad, GstCaps * caps) +{ + GstGLFilter *filter; + gboolean ret; + GstStructure *structure; + + filter = GST_GL_FILTER (gst_pad_get_parent (pad)); + + structure = gst_caps_get_structure (caps, 0); + + ret = gst_structure_get_int (structure, "width", &filter->width); + ret &= gst_structure_get_int (structure, "height", &filter->height); + if (!ret) + return FALSE; + + GST_ERROR ("setcaps %d %d", filter->width, filter->height); + + ret = gst_pad_set_caps (filter->srcpad, caps); + + return ret; +} + +static GstFlowReturn +gst_gl_filter_chain (GstPad * pad, GstBuffer * buf) +{ + GstGLFilter *filter; + GstGLBuffer *inbuf; + GstGLBuffer *outbuf; + + filter = GST_GL_FILTER (gst_pad_get_parent (pad)); + inbuf = GST_GL_BUFFER (buf); + + outbuf = gst_gl_buffer_new (inbuf->display, filter->format, + filter->width, filter->height); + + gst_buffer_copy_metadata (GST_BUFFER (outbuf), 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_pad_push (filter->srcpad, GST_BUFFER (outbuf)); + + gst_object_unref (filter); + return GST_FLOW_OK; +} + +static GstStateChangeReturn +gst_gl_filter_change_state (GstElement * element, GstStateChange transition) +{ + GstGLFilter *filter; + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + GST_DEBUG ("change state"); + + filter = GST_GL_FILTER (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + gst_gl_filter_start (filter); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_gl_filter_stop (filter); + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + 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) +{ + GstGLDisplay *display; + +#if 0 + int pixmapAttribs[] = { + GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_RECTANGLE_EXT, + GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT, + None + }; +#endif + GLXFBConfig *fbconfigs; + int n; + int i; + GLXDrawable glxpixmap; + GLXContext context = 0; + int fb_index = 0; + int attrib[] = { GLX_RGBA, GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None + }; + XVisualInfo *visinfo; + + display = outbuf->display; + gst_gl_display_lock (display); + + //context = glXCreateContext (display->display, visinfo, NULL, True); + + dump_fbconfigs (display->display); + + fbconfigs = glXGetFBConfigs (display->display, display->screen_num, &n); + for (i = 0; i < n; i++) { + XVisualInfo *visinfo; + int value; + + GST_DEBUG ("fbconfig %d", i); + + visinfo = glXGetVisualFromFBConfig (display->display, fbconfigs[i]); + GST_DEBUG ("visinfo %p", visinfo); + + glXGetFBConfigAttrib (display->display, fbconfigs[i], + GLX_DRAWABLE_TYPE, &value); + if (!(value & GLX_WINDOW_BIT)) { + GST_DEBUG ("GLX_DRAWABLE_TYPE doesn't have GLX_WINDOW_BIT set"); + continue; + } + + glXGetFBConfigAttrib (display->display, fbconfigs[i], + GLX_BIND_TO_TEXTURE_TARGETS_EXT, &value); + if (!(value & GLX_TEXTURE_2D_BIT_EXT)) { + GST_DEBUG + ("GLX_BIND_TO_TEXTURE_TARGETS_EXT doesn't have GLX_TEXTURE_2D_BIT_EXT set"); + continue; + } + + glXGetFBConfigAttrib (display->display, fbconfigs[i], + GLX_BIND_TO_TEXTURE_RGBA_EXT, &value); + GST_DEBUG ("GLX_BIND_TO_TEXTURE_RGBA_EXT %d", value); + + } + + fb_index = 0; + +#if 0 + { + pb = glXCreatePbuffer (display->display, fbconfigs[fb_index], attribs); + } +#endif + + XSync (display->display, False); + visinfo = glXChooseVisual (display->display, 0, attrib); + glxpixmap = glXCreateGLXPixmap (display->display, visinfo, outbuf->pixmap); + + XSync (display->display, False); + + glXMakeCurrent (display->display, glxpixmap, context); + + glXMakeCurrent (display->display, None, NULL); + gst_gl_display_unlock (display); + + return TRUE; +} diff --git a/sys/glsink/gstglupload.c b/sys/glsink/gstglupload.c index 116d9d44..81d73175 100644 --- a/sys/glsink/gstglupload.c +++ b/sys/glsink/gstglupload.c @@ -78,7 +78,7 @@ static GstStaticPadTemplate gst_gl_upload_sink_pad_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBx) + GST_STATIC_CAPS (GST_VIDEO_CAPS_BGRx) ); enum @@ -99,6 +99,9 @@ static void gst_gl_upload_get_property (GObject * object, guint prop_id, static GstFlowReturn gst_gl_upload_chain (GstPad * pad, GstBuffer * buf); static void gst_gl_upload_reset (GstGLUpload * upload); +static GstStateChangeReturn +gst_gl_upload_change_state (GstElement * element, GstStateChange transition); +static gboolean gst_gl_upload_sink_setcaps (GstPad * pad, GstCaps * caps); static void @@ -123,11 +126,18 @@ gst_gl_upload_class_init (GstGLUploadClass * klass) gobject_class->set_property = gst_gl_upload_set_property; gobject_class->get_property = gst_gl_upload_get_property; + GST_ELEMENT_CLASS (klass)->change_state = gst_gl_upload_change_state; } static void gst_gl_upload_init (GstGLUpload * upload, GstGLUploadClass * klass) { + gst_element_create_all_pads (GST_ELEMENT (upload)); + + upload->sinkpad = gst_element_get_static_pad (GST_ELEMENT (upload), "sink"); + upload->srcpad = gst_element_get_static_pad (GST_ELEMENT (upload), "src"); + + gst_pad_set_setcaps_function (upload->sinkpad, gst_gl_upload_sink_setcaps); gst_pad_set_chain_function (upload->sinkpad, gst_gl_upload_chain); gst_gl_upload_reset (upload); @@ -162,6 +172,61 @@ gst_gl_upload_get_property (GObject * object, guint prop_id, static void gst_gl_upload_reset (GstGLUpload * upload) { + if (upload->display) { + g_object_unref (upload->display); + upload->display = NULL; + } + upload->format = GST_VIDEO_FORMAT_BGRx; +} + +static gboolean +gst_gl_upload_start (GstGLUpload * upload) +{ + gboolean ret; + + upload->format = GST_VIDEO_FORMAT_BGRx; + upload->display = gst_gl_display_new (); + ret = gst_gl_display_connect (upload->display, NULL); + + return ret; +} + +static gboolean +gst_gl_upload_stop (GstGLUpload * upload) +{ + gst_gl_upload_reset (upload); + + return TRUE; +} + +static gboolean +gst_gl_upload_sink_setcaps (GstPad * pad, GstCaps * caps) +{ + GstGLUpload *upload; + GstVideoFormat format; + int height; + int width; + gboolean ret; + GstCaps *srccaps; + + upload = GST_GL_UPLOAD (gst_pad_get_parent (pad)); + + ret = gst_video_format_parse_caps (caps, &format, &width, &height); + if (!ret) + return FALSE; + + upload->format = format; + upload->width = width; + upload->height = height; + + GST_ERROR ("setcaps %d %d %d", format, width, height); + + srccaps = gst_caps_new_simple ("video/x-raw-gl", + "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL); + ret = gst_pad_set_caps (upload->srcpad, srccaps); + gst_caps_unref (srccaps); + + return ret; } static GstFlowReturn @@ -177,6 +242,10 @@ gst_gl_upload_chain (GstPad * pad, GstBuffer * buf) gst_buffer_copy_metadata (GST_BUFFER (outbuf), buf, GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_FLAGS); + gst_buffer_set_caps (GST_BUFFER (outbuf), GST_PAD_CAPS (upload->srcpad)); + + GST_DEBUG ("uploading %p size %d", GST_BUFFER_DATA (buf), + GST_BUFFER_SIZE (buf)); gst_gl_buffer_upload (outbuf, GST_BUFFER_DATA (buf)); gst_pad_push (upload->srcpad, GST_BUFFER (outbuf)); @@ -184,3 +253,44 @@ gst_gl_upload_chain (GstPad * pad, GstBuffer * buf) gst_object_unref (upload); return GST_FLOW_OK; } + +static GstStateChangeReturn +gst_gl_upload_change_state (GstElement * element, GstStateChange transition) +{ + GstGLUpload *upload; + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + GST_DEBUG ("change state"); + + upload = GST_GL_UPLOAD (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + gst_gl_upload_start (upload); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + gst_gl_upload_stop (upload); + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return ret; +} diff --git a/sys/glsink/gstopengl.c b/sys/glsink/gstopengl.c index 7116174a..4889e0a6 100644 --- a/sys/glsink/gstopengl.c +++ b/sys/glsink/gstopengl.c @@ -33,6 +33,8 @@ #include GType gst_gl_upload_get_type (void); +GType gst_gl_download_get_type (void); +GType gst_gl_filter_get_type (void); static gboolean @@ -46,15 +48,17 @@ plugin_init (GstPlugin * plugin) return FALSE; } if (!gst_element_register (plugin, "glupload", - GST_RANK_MARGINAL, gst_gl_upload_get_type ())) { + GST_RANK_NONE, gst_gl_upload_get_type ())) { return FALSE; } -#if 0 if (!gst_element_register (plugin, "gldownload", - GST_RANK_MARGINAL, GST_TYPE_GL_DOWNLOAD)) { + GST_RANK_NONE, gst_gl_download_get_type ())) { + return FALSE; + } + if (!gst_element_register (plugin, "glfilter", + GST_RANK_NONE, gst_gl_filter_get_type ())) { return FALSE; } -#endif return TRUE; } -- cgit v1.2.1