| /* |
| * 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 (); |
| } |
| } |