--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstgldisplay.h"
+#include <gst/gst.h>
+
+
+//-------------------------------------------------------------------------------------------
+//--------------------------- TODO ----------------------------------------------------------
+// - send EOS when the user click on the window cross
+//-------------------------------------------------------------------------------------------
+
+
+//------------------------------------------------------------
+//-------------------- Private déclarations ------------------
+//------------------------------------------------------------
+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_glutDestroyWindow (GstGLDisplay* display);
+static void gst_gl_display_glutSetVisibleWindow (GstGLDisplay* display);
+static void gst_gl_display_glutPrepareTexture (GstGLDisplay* display);
+static void gst_gl_display_glutUpdateTexture (GstGLDisplay* display);
+static void gst_gl_display_glutCleanTexture (GstGLDisplay* display);
+static void gst_gl_display_glutUpdateVideo (GstGLDisplay* display);
+static void gst_gl_display_glutPostRedisplay (GstGLDisplay* display);
+static void gst_gl_display_glut_idle (void);
+static void gst_gl_display_glutDispatchAction (GstGLDisplayMsg *msg);
+static gboolean gst_gl_display_checkMsgValidity (GstGLDisplayMsg *msg);
+void gst_gl_display_lock (GstGLDisplay* display);
+void gst_gl_display_unlock (GstGLDisplay* display);
+void gst_gl_display_postMessage (GstGLDisplayAction action, GstGLDisplay* display);
+void gst_gl_display_onReshape(gint width, gint height);
+void gst_gl_display_draw (void);
+void gst_gl_display_onClose (void);
+void gst_gl_display_make_texture (GstGLDisplay* display);
+void gst_gl_display_fill_texture (GstGLDisplay* display);
+void gst_gl_display_draw_texture (GstGLDisplay* display);
+void gst_gl_display_draw_graphic (GstGLDisplay* display);
+void gst_gl_display_fill_video (GstGLDisplay* display);
+GLhandleARB gst_gl_display_loadGLSLprogram (gchar* textFProgram);
+void checkFramebufferStatus(void);
+GST_BOILERPLATE (GstGLDisplay, gst_gl_display, GObject, G_TYPE_OBJECT);
+
+
+//------------------------------------------------------------
+//-------------------- Glut context management ---------------
+//------------------------------------------------------------
+
+//(key=int glutWinId) and (value=GstGLDisplay *display)
+static GHashTable *gst_gl_display_map = NULL;
+
+//all glut functions and opengl primitives are called in this thread
+static GThread *gst_gl_display_glutThread = NULL;
+
+//-timepoped by glutIdleFunc
+static GAsyncQueue *gst_gl_display_messageQueue = NULL;
+
+
+//------------------------------------------------------------
+//---------------------- For klass GstGLDisplay ---------------
+//------------------------------------------------------------
+
+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->mutex = g_mutex_new ();
+ display->texturePool = g_queue_new ();
+ display->cond_make = g_cond_new ();
+ display->cond_fill = g_cond_new ();
+ display->cond_clear = g_cond_new ();
+ display->cond_video = g_cond_new ();
+ display->cond_create = g_cond_new ();
+ display->cond_destroy = g_cond_new ();
+
+ display->fbo = 0;
+ display->depthBuffer = 0;
+ display->textureFBO = 0;
+ display->textureFBOWidth = 0;
+ display->textureFBOHeight = 0;
+
+ display->graphicFBO = 0;
+ display->graphicDepthBuffer = 0;
+ display->graphicTexture = 0;
+
+ display->requestedTexture = 0;
+ display->requestedTexture_u = 0;
+ display->requestedTexture_v = 0;
+ display->requestedVideo_format = 0;
+ display->requestedTextureWidth = 0;
+ display->requestedTextureHeight = 0;
+
+ display->candidateTexture = 0;
+ display->candidateTexture_u = 0;
+ display->candidateTexture_v = 0;
+ display->candidateVideo_format = 0;
+ display->candidateTextureWidth = 0;
+ display->candidateTextureHeight = 0;
+ display->candidateData = NULL;
+
+ display->currentTexture = 0;
+ display->currentTexture_u = 0;
+ display->currentTexture_v = 0;
+ display->currentVideo_format = 0;
+ display->currentTextureWidth = 0;
+ display->currentTextureHeight = 0;
+
+ display->textureTrash = 0;
+ display->textureTrash_u = 0;
+ display->textureTrash_v = 0;
+
+ display->videoFBO = 0;
+ display->videoDepthBuffer = 0;
+ display->videoTexture = 0;
+ display->videoTexture_u = 0;
+ display->videoTexture_v = 0;
+ display->outputWidth = 0;
+ display->outputHeight = 0;
+ display->outputVideo_format = 0;
+ display->outputData = NULL;
+
+ display->glutWinId = -1;
+ display->winId = 0;
+ display->win_xpos = 0;
+ display->win_ypos = 0;
+ display->glcontext_width = 0;
+ display->glcontext_height = 0;
+ display->visible = FALSE;
+ display->clientReshapeCallback = NULL;
+ display->clientDrawCallback = NULL;
+ display->title = g_string_new ("OpenGL renderer ");
+
+ display->GLSLProgram_YUY2 = 0;
+ display->GLSLProgram_UYVY = 0;
+ display->GLSLProgram_I420_YV12 = 0;
+ display->GLSLProgram_AYUV = 0;
+
+ display->GLSLProgram_to_YUY2 = 0;
+ display->GLSLProgram_to_UYVY = 0;
+ display->GLSLProgram_to_I420_YV12 = 0;
+ display->GLSLProgram_to_AYUV = 0;
+
+ //YUY2:r,g,a
+ //UYVY:a,b,r
+ display->textFProgram_YUY2_UYVY =
+ "uniform sampler2DRect Ytex, UVtex;\n"
+ "void main(void) {\n"
+ " float fx, fy, y, u, v, r, g, b;\n"
+ " fx = gl_TexCoord[0].x;\n"
+ " fy = gl_TexCoord[0].y;\n"
+ " y = texture2DRect(Ytex,vec2(fx,fy)).%c;\n"
+ " u = texture2DRect(UVtex,vec2(fx*0.5,fy)).%c;\n"
+ " v = texture2DRect(UVtex,vec2(fx*0.5,fy)).%c;\n"
+ " y=1.164*(y-0.0627);\n"
+ " u=u-0.5;\n"
+ " v=v-0.5;\n"
+ " r = y+1.5958*v;\n"
+ " g = y-0.39173*u-0.81290*v;\n"
+ " b = y+2.017*u;\n"
+ " gl_FragColor = vec4(r, g, b, 1.0);\n"
+ "}\n";
+
+ display->textFProgram_I420_YV12 =
+ "uniform sampler2DRect Ytex,Utex,Vtex;\n"
+ "void main(void) {\n"
+ " float r,g,b,y,u,v;\n"
+ " vec2 nxy=gl_TexCoord[0].xy;\n"
+ " y=texture2DRect(Ytex,nxy*0.5).r;\n"
+ " u=texture2DRect(Utex,nxy).r;\n"
+ " v=texture2DRect(Vtex,nxy*0.5).r;\n"
+ " y=1.1643*(y-0.0625);\n"
+ " u=u-0.5;\n"
+ " v=v-0.5;\n"
+ " r=y+1.5958*v;\n"
+ " g=y-0.39173*u-0.81290*v;\n"
+ " b=y+2.017*u;\n"
+ " gl_FragColor=vec4(r,g,b,1.0);\n"
+ "}\n";
+
+ display->textFProgram_AYUV =
+ "uniform sampler2DRect tex;\n"
+ "void main(void) {\n"
+ " float r,g,b,y,u,v;\n"
+ " vec2 nxy=gl_TexCoord[0].xy;\n"
+ " y=texture2DRect(tex,nxy).r;\n"
+ " u=texture2DRect(tex,nxy).g;\n"
+ " v=texture2DRect(tex,nxy).b;\n"
+ " y=1.1643*(y-0.0625);\n"
+ " u=u-0.5;\n"
+ " v=v-0.5;\n"
+ " r=y+1.5958*v;\n"
+ " g=y-0.39173*u-0.81290*v;\n"
+ " b=y+2.017*u;\n"
+ " gl_FragColor=vec4(r,g,b,1.0);\n"
+ "}\n";
+
+ //YUY2:y2,u,y1,v
+ //UYVY:v,y1,u,y2
+ display->textFProgram_to_YUY2_UYVY =
+ "uniform sampler2DRect tex;\n"
+ "void main(void) {\n"
+ " float fx,fy,r,g,b,r2,g2,b2,y1,y2,u,v;\n"
+ " fx = gl_TexCoord[0].x;\n"
+ " fy = gl_TexCoord[0].y;\n"
+ " r=texture2DRect(tex,vec2(fx*2.0,fy)).r;\n"
+ " g=texture2DRect(tex,vec2(fx*2.0,fy)).g;\n"
+ " b=texture2DRect(tex,vec2(fx*2.0,fy)).b;\n"
+ " r2=texture2DRect(tex,vec2(fx*2.0+1.0,fy)).r;\n"
+ " g2=texture2DRect(tex,vec2(fx*2.0+1.0,fy)).g;\n"
+ " b2=texture2DRect(tex,vec2(fx*2.0+1.0,fy)).b;\n"
+ " y1=0.299011*r + 0.586987*g + 0.114001*b;\n"
+ " y2=0.299011*r2 + 0.586987*g2 + 0.114001*b2;\n"
+ " u=-0.148246*r -0.29102*g + 0.439266*b;\n"
+ " v=0.439271*r - 0.367833*g - 0.071438*b ;\n"
+ " y1=0.858885*y1 + 0.0625;\n"
+ " y2=0.858885*y2 + 0.0625;\n"
+ " u=u + 0.5;\n"
+ " v=v + 0.5;\n"
+ " gl_FragColor=vec4(%s);\n"
+ "}\n";
+
+ display->textFProgram_to_I420_YV12 =
+ "uniform sampler2DRect tex;\n"
+ "uniform float w, h;\n"
+ "void main(void) {\n"
+ " float r,g,b,r2,b2,g2,y,u,v;\n"
+ " vec2 nxy=gl_TexCoord[0].xy;\n"
+ " vec2 nxy2=mod(2.0*nxy, vec2(w, h));\n"
+ " r=texture2DRect(tex,nxy).r;\n"
+ " g=texture2DRect(tex,nxy).g;\n"
+ " b=texture2DRect(tex,nxy).b;\n"
+ " r2=texture2DRect(tex,nxy2).r;\n"
+ " g2=texture2DRect(tex,nxy2).g;\n"
+ " b2=texture2DRect(tex,nxy2).b;\n"
+ " y=0.299011*r + 0.586987*g + 0.114001*b;\n"
+ " u=-0.148246*r2 -0.29102*g2 + 0.439266*b2;\n"
+ " v=0.439271*r2 - 0.367833*g2 - 0.071438*b2 ;\n"
+ " y=0.858885*y + 0.0625;\n"
+ " u=u + 0.5;\n"
+ " v=v + 0.5;\n"
+ " gl_FragData[0] = vec4(y, 0.0, 0.0, 1.0);\n"
+ " gl_FragData[1] = vec4(u, 0.0, 0.0, 1.0);\n"
+ " gl_FragData[2] = vec4(v, 0.0, 0.0, 1.0);\n"
+ "}\n";
+
+ display->textFProgram_to_AYUV =
+ "uniform sampler2DRect tex;\n"
+ "void main(void) {\n"
+ " float r,g,b,y,u,v;\n"
+ " vec2 nxy=gl_TexCoord[0].xy;\n"
+ " r=texture2DRect(tex,nxy).r;\n"
+ " g=texture2DRect(tex,nxy).g;\n"
+ " b=texture2DRect(tex,nxy).b;\n"
+ " y=0.299011*r + 0.586987*g + 0.114001*b;\n"
+ " u=-0.148246*r -0.29102*g + 0.439266*b;\n"
+ " v=0.439271*r - 0.367833*g - 0.071438*b ;\n"
+ " y=0.858885*y + 0.0625;\n"
+ " u=u + 0.5;\n"
+ " v=v + 0.5;\n"
+ " gl_FragColor=vec4(y,u,v,1.0);\n"
+ "}\n";
+}
+
+static void
+gst_gl_display_finalize (GObject *object)
+{
+ GstGLDisplay *display = GST_GL_DISPLAY (object);
+
+ //request glut window destruction
+ //blocking call because display must be alive
+ gst_gl_display_lock (display);
+ gst_gl_display_postMessage (GST_GL_DISPLAY_ACTION_DESTROY, display);
+ g_cond_wait (display->cond_destroy, display->mutex);
+ gst_gl_display_unlock (display);
+
+ if (display->texturePool) {
+ g_queue_free (display->texturePool);
+ display->texturePool = NULL;
+ }
+
+ if (display->title) {
+ g_string_free (display->title, TRUE);
+ display->title = NULL;
+ }
+ if (display->mutex) {
+ g_mutex_free (display->mutex);
+ display->mutex = NULL;
+ }
+ if (display->cond_make) {
+ g_cond_free (display->cond_make);
+ display->cond_make = NULL;
+ }
+ if (display->cond_fill) {
+ g_cond_free (display->cond_fill);
+ display->cond_fill = NULL;
+ }
+ if (display->cond_clear) {
+ g_cond_free (display->cond_clear);
+ display->cond_clear = NULL;
+ }
+ if (display->cond_video) {
+ g_cond_free (display->cond_video);
+ display->cond_video = NULL;
+ }
+ if (display->cond_create) {
+ g_cond_free (display->cond_create);
+ display->cond_create = NULL;
+ }
+ if (display->cond_destroy) {
+ g_cond_free (display->cond_destroy);
+ display->cond_destroy = NULL;
+ }
+ if (display->clientReshapeCallback)
+ display->clientReshapeCallback = NULL;
+ if (display->clientDrawCallback)
+ display->clientDrawCallback = NULL;
+
+ //at this step, the next condition imply that the last display has been pushed
+ if (g_hash_table_size (gst_gl_display_map) == 0)
+ {
+ g_thread_join (gst_gl_display_glutThread);
+ 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);
+ }
+}
+
+
+/* The glut thread handles glut events and GstGLDisplayMsg messages */
+static gpointer
+gst_gl_display_glutThreadFunc (GstGLDisplay *display)
+{
+ static char *argv = "gst-launch-0.10.exe";
+ static gint argc = 1;
+
+ glutInit(&argc, &argv);
+ glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
+
+ glutIdleFunc (gst_gl_display_glut_idle);
+
+ gst_gl_display_lock (display);
+ gst_gl_display_glutCreateWindow (display);
+ gst_gl_display_unlock (display);
+
+ g_print ("Glut mainLoop start\n");
+ glutMainLoop ();
+ g_print ("Glut mainLoop exited\n");
+
+ return NULL;
+}
+
+
+/* Called by the idle function or when creating glut_thread */
+static void
+gst_gl_display_glutCreateWindow (GstGLDisplay *display)
+{
+ gint glutWinId = 0;
+ GList *keys = NULL;
+ gchar buffer[5];
+ GLenum err = 0;
+
+ //prepare opengl context
+ glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
+ glutInitWindowPosition(display->win_xpos, display->win_ypos);
+ glutInitWindowSize(display->glcontext_width, display->glcontext_height);
+
+ //create opengl context
+ sprintf_s(buffer, 5, "%d", glutWinId);
+ display->title = g_string_append (display->title, buffer);
+ glutWinId = glutCreateWindow (display->title->str, display->winId);
+
+ if (display->visible)
+ glutShowWindow ();
+ else
+ glutHideWindow ();
+
+ //Init glew
+ err = glewInit();
+ if (err != GLEW_OK)
+ g_print ("Error: %s\n", glewGetErrorString(err));
+ else
+ g_print ("Context %d, Using GLEW %s\n", glutWinId, glewGetString(GLEW_VERSION));
+
+ if (GLEW_EXT_framebuffer_object)
+ {
+ g_print ("Context %d, EXT_framebuffer_object supported: yes\n", glutWinId);
+
+ //-- init intput frame buffer object (video -> GL)
+
+ //setup FBO
+ glGenFramebuffersEXT (1, &display->fbo);
+ glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->fbo);
+
+ //setup the render buffer for depth
+ glGenRenderbuffersEXT(1, &display->depthBuffer);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, display->depthBuffer);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
+ display->textureFBOWidth, display->textureFBOHeight);
+
+ //setup a texture to render to
+ glGenTextures (1, &display->textureFBO);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, display->textureFBO);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
+ display->textureFBOWidth, display->textureFBOHeight, 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->textureFBO, 0);
+
+ //attach the depth render buffer to the FBO
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, display->depthBuffer);
+
+ g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) ==
+ GL_FRAMEBUFFER_COMPLETE_EXT);
+
+ //unbind the FBO
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+ //-- init graphic frame buffer object (GL texture -> GL scene)
+
+ //setup FBO
+ glGenFramebuffersEXT (1, &display->graphicFBO);
+ glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->graphicFBO);
+
+ //setup the render buffer for depth
+ glGenRenderbuffersEXT(1, &display->graphicDepthBuffer);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, display->graphicDepthBuffer);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
+ display->glcontext_width, display->glcontext_height);
+
+ //setup a texture to render to
+ glGenTextures (1, &display->graphicTexture);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, display->graphicTexture);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
+ display->glcontext_width, display->glcontext_height, 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->graphicTexture, 0);
+
+ //attach the depth render buffer to the FBO
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, display->graphicDepthBuffer);
+
+ g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) ==
+ GL_FRAMEBUFFER_COMPLETE_EXT);
+
+ //unbind the FBO
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+ //-- init output frame buffer object (GL -> video)
+
+ display->outputWidth = display->glcontext_width;
+ display->outputHeight = display->glcontext_height;
+
+ //setup FBO
+ glGenFramebuffersEXT (1, &display->videoFBO);
+ glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, display->videoFBO);
+
+ //setup the render buffer for depth
+ glGenRenderbuffersEXT(1, &display->videoDepthBuffer);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, display->videoDepthBuffer);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT,
+ display->outputWidth, display->outputHeight);
+
+ //setup a first texture to render to
+ glGenTextures (1, &display->videoTexture);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, display->videoTexture);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
+ display->outputWidth, display->outputHeight, 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 first texture to the FBO to renderer to
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_RECTANGLE_ARB, display->videoTexture, 0);
+
+ //setup a second texture to render to
+ glGenTextures (1, &display->videoTexture_u);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, display->videoTexture_u);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
+ display->outputWidth, display->outputHeight, 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 second texture to the FBO to renderer to
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT,
+ GL_TEXTURE_RECTANGLE_ARB, display->videoTexture_u, 0);
+
+ //setup a third texture to render to
+ glGenTextures (1, &display->videoTexture_v);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, display->videoTexture_v);
+ glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
+ display->outputWidth, display->outputHeight, 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 third texture to the FBO to renderer to
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT2_EXT,
+ GL_TEXTURE_RECTANGLE_ARB, display->videoTexture_v, 0);
+
+ //attach the depth render buffer to the FBO
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
+ GL_RENDERBUFFER_EXT, display->videoDepthBuffer);
+
+ checkFramebufferStatus();
+
+ g_assert (glCheckFramebufferStatusEXT (GL_FRAMEBUFFER_EXT) ==
+ GL_FRAMEBUFFER_COMPLETE_EXT);
+
+ //unbind the FBO
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+ display->multipleRT[0] = GL_COLOR_ATTACHMENT0_EXT;
+ display->multipleRT[1] = GL_COLOR_ATTACHMENT1_EXT;
+ display->multipleRT[2] = GL_COLOR_ATTACHMENT2_EXT;
+
+ }
+ else
+ {
+ g_print ("Context %d, EXT_framebuffer_object supported: no\n", glutWinId);
+ g_assert_not_reached ();
+ }
+
+ //check if fragment program is available, then load them
+ if (GLEW_ARB_vertex_program)
+ {
+ gchar program[2048];
+
+ g_print ("Context %d, ARB_fragment_program supported: yes\n", glutWinId);
+
+ //from video to texture
+
+ sprintf_s (program, 2048, display->textFProgram_YUY2_UYVY, 'r', 'g', 'a');
+ display->GLSLProgram_YUY2 = gst_gl_display_loadGLSLprogram (program);
+
+ sprintf_s (program, 2048, display->textFProgram_YUY2_UYVY, 'a', 'b', 'r');
+ display->GLSLProgram_UYVY = gst_gl_display_loadGLSLprogram (program);
+
+ display->GLSLProgram_I420_YV12 = gst_gl_display_loadGLSLprogram (display->textFProgram_I420_YV12);
+
+ display->GLSLProgram_AYUV = gst_gl_display_loadGLSLprogram (display->textFProgram_AYUV);
+
+ //from texture to video
+
+ sprintf_s (program, 2048, display->textFProgram_to_YUY2_UYVY, "y2,u,y1,v");
+ display->GLSLProgram_to_YUY2 = gst_gl_display_loadGLSLprogram (program);
+
+ sprintf_s (program, 2048, display->textFProgram_to_YUY2_UYVY, "v,y1,u,y2");
+ display->GLSLProgram_to_UYVY = gst_gl_display_loadGLSLprogram (program);
+
+ display->GLSLProgram_to_I420_YV12 = gst_gl_display_loadGLSLprogram (display->textFProgram_to_I420_YV12);
+
+ display->GLSLProgram_to_AYUV = gst_gl_display_loadGLSLprogram (display->textFProgram_to_AYUV);
+ }
+ else
+ {
+ g_print ("Context %d, ARB_fragment_program supported: no\n", glutWinId);
+ g_assert_not_reached ();
+ }
+
+ //setup callbacks
+ glutReshapeFunc (gst_gl_display_onReshape);
+ glutDisplayFunc (gst_gl_display_draw);
+ glutCloseFunc (gst_gl_display_onClose);
+
+ //insert glut context to the map
+ display->glutWinId = glutWinId;
+ g_hash_table_insert (gst_gl_display_map, glutWinId, display);
+
+ //check glut id validity
+ g_assert (glutGetWindow() == glutWinId);
+ g_print ("Context %d initialized\n", display->glutWinId);
+
+ //release display constructor
+ g_cond_signal (display->cond_create);
+}
+
+
+/* Called by the idle function */
+static void
+gst_gl_display_glutDestroyWindow (GstGLDisplay *display)
+{
+ glutSetWindow (display->glutWinId);
+ glutReshapeFunc (NULL);
+ glutDestroyWindow (display->glutWinId);
+ glUseProgramObjectARB (0);
+
+ glDeleteObjectARB (display->GLSLProgram_YUY2);
+ glDeleteObjectARB (display->GLSLProgram_UYVY);
+ glDeleteObjectARB (display->GLSLProgram_I420_YV12);
+ glDeleteObjectARB (display->GLSLProgram_AYUV);
+
+ glDeleteObjectARB (display->GLSLProgram_to_YUY2);
+ glDeleteObjectARB (display->GLSLProgram_to_UYVY);
+ glDeleteObjectARB (display->GLSLProgram_to_I420_YV12);
+ glDeleteObjectARB (display->GLSLProgram_to_AYUV);
+
+ glDeleteFramebuffersEXT (1, &display->fbo);
+ glDeleteRenderbuffersEXT(1, &display->depthBuffer);
+ glDeleteTextures (1, &display->textureFBO);
+
+ glDeleteFramebuffersEXT (1, &display->graphicFBO);
+ glDeleteRenderbuffersEXT(1, &display->graphicDepthBuffer);
+ glDeleteTextures (1, &display->graphicTexture);
+
+ glDeleteFramebuffersEXT (1, &display->videoFBO);
+ glDeleteRenderbuffersEXT(1, &display->videoDepthBuffer);
+ glDeleteTextures (1, &display->videoTexture);
+ glDeleteTextures (1, &display->videoTexture_u);
+ glDeleteTextures (1, &display->videoTexture_v);
+
+ //clean up the texture pool
+ while (g_queue_get_length (display->texturePool))
+ {
+ GstGLDisplayTex* tex = g_queue_pop_head (display->texturePool);
+
+ //delete textures
+ glDeleteTextures (1, &tex->texture);
+ if (tex->texture_u) {
+ glDeleteTextures (1, &tex->texture_u);
+ }
+ if (tex->texture_v) {
+ glDeleteTextures (1, &tex->texture_v);
+ }
+ }
+
+ g_hash_table_remove (gst_gl_display_map, 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)
+ glutLeaveMainLoop ();
+
+ //release display destructor
+ g_cond_signal (display->cond_destroy);
+}
+
+
+/* Called by the idle function */
+static void
+gst_gl_display_glutSetVisibleWindow (GstGLDisplay *display)
+{
+ glutSetWindow (display->glutWinId);
+ if (display->visible)
+ glutShowWindow ();
+ else
+ glutHideWindow ();
+}
+
+
+/* Called by the idle function */
+static void
+gst_gl_display_glutPrepareTexture (GstGLDisplay * display)
+{
+ glutSetWindow (display->glutWinId);
+ gst_gl_display_make_texture (display);
+ g_cond_signal (display->cond_make);
+}
+
+
+/* Called by the idle function */
+static void
+gst_gl_display_glutUpdateTexture (GstGLDisplay * display)
+{
+ glutSetWindow (display->glutWinId);
+ gst_gl_display_fill_texture (display);
+ gst_gl_display_draw_texture (display);
+ g_cond_signal (display->cond_fill);
+}
+
+
+/* Called by the idle function */
+static void
+gst_gl_display_glutCleanTexture (GstGLDisplay * display)
+{
+ GstGLDisplayTex* tex = NULL;
+
+ glutSetWindow (display->glutWinId);
+
+ //contructuct a texture pool element
+ tex = g_new0 (GstGLDisplayTex, 1);
+ tex->texture = display->textureTrash;
+ tex->texture_u = display->textureTrash_u;
+ tex->texture_v = display->textureTrash_v;
+
+ display->textureTrash = 0;
+ display->textureTrash_u = 0;
+ display->textureTrash_v = 0;
+
+ //add tex to the pool, it makes texture allocation reusable
+ g_queue_push_tail (display->texturePool, tex);
+
+ g_cond_signal (display->cond_clear);
+}
+
+
+/* Called by the idle function */
+static void
+gst_gl_display_glutUpdateVideo (GstGLDisplay * display)
+{
+ glutSetWindow (display->glutWinId);
+ gst_gl_display_draw_graphic (display);
+ gst_gl_display_fill_video (display);
+ g_cond_signal (display->cond_video);
+}
+
+
+/* Called by the idle function */
+static void
+gst_gl_display_glutPostRedisplay (GstGLDisplay * display)
+{
+ glutSetWindow (display->glutWinId);
+ glutPostRedisplay ();
+}
+
+
+/* Called continuously from freeglut while no events are pending */
+static void
+gst_gl_display_glut_idle (void)
+{
+ GTimeVal timeout;
+ GstGLDisplayMsg *msg;
+
+ //check for pending actions that require a glut context
+ g_get_current_time (&timeout);
+ g_time_val_add (&timeout, 1000000L); //timeout 1 sec
+ msg = g_async_queue_timed_pop (gst_gl_display_messageQueue, &timeout);
+ if (msg)
+ {
+ if (gst_gl_display_checkMsgValidity (msg))
+ gst_gl_display_glutDispatchAction (msg);
+ while (g_async_queue_length (gst_gl_display_messageQueue))
+ {
+ msg = g_async_queue_pop (gst_gl_display_messageQueue);
+ if (gst_gl_display_checkMsgValidity (msg))
+ gst_gl_display_glutDispatchAction (msg);
+ }
+ }
+ else g_print ("timeout reached in idle func\n");
+}
+
+
+/* Called by the glut idle function */
+static void
+gst_gl_display_glutDispatchAction (GstGLDisplayMsg* msg)
+{
+ gst_gl_display_lock (msg->display);
+ switch (msg->action)
+ {
+ case GST_GL_DISPLAY_ACTION_CREATE:
+ gst_gl_display_glutCreateWindow (msg->display);
+ break;
+ case GST_GL_DISPLAY_ACTION_DESTROY:
+ gst_gl_display_glutDestroyWindow (msg->display);
+ break;
+ case GST_GL_DISPLAY_ACTION_VISIBLE:
+ gst_gl_display_glutSetVisibleWindow (msg->display);
+ break;
+ case GST_GL_DISPLAY_ACTION_PREPARE:
+ gst_gl_display_glutPrepareTexture (msg->display);
+ break;
+ case GST_GL_DISPLAY_ACTION_CHANGE:
+ gst_gl_display_glutUpdateTexture (msg->display);
+ break;
+ case GST_GL_DISPLAY_ACTION_CLEAR:
+ gst_gl_display_glutCleanTexture (msg->display);
+ break;
+ case GST_GL_DISPLAY_ACTION_VIDEO:
+ gst_gl_display_glutUpdateVideo (msg->display);
+ break;
+ case GST_GL_DISPLAY_ACTION_REDISPLAY:
+ gst_gl_display_glutPostRedisplay (msg->display);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ gst_gl_display_unlock (msg->display);
+ g_free (msg);
+}
+
+
+/* Return false if the message is out of date */
+static gboolean
+gst_gl_display_checkMsgValidity (GstGLDisplayMsg *msg)
+{
+ gboolean valid = TRUE;
+
+ switch (msg->action)
+ {
+ case GST_GL_DISPLAY_ACTION_CREATE:
+ valid = TRUE;
+ break;
+ case GST_GL_DISPLAY_ACTION_DESTROY:
+ case GST_GL_DISPLAY_ACTION_VISIBLE:
+ case GST_GL_DISPLAY_ACTION_PREPARE:
+ case GST_GL_DISPLAY_ACTION_CHANGE:
+ case GST_GL_DISPLAY_ACTION_CLEAR:
+ case GST_GL_DISPLAY_ACTION_VIDEO:
+ case GST_GL_DISPLAY_ACTION_REDISPLAY:
+ //msg is out of date if the associated display is not in the map
+ if (!g_hash_table_lookup (gst_gl_display_map, msg->glutWinId))
+ valid = FALSE;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ return valid;
+}
+
+
+//------------------------------------------------------------
+//---------------------- For each GstGLDisplay ---------------
+//------------------------------------------------------------
+
+GstGLDisplay *
+gst_gl_display_new (void)
+{
+ return g_object_new (GST_TYPE_GL_DISPLAY, NULL);
+}
+
+/* Init an opengl context */
+void
+gst_gl_display_initGLContext (GstGLDisplay *display,
+ GLint x, GLint y,
+ GLint graphic_width, GLint graphic_height,
+ GLint video_width, GLint video_height,
+ gulong winId,
+ gboolean visible)
+{
+ gst_gl_display_lock (display);
+
+ display->winId = winId;
+ display->win_xpos = x;
+ display->win_ypos = y;
+ display->glcontext_width = graphic_width;
+ display->glcontext_height = graphic_height;
+ display->textureFBOWidth = video_width;
+ display->textureFBOHeight = video_height;
+ display->visible = visible;
+
+ //if no glut_thread exists, create it with a window associated to the display
+ if (!gst_gl_display_map)
+ {
+ gst_gl_display_messageQueue = g_async_queue_new ();
+ gst_gl_display_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+ gst_gl_display_glutThread = g_thread_create (
+ (GThreadFunc) gst_gl_display_glutThreadFunc, display, TRUE, NULL);
+ g_cond_wait (display->cond_create, display->mutex);
+ }
+ //request glut window creation
+ else
+ {
+ //blocking call because glut context must be alive
+ gst_gl_display_postMessage (GST_GL_DISPLAY_ACTION_CREATE, display);
+ g_cond_wait (display->cond_create, display->mutex);
+ }
+ gst_gl_display_unlock (display);
+}
+
+
+void
+gst_gl_display_lock (GstGLDisplay * display)
+{
+ g_mutex_lock (display->mutex);
+}
+
+
+void
+gst_gl_display_unlock (GstGLDisplay * display)
+{
+ g_mutex_unlock (display->mutex);
+}
+
+
+/* Post a message that will be handled by the idle function */
+void
+gst_gl_display_postMessage (GstGLDisplayAction action, GstGLDisplay* display)
+{
+ GstGLDisplayMsg* msg = g_new0 (GstGLDisplayMsg, 1);
+ msg->action = action;
+ msg->glutWinId = display->glutWinId;
+ msg->display = display;
+ g_async_queue_push (gst_gl_display_messageQueue, msg);
+}
+
+
+/* Called by gst_gl elements */
+void
+gst_gl_display_setClientReshapeCallback (GstGLDisplay * display, CRCB cb)
+{
+ gst_gl_display_lock (display);
+ display->clientReshapeCallback = cb;
+ gst_gl_display_unlock (display);
+}
+
+
+/* Called by gst_gl elements */
+void
+gst_gl_display_setClientDrawCallback (GstGLDisplay * display, CDCB cb)
+{
+ gst_gl_display_lock (display);
+ display->clientDrawCallback = cb;
+ gst_gl_display_unlock (display);
+}
+
+
+/* Called by gst gl elements */
+void
+gst_gl_display_setVisibleWindow (GstGLDisplay * display, gboolean visible)
+{
+ gst_gl_display_lock (display);
+ if (display->visible != visible)
+ {
+ display->visible = visible;
+ gst_gl_display_postMessage (GST_GL_DISPLAY_ACTION_VISIBLE, display);
+ }
+ gst_gl_display_unlock (display);
+}
+
+
+/* Called by gstglbuffer */
+void
+gst_gl_display_textureRequested (GstGLDisplay * display, GstVideoFormat video_format,
+ gint width, gint height, guint *texture,
+ guint *texture_u, guint *texture_v)
+{
+ gst_gl_display_lock (display);
+ display->requestedVideo_format = video_format;
+ display->requestedTextureWidth = width;
+ display->requestedTextureHeight = height;
+ gst_gl_display_postMessage (GST_GL_DISPLAY_ACTION_PREPARE, display);
+ g_cond_wait (display->cond_make, display->mutex);
+ *texture = display->requestedTexture;
+ *texture_u = display->requestedTexture_u;
+ *texture_v = display->requestedTexture_v;
+ gst_gl_display_unlock (display);
+}
+
+
+/* Called by gst_gl elements */
+void
+gst_gl_display_textureChanged (GstGLDisplay * display, GstVideoFormat video_format,
+ GLuint texture, GLuint texture_u, GLuint texture_v,
+ gint width, gint height, gpointer data)
+{
+ gst_gl_display_lock (display);
+ display->candidateTexture = texture;
+ display->candidateTexture_u = texture_u;
+ display->candidateTexture_v = texture_v;
+ display->candidateVideo_format = video_format;
+ display->candidateTextureWidth = width;
+ display->candidateTextureHeight = height;
+ display->candidateData = data;
+ gst_gl_display_postMessage (GST_GL_DISPLAY_ACTION_CHANGE, display);
+ g_cond_wait (display->cond_fill, display->mutex);
+ gst_gl_display_unlock (display);
+}
+
+
+/* Called by gstglbuffer */
+void
+gst_gl_display_clearTexture (GstGLDisplay * display, guint texture,
+ guint texture_u, guint texture_v)
+{
+ gst_gl_display_lock (display);
+ display->textureTrash = texture;
+ display->textureTrash_u = texture_u;
+ display->textureTrash_v = texture_v;
+ gst_gl_display_postMessage (GST_GL_DISPLAY_ACTION_CLEAR, display);
+ g_cond_wait (display->cond_clear, display->mutex);
+ gst_gl_display_unlock (display);
+}
+
+
+/* Called by gst_gl elements */
+void
+gst_gl_display_videoChanged (GstGLDisplay* display, GstVideoFormat video_format,
+ gpointer data)
+{
+ gst_gl_display_lock (display);
+ //data size is aocciated to the glcontext size
+ display->outputVideo_format = video_format;
+ display->outputData = data;
+ gst_gl_display_postMessage (GST_GL_DISPLAY_ACTION_VIDEO, display);
+ g_cond_wait (display->cond_video, display->mutex);
+ gst_gl_display_unlock (display);
+}
+
+
+/* Called by gst_gl elements */
+void
+gst_gl_display_postRedisplay (GstGLDisplay* display)
+{
+ gst_gl_display_lock (display);
+ gst_gl_display_postMessage (GST_GL_DISPLAY_ACTION_REDISPLAY, display);
+ gst_gl_display_unlock (display);
+}
+
+
+/* Called by gst_gl elements */
+void
+gst_gl_display_set_windowId (GstGLDisplay* display, gulong winId)
+{
+ static gint glheight = 0;
+
+ //g_print ("Display::gst_gl_display_set_windowId\n");
+
+ gst_gl_display_lock (display);
+ gst_gl_display_postMessage (GST_GL_DISPLAY_ACTION_DESTROY, display);
+ g_cond_wait (display->cond_destroy, display->mutex);
+ gst_gl_display_unlock (display);
+
+ if (g_hash_table_size (gst_gl_display_map) == 0)
+ {
+ g_thread_join (gst_gl_display_glutThread);
+ 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);
+ gst_gl_display_map = NULL;
+ }
+
+ //init opengl context
+ gst_gl_display_initGLContext (display,
+ 50, glheight++ * (display->glcontext_height+50) + 50,
+ display->glcontext_width, display->glcontext_height,
+ display->textureFBOWidth, display->textureFBOHeight,
+ winId,
+ TRUE);
+
+}
+
+
+/* glutReshapeFunc callback */
+void
+gst_gl_display_onReshape(gint width, gint height)
+{
+ gint glutWinId = 0;
+ GstGLDisplay *display = NULL;
+
+ //retrieve the display associated to the glut context
+ glutWinId = glutGetWindow ();
+ display = g_hash_table_lookup (gst_gl_display_map, glutWinId);
+
+ //glutGetWindow return 0 if no windows exists, then g_hash_table_lookup return NULL
+ if (display == NULL) return;
+
+ gst_gl_display_lock (display);
+
+ //check if a client reshape callback is registered
+ if (display->clientReshapeCallback)
+ display->clientReshapeCallback(width, height);
+
+ //default reshape
+ else
+ {
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluOrtho2D(0, width, 0, height);
+ glMatrixMode(GL_MODELVIEW);
+ }
+
+ gst_gl_display_unlock (display);
+}
+
+/* glutDisplayFunc callback */
+void gst_gl_display_draw(void)
+{
+ gint glutWinId = 0;
+ GstGLDisplay *display = NULL;
+
+ //retrieve the display associated to the glut context
+ glutWinId = glutGetWindow ();
+ display = g_hash_table_lookup (gst_gl_display_map, glutWinId);
+
+ //glutGetWindow return 0 if no windows exists, then g_hash_table_lookup return NULL
+ if (display == NULL) return;
+
+ //lock the display because gstreamer elements
+ //(and so the main thread) may modify it
+ gst_gl_display_lock (display);
+
+ //check if video format has been setup
+ if (!display->currentVideo_format)
+ {
+ gst_gl_display_unlock (display);
+ return;
+ }
+
+ //opengl scene
+
+ glUseProgramObjectARB (0);
+ glDisable (GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, 0);
+
+ //check if a client draw callback is registered
+ if (display->clientDrawCallback)
+ {
+ gboolean doRedisplay =
+ display->clientDrawCallback(display->textureFBO,
+ display->textureFBOWidth, display->textureFBOHeight);
+
+ glFlush();
+ glutSwapBuffers();
+
+ if (doRedisplay)
+ gst_gl_display_postMessage (GST_GL_DISPLAY_ACTION_REDISPLAY, display);
+ }
+ //default opengl scene
+ else
+ {
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->textureFBO);
+ glEnable (GL_TEXTURE_RECTANGLE_ARB);
+
+ glBegin (GL_QUADS);
+ glTexCoord2i (display->textureFBOWidth, 0);
+ glVertex2f (1.0f, 1.0f);
+ glTexCoord2i (0, 0);
+ glVertex2f (-1.0f, 1.0f);
+ glTexCoord2i (0, display->textureFBOHeight);
+ glVertex2f (-1.0f, -1.0f);
+ glTexCoord2i (display->textureFBOWidth, display->textureFBOHeight);
+ glVertex2f (1.0f, -1.0f);
+ glEnd ();
+
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+ glFlush();
+ glutSwapBuffers();
+
+ }//end default opengl scene
+
+ gst_gl_display_unlock (display);
+}
+
+
+/* glutCloseFunc callback */
+void gst_gl_display_onClose (void)
+{
+ gint glutWinId = 0;
+ GstGLDisplay* display = NULL;
+
+ //retrieve the display associated to the glut context
+ glutWinId = glutGetWindow ();
+ display = g_hash_table_lookup (gst_gl_display_map, glutWinId);
+
+ //glutGetWindow return 0 if no windows exists, then g_hash_table_lookup return NULL
+ if (display == NULL) return;
+
+ g_print ("on close\n");
+ //gst_event_new_eos();
+}
+
+
+/* called by gst_gl_display_glutPrepareTexture (in the glut thread) */
+void gst_gl_display_make_texture (GstGLDisplay * display)
+{
+ GstGLDisplayTex* tex = NULL;
+
+ //check if there is a tex available in the pool
+ if (g_queue_get_length (display->texturePool))
+ tex = g_queue_pop_head (display->texturePool);
+
+ //one tex is available
+ if (tex)
+ display->requestedTexture = tex->texture;
+ else
+ glGenTextures (1, &display->requestedTexture);
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->requestedTexture);
+ switch (display->requestedVideo_format) {
+ case GST_VIDEO_FORMAT_RGBx:
+ case GST_VIDEO_FORMAT_BGRx:
+ case GST_VIDEO_FORMAT_xRGB:
+ case GST_VIDEO_FORMAT_xBGR:
+ case GST_VIDEO_FORMAT_RGBA:
+ case GST_VIDEO_FORMAT_BGRA:
+ case GST_VIDEO_FORMAT_ARGB:
+ case GST_VIDEO_FORMAT_ABGR:
+ case GST_VIDEO_FORMAT_AYUV:
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA,
+ display->requestedTextureWidth, display->requestedTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ break;
+
+ case GST_VIDEO_FORMAT_RGB:
+ case GST_VIDEO_FORMAT_BGR:
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB,
+ display->requestedTextureWidth, display->requestedTextureHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
+ break;
+
+ case GST_VIDEO_FORMAT_YUY2:
+ case GST_VIDEO_FORMAT_UYVY:
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE_ALPHA,
+ display->requestedTextureWidth, display->requestedTextureHeight,
+ 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
+
+ //one tex is available
+ if (tex)
+ display->requestedTexture_u = tex->texture_u;
+ else
+ glGenTextures (1, &display->requestedTexture_u);
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->requestedTexture_u);
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8,
+ display->requestedTextureWidth, display->requestedTextureHeight,
+ 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
+ break;
+
+ case GST_VIDEO_FORMAT_I420:
+ case GST_VIDEO_FORMAT_YV12:
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE,
+ display->requestedTextureWidth, display->requestedTextureHeight,
+ 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
+
+ //one tex is available
+ if (tex)
+ display->requestedTexture_u = tex->texture_u;
+ else
+ glGenTextures (1, &display->requestedTexture_u);
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->requestedTexture_u);
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE,
+ GST_ROUND_UP_2 (display->requestedTextureWidth) / 2,
+ GST_ROUND_UP_2 (display->requestedTextureHeight) / 2,
+ 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
+
+ //one tex is available
+ if (tex)
+ display->requestedTexture_v = tex->texture_v;
+ else
+ glGenTextures (1, &display->requestedTexture_v);
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->requestedTexture_v);
+ glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, GL_LUMINANCE,
+ GST_ROUND_UP_2 (display->requestedTextureWidth) / 2,
+ GST_ROUND_UP_2 (display->requestedTextureHeight) / 2,
+ 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+ if (tex)
+ g_free (tex);
+}
+
+
+/* called by gst_gl_display_glutUpdateTexture (in the glut thread) */
+void
+gst_gl_display_fill_texture (GstGLDisplay * display)
+{
+ GstVideoFormat video_format = display->candidateVideo_format;
+ gint width = display->candidateTextureWidth;
+ gint height = display->candidateTextureHeight;
+ gpointer data = display->candidateData;
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->candidateTexture);
+
+ switch (video_format) {
+ case GST_VIDEO_FORMAT_RGBx:
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
+ GL_RGBA, GL_UNSIGNED_BYTE, data);
+ break;
+ case GST_VIDEO_FORMAT_BGRx:
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
+ GL_BGRA, GL_UNSIGNED_BYTE, data);
+ break;
+ case GST_VIDEO_FORMAT_AYUV:
+ case GST_VIDEO_FORMAT_xRGB:
+ 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:
+ 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:
+ case GST_VIDEO_FORMAT_UYVY:
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
+ GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, data);
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->candidateTexture_u);
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0,
+ GST_ROUND_UP_2 (width) / 2, height,
+ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
+ break;
+ case GST_VIDEO_FORMAT_I420:
+ case GST_VIDEO_FORMAT_YV12:
+ {
+ gint offsetU = 0;
+ gint offsetV = 0;
+
+ switch (video_format)
+ {
+ case GST_VIDEO_FORMAT_I420:
+ offsetU = 1;
+ offsetV = 2;
+ break;
+ case GST_VIDEO_FORMAT_YV12:
+ offsetU = 2;
+ offsetV = 1;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, width, height,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, data);
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->candidateTexture_u);
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0,
+ GST_ROUND_UP_2 (width) / 2, GST_ROUND_UP_2 (height) / 2,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ (guint8 *) data +
+ gst_video_format_get_component_offset (video_format, offsetU, width, height));
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->candidateTexture_v);
+ glTexSubImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0,
+ GST_ROUND_UP_2 (width) / 2, GST_ROUND_UP_2 (height) / 2,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ (guint8 *) data +
+ gst_video_format_get_component_offset (video_format, offsetV, width, height));
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ //candidate textures can now be used
+ display->currentTexture = display->candidateTexture;
+ display->currentTexture_u = display->candidateTexture_u;
+ display->currentTexture_v = display->candidateTexture_v;
+ display->currentVideo_format = display->candidateVideo_format;
+ display->currentTextureWidth = display->candidateTextureWidth;
+ display->currentTextureHeight = display->candidateTextureHeight;
+
+}
+
+
+/* called by gst_gl_display_glutUpdateTexture (in the glut thread) */
+void
+gst_gl_display_draw_texture (GstGLDisplay* display)
+{
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, display->fbo);
+
+ glPushAttrib(GL_VIEWPORT_BIT);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ gluOrtho2D(0.0, display->textureFBOWidth, 0.0, display->textureFBOHeight);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glViewport(0, 0, display->textureFBOWidth, display->textureFBOHeight);
+
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ switch (display->currentVideo_format)
+ {
+ case GST_VIDEO_FORMAT_RGBx:
+ case GST_VIDEO_FORMAT_BGRx:
+ case GST_VIDEO_FORMAT_xRGB:
+ case GST_VIDEO_FORMAT_xBGR:
+ {
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->currentTexture);
+ 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);
+ glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ }
+ break;
+
+ case GST_VIDEO_FORMAT_YUY2:
+ case GST_VIDEO_FORMAT_UYVY:
+ {
+ gint i=0;
+ GLhandleARB GLSLProgram_YUY2_UYVY = 0;
+
+ switch (display->currentVideo_format)
+ {
+ case GST_VIDEO_FORMAT_YUY2:
+ GLSLProgram_YUY2_UYVY = display->GLSLProgram_YUY2;
+ break;
+ case GST_VIDEO_FORMAT_UYVY:
+ GLSLProgram_YUY2_UYVY = display->GLSLProgram_UYVY;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ glUseProgramObjectARB (GLSLProgram_YUY2_UYVY);
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ glActiveTextureARB(GL_TEXTURE1_ARB);
+ i = glGetUniformLocationARB (GLSLProgram_YUY2_UYVY, "UVtex");
+ glUniform1iARB (i, 1);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->currentTexture_u);
+ 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);
+
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ i = glGetUniformLocationARB (GLSLProgram_YUY2_UYVY, "Ytex");
+ glUniform1iARB (i, 0);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->currentTexture);
+ 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);
+ }
+ break;
+
+ case GST_VIDEO_FORMAT_I420:
+ case GST_VIDEO_FORMAT_YV12:
+ {
+ gint i=0;
+
+ glUseProgramObjectARB (display->GLSLProgram_I420_YV12);
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ glActiveTextureARB(GL_TEXTURE1_ARB);
+ i = glGetUniformLocationARB (display->GLSLProgram_I420_YV12, "Utex");
+ glUniform1iARB (i, 1);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->currentTexture_u);
+ 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);
+
+ glActiveTextureARB(GL_TEXTURE2_ARB);
+ i = glGetUniformLocationARB (display->GLSLProgram_I420_YV12, "Vtex");
+ glUniform1iARB (i, 2);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->currentTexture_v);
+ 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);
+
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ i = glGetUniformLocationARB (display->GLSLProgram_I420_YV12, "Ytex");
+ glUniform1iARB (i, 0);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->currentTexture);
+ 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);
+ }
+ break;
+
+ case GST_VIDEO_FORMAT_AYUV:
+ {
+ gint i=0;
+
+ glUseProgramObjectARB (display->GLSLProgram_AYUV);
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ i = glGetUniformLocationARB (display->GLSLProgram_AYUV, "tex");
+ glUniform1iARB (i, 0);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->currentTexture);
+ 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);
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+
+ }//end switch display->currentVideo_format
+
+ glBegin (GL_QUADS);
+ glTexCoord2i (display->currentTextureWidth, 0);
+ glVertex2f (1.0f, -1.0f);
+ glTexCoord2i (0, 0);
+ glVertex2f (-1.0f, -1.0f);
+ glTexCoord2i (0, display->currentTextureHeight);
+ glVertex2f (-1.0f, 1.0f);
+ glTexCoord2i (display->currentTextureWidth, display->currentTextureHeight);
+ glVertex2f (1.0f, 1.0f);
+ glEnd ();
+
+ glDrawBuffer(GL_NONE);
+
+ glUseProgramObjectARB (0);
+
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopAttrib();
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+ checkFramebufferStatus();
+}
+
+
+/* called by gst_gl_display_glutUpdateTexture (in the glut thread) */
+void
+gst_gl_display_draw_graphic (GstGLDisplay* display)
+{
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, display->graphicFBO);
+
+ glPushAttrib(GL_VIEWPORT_BIT);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ gluPerspective(45, (gfloat)display->glcontext_width/(gfloat)display->glcontext_height, 0.1, 100);
+ //gluOrtho2D(0.0, display->glcontext_width, 0.0, display->glcontext_height);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glViewport(0, 0, display->glcontext_width, display->glcontext_height);
+
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+
+ //check if a client draw callback is registered
+ if (display->clientDrawCallback)
+ {
+ display->clientDrawCallback(display->textureFBO,
+ display->textureFBOWidth, display->textureFBOHeight);
+ }
+ else
+ {
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->textureFBO);
+ glEnable (GL_TEXTURE_RECTANGLE_ARB);
+
+ glBegin (GL_QUADS);
+ glTexCoord2i (display->textureFBOWidth, 0);
+ glVertex2f (1.0f, 1.0f);
+ glTexCoord2i (0, 0);
+ glVertex2f (-1.0f, 1.0f);
+ glTexCoord2i (0, display->textureFBOHeight);
+ glVertex2f (-1.0f, -1.0f);
+ glTexCoord2i (display->textureFBOWidth, display->textureFBOHeight);
+ glVertex2f (1.0f, -1.0f);
+ glEnd ();
+ }
+
+ glDrawBuffer(GL_NONE);
+
+ glUseProgramObjectARB (0);
+
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopAttrib();
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+
+ checkFramebufferStatus();
+}
+
+
+/* called by gst_gl_display_glutUpdateVideo (in the glut thread) */
+void
+gst_gl_display_fill_video (GstGLDisplay* display)
+{
+
+ gint width = display->outputWidth;
+ gint height = display->outputHeight;
+ GstVideoFormat outputVideo_format = display->outputVideo_format;
+ gpointer data = display->outputData;
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, display->videoFBO);
+
+ glPushAttrib(GL_VIEWPORT_BIT);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ gluOrtho2D(0.0, width, 0.0, height);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glViewport(0, 0, width, height);
+
+ switch (outputVideo_format)
+ {
+ case GST_VIDEO_FORMAT_RGBx:
+ case GST_VIDEO_FORMAT_BGRx:
+ case GST_VIDEO_FORMAT_xRGB:
+ case GST_VIDEO_FORMAT_xBGR:
+ {
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->graphicTexture);
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+ }
+ break;
+
+ case GST_VIDEO_FORMAT_YUY2:
+ case GST_VIDEO_FORMAT_UYVY:
+ {
+ gint i=0;
+ GLhandleARB GLSLProgram_to_YUY2_UYVY = 0;
+
+ switch (outputVideo_format)
+ {
+ case GST_VIDEO_FORMAT_YUY2:
+ GLSLProgram_to_YUY2_UYVY = display->GLSLProgram_to_YUY2;
+ break;
+ case GST_VIDEO_FORMAT_UYVY:
+ GLSLProgram_to_YUY2_UYVY = display->GLSLProgram_to_UYVY;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glUseProgramObjectARB (GLSLProgram_to_YUY2_UYVY);
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ i = glGetUniformLocationARB (GLSLProgram_to_YUY2_UYVY, "tex");
+ glUniform1iARB (i, 0);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->graphicTexture);
+ }
+ break;
+
+ case GST_VIDEO_FORMAT_I420:
+ case GST_VIDEO_FORMAT_YV12:
+ {
+ gint i=0;
+
+ glDrawBuffers(3, display->multipleRT);
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glUseProgramObjectARB (display->GLSLProgram_to_I420_YV12);
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ i = glGetUniformLocationARB (display->GLSLProgram_to_I420_YV12, "tex");
+ glUniform1iARB (i, 0);
+ i = glGetUniformLocationARB (display->GLSLProgram_to_I420_YV12, "w");
+ glUniform1fARB (i, (gfloat)width);
+ i = glGetUniformLocationARB (display->GLSLProgram_to_I420_YV12, "h");
+ glUniform1fARB (i, (gfloat)height);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->graphicTexture);
+ }
+ break;
+
+ case GST_VIDEO_FORMAT_AYUV:
+ {
+ gint i=0;
+
+ glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glUseProgramObjectARB (display->GLSLProgram_to_AYUV);
+
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
+
+ glActiveTextureARB(GL_TEXTURE0_ARB);
+ i = glGetUniformLocationARB (display->GLSLProgram_to_AYUV, "tex");
+ glUniform1iARB (i, 0);
+ glBindTexture (GL_TEXTURE_RECTANGLE_ARB, display->graphicTexture);
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+
+ }//end switch display->currentVideo_format
+
+ glBegin (GL_QUADS);
+ glTexCoord2i (width, 0);
+ glVertex2f (1.0f, 1.0f);
+ glTexCoord2i (0, 0);
+ glVertex2f (-1.0f, 1.0f);
+ glTexCoord2i (0, height);
+ glVertex2f (-1.0f, -1.0f);
+ glTexCoord2i (width, height);
+ glVertex2f (1.0f, -1.0f);
+ glEnd ();
+
+ glDrawBuffer(GL_NONE);
+
+ glUseProgramObjectARB (0);
+
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopAttrib();
+
+ glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
+
+ checkFramebufferStatus();
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, display->videoFBO);
+ glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+
+ switch (outputVideo_format) {
+ case GST_VIDEO_FORMAT_RGBx:
+ glReadPixels (0, 0, width, height, GL_RGBA,
+ GL_UNSIGNED_BYTE, data);
+ break;
+ case GST_VIDEO_FORMAT_BGRx:
+ glReadPixels (0, 0, width, height, GL_BGRA,
+ GL_UNSIGNED_BYTE, data);
+ break;
+ case GST_VIDEO_FORMAT_xBGR:
+ glReadPixels (0, 0, width, height, GL_RGBA,
+ GL_UNSIGNED_INT_8_8_8_8, data);
+ break;
+ case GST_VIDEO_FORMAT_AYUV:
+ case GST_VIDEO_FORMAT_xRGB:
+ glReadPixels (0, 0, width, height, GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8, data);
+ break;
+ case GST_VIDEO_FORMAT_YUY2:
+ case GST_VIDEO_FORMAT_UYVY:
+ glReadPixels (0, 0, GST_ROUND_UP_2 (width) / 2, height, GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV, data);
+ break;
+ case GST_VIDEO_FORMAT_I420:
+ case GST_VIDEO_FORMAT_YV12:
+ {
+ gint offsetU = 0;
+ gint offsetV = 0;
+
+ switch (outputVideo_format)
+ {
+ case GST_VIDEO_FORMAT_I420:
+ offsetU = 1;
+ offsetV = 2;
+ break;
+ case GST_VIDEO_FORMAT_YV12:
+ offsetU = 2;
+ offsetV = 1;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ glReadPixels (0, 0, width, height, GL_LUMINANCE,
+ GL_UNSIGNED_BYTE, data);
+
+ glReadBuffer(GL_COLOR_ATTACHMENT1_EXT);
+ glReadPixels (0, 0, GST_ROUND_UP_2 (width) / 2, GST_ROUND_UP_2 (height) / 2,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ (guint8 *) data +
+ gst_video_format_get_component_offset (outputVideo_format, offsetU, width, height));
+
+ glReadBuffer(GL_COLOR_ATTACHMENT2_EXT);
+ glReadPixels (0, 0, GST_ROUND_UP_2 (width) / 2, GST_ROUND_UP_2 (height) / 2,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE,
+ (guint8 *) data +
+ gst_video_format_get_component_offset (outputVideo_format, offsetV, width, height));
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
+ checkFramebufferStatus();
+}
+
+
+/* called by gst_gl_display_glutCreateWindow (in the glut thread) */
+GLhandleARB
+gst_gl_display_loadGLSLprogram (gchar* textFProgram)
+{
+ GLhandleARB FHandle = 0;
+ GLhandleARB PHandle = 0;
+ gchar s[32768];
+ gint i = 0;
+
+ //Set up program objects
+ PHandle = glCreateProgramObjectARB ();
+
+ //Compile the shader
+ FHandle = glCreateShaderObjectARB (GL_FRAGMENT_SHADER_ARB);
+ glShaderSourceARB (FHandle, 1, &textFProgram, NULL);
+ glCompileShaderARB (FHandle);
+
+ //Print the compilation log
+ glGetObjectParameterivARB (FHandle, GL_OBJECT_COMPILE_STATUS_ARB, &i);
+ glGetInfoLogARB (FHandle, sizeof(s)/sizeof(char), NULL, s);
+ g_print ("Compile Log: %s\n", s);
+
+ //link the shader
+ glAttachObjectARB (PHandle, FHandle);
+ glLinkProgramARB (PHandle);
+
+ //Print the link log
+ glGetInfoLogARB (PHandle, sizeof(s)/sizeof(char), NULL, s);
+ g_print ("Link Log: %s\n", s);
+
+ return PHandle;
+}
+
+
+/* Called by gst_gl_display_fill_video */
+void
+checkFramebufferStatus(void)
+{
+
+ GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+
+ switch(status)
+ {
+ case GL_FRAMEBUFFER_COMPLETE_EXT:
+ break;
+
+ case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+ g_print("GL_FRAMEBUFFER_UNSUPPORTED_EXT\n");
+ break;
+
+ default:
+ g_print("General FBO error\n");
+ }
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstglgraphicmaker.h"
+
+
+#define GST_CAT_DEFAULT gst_gl_graphicmaker_debug
+ GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+/* inpect details */
+static const GstElementDetails element_details = {
+ "glgraphicmaker",
+ "Transform filter",
+ "output an opengl scene flux",
+ "Jhonny Bravo and Kelly"
+ };
+
+/* Source pad definition */
+static GstStaticPadTemplate gst_gl_graphicmaker_src_pad_template =
+GST_STATIC_PAD_TEMPLATE ("src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_GL_VIDEO_CAPS)
+ );
+
+/* Source pad definition */
+static GstStaticPadTemplate gst_gl_graphicmaker_sink_pad_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBx ";"
+ GST_VIDEO_CAPS_BGRx ";"
+ GST_VIDEO_CAPS_xRGB ";"
+ GST_VIDEO_CAPS_xBGR ";"
+ GST_VIDEO_CAPS_YUV ("{ I420, YV12, YUY2, UYVY, AYUV }"))
+ );
+
+/* Properties */
+enum
+{
+ PROP_0,
+ PROP_GLCONTEXT_WIDTH,
+ PROP_GLCONTEXT_HEIGHT,
+ PROP_CLIENT_RESHAPE_CALLBACK,
+ PROP_CLIENT_DRAW_CALLBACK
+};
+
+#define DEBUG_INIT(bla) \
+ GST_DEBUG_CATEGORY_INIT (gst_gl_graphicmaker_debug, "glgraphicmaker", 0, "glgraphicmaker element");
+
+GST_BOILERPLATE_FULL (GstGLGraphicmaker, gst_gl_graphicmaker, GstBaseTransform,
+ GST_TYPE_BASE_TRANSFORM, DEBUG_INIT);
+
+static void gst_gl_graphicmaker_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_gl_graphicmaker_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void gst_gl_graphicmaker_reset (GstGLGraphicmaker* graphicmaker);
+static gboolean gst_gl_graphicmaker_set_caps (GstBaseTransform * bt,
+ GstCaps * incaps, GstCaps * outcaps);
+static GstCaps *gst_gl_graphicmaker_transform_caps (GstBaseTransform * bt,
+ GstPadDirection direction, GstCaps * caps);
+static gboolean gst_gl_graphicmaker_start (GstBaseTransform * bt);
+static gboolean gst_gl_graphicmaker_stop (GstBaseTransform * bt);
+static GstFlowReturn gst_gl_graphicmaker_prepare_output_buffer (GstBaseTransform *
+ trans, GstBuffer * input, gint size, GstCaps * caps, GstBuffer ** buf);
+static GstFlowReturn gst_gl_graphicmaker_transform (GstBaseTransform * trans,
+ GstBuffer * inbuf, GstBuffer * outbuf);
+static gboolean gst_gl_graphicmaker_get_unit_size (GstBaseTransform * trans,
+ GstCaps * caps, guint * size);
+
+
+static void
+gst_gl_graphicmaker_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_graphicmaker_src_pad_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_gl_graphicmaker_sink_pad_template));
+}
+
+static void
+gst_gl_graphicmaker_class_init (GstGLGraphicmakerClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gobject_class->set_property = gst_gl_graphicmaker_set_property;
+ gobject_class->get_property = gst_gl_graphicmaker_get_property;
+
+ GST_BASE_TRANSFORM_CLASS (klass)->transform_caps =
+ gst_gl_graphicmaker_transform_caps;
+ GST_BASE_TRANSFORM_CLASS (klass)->transform = gst_gl_graphicmaker_transform;
+ GST_BASE_TRANSFORM_CLASS (klass)->start = gst_gl_graphicmaker_start;
+ GST_BASE_TRANSFORM_CLASS (klass)->stop = gst_gl_graphicmaker_stop;
+ GST_BASE_TRANSFORM_CLASS (klass)->set_caps = gst_gl_graphicmaker_set_caps;
+ GST_BASE_TRANSFORM_CLASS (klass)->get_unit_size = gst_gl_graphicmaker_get_unit_size;
+ GST_BASE_TRANSFORM_CLASS (klass)->prepare_output_buffer =
+ gst_gl_graphicmaker_prepare_output_buffer;
+
+
+ g_object_class_install_property (gobject_class, PROP_GLCONTEXT_WIDTH,
+ g_param_spec_int ("glcontext_width", "OpenGL context width",
+ "Change the opengl context width", 0, INT_MAX, 0,
+ G_PARAM_WRITABLE));
+
+ g_object_class_install_property (gobject_class, PROP_GLCONTEXT_HEIGHT,
+ g_param_spec_int ("glcontext_height", "OpenGL context height",
+ "Change the opengl context height", 0, INT_MAX, 0,
+ G_PARAM_WRITABLE));
+
+ g_object_class_install_property (gobject_class, PROP_CLIENT_RESHAPE_CALLBACK,
+ g_param_spec_pointer ("client_reshape_callback", "Client reshape callback",
+ "Executed in next glut loop iteration when window size is changed",
+ G_PARAM_WRITABLE));
+
+ g_object_class_install_property (gobject_class, PROP_CLIENT_DRAW_CALLBACK,
+ g_param_spec_pointer ("client_draw_callback", "Client draw callback",
+ "Executed in next glut loop iteration when glutPostRedisplay is called",
+ G_PARAM_WRITABLE));
+}
+
+static void
+gst_gl_graphicmaker_init (GstGLGraphicmaker* graphicmaker, GstGLGraphicmakerClass * klass)
+{
+ gst_gl_graphicmaker_reset (graphicmaker);
+}
+
+static void
+gst_gl_graphicmaker_set_property (GObject* object, guint prop_id,
+ const GValue* value, GParamSpec* pspec)
+{
+ GstGLGraphicmaker* graphicmaker = GST_GL_GRAPHICMAKER (object);
+
+ switch (prop_id) {
+ case PROP_GLCONTEXT_WIDTH:
+ {
+ graphicmaker->glcontext_width = g_value_get_int (value);
+ break;
+ }
+ case PROP_GLCONTEXT_HEIGHT:
+ {
+ graphicmaker->glcontext_height = g_value_get_int (value);
+ break;
+ }
+ case PROP_CLIENT_RESHAPE_CALLBACK:
+ {
+ graphicmaker->clientReshapeCallback = g_value_get_pointer (value);
+ break;
+ }
+ case PROP_CLIENT_DRAW_CALLBACK:
+ {
+ graphicmaker->clientDrawCallback = g_value_get_pointer (value);
+ break;
+ }
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_gl_graphicmaker_get_property (GObject* object, guint prop_id,
+ GValue* value, GParamSpec* pspec)
+{
+ //GstGLGraphicmaker *graphicmaker = GST_GL_GRAPHICMAKER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_gl_graphicmaker_reset (GstGLGraphicmaker* graphicmaker)
+{
+ if (graphicmaker->display) {
+ g_object_unref (graphicmaker->display);
+ graphicmaker->display = NULL;
+ }
+ graphicmaker->peek = FALSE;
+
+ graphicmaker->glcontext_width = 0;
+ graphicmaker->glcontext_height = 0;
+ graphicmaker->clientReshapeCallback = NULL;
+ graphicmaker->clientDrawCallback = NULL;
+}
+
+static gboolean
+gst_gl_graphicmaker_start (GstBaseTransform * bt)
+{
+ GstGLGraphicmaker* graphicmaker = GST_GL_GRAPHICMAKER (bt);
+
+ return TRUE;
+}
+
+static gboolean
+gst_gl_graphicmaker_stop (GstBaseTransform * bt)
+{
+ GstGLGraphicmaker* graphicmaker = GST_GL_GRAPHICMAKER (bt);
+
+ gst_gl_graphicmaker_reset (graphicmaker);
+
+ return TRUE;
+}
+
+static GstCaps *
+gst_gl_graphicmaker_transform_caps (GstBaseTransform * bt,
+ GstPadDirection direction, GstCaps * caps)
+{
+ GstGLGraphicmaker* graphicmaker;
+ GstStructure* structure;
+ GstCaps* newcaps, *newothercaps;
+ GstStructure* newstruct;
+ const GValue* width_value;
+ const GValue* height_value;
+ const GValue* framerate_value;
+ const GValue* par_value;
+
+ graphicmaker = GST_GL_GRAPHICMAKER (bt);
+
+ GST_ERROR ("transform caps %" GST_PTR_FORMAT, caps);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ width_value = gst_structure_get_value (structure, "width");
+ height_value = gst_structure_get_value (structure, "height");
+ framerate_value = gst_structure_get_value (structure, "framerate");
+ par_value = gst_structure_get_value (structure, "pixel-aspect-ratio");
+
+ if (direction == GST_PAD_SRC)
+ {
+ newothercaps = gst_caps_new_simple ("video/x-raw-rgb", NULL);
+ newstruct = gst_caps_get_structure (newothercaps, 0);
+ gst_structure_set_value (newstruct, "width", width_value);
+ gst_structure_set_value (newstruct, "height", height_value);
+ gst_structure_set_value (newstruct, "framerate", framerate_value);
+ if (par_value)
+ gst_structure_set_value (newstruct, "pixel-aspect-ratio", par_value);
+ else
+ gst_structure_set (newstruct, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ 1, 1, NULL);
+ newcaps = gst_caps_new_simple ("video/x-raw-yuv", NULL);
+ gst_caps_append(newcaps, newothercaps);
+ newstruct = gst_caps_get_structure (newcaps, 0);
+ gst_structure_set_value (newstruct, "width", width_value);
+ gst_structure_set_value (newstruct, "height", height_value);
+ }
+ else
+ {
+ newcaps = gst_caps_new_simple ("video/x-raw-gl", NULL);
+ newstruct = gst_caps_get_structure (newcaps, 0);
+ if (graphicmaker->glcontext_width != 0 && graphicmaker->glcontext_height != 0)
+ {
+ GValue value_w = { 0 };
+ GValue value_h = { 0 };
+ g_value_init (&value_w, G_TYPE_INT);
+ g_value_init (&value_h, G_TYPE_INT);
+ g_value_set_int (&value_w, graphicmaker->glcontext_width);
+ g_value_set_int (&value_h, graphicmaker->glcontext_height);
+ gst_structure_set_value (newstruct, "width", &value_w);
+ gst_structure_set_value (newstruct, "height", &value_h);
+ g_value_unset (&value_w);
+ g_value_unset (&value_h);
+ }
+ else
+ {
+ gst_structure_set_value (newstruct, "width", width_value);
+ gst_structure_set_value (newstruct, "height", height_value);
+ }
+ }
+
+
+ gst_structure_set_value (newstruct, "framerate", framerate_value);
+ if (par_value)
+ gst_structure_set_value (newstruct, "pixel-aspect-ratio", par_value);
+ else
+ gst_structure_set (newstruct, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+ 1, 1, NULL);
+
+ GST_ERROR ("new caps %" GST_PTR_FORMAT, newcaps);
+
+ return newcaps;
+}
+
+static gboolean
+gst_gl_graphicmaker_set_caps (GstBaseTransform* bt, GstCaps* incaps,
+ GstCaps* outcaps)
+{
+ GstGLGraphicmaker* graphicmaker;
+ gboolean ret;
+
+ graphicmaker = GST_GL_GRAPHICMAKER (bt);
+
+ GST_DEBUG ("called with %" GST_PTR_FORMAT, incaps);
+
+ ret = gst_video_format_parse_caps (incaps, &graphicmaker->video_format,
+ &graphicmaker->width, &graphicmaker->height);
+
+ if (!ret) {
+ GST_DEBUG ("bad caps");
+ return FALSE;
+ }
+
+ graphicmaker->display = gst_gl_display_new ();
+
+ //client opengl context size
+ if (graphicmaker->glcontext_width != 0 && graphicmaker->glcontext_height != 0)
+ gst_gl_display_initGLContext (graphicmaker->display, 0, 0,
+ graphicmaker->glcontext_width, graphicmaker->glcontext_height,
+ graphicmaker->width, graphicmaker->height, 0, FALSE);
+ //default opengl context size
+ else
+ {
+ //init unvisible opengl context
+ static gint glcontext_y = 0;
+ gst_gl_display_initGLContext (graphicmaker->display,
+ 50, glcontext_y++ * (graphicmaker->height+50) + 50,
+ graphicmaker->width, graphicmaker->height,
+ graphicmaker->width, graphicmaker->height, 0, FALSE);
+ }
+
+ //set the client reshape callback
+ gst_gl_display_setClientReshapeCallback (graphicmaker->display,
+ graphicmaker->clientReshapeCallback);
+
+ //set the client draw callback
+ gst_gl_display_setClientDrawCallback (graphicmaker->display,
+ graphicmaker->clientDrawCallback);
+
+ return ret;
+}
+
+static gboolean
+gst_gl_graphicmaker_get_unit_size (GstBaseTransform * trans, GstCaps * caps,
+ guint * size)
+{
+ gboolean ret;
+ GstStructure *structure;
+ gint width;
+ gint height;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (gst_structure_has_name (structure, "video/x-raw-gl"))
+ {
+ GstVideoFormat video_format;
+
+ 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);
+ }
+ else
+ {
+ GstVideoFormat video_format;
+
+ ret = gst_video_format_parse_caps (caps, &video_format, &width, &height);
+ if (ret)
+ *size = gst_video_format_get_size (video_format, width, height);
+ }
+
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_gl_graphicmaker_prepare_output_buffer (GstBaseTransform* trans,
+ GstBuffer* input, gint size, GstCaps* caps, GstBuffer** buf)
+{
+ GstGLGraphicmaker* graphicmaker;
+ GstGLBuffer* gl_outbuf;
+
+ graphicmaker = GST_GL_GRAPHICMAKER (trans);
+
+ //blocking call
+
+ //client opengl context size
+ if (graphicmaker->glcontext_width != 0 && graphicmaker->glcontext_height != 0)
+ gl_outbuf = gst_gl_buffer_new_from_video_format (graphicmaker->display,
+ graphicmaker->video_format,
+ graphicmaker->glcontext_width, graphicmaker->glcontext_height,
+ graphicmaker->width, graphicmaker->height);
+ //default opengl context size
+ else
+ gl_outbuf = gst_gl_buffer_new_from_video_format (graphicmaker->display,
+ graphicmaker->video_format,
+ graphicmaker->width, graphicmaker->height,
+ graphicmaker->width, graphicmaker->height);
+ *buf = GST_BUFFER (gl_outbuf);
+ gst_buffer_set_caps (*buf, caps);
+
+ return GST_FLOW_OK;
+}
+
+
+static GstFlowReturn
+gst_gl_graphicmaker_transform (GstBaseTransform* trans, GstBuffer* inbuf,
+ GstBuffer* outbuf)
+{
+ GstGLGraphicmaker* graphicmaker;
+ GstGLBuffer* gl_outbuf = GST_GL_BUFFER (outbuf);
+
+ graphicmaker = GST_GL_GRAPHICMAKER (trans);
+
+ GST_DEBUG ("making graphic %p size %d",
+ GST_BUFFER_DATA (inbuf), GST_BUFFER_SIZE (inbuf));
+
+ //blocking call
+ gst_gl_display_textureChanged(graphicmaker->display, graphicmaker->video_format,
+ gl_outbuf->texture, gl_outbuf->texture_u, gl_outbuf->texture_v,
+ gl_outbuf->width, gl_outbuf->height, GST_BUFFER_DATA (inbuf));
+
+ return GST_FLOW_OK;
+}