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,200 +22,214 @@
#include "pipeline.h"
Pipeline::Pipeline(GstGLContext *context,
const QString &videoLocation,
QObject *parent)
: QObject(parent),
m_videoLocation(videoLocation),
m_loop(NULL),
m_bus(NULL),
m_pipeline(NULL)
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->context = context;
this->configure();
this->display = display;
this->context = context;
this->configure ();
}
Pipeline::~Pipeline()
Pipeline::~Pipeline ()
{
}
void
Pipeline::configure()
Pipeline::configure ()
{
#ifdef Q_WS_WIN
m_loop = g_main_loop_new (NULL, FALSE);
m_loop = g_main_loop_new (NULL, FALSE);
#endif
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
{
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());
m_pipeline = GST_PIPELINE (gst_parse_launch (pipeline, NULL));
g_free (pipeline);
}
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 {
QByteArray ba = m_videoLocation.toLocal8Bit ();
qDebug ("Loading video: %s", 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_object_unref(m_bus);
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)
{
qDebug ("gl element could not be found");
return;
}
g_object_set(G_OBJECT (gl_element), "other-context",
this->context, NULL);
gst_object_unref(gl_element);
/* Retrieve the last 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);
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)
{
qDebug("failed to pause pipeline");
return;
}
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) {
qDebug ("failed to pause pipeline");
return;
}
}
void
Pipeline::start()
Pipeline::start ()
{
// set a callback to retrieve the gst gl textures
GstElement *fakesink = gst_bin_get_by_name(GST_BIN(this->m_pipeline),
"fakesink0");
g_object_set(G_OBJECT (fakesink), "signal-handoffs", TRUE, NULL);
g_signal_connect(fakesink, "handoff", G_CALLBACK (on_gst_buffer), this);
gst_object_unref(fakesink);
// set a callback to retrieve the gst gl textures
GstElement *fakesink = gst_bin_get_by_name (GST_BIN (this->m_pipeline),
"fakesink0");
g_object_set (G_OBJECT (fakesink), "signal-handoffs", TRUE, NULL);
g_signal_connect (fakesink, "handoff", G_CALLBACK (on_gst_buffer), this);
gst_object_unref (fakesink);
GstStateChangeReturn ret =
gst_element_set_state(GST_ELEMENT(this->m_pipeline), GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE)
{
qDebug("Failed to start up pipeline!");
GstStateChangeReturn ret =
gst_element_set_state (GST_ELEMENT (this->m_pipeline), GST_STATE_PLAYING);
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)
{
GError *err = NULL;
gst_message_parse_error (msg, &err, NULL);
qDebug ("ERROR: %s", err->message);
g_error_free (err);
gst_message_unref (msg);
}
return;
/* 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) {
GError *err = NULL;
gst_message_parse_error (msg, &err, NULL);
qDebug ("ERROR: %s", err->message);
g_error_free (err);
gst_message_unref (msg);
}
return;
}
#ifdef Q_WS_WIN
g_main_loop_run(m_loop);
g_main_loop_run (m_loop);
#endif
}
/* fakesink handoff callback */
void
Pipeline::on_gst_buffer(GstElement * element,
GstBuffer * buf,
GstPad * pad,
Pipeline* p)
Pipeline::on_gst_buffer (GstElement * element,
GstBuffer * buf, GstPad * pad, Pipeline * p)
{
Q_UNUSED(pad)
Q_UNUSED(element)
Q_UNUSED (pad)
Q_UNUSED (element)
/* ref then push buffer to use it in qt */
gst_buffer_ref(buf);
p->queue_input_buf.put(buf);
/* ref then push buffer to use it in qt */
gst_buffer_ref (buf);
p->queue_input_buf.put (buf);
if (p->queue_input_buf.size() > 3)
p->notifyNewFrame();
if (p->queue_input_buf.size () > 3)
p->notifyNewFrame ();
/* pop then unref buffer we have finished to use in qt */
if (p->queue_output_buf.size() > 3)
{
GstBuffer *buf_old = (p->queue_output_buf.get());
if (buf_old)
gst_buffer_unref(buf_old);
}
/* pop then unref buffer we have finished to use in qt */
if (p->queue_output_buf.size () > 3) {
GstBuffer *buf_old = (p->queue_output_buf.get ());
if (buf_old)
gst_buffer_unref (buf_old);
}
}
void
Pipeline::stop()
Pipeline::stop ()
{
#ifdef Q_WS_WIN
g_main_loop_quit(m_loop);
g_main_loop_quit (m_loop);
#else
emit stopRequested();
emit stopRequested ();
#endif
}
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;
while(this->queue_input_buf.size())
{
buf = (GstBuffer*)(this->queue_input_buf.get());
gst_buffer_unref(buf);
}
while(this->queue_output_buf.size())
{
buf = (GstBuffer*)(this->queue_output_buf.get());
gst_buffer_unref(buf);
}
GstBuffer *buf;
while (this->queue_input_buf.size ()) {
buf = (GstBuffer *) (this->queue_input_buf.get ());
gst_buffer_unref (buf);
}
while (this->queue_output_buf.size ()) {
buf = (GstBuffer *) (this->queue_output_buf.get ());
gst_buffer_unref (buf);
}
gst_object_unref(m_pipeline);
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)
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:
qDebug("End-of-stream received. Stopping.");
p->stop();
break;
case GST_MESSAGE_ERROR:
{
gchar *debug = NULL;
GError *err = NULL;
gst_message_parse_error(msg, &err, &debug);
qDebug("Error: %s", err->message);
g_error_free (err);
if(debug)
{
qDebug("Debug deails: %s", debug);
g_free(debug);
}
p->stop();
break;
}
default:
break;
gchar *
debug = NULL;
GError *
err = NULL;
gst_message_parse_error (msg, &err, &debug);
qDebug ("Error: %s", err->message);
g_error_free (err);
if (debug) {
qDebug ("Debug deails: %s", debug);
g_free (debug);
}
p->stop ();
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
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,220 +25,260 @@
#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();
extern void *qt_current_nsopengl_context ();
#endif
QGLRenderer::QGLRenderer(const QString &videoLocation,
QWidget *parent)
: QGLWidget(parent),
videoLoc(videoLocation),
gst_thread(NULL),
closing(false),
frame(NULL)
QGLRenderer::QGLRenderer (const QString & videoLocation, QWidget * parent)
:
QGLWidget (parent),
videoLoc (videoLocation),
gst_thread (NULL),
closing (false),
frame (NULL)
{
move(20, 10);
resize(640, 480);
move (20, 10);
resize (640, 480);
}
QGLRenderer::~QGLRenderer()
QGLRenderer::~QGLRenderer ()
{
}
void
QGLRenderer::initializeGL()
QGLRenderer::initializeGL ()
{
GstGLContext *context;
GstGLDisplay *display;
GstGLContext *context;
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
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);
gst_object_unref (display);
// We need to unset Qt context before initializing gst-gl plugin.
// 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);
this->makeCurrent();
// We need to unset Qt context before initializing gst-gl plugin.
// Otherwise the attempt to share gst-gl context with Qt will fail.
this->doneCurrent ();
this->gst_thread =
new GstThread (display, context, this->videoLoc,
SLOT (newFrame ()), this);
this->makeCurrent ();
QObject::connect(this->gst_thread, SIGNAL(finished()),
this, SLOT(close()));
QObject::connect(this, SIGNAL(closeRequested()),
this->gst_thread, SLOT(stop()), Qt::QueuedConnection);
QObject::connect (this->gst_thread, SIGNAL (finished ()),
this, SLOT (close ()));
QObject::connect (this, SIGNAL (closeRequested ()),
this->gst_thread, SLOT (stop ()), Qt::QueuedConnection);
qglClearColor(QApplication::palette().color(QPalette::Active,
QPalette::Window));
//glShadeModel(GL_FLAT);
//glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
qglClearColor (QApplication::palette ().color (QPalette::Active,
QPalette::Window));
//glShadeModel(GL_FLAT);
//glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
glEnable (GL_TEXTURE_2D); // Enable Texture Mapping
this->gst_thread->start();
this->gst_thread->start ();
}
void
QGLRenderer::resizeGL(int width, int height)
QGLRenderer::resizeGL (int width, int height)
{
// Reset The Current Viewport And Perspective Transformation
glViewport(0, 0, width, height);
glViewport (0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective(45.0f, (GLfloat)width/(GLfloat)height, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
gluPerspective (45.0f, (GLfloat) width / (GLfloat) height, 0.1f, 100.0f);
glMatrixMode (GL_MODELVIEW);
}
void
QGLRenderer::newFrame()
QGLRenderer::newFrame ()
{
Pipeline *pipeline = this->gst_thread->getPipeline();
if(!pipeline)
Pipeline *pipeline = this->gst_thread->getPipeline ();
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;
}
/* frame is initialized as null */
if (this->frame)
pipeline->queue_output_buf.put(this->frame);
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);
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) */
this->updateGL();
}
glTranslatef (0.0f, 0.0f, -5.0f);
static void flushGstreamerGL(GstGLContext* context,void *data){
context->gl_vtable->Flush();
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::paintGL()
QGLRenderer::closeEvent (QCloseEvent * event)
{
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;
}
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();
}
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