diff --git a/gst-libs/gst/gl/gstglbuffer.c b/gst-libs/gst/gl/gstglbuffer.c index 40eb4ddef0..833318a84e 100644 --- a/gst-libs/gst/gl/gstglbuffer.c +++ b/gst-libs/gst/gl/gstglbuffer.c @@ -95,7 +95,7 @@ gst_gl_buffer_new_from_video_format (GstGLDisplay* display, { GstGLBuffer *buffer; - g_return_val_if_fail (video_format != GST_VIDEO_FORMAT_UNKNOWN, NULL); + //g_return_val_if_fail (video_format != GST_VIDEO_FORMAT_UNKNOWN, NULL); g_return_val_if_fail (display != NULL, NULL); g_return_val_if_fail (width > 0, NULL); g_return_val_if_fail (height > 0, NULL); @@ -108,10 +108,11 @@ gst_gl_buffer_new_from_video_format (GstGLDisplay* display, buffer->video_format = video_format; GST_BUFFER_SIZE (buffer) = gst_gl_buffer_format_get_size (video_format, context_width, context_height); - //blocking call, init texture - gst_gl_display_textureRequested (buffer->display, buffer->video_format, - buffer->width, buffer->height, - &buffer->texture, &buffer->texture_u, &buffer->texture_v) ; + //blocking call, init texture + if (video_format != GST_VIDEO_FORMAT_UNKNOWN) + gst_gl_display_textureRequested (buffer->display, buffer->video_format, + buffer->width, buffer->height, + &buffer->texture, &buffer->texture_u, &buffer->texture_v) ; return buffer; } diff --git a/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c index a48e0bf58e..2d8982e264 100644 --- a/gst-libs/gst/gl/gstgldisplay.c +++ b/gst-libs/gst/gl/gstgldisplay.c @@ -28,6 +28,7 @@ static void gst_gl_display_finalize (GObject * object); static gpointer gst_gl_display_glutThreadFunc (GstGLDisplay* display); static void gst_gl_display_glutCreateWindow (GstGLDisplay* display); +static void gst_gl_display_glutGenerateFBO (GstGLDisplay *display); static void gst_gl_display_glutDestroyWindow (GstGLDisplay* display); static void gst_gl_display_glutSetVisibleWindow (GstGLDisplay* display); static void gst_gl_display_glutPrepareTexture (GstGLDisplay* display); @@ -93,6 +94,7 @@ gst_gl_display_init (GstGLDisplay *display, GstGLDisplayClass *klass) display->cond_fill = g_cond_new (); display->cond_clear = g_cond_new (); display->cond_video = g_cond_new (); + display->cond_generateFBO = g_cond_new (); display->cond_create = g_cond_new (); display->cond_destroy = g_cond_new (); @@ -106,6 +108,12 @@ gst_gl_display_init (GstGLDisplay *display, GstGLDisplayClass *klass) display->graphicDepthBuffer = 0; display->graphicTexture = 0; + display->requestedFBO = 0; + display->requestedDepthBuffer = 0; + display->requestedTextureFBO = 0; + display->requestedTextureFBOWidth = 0; + display->requestedTextureFBOHeight = 0; + display->requestedTexture = 0; display->requestedTexture_u = 0; display->requestedTexture_v = 0; @@ -326,6 +334,10 @@ gst_gl_display_finalize (GObject *object) g_cond_free (display->cond_video); display->cond_video = NULL; } + if (display->cond_generateFBO) { + g_cond_free (display->cond_generateFBO); + display->cond_generateFBO = NULL; + } if (display->cond_create) { g_cond_free (display->cond_create); display->cond_create = NULL; @@ -343,7 +355,7 @@ gst_gl_display_finalize (GObject *object) if (g_hash_table_size (gst_gl_display_map) == 0) { g_thread_join (gst_gl_display_glutThread); - GST_DEBUG ("Glut thread joined"); + g_print ("Glut thread joined\n"); gst_gl_display_glutThread = NULL; g_async_queue_unref (gst_gl_display_messageQueue); g_hash_table_unref (gst_gl_display_map); @@ -370,9 +382,9 @@ gst_gl_display_glutThreadFunc (GstGLDisplay *display) gst_gl_display_glutCreateWindow (display); gst_gl_display_unlock (display); - GST_DEBUG ("Glut mainLoop start"); + g_print ("Glut mainLoop start\n"); glutMainLoop (); - GST_DEBUG ("Glut mainLoop exited"); + g_print ("Glut mainLoop exited\n"); return NULL; } @@ -397,7 +409,7 @@ gst_gl_display_glutCreateWindow (GstGLDisplay *display) display->title = g_string_append (display->title, buffer); glutWinId = glutCreateWindow (display->title->str, display->winId); - GST_DEBUG ("Context %d created\n", glutWinId); + g_print ("Context %d created\n", glutWinId); if (display->visible) glutShowWindow (); @@ -646,6 +658,53 @@ gst_gl_display_glutCreateWindow (GstGLDisplay *display) } +/* Called by the idle funtion */ +static void +gst_gl_display_glutGenerateFBO (GstGLDisplay *display) +{ + + glutSetWindow (display->glutWinId); + + //-- generate frame buffer object + + //setup FBO + glGenFramebuffersEXT (1, &display->requestedFBO); + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->requestedFBO); + + //setup the render buffer for depth + glGenRenderbuffersEXT(1, &display->requestedDepthBuffer); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, display->requestedDepthBuffer); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, + display->requestedTextureFBOWidth, display->requestedTextureFBOHeight); + + //setup a texture to render to + glGenTextures (1, &display->requestedTextureFBO); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, display->requestedTextureFBO); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, + display->requestedTextureFBOWidth, display->requestedTextureFBOHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + 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_TO_EDGE); + glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + //attach the texture to the FBO to renderer to + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, + GL_TEXTURE_RECTANGLE_ARB, display->requestedTextureFBO, 0); + + //attach the depth render buffer to the FBO + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, + GL_RENDERBUFFER_EXT, display->requestedDepthBuffer); + + g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) == + GL_FRAMEBUFFER_COMPLETE_EXT); + + //unbind the FBO + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); + + g_cond_signal (display->cond_video); +} + + /* Called by the idle function */ static void gst_gl_display_glutDestroyWindow (GstGLDisplay *display) @@ -695,7 +754,7 @@ gst_gl_display_glutDestroyWindow (GstGLDisplay *display) } g_hash_table_remove (gst_gl_display_map, GINT_TO_POINTER (display->glutWinId)); - GST_DEBUG ("glut window destroyed: %d", display->glutWinId); + g_print ("glut window destroyed: %d\n", display->glutWinId); //if the map is empty, leaveMainloop and join the thread if (g_hash_table_size (gst_gl_display_map) == 0) @@ -806,7 +865,7 @@ gst_gl_display_glut_idle (void) gst_gl_display_glutDispatchAction (msg); } } - else GST_DEBUG ("timeout reached in idle func"); + else g_print ("timeout reached in idle func\n"); } @@ -841,6 +900,9 @@ gst_gl_display_glutDispatchAction (GstGLDisplayMsg* msg) case GST_GL_DISPLAY_ACTION_REDISPLAY: gst_gl_display_glutPostRedisplay (msg->display); break; + case GST_GL_DISPLAY_ACTION_GENFBO: + gst_gl_display_glutGenerateFBO (msg->display); + break; default: g_assert_not_reached (); } @@ -867,6 +929,7 @@ gst_gl_display_checkMsgValidity (GstGLDisplayMsg *msg) case GST_GL_DISPLAY_ACTION_CLEAR: case GST_GL_DISPLAY_ACTION_VIDEO: case GST_GL_DISPLAY_ACTION_REDISPLAY: + case GST_GL_DISPLAY_ACTION_GENFBO: //msg is out of date if the associated display is not in the map if (!g_hash_table_lookup (gst_gl_display_map, GINT_TO_POINTER (msg->glutWinId))) valid = FALSE; @@ -1010,7 +1073,7 @@ gst_gl_display_textureRequested (GstGLDisplay * display, GstVideoFormat video_fo /* Called by gst_gl elements */ void -gst_gl_display_textureChanged (GstGLDisplay * display, GstVideoFormat video_format, +gst_gl_display_textureChanged (GstGLDisplay* display, GstVideoFormat video_format, GLuint texture, GLuint texture_u, GLuint texture_v, gint width, gint height, gpointer data) { @@ -1030,7 +1093,7 @@ gst_gl_display_textureChanged (GstGLDisplay * display, GstVideoFormat video_form /* Called by gstglbuffer */ void -gst_gl_display_clearTexture (GstGLDisplay * display, guint texture, +gst_gl_display_clearTexture (GstGLDisplay* display, guint texture, guint texture_u, guint texture_v) { gst_gl_display_lock (display); @@ -1074,6 +1137,23 @@ gst_gl_display_postRedisplay (GstGLDisplay* display) } +/* Called by gst_gl elements */ +void +gst_gl_display_requestFBO (GstGLDisplay* display, gint width, gint height, + guint* fbo, guint* depthbuffer, guint* texture) +{ + gst_gl_display_lock (display); + display->requestedTextureFBOWidth = width; + display->requestedTextureFBOHeight = height; + gst_gl_display_postMessage (GST_GL_DISPLAY_ACTION_GENFBO, display); + g_cond_wait (display->cond_generateFBO, display->mutex); + *fbo = display->requestedFBO; + *depthbuffer = display->requestedDepthBuffer; + *texture = display->requestedTextureFBO; + gst_gl_display_unlock (display); +} + + /* Called by gst_gl elements */ void gst_gl_display_set_windowId (GstGLDisplay* display, gulong winId) @@ -1088,7 +1168,7 @@ gst_gl_display_set_windowId (GstGLDisplay* display, gulong winId) if (g_hash_table_size (gst_gl_display_map) == 0) { g_thread_join (gst_gl_display_glutThread); - GST_DEBUG ("Glut thread joined when setting winId"); + g_print ("Glut thread joined when setting winId\n"); gst_gl_display_glutThread = NULL; g_async_queue_unref (gst_gl_display_messageQueue); g_hash_table_unref (gst_gl_display_map); diff --git a/gst-libs/gst/gl/gstgldisplay.h b/gst-libs/gst/gl/gstgldisplay.h index f45d4dc6b7..fe5816ec01 100644 --- a/gst-libs/gst/gl/gstgldisplay.h +++ b/gst-libs/gst/gl/gstgldisplay.h @@ -50,7 +50,8 @@ typedef enum { GST_GL_DISPLAY_ACTION_CHANGE, GST_GL_DISPLAY_ACTION_CLEAR, GST_GL_DISPLAY_ACTION_VIDEO, - GST_GL_DISPLAY_ACTION_REDISPLAY + GST_GL_DISPLAY_ACTION_REDISPLAY, + GST_GL_DISPLAY_ACTION_GENFBO } GstGLDisplayAction; @@ -78,20 +79,21 @@ typedef gboolean (* CDCB) ( GLuint, GLuint, GLuint); struct _GstGLDisplay { GObject object; - GMutex *mutex; + GMutex* mutex; GQueue* texturePool; - GCond *cond_make; - GCond *cond_fill; - GCond *cond_clear; - GCond *cond_video; + GCond* cond_make; + GCond* cond_fill; + GCond* cond_clear; + GCond* cond_video; + GCond* cond_generateFBO; - GCond *cond_create; - GCond *cond_destroy; + GCond* cond_create; + GCond* cond_destroy; gint glutWinId; gulong winId; - GString *title; + GString* title; gint win_xpos; gint win_ypos; gint glcontext_width; @@ -111,6 +113,13 @@ struct _GstGLDisplay { GLuint graphicDepthBuffer; GLuint graphicTexture; + //filter frame buffer object (GL -> GL) + GLuint requestedFBO; + GLuint requestedDepthBuffer; + GLuint requestedTextureFBO; + GLuint requestedTextureFBOWidth; + GLuint requestedTextureFBOHeight; + GLuint requestedTexture; GLuint requestedTexture_u; GLuint requestedTexture_v; @@ -211,6 +220,8 @@ void gst_gl_display_clearTexture (GstGLDisplay* display, guint texture, void gst_gl_display_videoChanged (GstGLDisplay* display, GstVideoFormat video_format, gpointer data); gboolean gst_gl_display_postRedisplay (GstGLDisplay* display); +void gst_gl_display_requestFBO (GstGLDisplay* display, gint width, gint height, + guint* fbo, guint* depthbuffer, guint* texture); void gst_gl_display_set_windowId (GstGLDisplay* display, gulong winId); #endif diff --git a/gst/gl/gstglfilter.c b/gst/gl/gstglfilter.c new file mode 100644 index 0000000000..098584183b --- /dev/null +++ b/gst/gl/gstglfilter.c @@ -0,0 +1,329 @@ +/* + * GStreamer + * Copyright (C) 2008 Julien Isorce + * + * 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 "gstglfilter.h" + +#define GST_CAT_DEFAULT gst_gl_filter_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + + +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) + ); + +#define DEBUG_INIT(bla) \ + GST_DEBUG_CATEGORY_INIT (gst_gl_filter_debug, "glfilter", 0, "glfilter element"); + +GST_BOILERPLATE_FULL (GstGLFilter, gst_gl_filter, GstBaseTransform, + GST_TYPE_BASE_TRANSFORM, 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 void gst_gl_filter_reset (GstGLFilter * filter); +static gboolean gst_gl_filter_start (GstBaseTransform * bt); +static gboolean gst_gl_filter_stop (GstBaseTransform * bt); +static gboolean gst_gl_filter_get_unit_size (GstBaseTransform * trans, + GstCaps * caps, guint * size); +static GstFlowReturn gst_gl_filter_transform (GstBaseTransform * bt, + GstBuffer * inbuf, GstBuffer * outbuf); +static GstFlowReturn gst_gl_filter_prepare_output_buffer (GstBaseTransform * + trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf); +static gboolean gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps, + GstCaps * outcaps); +static gboolean gst_gl_filter_do_transform (GstGLFilter * filter, + GstGLBuffer * inbuf, GstGLBuffer * outbuf); + + +static void +gst_gl_filter_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + 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_BASE_TRANSFORM_CLASS (klass)->transform = gst_gl_filter_transform; + GST_BASE_TRANSFORM_CLASS (klass)->start = gst_gl_filter_start; + GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_filter_stop; + GST_BASE_TRANSFORM_CLASS (klass)->set_caps = gst_gl_filter_set_caps; + GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size = gst_gl_filter_get_unit_size; + GST_BASE_TRANSFORM_CLASS (klass)->prepare_output_buffer = + gst_gl_filter_prepare_output_buffer; +} + +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_gl_display_requestFBO + + filter->fbo = */ + + 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->video_format = GST_VIDEO_FORMAT_UNKNOWN; + filter->width = 0; + filter->height = 0; +} + +static gboolean +gst_gl_filter_start (GstBaseTransform* bt) +{ + return TRUE; +} + +static gboolean +gst_gl_filter_stop (GstBaseTransform* bt) +{ + GstGLFilter *filter = GST_GL_FILTER (bt); + + gst_gl_filter_reset (filter); + + return TRUE; +} + +static gboolean +gst_gl_filter_get_unit_size (GstBaseTransform* trans, GstCaps* caps, + guint* size) +{ + gboolean ret; + GstVideoFormat video_format; + gint width; + gint height; + + ret = gst_gl_buffer_format_parse_caps (caps, &video_format, &width, &height); + if (ret) + *size = gst_gl_buffer_format_get_size (video_format, width, height); + + return TRUE; +} + +static GstFlowReturn +gst_gl_filter_prepare_output_buffer (GstBaseTransform* trans, + GstBuffer* inbuf, gint size, GstCaps* caps, GstBuffer** buf) +{ + GstGLFilter* filter; + GstGLBuffer* gl_inbuf = GST_GL_BUFFER (inbuf); + GstGLBuffer* gl_outbuf; + + filter = GST_GL_FILTER (trans); + + if (filter->display == NULL) + filter->display = g_object_ref (gl_inbuf->display); + + gl_outbuf = gst_gl_buffer_new_from_video_format (filter->display, + filter->video_format, + filter->width, filter->height, + filter->width, filter->height); + + *buf = GST_BUFFER (gl_outbuf); + gst_buffer_set_caps (*buf, caps); + + g_print ("gstglfilter: gst_gl_filter_prepare_output_buffer\n"); + + return GST_FLOW_OK; +} + +static gboolean +gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps, + GstCaps * outcaps) +{ + GstGLFilter *filter; + gboolean ret; + + filter = GST_GL_FILTER (bt); + + ret = gst_gl_buffer_format_parse_caps (incaps, &filter->video_format, + &filter->width, &filter->height); + + if (!ret) + { + GST_DEBUG ("bad caps"); + return FALSE; + } + + GST_ERROR ("set_caps %d %d", filter->width, filter->height); + + return ret; +} + +static GstFlowReturn +gst_gl_filter_transform (GstBaseTransform * bt, GstBuffer * inbuf, + GstBuffer * outbuf) +{ + GstGLFilter* filter; + GstGLBuffer* gl_inbuf = GST_GL_BUFFER (inbuf); + GstGLBuffer* gl_outbuf = GST_GL_BUFFER (outbuf); + + filter = GST_GL_FILTER (bt); + + g_print ("gstglfilter: gst_gl_filter_transform\n"); + + gst_gl_filter_do_transform (filter, gl_inbuf, gl_outbuf); + + return GST_FLOW_OK; +} + +static gboolean +gst_gl_filter_do_transform (GstGLFilter * filter, + GstGLBuffer * inbuf, GstGLBuffer * outbuf) +{ + GstGLDisplay* display = inbuf->display; + GstGLFilterClass* filter_class = GST_GL_FILTER_GET_CLASS (filter); + + outbuf->texture = inbuf->texture; + + /*unsigned int fbo; + + gst_gl_display_lock (display); + + glGenFramebuffersEXT (1, &fbo); + glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, fbo); + + glFramebufferTexture2DEXT (GL_FRAMEBUFFER_EXT, + GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, outbuf->texture, 0); + + glDrawBuffer (GL_COLOR_ATTACHMENT0_EXT); + glReadBuffer (GL_COLOR_ATTACHMENT0_EXT); + + g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) == + GL_FRAMEBUFFER_COMPLETE_EXT); + + glViewport (0, 0, outbuf->width, outbuf->height); + + glClearColor (0.3, 0.3, 0.3, 1.0); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + + glDisable (GL_CULL_FACE); + glEnableClientState (GL_TEXTURE_COORD_ARRAY); + + glColor4f (1, 1, 1, 1); + + glEnable (GL_TEXTURE_RECTANGLE_ARB); + glActiveTexture (GL_TEXTURE0); + glBindTexture (GL_TEXTURE_RECTANGLE_ARB, inbuf->texture);*/ + + filter_class->filter (filter, inbuf, outbuf); +/* +#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); + 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); + 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 (); +#endif + + glFlush (); + + glDeleteFramebuffersEXT (1, &fbo); + + gst_gl_display_unlock (display);*/ + + return TRUE; +} diff --git a/gst/gl/gstglfilter.h b/gst/gl/gstglfilter.h new file mode 100644 index 0000000000..1549547dc3 --- /dev/null +++ b/gst/gl/gstglfilter.h @@ -0,0 +1,64 @@ +/* + * GStreamer + * Copyright (C) 2008 Julien Isorce + * + * 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 + +#include "gstglbuffer.h" + +#define GST_TYPE_GL_FILTER (gst_gl_filter_get_type()) +#define GST_GL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER,GstGLFilter)) +#define GST_IS_GL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER)) +#define GST_GL_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER,GstGLFilterClass)) +#define GST_IS_GL_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER)) +#define GST_GL_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER,GstGLFilterClass)) +typedef struct _GstGLFilter GstGLFilter; +typedef struct _GstGLFilterClass GstGLFilterClass; + +typedef gboolean (*GstGLFilterProcessFunc) (GstGLFilter *filter, + GstGLBuffer *inbuf, GstGLBuffer *outbuf); + +struct _GstGLFilter +{ + GstBaseTransform base_transform; + + GstPad *srcpad; + GstPad *sinkpad; + + GstGLDisplay *display; + GstVideoFormat video_format; + int width; + int height; +}; + +struct _GstGLFilterClass +{ + GstBaseTransformClass base_transform_class; + GstGLFilterProcessFunc filter; +}; + +GType gst_gl_filter_get_type(void); + +#endif + diff --git a/gst/gl/gstglfiltercube.c b/gst/gl/gstglfiltercube.c new file mode 100644 index 0000000000..fcab2f224b --- /dev/null +++ b/gst/gl/gstglfiltercube.c @@ -0,0 +1,187 @@ +/* + * GStreamer + * Copyright (C) 2008 Julien Isorce + * + * 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 "gstglfiltercube.h" + +#define GST_CAT_DEFAULT gst_gl_filter_cube_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +static const GstElementDetails element_details = + GST_ELEMENT_DETAILS ("OpenGL cube filter", + "Filter/Effect", + "Put input texture on the cube faces", + "Julien Isorce "); + +enum +{ + PROP_0 +}; + +#define DEBUG_INIT(bla) \ + GST_DEBUG_CATEGORY_INIT (gst_gl_filter_cube_debug, "glfiltercube", 0, "glfiltercube element"); + +GST_BOILERPLATE_FULL (GstGLFilterCube, gst_gl_filter_cube, GstGLFilter, + GST_TYPE_GL_FILTER, DEBUG_INIT); + +static void gst_gl_filter_cube_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_gl_filter_cube_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static gboolean gst_gl_filter_cube_filter (GstGLFilter * filter, + GstGLBuffer * inbuf, GstGLBuffer * outbuf); + + +static void +gst_gl_filter_cube_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_set_details (element_class, &element_details); +} + +static void +gst_gl_filter_cube_class_init (GstGLFilterCubeClass * klass) +{ + GObjectClass *gobject_class; + + gobject_class = (GObjectClass *) klass; + gobject_class->set_property = gst_gl_filter_cube_set_property; + gobject_class->get_property = gst_gl_filter_cube_get_property; + + GST_GL_FILTER_CLASS (klass)->filter = gst_gl_filter_cube_filter; +} + +static void +gst_gl_filter_cube_init (GstGLFilterCube * filter, + GstGLFilterCubeClass * klass) +{ +} + +static void +gst_gl_filter_cube_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + //GstGLFilterCube *filter = GST_GL_FILTER_CUBE (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_gl_filter_cube_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + //GstGLFilterCube *filter = GST_GL_FILTER_CUBE (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static gboolean +gst_gl_filter_cube_filter (GstGLFilter * filter, GstGLBuffer * inbuf, + GstGLBuffer * outbuf) +{ + GstGLFilterCube* cube = GST_GL_FILTER_CUBE(filter); + + g_print ("gstglfiltercube: gst_gl_filter_cube_filter\n"); + /*int i, j; + double *vertex_x, *vertex_y; + + 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); + + + + 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); + } + + + +#define N 10 +#define SCALE (1.0/N) +#define NOISE() (0.1*SCALE*g_random_double_range(-1,1)) + vertex_x = malloc (sizeof (double) * (N + 1) * (N + 1)); + vertex_y = malloc (sizeof (double) * (N + 1) * (N + 1)); + for (j = 0; j < N + 1; j++) { + for (i = 0; i < N + 1; i++) { + vertex_x[j * (N + 1) + i] = i * SCALE + NOISE (); + vertex_y[j * (N + 1) + i] = j * SCALE + NOISE (); + } + } + for (j = 0; j < N; j++) { + for (i = 0; i < N; i++) { + glBegin (GL_QUADS); + glNormal3f (0, 0, -1); + glTexCoord2f (i * SCALE, j * SCALE); + glVertex3f (vertex_x[j * (N + 1) + i], vertex_y[j * (N + 1) + i], 0); + glTexCoord2f ((i + 1) * SCALE, j * SCALE); + glVertex3f (vertex_x[j * (N + 1) + (i + 1)], + vertex_y[j * (N + 1) + (i + 1)], 0); + glTexCoord2f ((i + 1) * SCALE, (j + 1) * SCALE); + glVertex3f (vertex_x[(j + 1) * (N + 1) + (i + 1)], + vertex_y[(j + 1) * (N + 1) + (i + 1)], 0); + glTexCoord2f (i * SCALE, (j + 1) * SCALE); + glVertex3f (vertex_x[(j + 1) * (N + 1) + i], + vertex_y[(j + 1) * (N + 1) + i], 0); + glEnd (); + } + } + free (vertex_x); + free (vertex_y); + + + glFlush (); + + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + glMatrixMode (GL_TEXTURE); + glLoadIdentity (); + 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/gstglfiltercube.h b/gst/gl/gstglfiltercube.h new file mode 100644 index 0000000000..37fca0956e --- /dev/null +++ b/gst/gl/gstglfiltercube.h @@ -0,0 +1,52 @@ +/* + * GStreamer + * Copyright (C) 2008 Julien Isorce + * + * 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_FILTERCUBE_H_ +#define _GST_GL_FILTERCUBE_H_ + +#include "gstglfilter.h" + +G_BEGIN_DECLS + +#define GST_TYPE_GL_FILTER_CUBE (gst_gl_filter_cube_get_type()) +#define GST_GL_FILTER_CUBE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_FILTER_CUBE,GstGLFilterCube)) +#define GST_IS_GL_FILTER_CUBE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_FILTER_CUBE)) +#define GST_GL_FILTER_CUBE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_FILTER_CUBE,GstGLFilterCubeClass)) +#define GST_IS_GL_FILTER_CUBE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_FILTER_CUBE)) +#define GST_GL_FILTER_CUBE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_FILTER_CUBE,GstGLFilterCubeClass)) +typedef struct _GstGLFilterCube GstGLFilterCube; +typedef struct _GstGLFilterCubeClass GstGLFilterCubeClass; + +struct _GstGLFilterCube +{ + GstGLFilter filter; + +}; + +struct _GstGLFilterCubeClass +{ + GstGLFilterClass filter_class; +}; + +GType gst_gl_glfiltercube_get_type (void); + +G_END_DECLS + +#endif /* _GST_GLFILTERCUBE_H_ */ diff --git a/gst/gl/gstglgraphicmaker.c b/gst/gl/gstglgraphicmaker.c index 4b4015e305..d487b290f4 100644 --- a/gst/gl/gstglgraphicmaker.c +++ b/gst/gl/gstglgraphicmaker.c @@ -199,7 +199,8 @@ gst_gl_graphicmaker_get_property (GObject* object, guint prop_id, static void gst_gl_graphicmaker_reset (GstGLGraphicmaker* graphicmaker) { - if (graphicmaker->display) { + if (graphicmaker->display) + { g_object_unref (graphicmaker->display); graphicmaker->display = NULL; } @@ -322,7 +323,8 @@ gst_gl_graphicmaker_set_caps (GstBaseTransform* bt, GstCaps* incaps, ret = gst_video_format_parse_caps (incaps, &graphicmaker->video_format, &graphicmaker->width, &graphicmaker->height); - if (!ret) { + if (!ret) + { GST_DEBUG ("bad caps"); return FALSE; } diff --git a/gst/gl/gstglimagesink.c b/gst/gl/gstglimagesink.c index 1b8ec7eead..906ecaa194 100644 --- a/gst/gl/gstglimagesink.c +++ b/gst/gl/gstglimagesink.c @@ -280,55 +280,59 @@ gst_glimage_sink_start (GstBaseSink * bsink) static gboolean gst_glimage_sink_stop (GstBaseSink * bsink) { - GstGLImageSink *glimage_sink; + GstGLImageSink *glimage_sink; - GST_DEBUG ("stop"); + GST_DEBUG ("stop"); - glimage_sink = GST_GLIMAGE_SINK (bsink); + glimage_sink = GST_GLIMAGE_SINK (bsink); - if (glimage_sink->stored_buffer) { - gst_buffer_unref (glimage_sink->stored_buffer); - glimage_sink->stored_buffer = NULL; - } - if (glimage_sink->display) { - gst_gl_display_setVisibleWindow (glimage_sink->display, FALSE); - g_object_unref (glimage_sink->display); - glimage_sink->display = NULL; - } + if (glimage_sink->stored_buffer) + { + gst_buffer_unref (glimage_sink->stored_buffer); + glimage_sink->stored_buffer = NULL; + } + if (glimage_sink->display) + { + gst_gl_display_setVisibleWindow (glimage_sink->display, FALSE); + g_object_unref (glimage_sink->display); + glimage_sink->display = NULL; + } - return TRUE; + return TRUE; } static gboolean gst_glimage_sink_unlock (GstBaseSink * bsink) { - //GstGLImageSink* glimage_sink = GST_GLIMAGE_SINK (bsink); + //GstGLImageSink* glimage_sink = GST_GLIMAGE_SINK (bsink); - GST_DEBUG ("unlock"); + GST_DEBUG ("unlock"); - return TRUE; + return TRUE; } static void gst_glimage_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, GstClockTime * start, GstClockTime * end) { - GstGLImageSink *glimagesink; + GstGLImageSink *glimagesink; - glimagesink = GST_GLIMAGE_SINK (bsink); + glimagesink = GST_GLIMAGE_SINK (bsink); - if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { - *start = GST_BUFFER_TIMESTAMP (buf); - if (GST_BUFFER_DURATION_IS_VALID (buf)) { - *end = *start + GST_BUFFER_DURATION (buf); - } else { - if (glimagesink->fps_n > 0) { - *end = *start + - gst_util_uint64_scale_int (GST_SECOND, glimagesink->fps_d, - glimagesink->fps_n); - } + if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) + { + *start = GST_BUFFER_TIMESTAMP (buf); + if (GST_BUFFER_DURATION_IS_VALID (buf)) + *end = *start + GST_BUFFER_DURATION (buf); + else + { + if (glimagesink->fps_n > 0) { + *end = *start + + gst_util_uint64_scale_int (GST_SECOND, glimagesink->fps_d, + glimagesink->fps_n); + } + } } - } } diff --git a/gst/gl/gstopengl.c b/gst/gl/gstopengl.c index f19fb53650..c588ba26b1 100644 --- a/gst/gl/gstopengl.c +++ b/gst/gl/gstopengl.c @@ -23,6 +23,7 @@ #endif #include "gstglgraphicmaker.h" +#include "gstglfiltercube.h" #include "gstglvideomaker.h" #include "gstglimagesink.h" @@ -34,17 +35,22 @@ static gboolean plugin_init (GstPlugin * plugin) { GST_DEBUG_CATEGORY_INIT (gst_gl_gstgl_debug, "gstopengl", 0, "gstopengl"); - - if (!gst_element_register (plugin, "glvideomaker", - GST_RANK_NONE, GST_TYPE_GL_VIDEOMAKER)) { - return FALSE; - } if (!gst_element_register (plugin, "glgraphicmaker", GST_RANK_NONE, GST_TYPE_GL_GRAPHICMAKER)) { return FALSE; } + if (!gst_element_register (plugin, "glfiltercube", + GST_RANK_NONE, GST_TYPE_GL_FILTER_CUBE)) { + return FALSE; + } + + if (!gst_element_register (plugin, "glvideomaker", + GST_RANK_NONE, GST_TYPE_GL_VIDEOMAKER)) { + return FALSE; + } + if (!gst_element_register (plugin, "glimagesink", GST_RANK_NONE, GST_TYPE_GLIMAGE_SINK)) { return FALSE;