1 /*
2 * GStreamer
3 * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com>
4 * Copyright (C) 2009 Andrey Nechypurenko <andreynech@gmail.com>
5 * Copyright (C) 2010 Nuno Santos <nunosantos@imaginando.net>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include <QGLWidget>
24 #include <QApplication>
25 #include <QDebug>
26 #include <QCloseEvent>
27
28 #include <gst/video/video.h>
29 #include <gst/gl/gl.h>
30 #include <gst/gl/gstglfuncs.h>
31
32 #if GST_GL_HAVE_PLATFORM_GLX
33 #include <GL/glx.h>
34 #include <QX11Info>
35 #include <gst/gl/x11/gstgldisplay_x11.h>
36 #endif
37
38 #include "gstthread.h"
39 #include "qglrenderer.h"
40 #include "pipeline.h"
41
42 #if defined(Q_WS_MAC)
43 extern void *qt_current_nsopengl_context ();
44 #endif
45
QGLRenderer(const QString & videoLocation,QWidget * parent)46 QGLRenderer::QGLRenderer (const QString & videoLocation, QWidget * parent)
47 :
48 QGLWidget (parent),
49 videoLoc (videoLocation),
50 gst_thread (NULL),
51 closing (false),
52 frame (NULL)
53 {
54 move (20, 10);
55 resize (640, 480);
56 }
57
~QGLRenderer()58 QGLRenderer::~QGLRenderer ()
59 {
60 }
61
62 void
initializeGL()63 QGLRenderer::initializeGL ()
64 {
65 GstGLContext *context;
66 GstGLDisplay *display;
67
68 #if GST_GL_HAVE_PLATFORM_GLX
69 display =
70 (GstGLDisplay *) gst_gl_display_x11_new_with_display (QX11Info::
71 display ());
72 #else
73 display = gst_gl_display_new ();
74 #endif
75
76 /* FIXME: Allow the choice at runtime */
77 #if GST_GL_HAVE_PLATFORM_WGL
78 context =
79 gst_gl_context_new_wrapped (display, (guintptr) wglGetCurrentContext (),
80 GST_GL_PLATFORM_WGL, GST_GL_API_OPENGL);
81 #elif GST_GL_HAVE_PLATFORM_CGL
82 context =
83 gst_gl_context_new_wrapped (display,
84 (guintptr) qt_current_nsopengl_context (), GST_GL_PLATFORM_CGL,
85 GST_GL_API_OPENGL);
86 #elif GST_GL_HAVE_PLATFORM_GLX
87 context =
88 gst_gl_context_new_wrapped (display, (guintptr) glXGetCurrentContext (),
89 GST_GL_PLATFORM_GLX, GST_GL_API_OPENGL);
90 #endif
91 gst_object_unref (display);
92
93 // We need to unset Qt context before initializing gst-gl plugin.
94 // Otherwise the attempt to share gst-gl context with Qt will fail.
95 this->doneCurrent ();
96 this->gst_thread =
97 new GstThread (display, context, this->videoLoc,
98 SLOT (newFrame ()), this);
99 this->makeCurrent ();
100
101 QObject::connect (this->gst_thread, SIGNAL (finished ()),
102 this, SLOT (close ()));
103 QObject::connect (this, SIGNAL (closeRequested ()),
104 this->gst_thread, SLOT (stop ()), Qt::QueuedConnection);
105
106 qglClearColor (QApplication::palette ().color (QPalette::Active,
107 QPalette::Window));
108 //glShadeModel(GL_FLAT);
109 //glEnable(GL_DEPTH_TEST);
110 //glEnable(GL_CULL_FACE);
111 glEnable (GL_TEXTURE_2D); // Enable Texture Mapping
112
113 this->gst_thread->start ();
114 }
115
116 void
resizeGL(int width,int height)117 QGLRenderer::resizeGL (int width, int height)
118 {
119 // Reset The Current Viewport And Perspective Transformation
120 glViewport (0, 0, width, height);
121
122 glMatrixMode (GL_PROJECTION);
123 glLoadIdentity ();
124
125 glMatrixMode (GL_MODELVIEW);
126 }
127
128 void
newFrame()129 QGLRenderer::newFrame ()
130 {
131 Pipeline *pipeline = this->gst_thread->getPipeline ();
132 if (!pipeline)
133 return;
134
135 /* frame is initialized as null */
136 if (this->frame)
137 pipeline->queue_output_buf.put (this->frame);
138
139 this->frame = pipeline->queue_input_buf.get ();
140
141 /* direct call to paintGL (no queued) */
142 this->updateGL ();
143 }
144
145 static void
flushGstreamerGL(GstGLContext * context,void * data G_GNUC_UNUSED)146 flushGstreamerGL (GstGLContext * context, void *data G_GNUC_UNUSED)
147 {
148 context->gl_vtable->Flush ();
149 }
150
151 void
paintGL()152 QGLRenderer::paintGL ()
153 {
154 static GLfloat xrot = 0;
155 static GLfloat yrot = 0;
156 static GLfloat zrot = 0;
157
158 if (this->frame) {
159 guint tex_id;
160 GstMemory *mem;
161 GstVideoInfo v_info;
162 GstVideoFrame v_frame;
163 GstVideoMeta *v_meta;
164
165 mem = gst_buffer_peek_memory (this->frame, 0);
166 v_meta = gst_buffer_get_video_meta (this->frame);
167
168 Q_ASSERT (gst_is_gl_memory (mem));
169
170 GstGLMemory *gl_memory = (GstGLMemory *) mem;
171
172 gst_gl_context_thread_add (gl_memory->mem.context, flushGstreamerGL, NULL);
173
174 gst_video_info_set_format (&v_info, v_meta->format, v_meta->width,
175 v_meta->height);
176
177 gst_video_frame_map (&v_frame, &v_info, this->frame,
178 (GstMapFlags) (GST_MAP_READ | GST_MAP_GL));
179
180 tex_id = *(guint *) v_frame.data[0];
181
182 glEnable (GL_DEPTH_TEST);
183
184 glEnable (GL_TEXTURE_2D);
185 glBindTexture (GL_TEXTURE_2D, tex_id);
186 if (glGetError () != GL_NO_ERROR) {
187 qDebug ("failed to bind texture that comes from gst-gl");
188 emit closeRequested ();
189 return;
190 }
191
192 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
193 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
194 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
195 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
196 glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
197
198 glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
199 glMatrixMode (GL_MODELVIEW);
200 glLoadIdentity ();
201
202 glScalef (0.5f, 0.5f, 0.5f);
203
204 glRotatef (xrot, 1.0f, 0.0f, 0.0f);
205 glRotatef (yrot, 0.0f, 1.0f, 0.0f);
206 glRotatef (zrot, 0.0f, 0.0f, 1.0f);
207
208 glBegin (GL_QUADS);
209 // Front Face
210 glTexCoord2f (1.0f, 0.0f);
211 glVertex3f (-1.0f, -1.0f, 1.0f);
212 glTexCoord2f (0.0f, 0.0f);
213 glVertex3f (1.0f, -1.0f, 1.0f);
214 glTexCoord2f (0.0f, 1.0f);
215 glVertex3f (1.0f, 1.0f, 1.0f);
216 glTexCoord2f (1.0f, 1.0f);
217 glVertex3f (-1.0f, 1.0f, 1.0f);
218 // Back Face
219 glTexCoord2f (0.0f, 0.0f);
220 glVertex3f (-1.0f, -1.0f, -1.0f);
221 glTexCoord2f (0.0f, 1.0f);
222 glVertex3f (-1.0f, 1.0f, -1.0f);
223 glTexCoord2f (1.0f, 1.0f);
224 glVertex3f (1.0f, 1.0f, -1.0f);
225 glTexCoord2f (1.0f, 0.0f);
226 glVertex3f (1.0f, -1.0f, -1.0f);
227 // Top Face
228 glTexCoord2f (1.0f, 1.0f);
229 glVertex3f (-1.0f, 1.0f, -1.0f);
230 glTexCoord2f (1.0f, 0.0f);
231 glVertex3f (-1.0f, 1.0f, 1.0f);
232 glTexCoord2f (0.0f, 0.0f);
233 glVertex3f (1.0f, 1.0f, 1.0f);
234 glTexCoord2f (0.0f, 1.0f);
235 glVertex3f (1.0f, 1.0f, -1.0f);
236 // Bottom Face
237 glTexCoord2f (1.0f, 0.0f);
238 glVertex3f (-1.0f, -1.0f, -1.0f);
239 glTexCoord2f (0.0f, 0.0f);
240 glVertex3f (1.0f, -1.0f, -1.0f);
241 glTexCoord2f (0.0f, 1.0f);
242 glVertex3f (1.0f, -1.0f, 1.0f);
243 glTexCoord2f (1.0f, 1.0f);
244 glVertex3f (-1.0f, -1.0f, 1.0f);
245 // Right face
246 glTexCoord2f (0.0f, 0.0f);
247 glVertex3f (1.0f, -1.0f, -1.0f);
248 glTexCoord2f (0.0f, 1.0f);
249 glVertex3f (1.0f, 1.0f, -1.0f);
250 glTexCoord2f (1.0f, 1.0f);
251 glVertex3f (1.0f, 1.0f, 1.0f);
252 glTexCoord2f (1.0f, 0.0f);
253 glVertex3f (1.0f, -1.0f, 1.0f);
254 // Left Face
255 glTexCoord2f (1.0f, 0.0f);
256 glVertex3f (-1.0f, -1.0f, -1.0f);
257 glTexCoord2f (0.0f, 0.0f);
258 glVertex3f (-1.0f, -1.0f, 1.0f);
259 glTexCoord2f (0.0f, 1.0f);
260 glVertex3f (-1.0f, 1.0f, 1.0f);
261 glTexCoord2f (1.0f, 1.0f);
262 glVertex3f (-1.0f, 1.0f, -1.0f);
263 glEnd ();
264
265 xrot += 0.3f;
266 yrot += 0.2f;
267 zrot += 0.4f;
268
269 glLoadIdentity();
270 glDisable(GL_DEPTH_TEST);
271 glBindTexture (GL_TEXTURE_2D, 0);
272
273 gst_video_frame_unmap (&v_frame);
274 }
275 }
276
277 void
closeEvent(QCloseEvent * event)278 QGLRenderer::closeEvent (QCloseEvent * event)
279 {
280 if (this->closing == false) {
281 this->closing = true;
282 emit closeRequested ();
283 event->ignore ();
284 }
285 }
286