summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--configure.ac18
-rw-r--r--sys/Makefile.am14
-rw-r--r--sys/glsink/Makefile.am6
-rw-r--r--sys/glsink/glimagesink.c1911
-rw-r--r--sys/glsink/glimagesink.h137
6 files changed, 593 insertions, 1502 deletions
diff --git a/ChangeLog b/ChangeLog
index 222749aa..e9fee14e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2006-01-27 David Schleef <ds@schleef.org>
+
+ * configure.ac:
+ * sys/Makefile.am:
+ * sys/glsink/Makefile.am:
+ * sys/glsink/glimagesink.c:
+ * sys/glsink/glimagesink.h:
+ revival of glimagesink. Kind of works.
+
2006-01-27 Tim-Philipp Müller <tim at centricular dot net>
* ext/faad/gstfaad.c: (gst_faad_setcaps),
diff --git a/configure.ac b/configure.ac
index 5f0fb04f..33106b4c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -319,6 +319,14 @@ dnl ###########################
dnl # Configure external libs #
dnl ###########################
+#dnl *** cairo ***
+#translit(dnm, m, l) AM_CONDITIONAL(USE_CAIRO, true)
+#GST_CHECK_FEATURE(CAIRO, [cairo plug-in], cairo, [
+# PKG_CHECK_MODULES(CAIRO, cairo >= 1.0 glitz-glx, HAVE_CAIRO=yes, HAVE_CAIRO=no)
+# AC_SUBST(CAIRO_CFLAGS)
+# AC_SUBST(CAIRO_LIBS)
+#])
+
dnl **** DirectFB ****
translit(dnm, m, l) AM_CONDITIONAL(USE_DIRECTFB, true)
GST_CHECK_FEATURE(DIRECTFB, [directfb], dfbvideosink , [
@@ -536,6 +544,13 @@ GST_CHECK_FEATURE(GSM, [GSM library], gsmenc gsmdec, [
AC_SUBST(GSM_LIBS)
])
+dnl *** OpenGL ***
+translit(dnm, m, l) AM_CONDITIONAL(USE_OPENGL, true)
+GST_CHECK_FEATURE(OPENGL, [Open GL], glsink, [
+ GST_CHECK_LIBHEADER(GL, GLU, glTexImage2D,,
+ GL/gl.h, HAVE_OPENGL="yes", HAVE_OPENGL="no")
+])
+
dnl *** XVID ***
translit(dnm, m, l) AM_CONDITIONAL(USE_XVID, true)
GST_CHECK_FEATURE(XVID, [xvid plugins], xvid, [
@@ -633,13 +648,13 @@ gst/speed/Makefile
gst/qtdemux/Makefile
gst/tta/Makefile
sys/Makefile
+sys/glsink/Makefile
examples/Makefile
examples/directfb/Makefile
ext/Makefile
ext/directfb/Makefile
ext/faac/Makefile
ext/faad/Makefile
-ext/swfdec/Makefile
ext/wavpack/Makefile
ext/ivorbis/Makefile
ext/gsm/Makefile
@@ -649,6 +664,7 @@ ext/dts/Makefile
ext/divx/Makefile
ext/musepack/Makefile
ext/sdl/Makefile
+ext/swfdec/Makefile
ext/xvid/Makefile
docs/Makefile
docs/plugins/Makefile
diff --git a/sys/Makefile.am b/sys/Makefile.am
index 82df59ee..b64b99e8 100644
--- a/sys/Makefile.am
+++ b/sys/Makefile.am
@@ -28,12 +28,12 @@
# CDROM_DIR=
# endif
-# if USE_OPENGL
-# GL_DIR=glsink
-# else
-# GL_DIR=
-# endif
+if USE_OPENGL
+GL_DIR=glsink
+else
+GL_DIR=
+endif
-SUBDIRS =
+SUBDIRS = $(GL_DIR)
-DIST_SUBDIRS =
+DIST_SUBDIRS = glsink
diff --git a/sys/glsink/Makefile.am b/sys/glsink/Makefile.am
index 68c45153..e442f308 100644
--- a/sys/glsink/Makefile.am
+++ b/sys/glsink/Makefile.am
@@ -2,9 +2,9 @@
plugin_LTLIBRARIES = libgstglimagesink.la
libgstglimagesink_la_SOURCES = glimagesink.c
-libgstglimagesink_la_CFLAGS = $(GST_CFLAGS) $(X_CFLAGS)
-libgstglimagesink_la_LIBADD = $(X_LIBS) $(XSHM_LIBS) -lGL -lGLU\
- $(top_builddir)/gst-libs/gst/libgstinterfaces-$(GST_MAJORMINOR).la
+libgstglimagesink_la_CFLAGS = $(GST_CFLAGS) $(X_CFLAGS) $(GST_BASE_CFLAGS)
+libgstglimagesink_la_LIBADD = $(X_LIBS) $(XSHM_LIBS) -lGL -lGLU \
+ $(GST_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) -lgstinterfaces-$(GST_MAJORMINOR)
libgstglimagesink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
noinst_HEADERS = glimagesink.h
diff --git a/sys/glsink/glimagesink.c b/sys/glsink/glimagesink.c
index efef625a..348fc330 100644
--- a/sys/glsink/glimagesink.c
+++ b/sys/glsink/glimagesink.c
@@ -1,5 +1,6 @@
/* GStreamer
- * Copyright (C) <2003> Julien Moutte <julien@moutte.net>
+ * Copyright (C) 2003 Julien Moutte <julien@moutte.net>
+ * Copyright (C) 2005,2006 David A. Schleef <ds@schleef.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,1583 +22,785 @@
#include "config.h"
#endif
-/* Our interfaces */
-#include <gst/navigation/navigation.h>
-#include <gst/xoverlay/xoverlay.h>
-/* Object header */
-#include "glimagesink.h"
+#include <gst/gst.h>
+#include <gst/interfaces/xoverlay.h>
+#include <gst/video/gstvideosink.h>
+#include <gst/video/video.h>
-/* Debugging category */
-#include <gst/gstinfo.h>
-GST_DEBUG_CATEGORY_STATIC (gst_debug_glimagesink);
-#define GST_CAT_DEFAULT gst_debug_glimagesink
+#include <string.h>
-static void gst_glimagesink_buffer_free (GstBuffer * buffer);
+#include <GL/glx.h>
+#include <GL/gl.h>
+#include <GL/glu.h>
-/* ElementFactory information */
-static GstElementDetails gst_glimagesink_details =
-GST_ELEMENT_DETAILS ("Video sink",
- "Sink/Video",
- "An OpenGL 1.2 based videosink",
- "Gernot Ziegler <gz@lysator.liu.se>, Julien Moutte <julien@moutte.net>");
+GST_DEBUG_CATEGORY (gst_debug_glimage_sink);
+#define GST_CAT_DEFAULT gst_debug_glimage_sink
-/* Default template - initiated with class struct to allow gst-register to work
- without X running */
-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 ]")
- );
+#define GST_TYPE_GLIMAGE_SINK \
+ (gst_glimage_sink_get_type())
+#define GST_GLIMAGE_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GLIMAGE_SINK,GstGLImageSink))
+#define GST_GLIMAGE_SINK_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_GLIMAGE_SINK,GstGLImageSinkClass))
+#define GST_IS_GLIMAGE_SINK(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GLIMAGE_SINK))
+#define GST_IS_GLIMAGE_SINK_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_GLIMAGE_SINK))
-/* GLImageSink signals and args */
-enum
-{
- SIGNAL_HANDOFF,
- SIGNAL_BUFALLOC,
- LAST_SIGNAL
- /* FILL ME */
-};
+typedef struct _GstGLImageSink GstGLImageSink;
+typedef struct _GstGLImageSinkClass GstGLImageSinkClass;
-static guint gst_glimagesink_signals[LAST_SIGNAL] = { 0 };
-
-enum
+struct _GstGLImageSink
{
- ARG_0,
- ARG_DISPLAY,
- ARG_SYNCHRONOUS,
- ARG_SIGNAL_HANDOFFS
- /* FILL ME */
-};
+ GstVideoSink video_sink;
-static GstVideoSinkClass *parent_class = NULL;
+ /* properties */
+ char *display_name;
-/* ============================================================= */
-/* */
-/* Private Methods */
-/* */
-/* ============================================================= */
+ /* caps */
+ GstCaps *caps;
+ int fps_n, fps_d;
+ int par_n, par_d;
+ int height, width;
-/* 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;
+ Window window;
+ Window parent_window;
+ XVisualInfo *visinfo;
- g_return_val_if_fail (GST_IS_GLIMAGESINK (glimagesink), NULL);
+ Display *display;
+ GLXContext context;
- ximage = g_new0 (GstGLImage, 1);
+ int max_texture_size;
+ gboolean have_yuv;
- 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;
+ gboolean use_rgb;
+ gboolean use_rgbx;
+ gboolean use_yuy2;
+};
- printf ("No ximage_new yet !\n");
+struct _GstGLImageSinkClass
+{
+ GstVideoSinkClass video_sink_class;
- {
- ximage->data = g_malloc (ximage->size);
+};
- ximage->texid = 1000;
- }
+static void gst_glimage_sink_finalize (GObject * object);
+static void gst_glimage_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * param_spec);
+static void gst_glimage_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * param_spec);
- if (0) // can't fail !
- {
- if (ximage->data)
- g_free (ximage->data);
+static GstStateChangeReturn
+gst_glimage_sink_change_state (GstElement * element, GstStateChange transition);
+
+static void gst_glimage_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
+ GstClockTime * start, GstClockTime * end);
+static GstCaps *gst_glimage_sink_get_caps (GstBaseSink * bsink);
+static gboolean gst_glimage_sink_set_caps (GstBaseSink * bsink, GstCaps * caps);
+static GstFlowReturn gst_glimage_sink_render (GstBaseSink * bsink,
+ GstBuffer * buf);
+
+static void gst_glimage_sink_create_window (GstGLImageSink * glimage_sink);
+static gboolean gst_glimage_sink_init_display (GstGLImageSink * glimage_sink);
+static void gst_glimage_sink_update_caps (GstGLImageSink * glimage_sink);
+static void gst_glimage_sink_push_image (GstGLImageSink * glimage_sink,
+ GstBuffer * buf);
+
+static GstElementDetails gst_glimage_sink_details =
+GST_ELEMENT_DETAILS ("OpenGL video sink",
+ "Sink/Video",
+ "A videosink based on OpenGL",
+ "David Schleef <ds@schleef.org>");
- g_free (ximage);
- //ximage = NULL;
- }
+#ifdef GL_YCBCR_MESA
+#define YUV_CAPS ";" GST_VIDEO_CAPS_YUV ("{ UYVY, YUY2 }")
+#else
+#define YUV_CAPS
+#endif
+static GstStaticPadTemplate gst_glimage_sink_template =
+ GST_STATIC_PAD_TEMPLATE ("sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_STATIC_CAPS (GST_VIDEO_CAPS_RGBx ";" GST_VIDEO_CAPS_BGRx YUV_CAPS)
+ );
- g_mutex_unlock (glimagesink->x_lock);
+enum
+{
+ ARG_0,
+ ARG_DISPLAY
+};
- return ximage;
-}
+GST_BOILERPLATE (GstGLImageSink, gst_glimage_sink, GstVideoSink,
+ GST_TYPE_VIDEO_SINK);
-/* This function destroys a GstGLImage handling XShm availability */
static void
-gst_glimagesink_ximage_destroy (GstGLImageSink * glimagesink,
- GstGLImage * ximage)
+gst_glimage_sink_base_init (gpointer g_class)
{
- 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);
- }
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- g_mutex_unlock (glimagesink->x_lock);
+ gst_element_class_set_details (element_class, &gst_glimage_sink_details);
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_glimage_sink_template));
- g_free (ximage);
}
-/* This function puts a GstGLImage on a GstGLImagesink's window */
static void
-gst_glimagesink_ximage_put (GstGLImageSink * glimagesink, GstGLImage * ximage)
+gst_glimage_sink_class_init (GstGLImageSinkClass * klass)
{
- 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);
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+ GstBaseSinkClass *gstbasesink_class;
- glTexCoord2f (xmax, ymax);
- glVertex3f (1, -1, 0);
- glEnd ();
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+ gstbasesink_class = (GstBaseSinkClass *) klass;
-#if 1 // for pointer feedback, later
- glDisable (GL_TEXTURE_2D);
- if (glimagesink->pointer_moved)
- glColor3f (1, 1, 1);
- else
- glColor3f (1, 0, 1);
+ gobject_class->set_property = gst_glimage_sink_set_property;
+ gobject_class->get_property = gst_glimage_sink_get_property;
- if (glimagesink->pointer_button[0])
- glColor3f (1, 0, 0);
+ g_object_class_install_property (gobject_class, ARG_DISPLAY,
+ g_param_spec_string ("display", "Display", "X Display name",
+ NULL, G_PARAM_READWRITE));
- 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
+ gobject_class->finalize = gst_glimage_sink_finalize;
- glXSwapBuffers (glimagesink->xcontext->disp, glimagesink->window->win);
+ gstelement_class->change_state = gst_glimage_sink_change_state;
- g_mutex_unlock (glimagesink->x_lock);
+ gstbasesink_class->get_caps = gst_glimage_sink_get_caps;
+ gstbasesink_class->set_caps = gst_glimage_sink_set_caps;
+ gstbasesink_class->get_times = gst_glimage_sink_get_times;
+ gstbasesink_class->preroll = gst_glimage_sink_render;
+ gstbasesink_class->render = gst_glimage_sink_render;
}
-/* This function handles a GstXWindow creation */
-static GstGLWindow *
-gst_glimagesink_xwindow_new (GstGLImageSink * glimagesink, gint width,
- gint height)
+static void
+gst_glimage_sink_init (GstGLImageSink * glimage_sink,
+ GstGLImageSinkClass * glimage_sink_class)
{
- 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);
+ int screen;
- xwindow->width = width;
- xwindow->height = height;
- xwindow->internal = TRUE;
+ //glimage_sink->display = XOpenDisplay (NULL);
- g_mutex_lock (glimagesink->x_lock);
+ screen = DefaultScreen (glimage_sink->display);
- /* 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);
+ //XSynchronize(glimage_sink->display, True);
+ //XSetErrorHandler (error_handler);
+ glimage_sink->width = 400;
+ glimage_sink->height = 400;
- 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;
+ gst_glimage_sink_update_caps (glimage_sink);
+ glimage_sink->display_name = g_strdup ("");
}
-/* This function destroys a GstGLWindow */
static void
-gst_glimagesink_xwindow_destroy (GstGLImageSink * glimagesink,
- GstGLWindow * xwindow)
+gst_glimage_sink_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
{
- GstXContext *xcontext = glimagesink->xcontext;
+ GstGLImageSink *glimage_sink;
- g_return_if_fail (xwindow != NULL);
- g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink));
+ g_return_if_fail (GST_IS_GLIMAGE_SINK (object));
- g_mutex_lock (glimagesink->x_lock);
+ glimage_sink = GST_GLIMAGE_SINK (object);
- 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);
+ switch (prop_id) {
+ case ARG_DISPLAY:
+ if (glimage_sink->display_name) {
+ g_free (glimage_sink->display_name);
+ }
+ glimage_sink->display_name = g_strdup (g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
}
-#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)
+gst_glimage_sink_finalize (GObject * object)
{
- g_return_if_fail (xwindow != NULL);
- g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink));
-
- g_mutex_lock (glimagesink->x_lock);
+ GstGLImageSink *glimage_sink;
- xwindow->width = width;
- xwindow->height = height;
+ g_return_if_fail (GST_IS_GLIMAGE_SINK (object));
- XResizeWindow (glimagesink->xcontext->disp, xwindow->win,
- xwindow->width, xwindow->height);
+ glimage_sink = GST_GLIMAGE_SINK (object);
- printf ("No xwindow resize implemented yet !\n");
+ gst_caps_unref (glimage_sink->caps);
+ g_free (glimage_sink->display_name);
- g_mutex_unlock (glimagesink->x_lock);
}
static void
-gst_glimagesink_xwindow_update_geometry (GstGLImageSink * glimagesink,
- GstGLWindow * xwindow)
+gst_glimage_sink_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
{
- XWindowAttributes attr;
+ GstGLImageSink *glimage_sink;
- g_return_if_fail (xwindow != NULL);
- g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink));
+ g_return_if_fail (GST_IS_GLIMAGE_SINK (object));
- /* Update the window geometry */
- g_mutex_lock (glimagesink->x_lock);
- XGetWindowAttributes (glimagesink->xcontext->disp,
- glimagesink->window->win, &attr);
- g_mutex_unlock (glimagesink->x_lock);
+ glimage_sink = GST_GLIMAGE_SINK (object);
- // 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;
+ switch (prop_id) {
+ case ARG_DISPLAY:
+ g_value_set_string (value, g_strdup (glimage_sink->display_name));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
}
-#if 0
-static void
-gst_glimagesink_renegotiate_size (GstGLImageSink * glimagesink)
-{
- g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink));
-
- if (!glimagesink->window)
- return;
+/*
+ * GstElement methods
+ */
- gst_glimagesink_xwindow_update_geometry (glimagesink, glimagesink->window);
+static GstStateChangeReturn
+gst_glimage_sink_change_state (GstElement * element, GstStateChange transition)
+{
+ GstGLImageSink *glimage_sink;
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
- if (glimagesink->window->width <= 1 || glimagesink->window->height <= 1)
- return;
+ GST_DEBUG ("change state");
- if (GST_PAD_IS_NEGOTIATING (GST_VIDEOSINK_PAD (glimagesink)) ||
- !gst_pad_is_negotiated (GST_VIDEOSINK_PAD (glimagesink)))
- return;
+ glimage_sink = GST_GLIMAGE_SINK (element);
- /* 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));
+ switch (transition) {
+ case GST_STATE_CHANGE_NULL_TO_READY:
+ if (!gst_glimage_sink_init_display (glimage_sink)) {
+ GST_ELEMENT_ERROR (glimage_sink, RESOURCE, WRITE, (NULL),
+ ("Could not initialize OpenGL"));
+ return GST_STATE_CHANGE_FAILURE;
}
- }
+ break;
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ break;
+ default:
+ break;
}
-}
-#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;
+ ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+ if (ret == GST_STATE_CHANGE_FAILURE)
+ return ret;
- g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink));
+ switch (transition) {
+ case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ break;
+ case GST_STATE_CHANGE_PAUSED_TO_READY:
+ /* FIXME clear window */
+ glimage_sink->fps_n = 0;
+ glimage_sink->fps_d = 1;
+ GST_VIDEO_SINK_WIDTH (glimage_sink) = 0;
+ GST_VIDEO_SINK_HEIGHT (glimage_sink) = 0;
+ break;
+ case GST_STATE_CHANGE_READY_TO_NULL:
+ /* FIXME dispose of window */
+ break;
+ default:
+ break;
+ }
- //printf("handling xevents\n");
+ return ret;
+}
- //gst_glimagesink_renegotiate_size (glimagesink);
+/*
+ * GstBaseSink methods
+ */
- /* 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);
+static void
+gst_glimage_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
+ GstClockTime * start, GstClockTime * end)
+{
- 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);
+static GstCaps *
+gst_glimage_sink_get_caps (GstBaseSink * bsink)
+{
+ GstGLImageSink *glimage_sink;
- 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);
- }
+ glimage_sink = GST_GLIMAGE_SINK (bsink);
- /* 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);
- }
+ GST_DEBUG ("get caps returning %" GST_PTR_FORMAT, glimage_sink->caps);
- g_mutex_lock (glimagesink->x_lock);
- }
- g_mutex_unlock (glimagesink->x_lock);
+ return gst_caps_ref (glimage_sink->caps);
}
-/* 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)
+static gboolean
+gst_glimage_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
{
- 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);
+ GstGLImageSink *glimage_sink;
+ GstCaps *intersection;
+ GstStructure *structure;
+ int width;
+ int height;
+ gboolean ret;
+ const GValue *fps;
+ const GValue *par;
- xcontext = g_new0 (GstXContext, 1);
+ GST_DEBUG ("set caps with %" GST_PTR_FORMAT, caps);
- g_mutex_lock (glimagesink->x_lock);
+ glimage_sink = GST_GLIMAGE_SINK (bsink);
- xcontext->disp = XOpenDisplay (glimagesink->display_name);
+ intersection = gst_caps_intersect (glimage_sink->caps, caps);
- 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;
+ if (gst_caps_is_empty (intersection)) {
+ return FALSE;
}
- xcontext->screen_num = DefaultScreen (xcontext->disp);
- xcontext->screen = DefaultScreenOfDisplay (xcontext->disp);
+ gst_caps_unref (intersection);
- /* 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");
+ structure = gst_caps_get_structure (caps, 0);
+ ret = gst_structure_get_int (structure, "width", &width);
+ ret &= gst_structure_get_int (structure, "height", &height);
+ fps = gst_structure_get_value (structure, "framerate");
+ ret &= (fps != NULL);
+ par = gst_structure_get_value (structure, "pixel-aspect-ratio");
+
+ if (!ret)
+ return FALSE;
- if (xcontext->visualinfo == NULL)
- GST_ELEMENT_ERROR (glimagesink, RESOURCE, TOO_LAZY, (NULL),
- ("Could not open GLX connection"));
+ glimage_sink->width = width;
+ glimage_sink->height = height;
+ glimage_sink->fps_n = gst_value_get_fraction_numerator (fps);
+ glimage_sink->fps_d = gst_value_get_fraction_denominator (fps);
+ if (par) {
+ glimage_sink->par_n = gst_value_get_fraction_numerator (par);
+ glimage_sink->par_d = gst_value_get_fraction_denominator (par);
} else {
- GST_DEBUG ("Got Doublebuffered Visual!\n");
+ glimage_sink->par_n = 1;
+ glimage_sink->par_d = 1;
}
- 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, 0, 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;
+ GST_VIDEO_SINK_WIDTH (glimage_sink) = width;
+ GST_VIDEO_SINK_HEIGHT (glimage_sink) = height;
- xcontext->visual = DefaultVisual (xcontext->disp, xcontext->screen_num);
- xcontext->root = DefaultRootWindow (xcontext->disp);
+ if (strcmp (gst_structure_get_name (structure), "video/x-raw-rgb") == 0) {
+ int red_mask;
-#if 1
+ GST_DEBUG ("using RGB");
+ glimage_sink->use_rgb = TRUE;
+ gst_structure_get_int (structure, "red_mask", &red_mask);
- xcontext->white = XWhitePixel (xcontext->disp, xcontext->screen_num);
- xcontext->black = XBlackPixel (xcontext->disp, xcontext->screen_num);
- xcontext->depth = DefaultDepthOfScreen (xcontext->screen);
+ if (red_mask == 0xff000000) {
+ glimage_sink->use_rgbx = TRUE;
+ } else {
+ glimage_sink->use_rgbx = FALSE;
+ }
+ } else {
+ unsigned int fourcc;
- /* We get supported pixmap formats at supported depth */
- px_formats = XListPixmapFormats (xcontext->disp, &nb_formats);
+ GST_DEBUG ("using YUV");
+ glimage_sink->use_rgb = FALSE;
- if (!px_formats) {
- XCloseDisplay (xcontext->disp);
- g_mutex_unlock (glimagesink->x_lock);
- g_free (xcontext);
- return NULL;
+ gst_structure_get_fourcc (structure, "format", &fourcc);
+ if (fourcc == GST_MAKE_FOURCC ('Y', 'U', 'Y', '2')) {
+ glimage_sink->use_yuy2 = TRUE;
+ } else {
+ glimage_sink->use_yuy2 = FALSE;
+ }
}
- /* 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;
+#if 0
+ if (!glimage_sink->window) {
+ gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (glimage_sink));
}
-
- 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;
- }
+ if (!glimage_sink->window) {
+ gst_glimage_sink_create_window (glimage_sink);
}
- 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;
+ return TRUE;
}
-/* This function cleans the X context. Closing the Display and unrefing the
- caps for supported formats. */
-static void
-gst_glimagesink_xcontext_clear (GstGLImageSink * glimagesink)
+static GstFlowReturn
+gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf)
{
- g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink));
-
- gst_caps_free (glimagesink->xcontext->caps);
-
- g_mutex_lock (glimagesink->x_lock);
+ GstGLImageSink *glimage_sink;
- XCloseDisplay (glimagesink->xcontext->disp);
+ glimage_sink = GST_GLIMAGE_SINK (bsink);
- g_mutex_unlock (glimagesink->x_lock);
+ gst_glimage_sink_push_image (glimage_sink, buf);
- glimagesink->xcontext = NULL;
+ return GST_FLOW_OK;
}
-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
-=================
-*/
+/*
+ * helper functions
+ */
-static GstCaps *
-gst_glimagesink_fixate (GstPad * pad, const GstCaps * caps)
+static void
+gst_caps_set_all (GstCaps * caps, char *field, ...)
{
GstStructure *structure;
- GstCaps *newcaps;
-
- printf ("Linking the sink\n");
+ va_list var_args;
+ int i;
- if (gst_caps_get_size (caps) > 1)
- return NULL;
+ for (i = 0; i < gst_caps_get_size (caps); i++) {
+ structure = gst_caps_get_structure (caps, i);
- newcaps = gst_caps_copy (caps);
- structure = gst_caps_get_structure (newcaps, 0);
-
- if (gst_structure_fixate_field_nearest_int (structure, "width", 320)) {
- return newcaps;
- }
- if (gst_structure_fixate_field_nearest_int (structure, "height", 240)) {
- return newcaps;
+ va_start (var_args, field);
+ gst_structure_set_valist (structure, field, var_args);
+ va_end (var_args);
}
- if (gst_structure_fixate_field_nearest_double (structure, "framerate", 30.0)) {
- return newcaps;
- }
-
- gst_caps_free (newcaps);
- return NULL;
}
-static GstCaps *
-gst_glimagesink_getcaps (GstPad * pad)
+static void
+gst_glimage_sink_update_caps (GstGLImageSink * glimage_sink)
{
- GstGLImageSink *glimagesink;
+ GstCaps *caps;
+ int max_size;
- glimagesink = GST_GLIMAGESINK (gst_pad_get_parent (pad));
-
- if (glimagesink->xcontext)
- return gst_caps_copy (glimagesink->xcontext->caps);
+ if (glimage_sink->display == NULL) {
+ gst_caps_unref (glimage_sink->caps);
+ glimage_sink->caps =
+ gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD
+ (glimage_sink)));
+ return;
+ }
-#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 GL_YCBCR_MESA
+ if (glimage_sink->have_yuv) {
+ GstCaps *ycaps =
+ gst_caps_from_string (GST_VIDEO_CAPS_YUV ("{ UYVY, YUY2 }"));
+ gst_caps_append (ycaps, caps);
+ caps = ycaps;
+ }
#endif
- return gst_caps_from_string ("video/x-raw-yuv, "
- "framerate = (double) [ 1, 100 ], "
- "width = (int) [ 0, MAX ], " "height = (int) [ 0, MAX ]");
-}
-
-static GstPadLinkReturn
-gst_glimagesink_sink_link (GstPad * pad, const GstCaps * caps)
-{
- GstGLImageSink *glimagesink;
- gboolean ret;
- GstStructure *structure;
-
- 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)));
- ret &= gst_structure_get_int (structure, "height",
- &(GST_VIDEOSINK_HEIGHT (glimagesink)));
- ret &= gst_structure_get_double (structure,
- "framerate", &glimagesink->framerate);
- if (!ret)
- return GST_PAD_LINK_REFUSED;
-
- glimagesink->pixel_width = 1;
- gst_structure_get_int (structure, "pixel_width", &glimagesink->pixel_width);
-
- 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));
+ max_size = glimage_sink->max_texture_size;
+ if (max_size == 0) {
+ max_size = 1024;
}
- 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));
- } else if (!glimagesink->glimage) /* If no ximage, creating one */
- glimagesink->glimage = gst_glimagesink_ximage_new (glimagesink,
- GST_VIDEOSINK_WIDTH (glimagesink), GST_VIDEOSINK_HEIGHT (glimagesink));
-
- gst_x_overlay_got_desired_size (GST_X_OVERLAY (glimagesink),
- GST_VIDEOSINK_WIDTH (glimagesink), GST_VIDEOSINK_HEIGHT (glimagesink));
-
- return GST_PAD_LINK_OK;
-}
+ gst_caps_set_all (caps,
+ "width", GST_TYPE_INT_RANGE, 16, max_size,
+ "height", GST_TYPE_INT_RANGE, 16, max_size, NULL);
-static GstStateChangeReturn
-gst_glimagesink_change_state (GstElement * element, GstStateChange transition)
-{
- GstGLImageSink *glimagesink;
-
- printf ("change state\n");
-
- glimagesink = GST_GLIMAGESINK (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- /* Initializing the XContext */
- if (!glimagesink->xcontext) {
- glimagesink->xcontext = gst_glimagesink_xcontext_get (glimagesink);
- if (!glimagesink->xcontext)
- return GST_STATE_CHANGE_FAILURE;
- }
- printf ("null to ready done\n");
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- printf ("ready to paused\n");
- //if (glimagesink->window) // not needed with OpenGL
- // gst_glimagesink_xwindow_clear (glimagesink, glimagesink->window);
- glimagesink->time = 0;
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- glimagesink->framerate = 0;
- GST_VIDEOSINK_WIDTH (glimagesink) = 0;
- GST_VIDEOSINK_HEIGHT (glimagesink) = 0;
- break;
- case GST_STATE_CHANGE_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;
- }
- break;
+ if (glimage_sink->caps) {
+ gst_caps_unref (glimage_sink->caps);
}
-
- if (GST_ELEMENT_CLASS (parent_class)->change_state)
- return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- return GST_STATE_CHANGE_SUCCESS;
+ glimage_sink->caps = caps;
}
static void
-gst_glimagesink_chain (GstPad * pad, GstData * data)
+gst_glimage_sink_create_window (GstGLImageSink * glimage_sink)
{
- GstBuffer *buf = GST_BUFFER (data);
- GstGLImageSink *glimagesink;
-
- //printf("CHAIN CALL\n");
-
- g_return_if_fail (GST_IS_PAD (pad));
- g_return_if_fail (buf != NULL);
-
- glimagesink = GST_GLIMAGESINK (gst_pad_get_parent (pad));
-
- if (GST_IS_EVENT (data)) {
- gst_pad_event_default (pad, GST_EVENT (data));
- return;
- }
-
- buf = GST_BUFFER (data);
- /* update time */
- if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
- glimagesink->time = GST_BUFFER_TIMESTAMP (buf);
+ gboolean ret;
+ Window root;
+ XSetWindowAttributes attr;
+ Screen *screen;
+ int scrnum;
+ int mask;
+ int width, height;
+
+ screen = XDefaultScreenOfDisplay (glimage_sink->display);
+ scrnum = XScreenNumberOfScreen (screen);
+ root = XRootWindow (glimage_sink->display, scrnum);
+
+ if (glimage_sink->parent_window) {
+ XWindowAttributes pattr;
+
+ XGetWindowAttributes (glimage_sink->display, glimage_sink->parent_window,
+ &pattr);
+ width = pattr.width;
+ height = pattr.height;
+ } else {
+ width = GST_VIDEO_SINK (glimage_sink)->width;
+ height = GST_VIDEO_SINK (glimage_sink)->height;
+ }
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap (glimage_sink->display, root,
+ glimage_sink->visinfo->visual, AllocNone);
+ if (glimage_sink->parent_window) {
+ attr.override_redirect = True;
+ } else {
+ attr.override_redirect = False;
}
- 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 ! */
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect;
- gst_buffer_unref (buf);
- GST_ELEMENT_ERROR (glimagesink, CORE, NEGOTIATION, (NULL),
- ("no format defined before chain function"));
- return;
- }
- }
- }
+ GST_DEBUG ("creating window with size %d x %d", width, height);
- GST_DEBUG ("clock wait: %" GST_TIME_FORMAT,
- GST_TIME_ARGS (glimagesink->time));
+ glimage_sink->window = XCreateWindow (glimage_sink->display, root, 0, 0,
+ width, height,
+ 0, glimage_sink->visinfo->depth, InputOutput,
+ glimage_sink->visinfo->visual, mask, &attr);
- /// ah, BTW, I think the gst_element_wait should happen _before_ the ximage is shown
- if (GST_VIDEOSINK_CLOCK (glimagesink))
- gst_element_wait (GST_ELEMENT (glimagesink), glimagesink->time);
-
- /* set correct time for next buffer */
- if (!GST_BUFFER_TIMESTAMP_IS_VALID (buf) && glimagesink->framerate > 0)
- glimagesink->time += GST_SECOND / glimagesink->framerate;
+ if (glimage_sink->parent_window) {
+ ret = XReparentWindow (glimage_sink->display, glimage_sink->window,
+ glimage_sink->parent_window, 0, 0);
+ XMapWindow (glimage_sink->display, glimage_sink->window);
+ } else {
+ XMapWindow (glimage_sink->display, glimage_sink->window);
+ }
- gst_buffer_unref (buf);
+ glXMakeCurrent (glimage_sink->display, glimage_sink->window,
+ glimage_sink->context);
- if (!glimagesink->signal_handoffs)
- gst_glimagesink_handle_xevents (glimagesink, pad);
+ glDepthFunc (GL_LESS);
+ glEnable (GL_DEPTH_TEST);
+ glClearColor (0.2, 0.2, 0.2, 1.0);
+ glViewport (0, 0, width, height);
}
-/* Buffer management */
-static void
-gst_glimagesink_buffer_free (GstBuffer * buffer)
+static gboolean
+gst_glimage_sink_init_display (GstGLImageSink * glimage_sink)
{
- GstGLImageSink *glimagesink;
- GstGLImage *ximage;
-
- ximage = GST_BUFFER_PRIVATE (buffer);
-
- g_assert (GST_IS_GLIMAGESINK (ximage->glimagesink));
- glimagesink = ximage->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;
+ Window window;
+
+ GST_ERROR ("initializing display");
+
+ glimage_sink->display = XOpenDisplay (NULL);
+ if (glimage_sink->display == NULL) {
+ GST_ERROR ("Could not open display");
+ return FALSE;
+ }
- /* 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. */
+ screen = XDefaultScreenOfDisplay (glimage_sink->display);
+ scrnum = XScreenNumberOfScreen (screen);
+ root = XRootWindow (glimage_sink->display, scrnum);
- g_mutex_lock (glimagesink->pool_lock);
- glimagesink->image_pool = g_slist_prepend (glimagesink->image_pool, ximage);
- g_mutex_unlock (glimagesink->pool_lock);
+ ret = glXQueryExtension (glimage_sink->display, &error_base, &event_base);
+ if (!ret) {
+ GST_ERROR ("No GLX extension");
+ return FALSE;
}
-}
-
-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");
+ visinfo = glXChooseVisual (glimage_sink->display, scrnum, attrib);
+ if (visinfo == NULL) {
+ GST_ERROR ("No usable visual");
+ return FALSE;
+ }
- glimagesink = GST_GLIMAGESINK (gst_pad_get_parent (pad));
+ glimage_sink->visinfo = visinfo;
- g_mutex_lock (glimagesink->pool_lock);
+ glimage_sink->context = glXCreateContext (glimage_sink->display,
+ visinfo, NULL, True);
- /* Walking through the pool cleaning unsuable images and searching for a
- suitable one */
- while (not_found && glimagesink->image_pool) {
- ximage = glimagesink->image_pool->data;
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap (glimage_sink->display, root,
+ visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask;
+ attr.override_redirect = True;
- if (ximage) {
- /* Removing from the pool */
- glimagesink->image_pool = g_slist_delete_link (glimagesink->image_pool,
- glimagesink->image_pool);
+ //mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWOverrideRedirect;
- 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 */
+ window = XCreateWindow (glimage_sink->display, root, 0, 0,
+ 100, 100, 0, visinfo->depth, InputOutput, visinfo->visual, mask, &attr);
- break;
- }
- }
- }
+ glXMakeCurrent (glimage_sink->display, window, glimage_sink->context);
- g_mutex_unlock (glimagesink->pool_lock);
+ glGetIntegerv (GL_MAX_TEXTURE_SIZE, &glimage_sink->max_texture_size);
- 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));
+ extstring = (const char *) glGetString (GL_EXTENSIONS);
+#ifdef GL_YCBCR_MESA
+ if (strstr (extstring, "GL_MESA_ycbcr_texture")) {
+ glimage_sink->have_yuv = TRUE;
+ } else {
+ glimage_sink->have_yuv = FALSE;
}
+#else
+ glimage_sink->have_yuv = FALSE;
+#endif
- if (ximage) {
- buffer = gst_buffer_new ();
-
- /* Storing some pointers in the buffer */
- GST_BUFFER_PRIVATE (buffer) = ximage;
-
- GST_BUFFER_DATA (buffer) = ximage->data;
- GST_BUFFER_FREE_DATA_FUNC (buffer) = gst_glimagesink_buffer_free;
- GST_BUFFER_SIZE (buffer) = ximage->size;
- return buffer;
- } else
- return NULL;
-}
-
-/* Interfaces stuff */
+ glXMakeCurrent (glimage_sink->display, None, NULL);
+ XDestroyWindow (glimage_sink->display, window);
-static gboolean
-gst_glimagesink_interface_supported (GstImplementsInterface * iface, GType type)
-{
- g_assert (type == GST_TYPE_NAVIGATION || type == GST_TYPE_X_OVERLAY);
return TRUE;
}
static void
-gst_glimagesink_interface_init (GstImplementsInterfaceClass * klass)
-{
- klass->supported = gst_glimagesink_interface_supported;
-}
-
-static void
-gst_glimagesink_navigation_send_event (GstNavigation * navigation,
- GstStructure * structure)
+gst_glimage_sink_push_image (GstGLImageSink * glimage_sink, GstBuffer * buf)
{
- GstGLImageSink *glimagesink = GST_GLIMAGESINK (navigation);
- GstEvent *event;
- gint x_offset, y_offset;
- double x, y;
-
- event = gst_event_new (GST_EVENT_NAVIGATION);
- event->event_data.structure.structure = structure;
-
- /* We are not converting the pointer coordinates as there's no hardware
- scaling done here. The only possible scaling is done by videoscale and
- videoscale will have to catch those events and tranform the coordinates
- to match the applied scaling. So here we just add the offset if the image
- is centered in the window. */
-
- x_offset = glimagesink->window->width - GST_VIDEOSINK_WIDTH (glimagesink);
- y_offset = glimagesink->window->height - GST_VIDEOSINK_HEIGHT (glimagesink);
-
- if (gst_structure_get_double (structure, "pointer_x", &x)) {
- x += x_offset;
- gst_structure_set (structure, "pointer_x", G_TYPE_DOUBLE, x, NULL);
- }
- if (gst_structure_get_double (structure, "pointer_y", &y)) {
- y += y_offset;
- gst_structure_set (structure, "pointer_y", G_TYPE_DOUBLE, y, NULL);
- }
-
- gst_pad_send_event (gst_pad_get_peer (GST_VIDEOSINK_PAD (glimagesink)),
- event);
-}
+ int texture_size;
+ XWindowAttributes attr;
-static void
-gst_glimagesink_navigation_init (GstNavigationInterface * iface)
-{
- iface->send_event = gst_glimagesink_navigation_send_event;
-}
+ g_return_if_fail (buf != NULL);
-static void
-gst_glimagesink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id)
-{
- GstGLImageSink *glimagesink = GST_GLIMAGESINK (overlay);
- GstGLWindow *xwindow = NULL;
- XWindowAttributes attr;
+ if (glimage_sink->display == NULL || glimage_sink->window == 0) {
+ g_warning ("display or window not set up\n");
+ }
- printf ("set_xwindow_id\n");
+ glXMakeCurrent (glimage_sink->display, glimage_sink->window,
+ glimage_sink->context);
- g_return_if_fail (GST_IS_GLIMAGESINK (glimagesink));
+ if (glimage_sink->parent_window) {
+ XGetWindowAttributes (glimage_sink->display, glimage_sink->parent_window,
+ &attr);
+ //gst_glimage_sink_set_window_size (glimage_sink, attr.width, attr.height);
+ } else {
+ XGetWindowAttributes (glimage_sink->display, glimage_sink->window, &attr);
+ glViewport (0, 0, attr.width, attr.height);
+ }
- /* If we already use that window return */
- if (glimagesink->window && (xwindow_id == glimagesink->window->win))
- return;
+ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- /* If the element has not initialized the X11 context try to do so */
- if (!glimagesink->xcontext)
- glimagesink->xcontext = gst_glimagesink_xcontext_get (glimagesink);
+ glMatrixMode (GL_PROJECTION);
+ glLoadIdentity ();
- if (!glimagesink->xcontext) {
- g_warning ("glimagesink was unable to obtain the X11 context.");
- return;
- }
+ glMatrixMode (GL_MODELVIEW);
+ glLoadIdentity ();
- /* Clear image pool as the images are unusable anyway */
- gst_glimagesink_imagepool_clear (glimagesink);
+ glDisable (GL_CULL_FACE);
+ glEnable (GL_TEXTURE_2D);
+ glEnableClientState (GL_TEXTURE_COORD_ARRAY);
- /* Clear the ximage */
- if (glimagesink->glimage) {
- gst_glimagesink_ximage_destroy (glimagesink, glimagesink->glimage);
- glimagesink->glimage = NULL;
- }
+ glColor4f (1, 1, 1, 1);
- /* If a window is there already we destroy it */
- if (glimagesink->window) {
- gst_glimagesink_xwindow_destroy (glimagesink, glimagesink->window);
- glimagesink->window = NULL;
- }
+#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);
- /* 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));
+ for (texture_size = 64;
+ (texture_size < GST_VIDEO_SINK (glimage_sink)->width ||
+ texture_size < GST_VIDEO_SINK (glimage_sink)->height) &&
+ (texture_size > 0); texture_size <<= 1);
+
+ if (glimage_sink->use_rgb) {
+ glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, texture_size,
+ texture_size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ if (glimage_sink->use_rgbx) {
+ glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
+ GST_VIDEO_SINK (glimage_sink)->width,
+ GST_VIDEO_SINK (glimage_sink)->height,
+ GL_RGBA, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
+ } else {
+ glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
+ GST_VIDEO_SINK (glimage_sink)->width,
+ GST_VIDEO_SINK (glimage_sink)->height,
+ GL_BGRA, GL_UNSIGNED_BYTE, GST_BUFFER_DATA (buf));
}
} 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;
- }
+#ifdef GL_YCBCR_MESA
+ 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 (glimage_sink->use_yuy2) {
+ glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
+ GST_VIDEO_SINK (glimage_sink)->width,
+ GST_VIDEO_SINK (glimage_sink)->height,
+ GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_REV_MESA, GST_BUFFER_DATA (buf));
+ } else {
+ glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0,
+ GST_VIDEO_SINK (glimage_sink)->width,
+ GST_VIDEO_SINK (glimage_sink)->height,
+ GL_YCBCR_MESA, GL_UNSIGNED_SHORT_8_8_MESA, GST_BUFFER_DATA (buf));
}
+#else
+ g_assert_not_reached ();
+#endif
}
- /* 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));
- }
-
- if (xwindow)
- glimagesink->window = xwindow;
-}
-
-static void
-gst_glimagesink_get_desired_size (GstXOverlay * overlay,
- guint * width, guint * height)
-{
- GstGLImageSink *glimagesink = GST_GLIMAGESINK (overlay);
-
- *width = GST_VIDEOSINK_WIDTH (glimagesink);
- *height = GST_VIDEOSINK_HEIGHT (glimagesink);
-}
-
-static void
-gst_glimagesink_expose (GstXOverlay * overlay)
-{
- GstGLImageSink *glimagesink = GST_GLIMAGESINK (overlay);
-
- if (!glimagesink->window)
- return;
+ glColor4f (1, 0, 1, 1);
+ glBegin (GL_QUADS);
- gst_glimagesink_xwindow_update_geometry (glimagesink, glimagesink->window);
+ glNormal3f (0, 0, -1);
- /* 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)
- return;
+ {
+ double xmax = GST_VIDEO_SINK (glimage_sink)->width / (double) texture_size;
+ double ymax = GST_VIDEO_SINK (glimage_sink)->height / (double) texture_size;
- //gst_glimagesink_xwindow_clear (glimagesink, glimagesink->window);
+ 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 ();
+ }
- if (glimagesink->cur_image)
- gst_glimagesink_ximage_put (glimagesink, glimagesink->cur_image);
+ glFlush ();
+ glXSwapBuffers (glimage_sink->display, glimage_sink->window);
}
-static void
-gst_glimagesink_xoverlay_init (GstXOverlayClass * iface)
-{
- iface->set_xwindow_id = gst_glimagesink_set_xwindow_id;
- iface->get_desired_size = gst_glimagesink_get_desired_size;
- iface->expose = gst_glimagesink_expose;
-}
-/* =========================================== */
-/* */
-/* Init & Class init */
-/* */
-/* =========================================== */
+#ifdef unused
-static void
-gst_glimagesink_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstGLImageSink *glimagesink;
- g_return_if_fail (GST_IS_GLIMAGESINK (object));
+static void gst_glimage_sink_set_window_size (GstGLImageSink * glimage_sink,
+ int width, int height);
- glimagesink = GST_GLIMAGESINK (object);
- switch (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;
- }
-}
static void
-gst_glimagesink_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
+gst_glimage_sink_set_window_size (GstGLImageSink * glimage_sink,
+ int width, int height)
{
- GstGLImageSink *glimagesink;
-
- g_return_if_fail (GST_IS_GLIMAGESINK (object));
-
- glimagesink = GST_GLIMAGESINK (object);
+ GST_DEBUG ("resizing to %d x %d",
+ GST_VIDEO_SINK_WIDTH (glimage_sink),
+ GST_VIDEO_SINK_HEIGHT (glimage_sink));
- switch (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;
+ if (glimage_sink->display && glimage_sink->window) {
+ XResizeWindow (glimage_sink->display, glimage_sink->window, width, height);
+ XSync (glimage_sink->display, False);
+ glViewport (0, 0, width, height);
}
}
-static void
-gst_glimagesink_finalize (GObject * object)
-{
- GstGLImageSink *glimagesink;
-
- 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);
-}
static void
-gst_glimagesink_init (GstGLImageSink * glimagesink)
+gst_glimage_sink_set_xwindow_id (GstXOverlay * overlay, XID xwindow_id)
{
- GST_VIDEOSINK_PAD (glimagesink) =
- gst_pad_new_from_template (gst_static_pad_template_get
- (&gst_glimagesink_sink_template_factory), "sink");
-
- gst_element_add_pad (GST_ELEMENT (glimagesink),
- GST_VIDEOSINK_PAD (glimagesink));
-
- gst_pad_set_chain_function (GST_VIDEOSINK_PAD (glimagesink),
- gst_glimagesink_chain);
- gst_pad_set_link_function (GST_VIDEOSINK_PAD (glimagesink),
- gst_glimagesink_sink_link);
- gst_pad_set_getcaps_function (GST_VIDEOSINK_PAD (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);
+ GstGLImageSink *glimage_sink = GST_GLIMAGE_SINK (overlay);
- glimagesink->display_name = NULL;
- glimagesink->xcontext = NULL;
- glimagesink->window = NULL;
- glimagesink->glimage = NULL;
- glimagesink->cur_image = NULL;
+ GST_DEBUG ("set_xwindow_id %ld", xwindow_id);
- glimagesink->framerate = 0;
+ g_return_if_fail (GST_IS_GLIMAGE_SINK (glimage_sink));
- 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;
-
- GST_OBJECT_FLAG_SET (glimagesink, GST_ELEMENT_THREAD_SUGGESTED);
- GST_OBJECT_FLAG_SET (glimagesink, GST_ELEMENT_EVENT_AWARE);
-}
+ /* If the element has not initialized the X11 context try to do so */
+ if (!glimage_sink->display) {
+ g_warning ("X display not inited\n");
+ }
-static void
-gst_glimagesink_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ if (glimage_sink->parent_window == xwindow_id)
+ return;
- gst_element_class_set_details (element_class, &gst_glimagesink_details);
+ glimage_sink->parent_window = xwindow_id;
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_glimagesink_sink_template_factory));
+ XSync (glimage_sink->display, False);
+ gst_glimage_sink_create_window (glimage_sink);
}
-static void
-gst_glimagesink_class_init (GstGLImageSinkClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
-
- parent_class = g_type_class_ref (GST_TYPE_VIDEOSINK);
-
- 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;
- gobject_class->get_property = gst_glimagesink_get_property;
-
- gstelement_class->change_state = gst_glimagesink_change_state;
-}
-
-/* ============================================================= */
-/* */
-/* Public Methods */
-/* */
-/* ============================================================= */
-
-/* =========================================== */
-/* */
-/* Object typing & Creation */
-/* */
-/* =========================================== */
-
-GType
-gst_glimagesink_get_type (void)
-{
- static GType glimagesink_type = 0;
-
- if (!glimagesink_type) {
- static const GTypeInfo glimagesink_info = {
- sizeof (GstGLImageSinkClass),
- gst_glimagesink_base_init,
- NULL,
- (GClassInitFunc) gst_glimagesink_class_init,
- NULL,
- NULL,
- sizeof (GstGLImageSink),
- 0,
- (GInstanceInitFunc) gst_glimagesink_init,
- };
- static const GInterfaceInfo iface_info = {
- (GInterfaceInitFunc) gst_glimagesink_interface_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo navigation_info = {
- (GInterfaceInitFunc) gst_glimagesink_navigation_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo overlay_info = {
- (GInterfaceInitFunc) gst_glimagesink_xoverlay_init,
- NULL,
- NULL,
- };
-
- glimagesink_type = g_type_register_static (GST_TYPE_VIDEOSINK,
- "GstGLImageSink", &glimagesink_info, 0);
-
- g_type_add_interface_static (glimagesink_type,
- GST_TYPE_IMPLEMENTS_INTERFACE, &iface_info);
- g_type_add_interface_static (glimagesink_type, GST_TYPE_NAVIGATION,
- &navigation_info);
- g_type_add_interface_static (glimagesink_type, GST_TYPE_X_OVERLAY,
- &overlay_info);
- }
-
- return glimagesink_type;
-}
-
static gboolean
plugin_init (GstPlugin * plugin)
{
- /* Loading the library containing GstVideoSink, our parent object */
- if (!gst_library_load ("gstvideo"))
- return FALSE;
-
if (!gst_element_register (plugin, "glimagesink",
- GST_RANK_SECONDARY, GST_TYPE_GLIMAGESINK))
+ GST_RANK_SECONDARY, GST_TYPE_GLIMAGE_SINK))
return FALSE;
- GST_DEBUG_CATEGORY_INIT (gst_debug_glimagesink, "glimagesink", 0,
+ GST_DEBUG_CATEGORY_INIT (gst_debug_glimage_sink, "glimagesink", 0,
"glimagesink element");
return TRUE;
@@ -1606,5 +809,5 @@ plugin_init (GstPlugin * plugin)
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"glimagesink",
- "OpenGL video output plugin based on OpenGL 1.2 calls",
+ "OpenGL video output plugin",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)
diff --git a/sys/glsink/glimagesink.h b/sys/glsink/glimagesink.h
deleted file mode 100644
index 15e866de..00000000
--- a/sys/glsink/glimagesink.h
+++ /dev/null
@@ -1,137 +0,0 @@
-/* GStreamer
- * Copyright (C) <2003> Julien Moutte <julien@moutte.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __GST_GLIMAGESINK_H__
-#define __GST_GLIMAGESINK_H__
-
-#include <gst/video/videosink.h>
-
-#include <X11/Xlib.h>
-#include <GL/glx.h>
-#include <GL/gl.h>
-#include <GL/glu.h>
-
-#include <string.h>
-#include <math.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_GLIMAGESINK \
- (gst_glimagesink_get_type())
-#define GST_GLIMAGESINK(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), GST_TYPE_GLIMAGESINK, GstGLImageSink))
-#define GST_GLIMAGESINK_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_GLIMAGESINK, GstGLImageSink))
-#define GST_IS_GLIMAGESINK(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_GLIMAGESINK))
-#define GST_IS_GLIMAGESINK_CLASS(obj) \
- (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_GLIMAGESINK))
-
-typedef struct _GstXContext GstXContext;
-typedef struct _GstGLWindow GstGLWindow;
-typedef struct _GstGLImage GstGLImage;
-
-typedef struct _GstGLImageSink GstGLImageSink;
-typedef struct _GstGLImageSinkClass GstGLImageSinkClass;
-
-/* Global X Context stuff */
-struct _GstXContext {
- Display *disp;
-
- Screen *screen;
- gint screen_num;
-
- Visual *visual;
- XVisualInfo *visualinfo;
-
- Window root;
- GLXContext glx;
-
- gulong white, black;
-
- gint depth;
- gint bpp;
- gint endianness;
-
- gboolean use_xshm;
-
- GstCaps *caps;
-};
-
-/* XWindow stuff */
-struct _GstGLWindow {
- XSetWindowAttributes attr;
- Window win;
- gint width, height;
- gboolean internal;
-};
-
-/* XImage stuff */
-struct _GstGLImage {
- /* Reference to the ximagesink we belong to */
- GstGLImageSink *glimagesink;
-
- GLuint texid;
-
- char *data;
- gint width, height, size;
-};
-
-struct _GstGLImageSink {
- /* Our element stuff */
- GstVideoSink videosink;
-
- char *display_name;
-
- GstXContext *xcontext;
- GstGLWindow *window;
- GstGLImage *glimage;
- GstGLImage *cur_image;
-
- gdouble framerate;
- GMutex *x_lock;
-
- gint pixel_width, pixel_height; /* Unused */
-
- GstClockTime time;
-
- GMutex *pool_lock;
- GSList *image_pool;
-
- guint pointer_x, pointer_y;
- gboolean pointer_moved;
- gboolean pointer_button[5];
-
- gboolean synchronous;
- gboolean signal_handoffs;
-};
-
-struct _GstGLImageSinkClass {
- GstVideoSinkClass parent_class;
-
- /* signals */
- void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad);
- void (*bufferalloc) (GstElement *element, GstBuffer *buf, GstPad *pad);
-};
-
-GType gst_glimagesink_get_type(void);
-
-G_END_DECLS
-
-#endif /* __GST_GLIMAGESINK_H__ */