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 committed by Tim-Philipp Müller
parent 491513adf6
commit 6b96a87003
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 This example illustrates how to integrate Gstreamer GL plugin with
Qt. In particular it uses glupload with fakesink elements to create Qt. In particular it uses glupload with fakesink elements to create
texture with decoded video frame. This texture is shared with texture with decoded video frame. This texture is shared with

View file

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

View file

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

View file

@ -22,200 +22,214 @@
#include "pipeline.h" #include "pipeline.h"
Pipeline::Pipeline(GstGLContext *context, Pipeline::Pipeline (GstGLDisplay *display,
const QString &videoLocation, GstGLContext * context, const QString & videoLocation, QObject * parent)
QObject *parent) :
: QObject(parent), QObject (parent),
m_videoLocation(videoLocation), m_videoLocation (videoLocation),
m_loop(NULL), m_loop (NULL),
m_bus(NULL), m_bus (NULL),
m_pipeline(NULL) m_pipeline (NULL)
{ {
this->context = context; this->display = display;
this->configure(); this->context = context;
this->configure ();
} }
Pipeline::~Pipeline() Pipeline::~Pipeline ()
{ {
} }
void void
Pipeline::configure() Pipeline::configure ()
{ {
#ifdef Q_WS_WIN #ifdef Q_WS_WIN
m_loop = g_main_loop_new (NULL, FALSE); m_loop = g_main_loop_new (NULL, FALSE);
#endif #endif
if(m_videoLocation.isEmpty()) if (m_videoLocation.isEmpty ()) {
{ qDebug ("No video file specified. Using video test source.");
qDebug("No video file specified. Using video test source."); m_pipeline =
m_pipeline = GST_PIPELINE (gst_parse_launch
GST_PIPELINE (gst_parse_launch ("videotestsrc ! "
("videotestsrc ! " "video/x-raw, width=640, height=480, "
"video/x-raw, width=640, height=480, " "framerate=(fraction)30/1 ! "
"framerate=(fraction)30/1 ! " "gleffects effect=5 ! fakesink sync=1", NULL));
"gleffects effect=5 ! fakesink sync=1", } else {
NULL)); QByteArray ba = m_videoLocation.toLocal8Bit ();
} qDebug ("Loading video: %s", ba.data ());
else gchar *pipeline = g_strdup_printf ("filesrc name=f ! "
{ "decodebin ! gleffects effect=5 ! " "fakesink sync=1");
QByteArray ba = m_videoLocation.toLocal8Bit(); m_pipeline = GST_PIPELINE (gst_parse_launch (pipeline, NULL));
qDebug("Loading video: %s", ba.data()); GstElement *f = gst_bin_get_by_name (GST_BIN (m_pipeline), "f");
gchar *pipeline = g_strdup_printf ("filesrc location='%s' ! " g_object_set (G_OBJECT (f), "location", ba.data (), NULL);
"decodebin ! gleffects effect=5 ! " gst_object_unref (GST_OBJECT (f));
"fakesink sync=1", ba.data()); g_free (pipeline);
m_pipeline = GST_PIPELINE (gst_parse_launch (pipeline, NULL)); }
g_free (pipeline);
}
m_bus = gst_pipeline_get_bus(GST_PIPELINE(m_pipeline)); m_bus = gst_pipeline_get_bus (GST_PIPELINE (m_pipeline));
gst_bus_add_watch(m_bus, (GstBusFunc) bus_call, this); gst_bus_add_watch (m_bus, (GstBusFunc) bus_call, this);
gst_object_unref(m_bus); 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 */ /* Retrieve the last gl element */
GstElement *gl_element = gst_bin_get_by_name(GST_BIN(m_pipeline), "gleffects0"); GstElement *gl_element =
if(!gl_element) gst_bin_get_by_name (GST_BIN (m_pipeline), "gleffects0");
{ if (!gl_element) {
qDebug ("gl element could not be found"); qDebug ("gl element could not be found");
return; return;
} }
g_object_set(G_OBJECT (gl_element), "other-context", g_object_set (G_OBJECT (gl_element), "other-context", this->context, NULL);
this->context, NULL); gst_object_unref (gl_element);
gst_object_unref(gl_element);
gst_element_set_state(GST_ELEMENT(this->m_pipeline), GST_STATE_PAUSED); gst_element_set_state (GST_ELEMENT (this->m_pipeline), GST_STATE_PAUSED);
GstState state = GST_STATE_PAUSED; GstState state = GST_STATE_PAUSED;
if(gst_element_get_state(GST_ELEMENT(this->m_pipeline), if (gst_element_get_state (GST_ELEMENT (this->m_pipeline),
&state, NULL, GST_CLOCK_TIME_NONE) &state, NULL, GST_CLOCK_TIME_NONE)
!= GST_STATE_CHANGE_SUCCESS) != GST_STATE_CHANGE_SUCCESS) {
{ qDebug ("failed to pause pipeline");
qDebug("failed to pause pipeline"); return;
return; }
}
} }
void void
Pipeline::start() Pipeline::start ()
{ {
// set a callback to retrieve the gst gl textures // set a callback to retrieve the gst gl textures
GstElement *fakesink = gst_bin_get_by_name(GST_BIN(this->m_pipeline), GstElement *fakesink = gst_bin_get_by_name (GST_BIN (this->m_pipeline),
"fakesink0"); "fakesink0");
g_object_set(G_OBJECT (fakesink), "signal-handoffs", TRUE, NULL); g_object_set (G_OBJECT (fakesink), "signal-handoffs", TRUE, NULL);
g_signal_connect(fakesink, "handoff", G_CALLBACK (on_gst_buffer), this); g_signal_connect (fakesink, "handoff", G_CALLBACK (on_gst_buffer), this);
gst_object_unref(fakesink); gst_object_unref (fakesink);
GstStateChangeReturn ret = GstStateChangeReturn ret =
gst_element_set_state(GST_ELEMENT(this->m_pipeline), GST_STATE_PLAYING); 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!");
qDebug("Failed to start up pipeline!");
/* check if there is an error message with details on the bus */ /* check if there is an error message with details on the bus */
GstMessage* msg = gst_bus_poll(this->m_bus, GST_MESSAGE_ERROR, 0); GstMessage *msg = gst_bus_poll (this->m_bus, GST_MESSAGE_ERROR, 0);
if (msg) if (msg) {
{ GError *err = NULL;
GError *err = NULL; gst_message_parse_error (msg, &err, NULL);
gst_message_parse_error (msg, &err, NULL); qDebug ("ERROR: %s", err->message);
qDebug ("ERROR: %s", err->message); g_error_free (err);
g_error_free (err); gst_message_unref (msg);
gst_message_unref (msg);
}
return;
} }
return;
}
#ifdef Q_WS_WIN #ifdef Q_WS_WIN
g_main_loop_run(m_loop); g_main_loop_run (m_loop);
#endif #endif
} }
/* fakesink handoff callback */ /* fakesink handoff callback */
void void
Pipeline::on_gst_buffer(GstElement * element, Pipeline::on_gst_buffer (GstElement * element,
GstBuffer * buf, GstBuffer * buf, GstPad * pad, Pipeline * p)
GstPad * pad,
Pipeline* p)
{ {
Q_UNUSED(pad) Q_UNUSED (pad)
Q_UNUSED(element) Q_UNUSED (element)
/* ref then push buffer to use it in qt */ /* ref then push buffer to use it in qt */
gst_buffer_ref(buf); gst_buffer_ref (buf);
p->queue_input_buf.put(buf); p->queue_input_buf.put (buf);
if (p->queue_input_buf.size() > 3) if (p->queue_input_buf.size () > 3)
p->notifyNewFrame(); p->notifyNewFrame ();
/* pop then unref buffer we have finished to use in qt */ /* 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 ());
GstBuffer *buf_old = (p->queue_output_buf.get()); if (buf_old)
if (buf_old) gst_buffer_unref (buf_old);
gst_buffer_unref(buf_old); }
}
} }
void void
Pipeline::stop() Pipeline::stop ()
{ {
#ifdef Q_WS_WIN #ifdef Q_WS_WIN
g_main_loop_quit(m_loop); g_main_loop_quit (m_loop);
#else #else
emit stopRequested(); emit stopRequested ();
#endif #endif
} }
void void
Pipeline::unconfigure() Pipeline::unconfigure ()
{ {
gst_element_set_state(GST_ELEMENT(this->m_pipeline), GST_STATE_NULL); gst_element_set_state (GST_ELEMENT (this->m_pipeline), GST_STATE_NULL);
GstBuffer *buf; GstBuffer *buf;
while(this->queue_input_buf.size()) while (this->queue_input_buf.size ()) {
{ buf = (GstBuffer *) (this->queue_input_buf.get ());
buf = (GstBuffer*)(this->queue_input_buf.get()); gst_buffer_unref (buf);
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);
buf = (GstBuffer*)(this->queue_output_buf.get()); }
gst_buffer_unref(buf);
}
gst_object_unref(m_pipeline); gst_object_unref (m_pipeline);
} }
gboolean gboolean Pipeline::bus_call (GstBus * bus, GstMessage * msg, Pipeline * p)
Pipeline::bus_call(GstBus *bus, GstMessage *msg, Pipeline* p)
{ {
Q_UNUSED(bus) 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 ();
break;
case GST_MESSAGE_ERROR:
{ {
case GST_MESSAGE_EOS: gchar *
qDebug("End-of-stream received. Stopping."); debug = NULL;
p->stop(); GError *
break; err = NULL;
gst_message_parse_error (msg, &err, &debug);
case GST_MESSAGE_ERROR: qDebug ("Error: %s", err->message);
{ g_error_free (err);
gchar *debug = NULL; if (debug) {
GError *err = NULL; qDebug ("Debug deails: %s", debug);
gst_message_parse_error(msg, &err, &debug); g_free (debug);
qDebug("Error: %s", err->message); }
g_error_free (err); p->stop ();
if(debug) break;
{
qDebug("Debug deails: %s", debug);
g_free(debug);
}
p->stop();
break;
}
default:
break;
} }
return TRUE; default:
break;
}
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 Q_OBJECT
public: public:
Pipeline(GstGLContext *context, Pipeline(GstGLDisplay *display, GstGLContext *context,
const QString &videoLocation, const QString &videoLocation,
QObject *parent); QObject *parent);
~Pipeline(); ~Pipeline();
@ -53,6 +53,7 @@ Q_SIGNALS:
void stopRequested(); void stopRequested();
private: private:
GstGLDisplay *display;
GstGLContext *context; GstGLContext *context;
const QString m_videoLocation; const QString m_videoLocation;
GMainLoop* m_loop; GMainLoop* m_loop;
@ -64,6 +65,7 @@ private:
static void on_gst_buffer(GstElement * element, GstBuffer * buf, GstPad * pad, Pipeline* p); 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 bus_call (GstBus *bus, GstMessage *msg, Pipeline* p);
static gboolean sync_bus_call (GstBus *bus, GstMessage *msg, Pipeline* p);
}; };
#endif #endif

View file

@ -25,220 +25,260 @@
#include <QDebug> #include <QDebug>
#include <QCloseEvent> #include <QCloseEvent>
#include <GL/glx.h>
#include <gst/video/video.h> #include <gst/video/video.h>
#include <gst/gl/gstglmemory.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 "gstthread.h"
#include "qglrenderer.h" #include "qglrenderer.h"
#include "pipeline.h" #include "pipeline.h"
#include <GL/glx.h>
#if defined(Q_WS_MAC) #if defined(Q_WS_MAC)
extern void *qt_current_nsopengl_context(); extern void *qt_current_nsopengl_context ();
#endif #endif
QGLRenderer::QGLRenderer(const QString &videoLocation, QGLRenderer::QGLRenderer (const QString & videoLocation, QWidget * parent)
QWidget *parent) :
: QGLWidget(parent), QGLWidget (parent),
videoLoc(videoLocation), videoLoc (videoLocation),
gst_thread(NULL), gst_thread (NULL),
closing(false), closing (false),
frame(NULL) frame (NULL)
{ {
move(20, 10); move (20, 10);
resize(640, 480); resize (640, 480);
} }
QGLRenderer::~QGLRenderer() QGLRenderer::~QGLRenderer ()
{ {
} }
void void
QGLRenderer::initializeGL() QGLRenderer::initializeGL ()
{ {
GstGLContext *context; GstGLContext *context;
GstGLDisplay *display; GstGLDisplay *display;
display = gst_gl_display_new (); #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 */ /* FIXME: Allow the choice at runtime */
#if GST_GL_HAVE_PLATFORM_WGL #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 #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 #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 #endif
gst_object_unref (display); gst_object_unref (display);
// We need to unset Qt context before initializing gst-gl plugin. // We need to unset Qt context before initializing gst-gl plugin.
// Otherwise the attempt to share gst-gl context with Qt will fail. // Otherwise the attempt to share gst-gl context with Qt will fail.
this->doneCurrent(); this->doneCurrent ();
this->gst_thread = this->gst_thread =
new GstThread(context, this->videoLoc, SLOT(newFrame()), this); new GstThread (display, context, this->videoLoc,
this->makeCurrent(); SLOT (newFrame ()), this);
this->makeCurrent ();
QObject::connect(this->gst_thread, SIGNAL(finished()), QObject::connect (this->gst_thread, SIGNAL (finished ()),
this, SLOT(close())); this, SLOT (close ()));
QObject::connect(this, SIGNAL(closeRequested()), QObject::connect (this, SIGNAL (closeRequested ()),
this->gst_thread, SLOT(stop()), Qt::QueuedConnection); this->gst_thread, SLOT (stop ()), Qt::QueuedConnection);
qglClearColor(QApplication::palette().color(QPalette::Active, qglClearColor (QApplication::palette ().color (QPalette::Active,
QPalette::Window)); QPalette::Window));
//glShadeModel(GL_FLAT); //glShadeModel(GL_FLAT);
//glEnable(GL_DEPTH_TEST); //glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE); //glEnable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping glEnable (GL_TEXTURE_2D); // Enable Texture Mapping
this->gst_thread->start(); this->gst_thread->start ();
} }
void void
QGLRenderer::resizeGL(int width, int height) QGLRenderer::resizeGL (int width, int height)
{ {
// Reset The Current Viewport And Perspective Transformation // Reset The Current Viewport And Perspective Transformation
glViewport(0, 0, width, height); glViewport (0, 0, width, height);
glMatrixMode(GL_PROJECTION); glMatrixMode (GL_PROJECTION);
glLoadIdentity(); glLoadIdentity ();
gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f); gluPerspective (45.0f, (GLfloat) width / (GLfloat) height, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW); glMatrixMode (GL_MODELVIEW);
} }
void void
QGLRenderer::newFrame() QGLRenderer::newFrame ()
{ {
Pipeline *pipeline = this->gst_thread->getPipeline(); Pipeline *pipeline = this->gst_thread->getPipeline ();
if(!pipeline) if (!pipeline)
return;
/* frame is initialized as null */
if (this->frame)
pipeline->queue_output_buf.put (this->frame);
this->frame = pipeline->queue_input_buf.get ();
/* direct call to paintGL (no queued) */
this->updateGL ();
}
static void
flushGstreamerGL (GstGLContext * context, void *data G_GNUC_UNUSED)
{
context->gl_vtable->Flush ();
}
void
QGLRenderer::paintGL ()
{
static GLfloat xrot = 0;
static GLfloat yrot = 0;
static GLfloat zrot = 0;
if (this->frame) {
guint tex_id;
GstMemory *mem;
GstVideoInfo v_info;
GstVideoFrame v_frame;
GstVideoMeta *v_meta;
mem = gst_buffer_peek_memory (this->frame, 0);
v_meta = gst_buffer_get_video_meta (this->frame);
Q_ASSERT (gst_is_gl_memory (mem));
GstGLMemory *gl_memory = (GstGLMemory *) mem;
gst_gl_context_thread_add (gl_memory->context, flushGstreamerGL, NULL);
gst_video_info_set_format (&v_info, v_meta->format, v_meta->width,
v_meta->height);
gst_video_frame_map (&v_frame, &v_info, this->frame,
(GstMapFlags) (GST_MAP_READ | GST_MAP_GL));
tex_id = *(guint *) v_frame.data[0];
glEnable (GL_DEPTH_TEST);
glEnable (GL_TEXTURE_2D);
glBindTexture (GL_TEXTURE_2D, tex_id);
if (glGetError () != GL_NO_ERROR) {
qDebug ("failed to bind texture that comes from gst-gl");
emit closeRequested ();
return; return;
}
/* frame is initialized as null */ glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
if (this->frame) glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
pipeline->queue_output_buf.put(this->frame); 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);
this->frame = pipeline->queue_input_buf.get(); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode (GL_MODELVIEW);
glLoadIdentity ();
/* direct call to paintGL (no queued) */ glTranslatef (0.0f, 0.0f, -5.0f);
this->updateGL();
}
static void flushGstreamerGL(GstGLContext* context,void *data){ glRotatef (xrot, 1.0f, 0.0f, 0.0f);
context->gl_vtable->Flush(); glRotatef (yrot, 0.0f, 1.0f, 0.0f);
glRotatef (zrot, 0.0f, 0.0f, 1.0f);
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);
// 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);
// 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);
// 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);
// 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);
// 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);
glEnd ();
xrot += 0.3f;
yrot += 0.2f;
zrot += 0.4f;
glBindTexture (GL_TEXTURE_2D, 0);
gst_video_frame_unmap (&v_frame);
}
} }
void void
QGLRenderer::paintGL() QGLRenderer::closeEvent (QCloseEvent * event)
{ {
static GLfloat xrot = 0; if (this->closing == false) {
static GLfloat yrot = 0; this->closing = true;
static GLfloat zrot = 0; emit closeRequested ();
event->ignore ();
if (this->frame) }
{
guint tex_id;
GstMemory *mem;
GstVideoInfo v_info;
GstVideoFrame v_frame;
GstVideoMeta *v_meta;
mem = gst_buffer_peek_memory (this->frame, 0);
v_meta = gst_buffer_get_video_meta (this->frame);
Q_ASSERT(gst_is_gl_memory (mem));
GstGLMemory *gl_memory=(GstGLMemory*)mem;
gst_gl_context_thread_add(gl_memory->context,flushGstreamerGL,NULL);
gst_video_info_set_format (&v_info, v_meta->format, v_meta->width,
v_meta->height);
gst_video_frame_map (&v_frame, &v_info, this->frame,
(GstMapFlags) (GST_MAP_READ | GST_MAP_GL));
tex_id = *(guint *) v_frame.data[0];
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex_id);
if(glGetError () != GL_NO_ERROR)
{
qDebug ("failed to bind texture that comes from gst-gl");
emit closeRequested();
return;
}
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);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f,0.0f,-5.0f);
glRotatef(xrot,1.0f,0.0f,0.0f);
glRotatef(yrot,0.0f,1.0f,0.0f);
glRotatef(zrot,0.0f,0.0f,1.0f);
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);
// 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);
// 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);
// 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);
// 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);
// 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);
glEnd();
xrot+=0.3f;
yrot+=0.2f;
zrot+=0.4f;
glBindTexture(GL_TEXTURE_2D, 0);
gst_video_frame_unmap(&v_frame);
}
}
void
QGLRenderer::closeEvent(QCloseEvent* event)
{
if(this->closing == false)
{
this->closing = true;
emit closeRequested();
event->ignore();
}
} }

View file

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