mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-28 12:41:05 +00:00
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:
parent
491513adf6
commit
6b96a87003
7 changed files with 378 additions and 318 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ unix:!mac {
|
||||||
-lgstgl-1.0 \
|
-lgstgl-1.0 \
|
||||||
-lGLU \
|
-lGLU \
|
||||||
-lGL
|
-lGL
|
||||||
|
QT += x11extras
|
||||||
}
|
}
|
||||||
mac {
|
mac {
|
||||||
DEFINES += MACOSX
|
DEFINES += MACOSX
|
||||||
|
|
Loading…
Reference in a new issue