From c07d2d5abf5ad83860a26fca370d7d7f141f374a Mon Sep 17 00:00:00 2001 From: David Schleef Date: Fri, 13 May 2005 22:16:56 +0000 Subject: sys/glsink/: Rewrite glimagesink from scratch. Lots more feature and bounds checking. Implement GstXOverlay. Handl... Original commit message from CVS: * sys/glsink/Makefile.am: * sys/glsink/glimagesink.c: * sys/glsink/glimagesink.h: Rewrite glimagesink from scratch. Lots more feature and bounds checking. Implement GstXOverlay. Handles YUV if the GL_MESA_ycbcr_texture extension is available. Still has issues with resizing that kinda look like X bugs. --- sys/glsink/glimagesink.c | 1389 ++++++++++------------------------------------ 1 file changed, 280 insertions(+), 1109 deletions(-) (limited to 'sys/glsink/glimagesink.c') diff --git a/sys/glsink/glimagesink.c b/sys/glsink/glimagesink.c index 13549a71..e7d847ad 100644 --- a/sys/glsink/glimagesink.c +++ b/sys/glsink/glimagesink.c @@ -1,5 +1,6 @@ /* GStreamer - * Copyright (C) <2003> Julien Moutte + * Copyright (C) 2003 Julien Moutte + * Copyright (C) 2005 David A. Schleef * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -17,6 +18,8 @@ * Boston, MA 02111-1307, USA. */ +#define ENABLE_YUV + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -24,6 +27,7 @@ /* Our interfaces */ #include #include +#include /* Object header */ #include "glimagesink.h" @@ -33,9 +37,9 @@ GST_DEBUG_CATEGORY_STATIC (gst_debug_glimagesink); #define GST_CAT_DEFAULT gst_debug_glimagesink -static void gst_glimagesink_buffer_free (GstBuffer * buffer); +static void gst_glimagesink_set_window_size (GstGLImageSink * glimagesink); + -/* ElementFactory information */ static GstElementDetails gst_glimagesink_details = GST_ELEMENT_DETAILS ("Video sink", "Sink/Video", @@ -48,778 +52,30 @@ static GstStaticPadTemplate gst_glimagesink_sink_template_factory = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, - GST_STATIC_CAPS ("video/x-raw-rgb, " - "framerate = (double) [ 1.0, 100.0 ], " - "width = (int) [ 1, MAX ], " - "height = (int) [ 1, MAX ]; " - "video/x-raw-yuv, " - "framerate = (double) [ 1.0, 100.0 ], " - "width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ]") + GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx +#ifdef ENABLE_YUV + ";" GST_VIDEO_CAPS_YUV ("{ UYVY, YUY2 }") +#endif + ) ); -/* GLImageSink signals and args */ +#if 0 enum { - SIGNAL_HANDOFF, - SIGNAL_BUFALLOC, LAST_SIGNAL - /* FILL ME */ }; static guint gst_glimagesink_signals[LAST_SIGNAL] = { 0 }; +#endif enum { ARG_0, - ARG_DISPLAY, - ARG_SYNCHRONOUS, - ARG_SIGNAL_HANDOFFS - /* FILL ME */ + ARG_DISPLAY }; static GstVideoSinkClass *parent_class = NULL; -/* ============================================================= */ -/* */ -/* Private Methods */ -/* */ -/* ============================================================= */ - -/* X11 and GLX stuff */ - -#define TEX_XSIZE 1024 -#define TEX_YSIZE 1024 - -/* This function handles GstGLImage creation - it creates data buffers and corresponding texture IDs */ -static GstGLImage * -gst_glimagesink_ximage_new (GstGLImageSink * glimagesink, gint width, - gint height) -{ - GstGLImage *ximage = NULL; - - g_return_val_if_fail (GST_IS_GLIMAGESINK (glimagesink), NULL); - - ximage = g_new0 (GstGLImage, 1); - - ximage->width = width; - ximage->height = height; - ximage->data = NULL; - ximage->glimagesink = glimagesink; - - g_mutex_lock (glimagesink->x_lock); - - ximage->size = - (glimagesink->xcontext->bpp / 8) * ximage->width * ximage->height; - - printf ("No ximage_new yet !\n"); - - { - ximage->data = g_malloc (ximage->size); - - ximage->texid = 1000; - } - - if (0) // can't fail ! - { - if (ximage->data) - g_free (ximage->data); - - g_free (ximage); - //ximage = NULL; - } - - g_mutex_unlock (glimagesink->x_lock); - - return ximage; -} - -/* This function destroys a GstGLImage handling XShm availability */ -static void -gst_glimagesink_ximage_destroy (GstGLImageSink * glimagesink, - GstGLImage * ximage) -{ - g_return_if_fail (ximage != NULL); - g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink)); - - /* If the destroyed image is the current one we destroy our reference too */ - if (glimagesink->cur_image == ximage) - glimagesink->cur_image = NULL; - - printf ("No ximage_destroy implemented yet !\n"); - - g_mutex_lock (glimagesink->x_lock); - - { - //if (ximage->ximage) // FIXME: doesnt exist - dealloc textures - // XDestroyImage (ximage->ximage); - } - - g_mutex_unlock (glimagesink->x_lock); - - g_free (ximage); -} - -/* This function puts a GstGLImage on a GstGLImagesink's window */ -static void -gst_glimagesink_ximage_put (GstGLImageSink * glimagesink, GstGLImage * ximage) -{ - float xmax; - float ymax; - float px; - float py; - - g_return_if_fail (ximage != NULL); - g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink)); - - if (glimagesink->signal_handoffs) { - g_warning ("Not drawing anything due to signal_handoffs !\n"); - return; - } - - /* Store a reference to the last image we put */ - if (glimagesink->cur_image != ximage) - glimagesink->cur_image = ximage; - - g_mutex_lock (glimagesink->x_lock); - - // both upload the video, and redraw the screen - - //printf("No ximage_put yet !\n"); - - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - - glMatrixMode (GL_MODELVIEW); - glLoadIdentity (); - //glTranslatef(0.0, 0.0, -5.0); - - glEnable (GL_TEXTURE_2D); - - glBindTexture (GL_TEXTURE_2D, ximage->texid); - glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, ximage->width, ximage->height, - GL_RGB, GL_UNSIGNED_BYTE, ximage->data); - - xmax = (float) ximage->width / TEX_XSIZE; - ymax = (float) ximage->height / TEX_YSIZE; - - //float aspect = ximage->width/(float)ximage->height; - - // don't know what to do with pixel aspect yet. - //float pixel_aspect = glimagesink->pixel_width/(float)glimagesink->pixel_height; - - //if (aspect != pixel_aspect) - // g_warning("screen aspect %f differs from pixel_aspect %f !", aspect, pixel_aspect); - - glColor4f (1, 1, 1, 1); - glBegin (GL_QUADS); - - glNormal3f (0, -1, 0); - - glTexCoord2f (xmax, 0); - glVertex3f (1, 1, 0); - - glTexCoord2f (0, 0); - glVertex3f (-1, 1, 0); - - glTexCoord2f (0, ymax); - glVertex3f (-1, -1, 0); - - glTexCoord2f (xmax, ymax); - glVertex3f (1, -1, 0); - glEnd (); - -#if 1 // for pointer feedback, later - glDisable (GL_TEXTURE_2D); - if (glimagesink->pointer_moved) - glColor3f (1, 1, 1); - else - glColor3f (1, 0, 1); - - if (glimagesink->pointer_button[0]) - glColor3f (1, 0, 0); - - px = 2 * glimagesink->pointer_x / (float) ximage->width - 1.0; - py = 2 * glimagesink->pointer_y / (float) ximage->height - 1.0; - glPointSize (10); - glBegin (GL_POINTS); - glVertex2f (px, -py); - glEnd (); -#endif - - glXSwapBuffers (glimagesink->xcontext->disp, glimagesink->window->win); - - g_mutex_unlock (glimagesink->x_lock); -} - -/* This function handles a GstXWindow creation */ -static GstGLWindow * -gst_glimagesink_xwindow_new (GstGLImageSink * glimagesink, gint width, - gint height) -{ - GstGLWindow *xwindow = NULL; - GstXContext *xcontext = glimagesink->xcontext; - Colormap cmap; - Atom wmDelete; - - if (glimagesink->signal_handoffs) { - g_warning ("NOT CREATING any window due to signal_handoffs !\n"); - return NULL; - } - - g_return_val_if_fail (GST_IS_GLIMAGESINK (glimagesink), NULL); - - xwindow = g_new0 (GstGLWindow, 1); - - xwindow->width = width; - xwindow->height = height; - xwindow->internal = TRUE; - - g_mutex_lock (glimagesink->x_lock); - - /* create a color map */ - cmap = - XCreateColormap (xcontext->disp, RootWindow (xcontext->disp, - xcontext->visualinfo->screen), xcontext->visualinfo->visual, - AllocNone); - xwindow->attr.colormap = cmap; - xwindow->attr.border_pixel = 0; - -#if 0 - /* set sizes */ - xwindow->x = 0; - xwindow->y = 0; - xwindow->width = 10; - xwindow->height = 10; - - xwindow->rotX = 0; - xwindow->rotY = 0; - xwindow->zoom = 1; - xwindow->zoomdir = 0.01; -#endif - - xwindow->attr.event_mask = - ExposureMask | KeyPressMask | ButtonPressMask | StructureNotifyMask; - - /* create a window in window mode */ - xwindow->win = XCreateWindow (xcontext->disp, /*xcontext->root, */ - RootWindow (xcontext->disp, xcontext->visualinfo->screen), - 0, 0, xwindow->width, xwindow->height, 0, xcontext->visualinfo->depth, - InputOutput, xcontext->visualinfo->visual, - CWBorderPixel | CWColormap | CWEventMask, &xwindow->attr); - - /* only set window title and handle wm_delete_events if in windowed mode */ - wmDelete = XInternAtom (xcontext->disp, "WM_DELETE_WINDOW", True); - XSetWMProtocols (xcontext->disp, xwindow->win, &wmDelete, 1); - XSetStandardProperties (xcontext->disp, xwindow->win, "glsink", - "glsink", None, NULL, 0, NULL); - -#if 0 - XSelectInput (xcontext->disp, xwindow->win, - ExposureMask | StructureNotifyMask); -#else // we want more than that - XSelectInput (glimagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask | ButtonPressMask | ButtonReleaseMask); -#endif - - //xwindow->win = XCreateSimpleWindow (glimagesink->xcontext->disp, - // glimagesink->xcontext->root, - // 0, 0, xwindow->width, xwindow->height, 0, 0, glimagesink->xcontext->black); - - XMapRaised (glimagesink->xcontext->disp, xwindow->win); - - /* connect the glx-context to the window */ - glXMakeCurrent (xcontext->disp, xwindow->win, xcontext->glx); - - printf ("Initializing OpenGL parameters\n"); - /* initialize OpenGL drawing */ - glDisable (GL_DEPTH_TEST); - //glShadeModel(GL_SMOOTH); - - glDisable (GL_TEXTURE_2D); - glDisable (GL_CULL_FACE); - glClearDepth (1.0f); - glClearColor (0, 0.5, 0, 1); - - // both upload the video, and redraw the screen - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - - //glEnable(GL_LIGHT0); // Quick And Dirty Lighting (Assumes Light0 Is Set Up) - //glEnable(GL_LIGHTING); // Enable Lighting - glDisable (GL_COLOR_MATERIAL); // Enable Material Coloring - glEnable (GL_AUTO_NORMAL); // let OpenGL generate the Normals - - glDisable (GL_BLEND); - - glPolygonMode (GL_FRONT, GL_FILL); - glPolygonMode (GL_BACK, GL_FILL); - - glShadeModel (GL_SMOOTH); - glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - - glBindTexture (GL_TEXTURE_2D, 1000); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, TEX_XSIZE, TEX_YSIZE, 0, GL_RGBA, - GL_UNSIGNED_BYTE, NULL); - - glXSwapBuffers (xcontext->disp, xwindow->win); - - g_mutex_unlock (glimagesink->x_lock); - - gst_x_overlay_got_xwindow_id (GST_X_OVERLAY (glimagesink), xwindow->win); - - return xwindow; -} - -/* This function destroys a GstGLWindow */ -static void -gst_glimagesink_xwindow_destroy (GstGLImageSink * glimagesink, - GstGLWindow * xwindow) -{ - GstXContext *xcontext = glimagesink->xcontext; - - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink)); - - g_mutex_lock (glimagesink->x_lock); - - if (glimagesink->signal_handoffs) { - g_warning ("NOT DESTROYING any window due to signal_handoff !\n"); - return; - } - - if (xcontext->glx) { - if (!glXMakeCurrent (xcontext->disp, None, NULL)) { - printf ("Could not release drawing context.\n"); - } - glXDestroyContext (xcontext->disp, xcontext->glx); - xcontext->glx = NULL; - } -#if 0 // not used: prepared for fs mode - /* switch back to original desktop resolution if we were in fs */ - if (GLWin.fs) { - XF86VidModeSwitchToMode (GLWin.dpy, GLWin.screen, &GLWin.deskMode); - XF86VidModeSetViewPort (GLWin.dpy, GLWin.screen, 0, 0); - } -#endif - - /* If we did not create that window we just free the GC and let it live */ - if (xwindow->internal) - XDestroyWindow (glimagesink->xcontext->disp, xwindow->win); - else - XSelectInput (glimagesink->xcontext->disp, xwindow->win, 0); - - printf ("Check Xwindow destroy !\n"); - - g_mutex_unlock (glimagesink->x_lock); - - g_free (xwindow); -} - -/* This function resizes a GstGLWindow */ -static void -gst_glimagesink_xwindow_resize (GstGLImageSink * glimagesink, - GstGLWindow * xwindow, guint width, guint height) -{ - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink)); - - g_mutex_lock (glimagesink->x_lock); - - xwindow->width = width; - xwindow->height = height; - - XResizeWindow (glimagesink->xcontext->disp, xwindow->win, - xwindow->width, xwindow->height); - - printf ("No xwindow resize implemented yet !\n"); - - g_mutex_unlock (glimagesink->x_lock); -} - -static void -gst_glimagesink_xwindow_update_geometry (GstGLImageSink * glimagesink, - GstGLWindow * xwindow) -{ - XWindowAttributes attr; - - g_return_if_fail (xwindow != NULL); - g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink)); - - /* Update the window geometry */ - g_mutex_lock (glimagesink->x_lock); - XGetWindowAttributes (glimagesink->xcontext->disp, - glimagesink->window->win, &attr); - g_mutex_unlock (glimagesink->x_lock); - - // FIXME: Need to introduce OpenGL setup here if PROJECTION_MATRIX depends on width/height - //printf("No update geometry implemented yet !\n"); - - glimagesink->window->width = attr.width; - glimagesink->window->height = attr.height; -} - -#if 0 -static void -gst_glimagesink_renegotiate_size (GstGLImageSink * glimagesink) -{ - g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink)); - - if (!glimagesink->window) - return; - - gst_glimagesink_xwindow_update_geometry (glimagesink, glimagesink->window); - - if (glimagesink->window->width <= 1 || glimagesink->window->height <= 1) - return; - - if (GST_PAD_IS_NEGOTIATING (GST_VIDEOSINK_PAD (glimagesink)) || - !gst_pad_is_negotiated (GST_VIDEOSINK_PAD (glimagesink))) - return; - - /* Window got resized or moved. We do caps negotiation again to get video - scaler to fit that new size only if size of the window differs from our - size. */ - - if (GST_VIDEOSINK_WIDTH (glimagesink) != glimagesink->window->width || - GST_VIDEOSINK_HEIGHT (glimagesink) != glimagesink->window->height) { - GstPadLinkReturn r; - - r = gst_pad_try_set_caps (GST_VIDEOSINK_PAD (glimagesink), - gst_caps_new_simple ("video/x-raw-rgb", - "bpp", G_TYPE_INT, glimagesink->xcontext->bpp, - "depth", G_TYPE_INT, glimagesink->xcontext->depth, - "endianness", G_TYPE_INT, glimagesink->xcontext->endianness, - "red_mask", G_TYPE_INT, glimagesink->xcontext->visual->red_mask, - "green_mask", G_TYPE_INT, glimagesink->xcontext->visual->green_mask, - "blue_mask", G_TYPE_INT, glimagesink->xcontext->visual->blue_mask, - "width", G_TYPE_INT, glimagesink->window->width, - "height", G_TYPE_INT, glimagesink->window->height, - "framerate", G_TYPE_DOUBLE, glimagesink->framerate, NULL)); - - if ((r == GST_PAD_LINK_OK) || (r == GST_PAD_LINK_DONE)) { - /* Renegotiation succeeded, we update our size and image */ - GST_VIDEOSINK_WIDTH (glimagesink) = glimagesink->window->width; - GST_VIDEOSINK_HEIGHT (glimagesink) = glimagesink->window->height; - - if ((glimagesink->glimage) && - ((GST_VIDEOSINK_WIDTH (glimagesink) != glimagesink->glimage->width) || - (GST_VIDEOSINK_HEIGHT (glimagesink) != - glimagesink->glimage->height))) { - /* We renew our ximage only if size changed */ - gst_glimagesink_ximage_destroy (glimagesink, glimagesink->glimage); - - glimagesink->glimage = gst_glimagesink_ximage_new (glimagesink, - GST_VIDEOSINK_WIDTH (glimagesink), - GST_VIDEOSINK_HEIGHT (glimagesink)); - } - } - } -} -#endif - -/* This function handles XEvents that might be in the queue. It generates - GstEvent that will be sent upstream in the pipeline to handle interactivity - and navigation. It will also listen for configure events on the window to - trigger caps renegotiation so on the fly software scaling can work. */ -static void -gst_glimagesink_handle_xevents (GstGLImageSink * glimagesink, GstPad * pad) -{ - XEvent e; - - glimagesink->pointer_moved = FALSE; - - g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink)); - - //printf("handling xevents\n"); - - //gst_glimagesink_renegotiate_size (glimagesink); - - /* Then we get all pointer motion events, only the last position is - interesting. */ - g_mutex_lock (glimagesink->x_lock); - while (XCheckWindowEvent (glimagesink->xcontext->disp, - glimagesink->window->win, PointerMotionMask, &e)) { - g_mutex_unlock (glimagesink->x_lock); - - switch (e.type) { - case MotionNotify: - glimagesink->pointer_x = e.xmotion.x; - glimagesink->pointer_y = e.xmotion.y; - glimagesink->pointer_moved = TRUE; - break; - default: - break; - } - - g_mutex_lock (glimagesink->x_lock); - } - g_mutex_unlock (glimagesink->x_lock); - - if (glimagesink->pointer_moved) { - GST_DEBUG ("glimagesink pointer moved over window at %d,%d", - glimagesink->pointer_x, glimagesink->pointer_y); - gst_navigation_send_mouse_event (GST_NAVIGATION (glimagesink), - "mouse-move", 0, glimagesink->pointer_x, glimagesink->pointer_y); - } - - /* We get all remaining events on our window to throw them upstream */ - g_mutex_lock (glimagesink->x_lock); - while (XCheckWindowEvent (glimagesink->xcontext->disp, - glimagesink->window->win, - KeyPressMask | KeyReleaseMask | - ButtonPressMask | ButtonReleaseMask, &e)) { - KeySym keysym; - - /* We lock only for the X function call */ - g_mutex_unlock (glimagesink->x_lock); - - switch (e.type) { - case ButtonPress: - /* Mouse button pressed/released over our window. We send upstream - events for interactivity/navigation */ - GST_DEBUG ("glimagesink button %d pressed over window at %d,%d", - e.xbutton.button, e.xbutton.x, e.xbutton.x); - glimagesink->pointer_button[e.xbutton.button - Button1] = TRUE; - gst_navigation_send_mouse_event (GST_NAVIGATION (glimagesink), - "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y); - break; - case ButtonRelease: - GST_DEBUG ("glimagesink button %d release over window at %d,%d", - e.xbutton.button, e.xbutton.x, e.xbutton.x); - glimagesink->pointer_button[e.xbutton.button - Button1] = FALSE; - gst_navigation_send_mouse_event (GST_NAVIGATION (glimagesink), - "mouse-button-release", e.xbutton.button, e.xbutton.x, e.xbutton.y); - break; - case KeyPress: - case KeyRelease: - /* Key pressed/released over our window. We send upstream - events for interactivity/navigation */ - GST_DEBUG ("glimagesink key %d released over window at %d,%d", - e.xkey.keycode, e.xkey.x, e.xkey.x); - keysym = XKeycodeToKeysym (glimagesink->xcontext->disp, - e.xkey.keycode, 0); - if (keysym != NoSymbol) { - gst_navigation_send_key_event (GST_NAVIGATION (glimagesink), - e.type == KeyPress ? - "key-press" : "key-release", XKeysymToString (keysym)); - } else { - gst_navigation_send_key_event (GST_NAVIGATION (glimagesink), - e.type == KeyPress ? "key-press" : "key-release", "unknown"); - } - break; - default: - GST_DEBUG ("glimagesink unhandled X event (%d)", e.type); - } - - g_mutex_lock (glimagesink->x_lock); - } - g_mutex_unlock (glimagesink->x_lock); -} - -/* attributes for a single buffered visual in RGBA format with at least - * 4 bits per color and a 16 bit depth buffer */ -static int attrListSingle[] = { - GLX_RGBA, - GLX_RED_SIZE, 4, - GLX_GREEN_SIZE, 4, - GLX_BLUE_SIZE, 4, - GLX_DEPTH_SIZE, 16, - None -}; - -/* attributes for a double buffered visual in RGBA format with at least - * 4 bits per color and a 16 bit depth buffer */ -static int attrListDouble[] = { - GLX_RGBA, GLX_DOUBLEBUFFER, - GLX_RED_SIZE, 4, - GLX_GREEN_SIZE, 4, - GLX_BLUE_SIZE, 4, - GLX_DEPTH_SIZE, 16, - None -}; - -/* This function get the X Display and global infos about it. Everything is - stored in our object and will be cleaned when the object is finalized. Note - here that caps for supported format are generated without any window or - image creation */ -static GstXContext * -gst_glimagesink_xcontext_get (GstGLImageSink * glimagesink) -{ - GstXContext *xcontext = NULL; - int glxMajorVersion, glxMinorVersion; - XPixmapFormatValues *px_formats = NULL; - gint nb_formats = 0, i; - - printf ("Acquiring X context\n"); - - g_return_val_if_fail (GST_IS_GLIMAGESINK (glimagesink), NULL); - - xcontext = g_new0 (GstXContext, 1); - - g_mutex_lock (glimagesink->x_lock); - - xcontext->disp = XOpenDisplay (glimagesink->display_name); - - if (!xcontext->disp) { - g_mutex_unlock (glimagesink->x_lock); - g_free (xcontext); - GST_ELEMENT_ERROR (glimagesink, RESOURCE, TOO_LAZY, (NULL), - ("Could not open display")); - return NULL; - } - - xcontext->screen_num = DefaultScreen (xcontext->disp); - xcontext->screen = DefaultScreenOfDisplay (xcontext->disp); - - /* get an appropriate visual */ - xcontext->visualinfo = - glXChooseVisual (xcontext->disp, xcontext->screen_num, attrListDouble); - if (xcontext->visualinfo == NULL) { - xcontext->visualinfo = - glXChooseVisual (xcontext->disp, xcontext->screen_num, attrListSingle); - GST_DEBUG ("Only Singlebuffered Visual!\n"); - - if (xcontext->visualinfo == NULL) - GST_ELEMENT_ERROR (glimagesink, RESOURCE, TOO_LAZY, (NULL), - ("Could not open GLX connection")); - } else { - GST_DEBUG ("Got Doublebuffered Visual!\n"); - } - glXQueryVersion (xcontext->disp, &glxMajorVersion, &glxMinorVersion); - GST_DEBUG ("glX-Version %d.%d\n", glxMajorVersion, glxMinorVersion); - - printf ("Creating GLX context\n"); - - /* create a GLX context */ - xcontext->glx = - glXCreateContext (xcontext->disp, xcontext->visualinfo, NULL, GL_TRUE); - - if (glXIsDirect (xcontext->disp, xcontext->glx)) - printf ("Congrats, you have Direct Rendering!\n"); - else - printf ("Sorry, no Direct Rendering possible!\n"); - - xcontext->endianness = - (ImageByteOrder (xcontext->disp) == - LSBFirst) ? G_LITTLE_ENDIAN : G_BIG_ENDIAN; - - xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num); - xcontext->root = DefaultRootWindow (xcontext->disp); - -#if 1 - - xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num); - xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num); - xcontext->depth = DefaultDepthOfScreen (xcontext->screen); - - /* We get supported pixmap formats at supported depth */ - px_formats = XListPixmapFormats (xcontext->disp, &nb_formats); - - if (!px_formats) { - XCloseDisplay (xcontext->disp); - g_mutex_unlock (glimagesink->x_lock); - g_free (xcontext); - return NULL; - } - - /* We get bpp value corresponding to our running depth */ - for (i = 0; i < nb_formats; i++) { - if (px_formats[i].depth == xcontext->depth) - xcontext->bpp = px_formats[i].bits_per_pixel; - } - - XFree (px_formats); -#endif - - /* our caps system handles 24/32bpp RGB as big-endian. */ - if ((xcontext->bpp == 24 || xcontext->bpp == 32) && - xcontext->endianness == G_LITTLE_ENDIAN) { - xcontext->endianness = G_BIG_ENDIAN; - xcontext->visual->red_mask = GUINT32_TO_BE (xcontext->visual->red_mask); - xcontext->visual->green_mask = GUINT32_TO_BE (xcontext->visual->green_mask); - xcontext->visual->blue_mask = GUINT32_TO_BE (xcontext->visual->blue_mask); - if (xcontext->bpp == 24) { - xcontext->visual->red_mask >>= 8; - xcontext->visual->green_mask >>= 8; - xcontext->visual->blue_mask >>= 8; - } - } - - xcontext->endianness = G_BIG_ENDIAN; - xcontext->visual->red_mask = 0xff0000; - xcontext->visual->green_mask = 0xff00; - xcontext->visual->blue_mask = 0xff; - xcontext->bpp = 24; - xcontext->depth = 24; - - //char yuvformat[4] = {'Y', 'V', '1', '2'}; - - if (!glimagesink->signal_handoffs) - xcontext->caps = gst_caps_new_simple ("video/x-raw-rgb", - "bpp", G_TYPE_INT, xcontext->bpp, - "depth", G_TYPE_INT, xcontext->depth, - "endianness", G_TYPE_INT, xcontext->endianness, - "red_mask", G_TYPE_INT, xcontext->visual->red_mask, - "green_mask", G_TYPE_INT, xcontext->visual->green_mask, - "blue_mask", G_TYPE_INT, xcontext->visual->blue_mask, - "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "framerate", GST_TYPE_DOUBLE_RANGE, 1.0, 100.0, NULL); - else - xcontext->caps = gst_caps_new_simple ("video/x-raw-yuv", - // "format", GST_TYPE_FOURCC, GST_PROPS_FOURCC (GST_STR_FOURCC ("YV12")), - "width", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "height", GST_TYPE_INT_RANGE, 1, G_MAXINT, - "framerate", GST_TYPE_DOUBLE_RANGE, 1.0, 100.0, NULL); - - g_mutex_unlock (glimagesink->x_lock); - - return xcontext; -} - -/* This function cleans the X context. Closing the Display and unrefing the - caps for supported formats. */ -static void -gst_glimagesink_xcontext_clear (GstGLImageSink * glimagesink) -{ - g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink)); - - gst_caps_free (glimagesink->xcontext->caps); - - g_mutex_lock (glimagesink->x_lock); - - XCloseDisplay (glimagesink->xcontext->disp); - - g_mutex_unlock (glimagesink->x_lock); - - glimagesink->xcontext = NULL; -} - -static void -gst_glimagesink_imagepool_clear (GstGLImageSink * glimagesink) -{ - g_mutex_lock (glimagesink->pool_lock); - - while (glimagesink->image_pool) { - GstGLImage *ximage = glimagesink->image_pool->data; - - glimagesink->image_pool = g_slist_delete_link (glimagesink->image_pool, - glimagesink->image_pool); - gst_glimagesink_ximage_destroy (glimagesink, ximage); - } - - g_mutex_unlock (glimagesink->pool_lock); -} - /* ================= Element stuff @@ -832,7 +88,7 @@ gst_glimagesink_fixate (GstPad * pad, const GstCaps * caps) GstStructure *structure; GstCaps *newcaps; - printf ("Linking the sink\n"); + GST_DEBUG ("Linking the sink"); if (gst_caps_get_size (caps) > 1) return NULL; @@ -855,26 +111,47 @@ gst_glimagesink_fixate (GstPad * pad, const GstCaps * caps) return NULL; } +static void +gst_caps_set_all (GstCaps * caps, char *field, ...) +{ + GstStructure *structure; + va_list var_args; + int i; + + for (i = 0; i < gst_caps_get_size (caps); i++) { + structure = gst_caps_get_structure (caps, i); + + va_start (var_args, field); + gst_structure_set_valist (structure, field, var_args); + va_end (var_args); + } +} + static GstCaps * gst_glimagesink_getcaps (GstPad * pad) { GstGLImageSink *glimagesink; + GstCaps *caps; glimagesink = GST_GLIMAGESINK (gst_pad_get_parent (pad)); - if (glimagesink->xcontext) - return gst_caps_copy (glimagesink->xcontext->caps); + if (glimagesink->display == NULL) { + return gst_caps_copy (gst_pad_get_pad_template_caps (pad)); + } -#if 0 - if (!glimagesink->signal_handoffs) - return gst_caps_from_string ("video/x-raw-rgb, " - "framerate = (double) [ 1, 100 ], " - "width = (int) [ 0, MAX ], " "height = (int) [ 0, MAX ]"); - else + caps = gst_caps_from_string (GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx); +#ifdef ENABLE_YUV + if (glimagesink->have_yuv) { + gst_caps_append (caps, + gst_caps_from_string (GST_VIDEO_CAPS_YUV ("{ UYVY, YUY2 }"))); + } #endif - return gst_caps_from_string ("video/x-raw-yuv, " - "framerate = (double) [ 1, 100 ], " - "width = (int) [ 0, MAX ], " "height = (int) [ 0, MAX ]"); + + gst_caps_set_all (caps, + "width", GST_TYPE_INT_RANGE, 16, glimagesink->max_texture_size, + "height", GST_TYPE_INT_RANGE, 16, glimagesink->max_texture_size, NULL); + + return caps; } static GstPadLinkReturn @@ -886,13 +163,6 @@ gst_glimagesink_sink_link (GstPad * pad, const GstCaps * caps) glimagesink = GST_GLIMAGESINK (gst_pad_get_parent (pad)); - if (!glimagesink->xcontext) - return GST_PAD_LINK_DELAYED; - - GST_DEBUG_OBJECT (glimagesink, - "sinkconnect possible caps %" GST_PTR_FORMAT " with given caps %" - GST_PTR_FORMAT, glimagesink->xcontext->caps, caps); - structure = gst_caps_get_structure (caps, 0); ret = gst_structure_get_int (structure, "width", &(GST_VIDEOSINK_WIDTH (glimagesink))); @@ -909,25 +179,31 @@ gst_glimagesink_sink_link (GstPad * pad, const GstCaps * caps) glimagesink->pixel_height = 1; gst_structure_get_int (structure, "pixel_height", &glimagesink->pixel_height); - /* Creating our window and our image */ - if (!glimagesink->window) - glimagesink->window = gst_glimagesink_xwindow_new (glimagesink, - GST_VIDEOSINK_WIDTH (glimagesink), GST_VIDEOSINK_HEIGHT (glimagesink)); - else { - if (glimagesink->window->internal) - gst_glimagesink_xwindow_resize (glimagesink, glimagesink->window, - GST_VIDEOSINK_WIDTH (glimagesink), - GST_VIDEOSINK_HEIGHT (glimagesink)); - } + if (strcmp (gst_structure_get_name (structure), "video/x-raw-rgb") == 0) { + int red_mask; - if ((glimagesink->glimage) && ((GST_VIDEOSINK_WIDTH (glimagesink) != glimagesink->glimage->width) || (GST_VIDEOSINK_HEIGHT (glimagesink) != glimagesink->glimage->height))) { /* We renew our ximage only if size changed */ - gst_glimagesink_ximage_destroy (glimagesink, glimagesink->glimage); + glimagesink->use_rgb = TRUE; + gst_structure_get_int (structure, "red_mask", &red_mask); - glimagesink->glimage = gst_glimagesink_ximage_new (glimagesink, - GST_VIDEOSINK_WIDTH (glimagesink), GST_VIDEOSINK_HEIGHT (glimagesink)); - } else if (!glimagesink->glimage) /* If no ximage, creating one */ - glimagesink->glimage = gst_glimagesink_ximage_new (glimagesink, - GST_VIDEOSINK_WIDTH (glimagesink), GST_VIDEOSINK_HEIGHT (glimagesink)); + if (red_mask == 0xff000000) { + glimagesink->use_rgbx = TRUE; + } else { + glimagesink->use_rgbx = FALSE; + } + } else { + unsigned int fourcc; + + glimagesink->use_rgb = FALSE; + + gst_structure_get_fourcc (structure, "format", &fourcc); + if (fourcc == GST_MAKE_FOURCC ('Y', 'U', 'Y', '2')) { + glimagesink->use_yuy2 = TRUE; + } else { + glimagesink->use_yuy2 = FALSE; + } + } + + gst_glimagesink_set_window_size (glimagesink); gst_x_overlay_got_desired_size (GST_X_OVERLAY (glimagesink), GST_VIDEOSINK_WIDTH (glimagesink), GST_VIDEOSINK_HEIGHT (glimagesink)); @@ -935,32 +211,124 @@ gst_glimagesink_sink_link (GstPad * pad, const GstCaps * caps) return GST_PAD_LINK_OK; } +static gboolean +gst_glimagesink_init_display (GstGLImageSink * glimagesink) +{ + gboolean ret; + XVisualInfo *visinfo; + Screen *screen; + Window root; + int scrnum; + int attrib[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, GLX_BLUE_SIZE, 8, None + }; + XSetWindowAttributes attr; + int error_base; + int event_base; + int mask; + const char *extstring; + + glimagesink->display = XOpenDisplay (NULL); + if (glimagesink->display == NULL) { + GST_ERROR ("Could not open display"); + return FALSE; + } + + screen = XDefaultScreenOfDisplay (glimagesink->display); + scrnum = XScreenNumberOfScreen (screen); + root = XRootWindow (glimagesink->display, scrnum); + + ret = glXQueryExtension (glimagesink->display, &error_base, &event_base); + if (!ret) { + GST_ERROR ("No GLX extension"); + return FALSE; + } + + visinfo = glXChooseVisual (glimagesink->display, scrnum, attrib); + if (visinfo == NULL) { + GST_ERROR ("No usable visual"); + return FALSE; + } + + glimagesink->context = glXCreateContext (glimagesink->display, + visinfo, NULL, True); + + attr.background_pixel = 0; + attr.border_pixel = 0; + attr.colormap = XCreateColormap (glimagesink->display, root, + visinfo->visual, AllocNone); + attr.event_mask = StructureNotifyMask | ExposureMask; + + mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask; + + glimagesink->window = XCreateWindow (glimagesink->display, root, + 0, 0, + GST_VIDEOSINK_WIDTH (glimagesink), GST_VIDEOSINK_HEIGHT (glimagesink), + 0, visinfo->depth, InputOutput, visinfo->visual, mask, &attr); + + XMapWindow (glimagesink->display, glimagesink->window); + XFree (visinfo); + + glXMakeCurrent (glimagesink->display, 0, NULL); + glXMakeCurrent (glimagesink->display, glimagesink->window, + glimagesink->context); + + glGetIntegerv (GL_MAX_TEXTURE_SIZE, &glimagesink->max_texture_size); + + extstring = (const char *) glGetString (GL_EXTENSIONS); + if (strstr (extstring, "GL_MESA_ycbcr_texture")) { + glimagesink->have_yuv = TRUE; + } else { + glimagesink->have_yuv = FALSE; + } + + glDepthFunc (GL_LESS); + glEnable (GL_DEPTH_TEST); + glClearColor (0.2, 0.2, 0.2, 1.0); + + return TRUE; +} + +static void +gst_glimagesink_set_window_size (GstGLImageSink * glimagesink) +{ + GST_ERROR ("resizing to %d x %d", + GST_VIDEOSINK_WIDTH (glimagesink), GST_VIDEOSINK_HEIGHT (glimagesink)); + + if (glimagesink->display) { + XResizeWindow (glimagesink->display, glimagesink->window, + GST_VIDEOSINK_WIDTH (glimagesink), GST_VIDEOSINK_HEIGHT (glimagesink)); + glXMakeCurrent (glimagesink->display, None, NULL); + glXMakeCurrent (glimagesink->display, glimagesink->window, + glimagesink->context); + } +} + static GstElementStateReturn gst_glimagesink_change_state (GstElement * element) { GstGLImageSink *glimagesink; - printf ("change state\n"); + GST_DEBUG ("change state"); glimagesink = GST_GLIMAGESINK (element); switch (GST_STATE_TRANSITION (element)) { case GST_STATE_NULL_TO_READY: - /* Initializing the XContext */ - if (!glimagesink->xcontext) { - glimagesink->xcontext = gst_glimagesink_xcontext_get (glimagesink); - if (!glimagesink->xcontext) - return GST_STATE_FAILURE; + if (!gst_glimagesink_init_display (glimagesink)) { + GST_ELEMENT_ERROR (glimagesink, RESOURCE, WRITE, (NULL), + ("Could not initialize OpenGL")); + return GST_STATE_FAILURE; } - printf ("null to ready done\n"); break; case GST_STATE_READY_TO_PAUSED: - printf ("ready to paused\n"); - //if (glimagesink->window) // not needed with OpenGL - // gst_glimagesink_xwindow_clear (glimagesink, glimagesink->window); + GST_DEBUG ("ready to paused"); glimagesink->time = 0; break; case GST_STATE_PAUSED_TO_PLAYING: + if (!glimagesink->parent_window) { + XMapWindow (glimagesink->display, glimagesink->window); + } break; case GST_STATE_PLAYING_TO_PAUSED: break; @@ -970,23 +338,7 @@ gst_glimagesink_change_state (GstElement * element) GST_VIDEOSINK_HEIGHT (glimagesink) = 0; break; case GST_STATE_READY_TO_NULL: - if (glimagesink->glimage) { - gst_glimagesink_ximage_destroy (glimagesink, glimagesink->glimage); - glimagesink->glimage = NULL; - } - - if (glimagesink->image_pool) - gst_glimagesink_imagepool_clear (glimagesink); - - if (glimagesink->window) { - gst_glimagesink_xwindow_destroy (glimagesink, glimagesink->window); - glimagesink->window = NULL; - } - - if (glimagesink->xcontext) { - gst_glimagesink_xcontext_clear (glimagesink); - glimagesink->xcontext = NULL; - } + /* FIXME dispose of window */ break; } @@ -1001,8 +353,9 @@ gst_glimagesink_chain (GstPad * pad, GstData * data) { GstBuffer *buf = GST_BUFFER (data); GstGLImageSink *glimagesink; + int texture_size; - //printf("CHAIN CALL\n"); + //GST_DEBUG("CHAIN CALL"); g_return_if_fail (GST_IS_PAD (pad)); g_return_if_fail (buf != NULL); @@ -1020,34 +373,6 @@ gst_glimagesink_chain (GstPad * pad, GstData * data) glimagesink->time = GST_BUFFER_TIMESTAMP (buf); } - if (glimagesink->signal_handoffs) - g_signal_emit (G_OBJECT (glimagesink), - gst_glimagesink_signals[SIGNAL_HANDOFF], 0, buf, pad); - else { - /* If this buffer has been allocated using our buffer management we simply - put the ximage which is in the PRIVATE pointer */ - if (GST_BUFFER_FREE_DATA_FUNC (buf) == gst_glimagesink_buffer_free) - gst_glimagesink_ximage_put (glimagesink, GST_BUFFER_PRIVATE (buf)); - else { /* Else we have to copy the data into our private image, */ - /* if we have one... */ - printf ("Non-locally allocated: Sub-optimal buffer transfer!\n"); - if (glimagesink->glimage) { -#if 0 - memcpy (glimagesink->glimage->ximage->data, - GST_BUFFER_DATA (buf), - MIN (GST_BUFFER_SIZE (buf), glimagesink->glimage->size)); -#endif - gst_glimagesink_ximage_put (glimagesink, glimagesink->glimage); - } else { /* No image available. Something went wrong during capsnego ! */ - - gst_buffer_unref (buf); - GST_ELEMENT_ERROR (glimagesink, CORE, NEGOTIATION, (NULL), - ("no format defined before chain function")); - return; - } - } - } - GST_DEBUG ("clock wait: %" GST_TIME_FORMAT, GST_TIME_ARGS (glimagesink->time)); @@ -1059,107 +384,92 @@ gst_glimagesink_chain (GstPad * pad, GstData * data) if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf) && glimagesink->framerate > 0) glimagesink->time += GST_SECOND / glimagesink->framerate; - gst_buffer_unref (buf); - - if (!glimagesink->signal_handoffs) - gst_glimagesink_handle_xevents (glimagesink, pad); -} - -/* Buffer management */ - -static void -gst_glimagesink_buffer_free (GstBuffer * buffer) -{ - GstGLImageSink *glimagesink; - GstGLImage *ximage; - - ximage = GST_BUFFER_PRIVATE (buffer); - - g_assert (GST_IS_GLIMAGESINK (ximage->glimagesink)); - glimagesink = ximage->glimagesink; - - /* If our geometry changed we can't reuse that image. */ - if ((ximage->width != GST_VIDEOSINK_WIDTH (glimagesink)) || - (ximage->height != GST_VIDEOSINK_HEIGHT (glimagesink))) - gst_glimagesink_ximage_destroy (glimagesink, ximage); - else { /* In that case we can reuse the image and add it to our image pool. */ - - g_mutex_lock (glimagesink->pool_lock); - glimagesink->image_pool = g_slist_prepend (glimagesink->image_pool, ximage); - g_mutex_unlock (glimagesink->pool_lock); - } -} - -static GstBuffer * -gst_glimagesink_buffer_alloc (GstPad * pad, guint64 offset, guint size) -{ - GstGLImageSink *glimagesink; - GstBuffer *buffer; - GstGLImage *ximage = NULL; - gboolean not_found = TRUE; - - //printf("Allocating new data buffer\n"); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glimagesink = GST_GLIMAGESINK (gst_pad_get_parent (pad)); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); - g_mutex_lock (glimagesink->pool_lock); + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); - /* Walking through the pool cleaning unsuable images and searching for a - suitable one */ - while (not_found && glimagesink->image_pool) { - ximage = glimagesink->image_pool->data; + glDisable (GL_CULL_FACE); + glEnable (GL_TEXTURE_2D); + glEnableClientState (GL_TEXTURE_COORD_ARRAY); - if (ximage) { - /* Removing from the pool */ - glimagesink->image_pool = g_slist_delete_link (glimagesink->image_pool, - glimagesink->image_pool); + glColor4f (1, 1, 1, 1); - if ((ximage->width != GST_VIDEOSINK_WIDTH (glimagesink)) || (ximage->height != GST_VIDEOSINK_HEIGHT (glimagesink))) { /* This image is unusable. Destroying... */ - gst_glimagesink_ximage_destroy (glimagesink, ximage); - ximage = NULL; - } else { /* We found a suitable image */ +#define TEXID 1000 + glBindTexture (GL_TEXTURE_2D, TEXID); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - break; - } + for (texture_size = 64; + (texture_size < GST_VIDEOSINK (glimagesink)->width || + texture_size < GST_VIDEOSINK (glimagesink)->height) && + (texture_size > 0); texture_size <<= 1); + + if (glimagesink->use_rgb) { + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, texture_size, + texture_size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + if (glimagesink->use_rgbx) { + glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, + GST_VIDEOSINK (glimagesink)->width, + GST_VIDEOSINK (glimagesink)->height, + GL_RGBA, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf)); + } else { + glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, + GST_VIDEOSINK (glimagesink)->width, + GST_VIDEOSINK (glimagesink)->height, + GL_BGRA, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf)); + } + } else { + glTexImage2D (GL_TEXTURE_2D, 0, GL_YCBCR_MESA, texture_size, + texture_size, 0, GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_REV_MESA, NULL); + + if (glimagesink->use_yuy2) { + glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, + GST_VIDEOSINK (glimagesink)->width, + GST_VIDEOSINK (glimagesink)->height, + GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_REV_MESA, GST_BUFFER_DATA (buf)); + } else { + glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, + GST_VIDEOSINK (glimagesink)->width, + GST_VIDEOSINK (glimagesink)->height, + GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_MESA, GST_BUFFER_DATA (buf)); } } - g_mutex_unlock (glimagesink->pool_lock); - - if (!ximage) { /* We found no suitable image in the pool. Creating... */ - ximage = gst_glimagesink_ximage_new (glimagesink, - GST_VIDEOSINK_WIDTH (glimagesink), GST_VIDEOSINK_HEIGHT (glimagesink)); - } - - if (ximage) { - buffer = gst_buffer_new (); + glColor4f (1, 0, 1, 1); + glBegin (GL_QUADS); - /* Storing some pointers in the buffer */ - GST_BUFFER_PRIVATE (buffer) = ximage; + glNormal3f (0, 0, -1); - GST_BUFFER_DATA (buffer) = (guint8 *) ximage->data; - GST_BUFFER_FREE_DATA_FUNC (buffer) = gst_glimagesink_buffer_free; - GST_BUFFER_SIZE (buffer) = ximage->size; - return buffer; - } else - return NULL; -} + { + double xmax = GST_VIDEOSINK (glimagesink)->width / (double) texture_size; + double ymax = GST_VIDEOSINK (glimagesink)->height / (double) texture_size; -/* Interfaces stuff */ + glTexCoord2f (xmax, 0); + glVertex3f (1.0, 1.0, 0); + glTexCoord2f (0, 0); + glVertex3f (-1.0, 1.0, 0); + glTexCoord2f (0, ymax); + glVertex3f (-1.0, -1.0, 0); + glTexCoord2f (xmax, ymax); + glVertex3f (1.0, -1.0, 0); + glEnd (); + } -static gboolean -gst_glimagesink_interface_supported (GstImplementsInterface * iface, GType type) -{ - g_assert (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY); - return TRUE; -} + glFlush (); + glXSwapBuffers (glimagesink->display, glimagesink->window); -static void -gst_glimagesink_interface_init (GstImplementsInterfaceClass * klass) -{ - klass->supported = gst_glimagesink_interface_supported; + gst_buffer_unref (buf); } +#if 0 static void gst_glimagesink_navigation_send_event (GstNavigation * navigation, GstStructure * structure) @@ -1199,114 +509,32 @@ gst_glimagesink_navigation_init (GstNavigationInterface * iface) { iface->send_event = gst_glimagesink_navigation_send_event; } +#endif static void gst_glimagesink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id) { GstGLImageSink *glimagesink = GST_GLIMAGESINK (overlay); - GstGLWindow *xwindow = NULL; - XWindowAttributes attr; - printf ("set_xwindow_id\n"); + GST_ERROR ("set_xwindow_id %ld", xwindow_id); g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink)); - /* If we already use that window return */ - if (glimagesink->window && (xwindow_id == glimagesink->window->win)) - return; - /* If the element has not initialized the X11 context try to do so */ - if (!glimagesink->xcontext) - glimagesink->xcontext = gst_glimagesink_xcontext_get (glimagesink); - - if (!glimagesink->xcontext) { - g_warning ("glimagesink was unable to obtain the X11 context."); - return; + if (!glimagesink->display) { + g_warning ("X display not inited\n"); } - /* Clear image pool as the images are unusable anyway */ - gst_glimagesink_imagepool_clear (glimagesink); - - /* Clear the ximage */ - if (glimagesink->glimage) { - gst_glimagesink_ximage_destroy (glimagesink, glimagesink->glimage); - glimagesink->glimage = NULL; - } - - /* If a window is there already we destroy it */ - if (glimagesink->window) { - gst_glimagesink_xwindow_destroy (glimagesink, glimagesink->window); - glimagesink->window = NULL; - } + if (glimagesink->parent_window == xwindow_id) + return; - /* If the xid is 0 we go back to an internal window */ - if (xwindow_id == 0) { - /* If no width/height caps nego did not happen window will be created - during caps nego then */ - if (GST_VIDEOSINK_WIDTH (glimagesink) && GST_VIDEOSINK_HEIGHT (glimagesink)) { - xwindow = gst_glimagesink_xwindow_new (glimagesink, - GST_VIDEOSINK_WIDTH (glimagesink), - GST_VIDEOSINK_HEIGHT (glimagesink)); - } - } else { - GST_ELEMENT_ERROR (glimagesink, RESOURCE, TOO_LAZY, (NULL), - ("glimagesink is incapable of connecting to other X windows !")); - exit (100); - - xwindow = g_new0 (GstGLWindow, 1); - - xwindow->win = xwindow_id; - - /* We get window geometry, set the event we want to receive, - and create a GC */ - g_mutex_lock (glimagesink->x_lock); - XGetWindowAttributes (glimagesink->xcontext->disp, xwindow->win, &attr); - xwindow->width = attr.width; - xwindow->height = attr.height; - xwindow->internal = FALSE; - XSelectInput (glimagesink->xcontext->disp, xwindow->win, ExposureMask | - StructureNotifyMask | PointerMotionMask | KeyPressMask | - KeyReleaseMask); - - //xwindow->gc = XCreateGC (glimagesink->xcontext->disp, xwindow->win, 0, NULL); - g_mutex_unlock (glimagesink->x_lock); - - /* If that new window geometry differs from our one we try to - renegotiate caps */ - if (gst_pad_is_negotiated (GST_VIDEOSINK_PAD (glimagesink)) && - (xwindow->width != GST_VIDEOSINK_WIDTH (glimagesink) || - xwindow->height != GST_VIDEOSINK_HEIGHT (glimagesink))) { - GstPadLinkReturn r; - - r = gst_pad_try_set_caps (GST_VIDEOSINK_PAD (glimagesink), - gst_caps_new_simple ("video/x-raw-rgb", - "bpp", G_TYPE_INT, glimagesink->xcontext->bpp, - "depth", G_TYPE_INT, glimagesink->xcontext->depth, - "endianness", G_TYPE_INT, glimagesink->xcontext->endianness, - "red_mask", G_TYPE_INT, glimagesink->xcontext->visual->red_mask, - "green_mask", G_TYPE_INT, - glimagesink->xcontext->visual->green_mask, "blue_mask", - G_TYPE_INT, glimagesink->xcontext->visual->blue_mask, "width", - G_TYPE_INT, xwindow->width, "height", G_TYPE_INT, xwindow->height, - "framerate", G_TYPE_DOUBLE, glimagesink->framerate, NULL)); - - /* If caps nego succeded updating our size */ - if ((r == GST_PAD_LINK_OK) || (r == GST_PAD_LINK_DONE)) { - GST_VIDEOSINK_WIDTH (glimagesink) = xwindow->width; - GST_VIDEOSINK_HEIGHT (glimagesink) = xwindow->height; - } - } - } + glimagesink->parent_window = xwindow_id; - /* Recreating our ximage */ - if (!glimagesink->glimage && - GST_VIDEOSINK_WIDTH (glimagesink) && GST_VIDEOSINK_HEIGHT (glimagesink)) { - glimagesink->glimage = gst_glimagesink_ximage_new (glimagesink, - GST_VIDEOSINK_WIDTH (glimagesink), GST_VIDEOSINK_HEIGHT (glimagesink)); - } + GST_ERROR ("reparenting window"); + XSync (glimagesink->display, FALSE); + XReparentWindow (glimagesink->display, glimagesink->window, xwindow_id, 0, 0); + XMapWindow (glimagesink->display, glimagesink->window); - if (xwindow) - glimagesink->window = xwindow; } static void @@ -1324,20 +552,10 @@ gst_glimagesink_expose (GstXOverlay * overlay) { GstGLImageSink *glimagesink = GST_GLIMAGESINK (overlay); - if (!glimagesink->window) - return; - - gst_glimagesink_xwindow_update_geometry (glimagesink, glimagesink->window); - - /* We don't act on internal window from outside that could cause some thread - race with the video sink own thread checking for configure event */ - if (glimagesink->window->internal) + if (!glimagesink->display) return; - //gst_glimagesink_xwindow_clear (glimagesink, glimagesink->window); - - if (glimagesink->cur_image) - gst_glimagesink_ximage_put (glimagesink, glimagesink->cur_image); + /* Don't need to do anything */ } static void @@ -1368,15 +586,6 @@ gst_glimagesink_set_property (GObject * object, guint prop_id, case ARG_DISPLAY: glimagesink->display_name = g_strdup (g_value_get_string (value)); break; - case ARG_SYNCHRONOUS: - glimagesink->synchronous = g_value_get_boolean (value); - if (glimagesink->xcontext) { - XSynchronize (glimagesink->xcontext->disp, glimagesink->synchronous); - case ARG_SIGNAL_HANDOFFS: - glimagesink->signal_handoffs = g_value_get_boolean (value); - break; - } - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1397,12 +606,6 @@ gst_glimagesink_get_property (GObject * object, guint prop_id, case ARG_DISPLAY: g_value_set_string (value, g_strdup (glimagesink->display_name)); break; - case ARG_SYNCHRONOUS: - g_value_set_boolean (value, glimagesink->synchronous); - break; - case ARG_SIGNAL_HANDOFFS: - g_value_set_boolean (value, glimagesink->signal_handoffs); - break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -1416,14 +619,6 @@ gst_glimagesink_finalize (GObject * object) glimagesink = GST_GLIMAGESINK (object); - if (glimagesink->display_name) { - g_free (glimagesink->display_name); - glimagesink->display_name = NULL; - } - - g_mutex_free (glimagesink->x_lock); - g_mutex_free (glimagesink->pool_lock); - G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -1445,26 +640,11 @@ gst_glimagesink_init (GstGLImageSink * glimagesink) gst_glimagesink_getcaps); gst_pad_set_fixate_function (GST_VIDEOSINK_PAD (glimagesink), gst_glimagesink_fixate); - gst_pad_set_bufferalloc_function (GST_VIDEOSINK_PAD (glimagesink), - gst_glimagesink_buffer_alloc); - - glimagesink->display_name = NULL; - glimagesink->xcontext = NULL; - glimagesink->window = NULL; - glimagesink->glimage = NULL; - glimagesink->cur_image = NULL; - - glimagesink->framerate = 0; - - glimagesink->x_lock = g_mutex_new (); - - glimagesink->pixel_width = glimagesink->pixel_height = 1; - - glimagesink->image_pool = NULL; - glimagesink->pool_lock = g_mutex_new (); - glimagesink->synchronous = FALSE; - glimagesink->signal_handoffs = FALSE; + glimagesink->pixel_width = 1; + glimagesink->pixel_height = 1; + GST_VIDEOSINK_WIDTH (glimagesink) = 100; + GST_VIDEOSINK_HEIGHT (glimagesink) = 100; GST_FLAG_SET (glimagesink, GST_ELEMENT_THREAD_SUGGESTED); GST_FLAG_SET (glimagesink, GST_ELEMENT_EVENT_AWARE); @@ -1495,31 +675,6 @@ gst_glimagesink_class_init (GstGLImageSinkClass * klass) g_object_class_install_property (gobject_class, ARG_DISPLAY, g_param_spec_string ("display", "Display", "X Display name", NULL, G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_SYNCHRONOUS, - g_param_spec_boolean ("synchronous", "Synchronous", "When enabled, runs " - "the X display in synchronous mode. (used only for debugging)", FALSE, - G_PARAM_READWRITE)); - g_object_class_install_property (gobject_class, ARG_SIGNAL_HANDOFFS, - g_param_spec_boolean ("signal-handoffs", "Signal handoffs", - "Send a signal before unreffing the buffer, forces YUV, no GL output", - FALSE, G_PARAM_READWRITE)); -#if 0 // needed ? - g_object_class_install_property (gobject_class, ARG_SIGNAL_BUFFER_ALLOC, - g_param_spec_boolean ("signal-bufferalloc", "Signal buffer allocation", - "Asks the application for a buffer allocation", FALSE, - G_PARAM_READWRITE)); -#endif - - gst_glimagesink_signals[SIGNAL_HANDOFF] = - g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstGLImageSinkClass, handoff), NULL, NULL, - gst_marshal_VOID__POINTER_OBJECT, G_TYPE_NONE, 2, - GST_TYPE_BUFFER, GST_TYPE_PAD); - gst_glimagesink_signals[SIGNAL_BUFALLOC] = - g_signal_new ("bufferalloc", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GstGLImageSinkClass, bufferalloc), NULL, NULL, - gst_marshal_VOID__POINTER_OBJECT, G_TYPE_NONE, 2, - GST_TYPE_BUFFER, GST_TYPE_PAD); gobject_class->finalize = gst_glimagesink_finalize; gobject_class->set_property = gst_glimagesink_set_property; @@ -1528,6 +683,18 @@ gst_glimagesink_class_init (GstGLImageSinkClass * klass) gstelement_class->change_state = gst_glimagesink_change_state; } +static gboolean +gst_glimagesink_interface_supported (GstImplementsInterface * iface, GType type) +{ + return TRUE; +} + +static void +gst_glimagesink_interface_init (GstImplementsInterfaceClass * klass) +{ + klass->supported = gst_glimagesink_interface_supported; +} + /* ============================================================= */ /* */ /* Public Methods */ @@ -1562,11 +729,13 @@ gst_glimagesink_get_type (void) NULL, NULL, }; +#if 0 static const GInterfaceInfo navigation_info = { (GInterfaceInitFunc) gst_glimagesink_navigation_init, NULL, NULL, }; +#endif static const GInterfaceInfo overlay_info = { (GInterfaceInitFunc) gst_glimagesink_xoverlay_init, NULL, @@ -1578,8 +747,10 @@ gst_glimagesink_get_type (void) g_type_add_interface_static (glimagesink_type, GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info); +#if 0 g_type_add_interface_static (glimagesink_type, GST_TYPE_NAVIGATION, &navigation_info); +#endif g_type_add_interface_static (glimagesink_type, GST_TYPE_X_OVERLAY, &overlay_info); } @@ -1595,7 +766,7 @@ plugin_init (GstPlugin * plugin) return FALSE; if (!gst_element_register (plugin, "glimagesink", - GST_RANK_SECONDARY, GST_TYPE_GLIMAGESINK)) + GST_RANK_PRIMARY + 1, GST_TYPE_GLIMAGESINK)) return FALSE; GST_DEBUG_CATEGORY_INIT (gst_debug_glimagesink, "glimagesink", 0, -- cgit v1.2.1