gstreamer/tests/examples/gl/qt/qglwtextureshare/qglrenderer.cpp
Jan Schmidt 37c70c8efa 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
2014-09-29 00:39:07 +10:00

284 lines
7.6 KiB
C++

/*
* GStreamer
* Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
* Copyright (C) 2009 Andrey Nechypurenko <andreynech@gmail.com>
* Copyright (C) 2010 Nuno Santos <nunosantos@imaginando.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <QGLWidget>
#include <QApplication>
#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"
#if defined(Q_WS_MAC)
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)
{
move (20, 10);
resize (640, 480);
}
QGLRenderer::~QGLRenderer ()
{
}
void
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);
#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);
#elif GST_GL_HAVE_PLATFORM_GLX
context =
gst_gl_context_new_wrapped (display, (guintptr) glXGetCurrentContext (),
GST_GL_PLATFORM_GLX, GST_GL_API_OPENGL);
#endif
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 (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);
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 ();
}
void
QGLRenderer::resizeGL (int width, int height)
{
// Reset The Current Viewport And Perspective Transformation
glViewport (0, 0, width, height);
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
gluPerspective (45.0f, (GLfloat) width / (GLfloat) height, 0.1f, 100.0f);
glMatrixMode (GL_MODELVIEW);
}
void
QGLRenderer::newFrame ()
{
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;
}
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 ();
}
}