examples: Fix Qt/GL qglwtextureshare example for X11

We need to pass the X11 display to GstGL or else it will
use its own X11 Display pointer, and the GL Context won't get shared
correctly on newer X servers
This commit is contained in:
Jan Schmidt 2014-09-29 00:23:57 +10:00
parent 0fd0683996
commit 37c70c8efa
7 changed files with 378 additions and 318 deletions

View file

@ -1,3 +1,6 @@
Requires: >= Qt 5.1 for the x11extras module (or else you need to
get x11extras from gitorious yourself)
This example illustrates how to integrate Gstreamer GL plugin with
Qt. In particular it uses glupload with fakesink elements to create
texture with decoded video frame. This texture is shared with

View file

@ -23,15 +23,15 @@
#include "gstthread.h"
GstThread::GstThread(GstGLContext *context,
GstThread::GstThread(GstGLDisplay *display,
GstGLContext *context,
const QString &videoLocation,
const char *renderer_slot,
QObject *parent):
QThread(parent),
m_videoLocation(videoLocation)
{
this->context = context;
m_pipeline = new Pipeline(this->context, m_videoLocation, this);
m_pipeline = new Pipeline(display, context, m_videoLocation, this);
QObject::connect(m_pipeline, SIGNAL(newFrameReady()), this->parent(), renderer_slot, Qt::QueuedConnection);
}

View file

@ -34,7 +34,8 @@ class GstThread : public QThread
Q_OBJECT
public:
GstThread(GstGLContext *context,
GstThread(GstGLDisplay *display,
GstGLContext *context,
const QString &videoLocation,
const char *renderer_slot,
QObject *parent = 0);
@ -50,7 +51,6 @@ protected:
void run();
private:
GstGLContext *context;
const QString m_videoLocation;
Pipeline* m_pipeline;
};

View file

@ -22,15 +22,16 @@
#include "pipeline.h"
Pipeline::Pipeline(GstGLContext *context,
const QString &videoLocation,
QObject *parent)
: QObject(parent),
Pipeline::Pipeline (GstGLDisplay *display,
GstGLContext * context, const QString & videoLocation, QObject * parent)
:
QObject (parent),
m_videoLocation (videoLocation),
m_loop (NULL),
m_bus (NULL),
m_pipeline (NULL)
{
this->display = display;
this->context = context;
this->configure ();
}
@ -47,49 +48,47 @@ Pipeline::configure()
m_loop = g_main_loop_new (NULL, FALSE);
#endif
if(m_videoLocation.isEmpty())
{
if (m_videoLocation.isEmpty ()) {
qDebug ("No video file specified. Using video test source.");
m_pipeline =
GST_PIPELINE (gst_parse_launch
("videotestsrc ! "
"video/x-raw, width=640, height=480, "
"framerate=(fraction)30/1 ! "
"gleffects effect=5 ! fakesink sync=1",
NULL));
}
else
{
"gleffects effect=5 ! fakesink sync=1", NULL));
} else {
QByteArray ba = m_videoLocation.toLocal8Bit ();
qDebug ("Loading video: %s", ba.data ());
gchar *pipeline = g_strdup_printf ("filesrc location='%s' ! "
"decodebin ! gleffects effect=5 ! "
"fakesink sync=1", ba.data());
gchar *pipeline = g_strdup_printf ("filesrc name=f ! "
"decodebin ! gleffects effect=5 ! " "fakesink sync=1");
m_pipeline = GST_PIPELINE (gst_parse_launch (pipeline, NULL));
GstElement *f = gst_bin_get_by_name (GST_BIN (m_pipeline), "f");
g_object_set (G_OBJECT (f), "location", ba.data (), NULL);
gst_object_unref (GST_OBJECT (f));
g_free (pipeline);
}
m_bus = gst_pipeline_get_bus (GST_PIPELINE (m_pipeline));
gst_bus_add_watch (m_bus, (GstBusFunc) bus_call, this);
gst_bus_enable_sync_message_emission (m_bus);
g_signal_connect (m_bus, "sync-message", G_CALLBACK (sync_bus_call), this);
gst_object_unref (m_bus);
/* Retrieve the last gl element */
GstElement *gl_element = gst_bin_get_by_name(GST_BIN(m_pipeline), "gleffects0");
if(!gl_element)
{
GstElement *gl_element =
gst_bin_get_by_name (GST_BIN (m_pipeline), "gleffects0");
if (!gl_element) {
qDebug ("gl element could not be found");
return;
}
g_object_set(G_OBJECT (gl_element), "other-context",
this->context, NULL);
g_object_set (G_OBJECT (gl_element), "other-context", this->context, NULL);
gst_object_unref (gl_element);
gst_element_set_state (GST_ELEMENT (this->m_pipeline), GST_STATE_PAUSED);
GstState state = GST_STATE_PAUSED;
if (gst_element_get_state (GST_ELEMENT (this->m_pipeline),
&state, NULL, GST_CLOCK_TIME_NONE)
!= GST_STATE_CHANGE_SUCCESS)
{
!= GST_STATE_CHANGE_SUCCESS) {
qDebug ("failed to pause pipeline");
return;
}
@ -107,14 +106,12 @@ Pipeline::start()
GstStateChangeReturn ret =
gst_element_set_state (GST_ELEMENT (this->m_pipeline), GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE)
{
if (ret == GST_STATE_CHANGE_FAILURE) {
qDebug ("Failed to start up pipeline!");
/* check if there is an error message with details on the bus */
GstMessage *msg = gst_bus_poll (this->m_bus, GST_MESSAGE_ERROR, 0);
if (msg)
{
if (msg) {
GError *err = NULL;
gst_message_parse_error (msg, &err, NULL);
qDebug ("ERROR: %s", err->message);
@ -123,7 +120,6 @@ Pipeline::start()
}
return;
}
#ifdef Q_WS_WIN
g_main_loop_run (m_loop);
#endif
@ -132,9 +128,7 @@ Pipeline::start()
/* fakesink handoff callback */
void
Pipeline::on_gst_buffer (GstElement * element,
GstBuffer * buf,
GstPad * pad,
Pipeline* p)
GstBuffer * buf, GstPad * pad, Pipeline * p)
{
Q_UNUSED (pad)
Q_UNUSED (element)
@ -147,8 +141,7 @@ Pipeline::on_gst_buffer(GstElement * element,
p->notifyNewFrame ();
/* pop then unref buffer we have finished to use in qt */
if (p->queue_output_buf.size() > 3)
{
if (p->queue_output_buf.size () > 3) {
GstBuffer *buf_old = (p->queue_output_buf.get ());
if (buf_old)
gst_buffer_unref (buf_old);
@ -171,13 +164,11 @@ Pipeline::unconfigure()
gst_element_set_state (GST_ELEMENT (this->m_pipeline), GST_STATE_NULL);
GstBuffer *buf;
while(this->queue_input_buf.size())
{
while (this->queue_input_buf.size ()) {
buf = (GstBuffer *) (this->queue_input_buf.get ());
gst_buffer_unref (buf);
}
while(this->queue_output_buf.size())
{
while (this->queue_output_buf.size ()) {
buf = (GstBuffer *) (this->queue_output_buf.get ());
gst_buffer_unref (buf);
}
@ -185,13 +176,11 @@ Pipeline::unconfigure()
gst_object_unref (m_pipeline);
}
gboolean
Pipeline::bus_call(GstBus *bus, GstMessage *msg, Pipeline* p)
gboolean Pipeline::bus_call (GstBus * bus, GstMessage * msg, Pipeline * p)
{
Q_UNUSED (bus)
switch(GST_MESSAGE_TYPE(msg))
{
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_EOS:
qDebug ("End-of-stream received. Stopping.");
p->stop ();
@ -199,13 +188,14 @@ Pipeline::bus_call(GstBus *bus, GstMessage *msg, Pipeline* p)
case GST_MESSAGE_ERROR:
{
gchar *debug = NULL;
GError *err = NULL;
gchar *
debug = NULL;
GError *
err = NULL;
gst_message_parse_error (msg, &err, &debug);
qDebug ("Error: %s", err->message);
g_error_free (err);
if(debug)
{
if (debug) {
qDebug ("Debug deails: %s", debug);
g_free (debug);
}
@ -219,3 +209,27 @@ Pipeline::bus_call(GstBus *bus, GstMessage *msg, Pipeline* p)
return TRUE;
}
gboolean Pipeline::sync_bus_call (GstBus * bus, GstMessage * msg, Pipeline * p)
{
switch (GST_MESSAGE_TYPE (msg)) {
case GST_MESSAGE_NEED_CONTEXT:
{
const gchar *
context_type;
gst_message_parse_context_type (msg, &context_type);
g_print ("got need context %s\n", context_type);
if (g_strcmp0 (context_type, GST_GL_DISPLAY_CONTEXT_TYPE) == 0) {
GstContext *display_context = gst_context_new (GST_GL_DISPLAY_CONTEXT_TYPE, TRUE);
gst_context_set_gl_display (display_context, p->display);
gst_element_set_context (GST_ELEMENT (msg->src), display_context);
}
break;
}
default:
break;
}
return FALSE;
}

View file

@ -34,7 +34,7 @@ class Pipeline : public QObject
Q_OBJECT
public:
Pipeline(GstGLContext *context,
Pipeline(GstGLDisplay *display, GstGLContext *context,
const QString &videoLocation,
QObject *parent);
~Pipeline();
@ -53,6 +53,7 @@ Q_SIGNALS:
void stopRequested();
private:
GstGLDisplay *display;
GstGLContext *context;
const QString m_videoLocation;
GMainLoop* m_loop;
@ -64,6 +65,7 @@ private:
static void on_gst_buffer(GstElement * element, GstBuffer * buf, GstPad * pad, Pipeline* p);
static gboolean bus_call (GstBus *bus, GstMessage *msg, Pipeline* p);
static gboolean sync_bus_call (GstBus *bus, GstMessage *msg, Pipeline* p);
};
#endif

View file

@ -25,22 +25,27 @@
#include <QDebug>
#include <QCloseEvent>
#include <GL/glx.h>
#include <gst/video/video.h>
#include <gst/gl/gstglmemory.h>
#if GST_GL_HAVE_PLATFORM_GLX
#include <QX11Info>
#include <gst/gl/x11/gstgldisplay_x11.h>
#endif
#include "gstthread.h"
#include "qglrenderer.h"
#include "pipeline.h"
#include <GL/glx.h>
#if defined(Q_WS_MAC)
extern void *qt_current_nsopengl_context ();
#endif
QGLRenderer::QGLRenderer(const QString &videoLocation,
QWidget *parent)
: QGLWidget(parent),
QGLRenderer::QGLRenderer (const QString & videoLocation, QWidget * parent)
:
QGLWidget (parent),
videoLoc (videoLocation),
gst_thread (NULL),
closing (false),
@ -60,15 +65,28 @@ QGLRenderer::initializeGL()
GstGLContext *context;
GstGLDisplay *display;
#if GST_GL_HAVE_PLATFORM_GLX
display =
(GstGLDisplay *) gst_gl_display_x11_new_with_display (QX11Info::
display ());
#else
display = gst_gl_display_new ();
#endif
/* FIXME: Allow the choice at runtime */
#if GST_GL_HAVE_PLATFORM_WGL
context = gst_gl_context_new_wrapped (display, (guintptr) wglGetCurrentContext (), GST_GL_PLATFORM_WGL, GST_GL_API_OPENGL);
context =
gst_gl_context_new_wrapped (display, (guintptr) wglGetCurrentContext (),
GST_GL_PLATFORM_WGL, GST_GL_API_OPENGL);
#elif GST_GL_HAVE_PLATFORM_CGL
context = gst_gl_context_new_wrapped (display, (guintptr) qt_current_nsopengl_context(), GST_GL_PLATFORM_CGL, GST_GL_API_OPENGL);
context =
gst_gl_context_new_wrapped (display,
(guintptr) qt_current_nsopengl_context (), GST_GL_PLATFORM_CGL,
GST_GL_API_OPENGL);
#elif GST_GL_HAVE_PLATFORM_GLX
context = gst_gl_context_new_wrapped (display, (guintptr) glXGetCurrentContext (), GST_GL_PLATFORM_GLX, GST_GL_API_OPENGL);
context =
gst_gl_context_new_wrapped (display, (guintptr) glXGetCurrentContext (),
GST_GL_PLATFORM_GLX, GST_GL_API_OPENGL);
#endif
gst_object_unref (display);
@ -76,7 +94,8 @@ QGLRenderer::initializeGL()
// Otherwise the attempt to share gst-gl context with Qt will fail.
this->doneCurrent ();
this->gst_thread =
new GstThread(context, this->videoLoc, SLOT(newFrame()), this);
new GstThread (display, context, this->videoLoc,
SLOT (newFrame ()), this);
this->makeCurrent ();
QObject::connect (this->gst_thread, SIGNAL (finished ()),
@ -124,7 +143,9 @@ QGLRenderer::newFrame()
this->updateGL ();
}
static void flushGstreamerGL(GstGLContext* context,void *data){
static void
flushGstreamerGL (GstGLContext * context, void *data G_GNUC_UNUSED)
{
context->gl_vtable->Flush ();
}
@ -135,8 +156,7 @@ QGLRenderer::paintGL()
static GLfloat yrot = 0;
static GLfloat zrot = 0;
if (this->frame)
{
if (this->frame) {
guint tex_id;
GstMemory *mem;
GstVideoInfo v_info;
@ -164,8 +184,7 @@ QGLRenderer::paintGL()
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, tex_id);
if(glGetError () != GL_NO_ERROR)
{
if (glGetError () != GL_NO_ERROR) {
qDebug ("failed to bind texture that comes from gst-gl");
emit closeRequested ();
return;
@ -173,10 +192,8 @@ QGLRenderer::paintGL()
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_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@ -191,35 +208,59 @@ QGLRenderer::paintGL()
glBegin (GL_QUADS);
// Front Face
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (-1.0f, -1.0f, 1.0f);
glTexCoord2f (0.0f, 0.0f);
glVertex3f (1.0f, -1.0f, 1.0f);
glTexCoord2f (0.0f, 1.0f);
glVertex3f (1.0f, 1.0f, 1.0f);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (-1.0f, 1.0f, 1.0f);
// Back Face
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f (0.0f, 0.0f);
glVertex3f (-1.0f, -1.0f, -1.0f);
glTexCoord2f (0.0f, 1.0f);
glVertex3f (-1.0f, 1.0f, -1.0f);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (1.0f, 1.0f, -1.0f);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (1.0f, -1.0f, -1.0f);
// Top Face
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (-1.0f, 1.0f, -1.0f);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (-1.0f, 1.0f, 1.0f);
glTexCoord2f (0.0f, 0.0f);
glVertex3f (1.0f, 1.0f, 1.0f);
glTexCoord2f (0.0f, 1.0f);
glVertex3f (1.0f, 1.0f, -1.0f);
// Bottom Face
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (-1.0f, -1.0f, -1.0f);
glTexCoord2f (0.0f, 0.0f);
glVertex3f (1.0f, -1.0f, -1.0f);
glTexCoord2f (0.0f, 1.0f);
glVertex3f (1.0f, -1.0f, 1.0f);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (-1.0f, -1.0f, 1.0f);
// Right face
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
glTexCoord2f (0.0f, 0.0f);
glVertex3f (1.0f, -1.0f, -1.0f);
glTexCoord2f (0.0f, 1.0f);
glVertex3f (1.0f, 1.0f, -1.0f);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (1.0f, 1.0f, 1.0f);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (1.0f, -1.0f, 1.0f);
// Left Face
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
glTexCoord2f (1.0f, 0.0f);
glVertex3f (-1.0f, -1.0f, -1.0f);
glTexCoord2f (0.0f, 0.0f);
glVertex3f (-1.0f, -1.0f, 1.0f);
glTexCoord2f (0.0f, 1.0f);
glVertex3f (-1.0f, 1.0f, 1.0f);
glTexCoord2f (1.0f, 1.0f);
glVertex3f (-1.0f, 1.0f, -1.0f);
glEnd ();
xrot += 0.3f;
@ -235,8 +276,7 @@ QGLRenderer::paintGL()
void
QGLRenderer::closeEvent (QCloseEvent * event)
{
if(this->closing == false)
{
if (this->closing == false) {
this->closing = true;
emit closeRequested ();
event->ignore ();

View file

@ -37,6 +37,7 @@ unix:!mac {
-lgstgl-1.0 \
-lGLU \
-lGL
QT += x11extras
}
mac {
DEFINES += MACOSX