Commit ea167016 authored by David Schleef's avatar David Schleef

revival of glimagesink. Kind of works.

Original commit message from CVS:
* configure.ac:
* sys/Makefile.am:
* sys/glsink/Makefile.am:
* sys/glsink/glimagesink.c:
* sys/glsink/glimagesink.h:
revival of glimagesink.  Kind of works.
parent b0ebf7d6
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),
......
......@@ -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
......
......@@ -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
......@@ -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
......
/* 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);