/* * GStreamer * Copyright (C) 2009 Julien Isorce * Copyright (C) 2009 Andrey Nechypurenko * Copyright (C) 2010 Nuno Santos * * 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 #include #include #include #include #include #include #if GST_GL_HAVE_PLATFORM_GLX #include #include #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 (); } }