/* * 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 "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; display = gst_gl_display_new (); /* FIXME: Allow the choice at runtime */ #if defined(GST_GL_HAVE_PLATFORM_WGL) context = gst_gl_context_new_wrapped (display, (guintptr) wglGetCurrentContext (), GST_GL_PLATFORM_WGL, GST_GL_API_OPENGL); #elif defined (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 defined(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(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(); } 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); if (gst_is_gl_memory (mem)) { 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); } } void QGLRenderer::closeEvent(QCloseEvent* event) { if(this->closing == false) { this->closing = true; emit closeRequested(); event->ignore(); } }