blob: 629cc895ff00f7964d7205a70dbf740221e4df79 [file] [log] [blame]
/*
* 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/gl.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 ();
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->mem.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 ();
glScalef (0.5f, 0.5f, 0.5f);
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;
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
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 ();
}
}