]> git.sesse.net Git - mlt/blob - src/modules/qt/consumer_qglsl.cpp
a1fb93656cdd504c6e34b5dc2a347d6ebdd1ad9b
[mlt] / src / modules / qt / consumer_qglsl.cpp
1 /*
2  * consumer_qglsl.cpp
3  * Copyright (C) 2012-2014 Dan Dennedy <dan@dennedy.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 #include <framework/mlt.h>
21 #include <QApplication>
22 #include <QLocale>
23 #include <QGLWidget>
24 #include <QMutex>
25 #include <QWaitCondition>
26 #include <QtGlobal>
27
28 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
29 #include <X11/Xlib.h>
30 #endif
31
32 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
33
34 class GLWidget : public QGLWidget
35 {
36 private:
37         QGLWidget *renderContext;
38         bool isInitialized;
39         QMutex mutex;
40         QWaitCondition condition;
41
42 public:
43         GLWidget()
44 #ifdef Q_OS_MAC
45                 : QGLWidget()
46 #else
47                 : QGLWidget(0, 0, Qt::SplashScreen)
48 #endif
49                 , renderContext(0)
50                 , isInitialized(false)
51         {
52                 resize(0, 0);
53                 show();
54         }
55
56         ~GLWidget()
57         {
58                 delete renderContext;
59         }
60
61         bool createRenderContext()
62         {
63                 if (!isInitialized) {
64                         mutex.lock();
65                         condition.wait(&mutex);
66                         mutex.unlock();
67                 }
68                 if (!renderContext) {
69                         renderContext = new QGLWidget(0, this, Qt::SplashScreen);
70                         renderContext->resize(0, 0);
71                         renderContext->makeCurrent();
72                 }
73                 return renderContext->isValid();
74         }
75
76 protected:
77         void initializeGL()
78         {
79                 condition.wakeAll();
80                 isInitialized = true;
81         }
82 };
83
84 #else // Qt 5
85
86 #include <QThread>
87 #include <QOpenGLContext>
88 #include <QOffscreenSurface>
89
90 typedef void* ( *thread_function_t )( void* );
91
92 class RenderThread : public QThread
93 {
94 public:
95         RenderThread(thread_function_t function, void *data)
96                 : QThread(0)
97                 , m_function(function)
98                 , m_data(data)
99         {
100                 m_context = new QOpenGLContext;
101                 m_context->create();
102                 m_context->moveToThread(this);
103                 m_surface = new QOffscreenSurface();
104                 m_surface->create();
105         }
106         ~RenderThread()
107         {
108 #ifndef Q_OS_WIN
109                 m_surface->destroy();
110                 delete m_surface;
111 #endif
112         }
113
114 protected:
115         void run()
116         {
117                 Q_ASSERT(m_context->isValid());
118                 m_context->makeCurrent(m_surface);
119                 m_function(m_data);
120                 m_context->doneCurrent();
121                 delete m_context;
122         }
123
124 private:
125         thread_function_t m_function;
126         void* m_data;
127         QOpenGLContext* m_context;
128         QOffscreenSurface* m_surface;
129 };
130
131 static void onThreadCreate(mlt_properties owner, mlt_consumer self,
132         RenderThread** thread, int* priority, thread_function_t function, void* data )
133 {
134         Q_UNUSED(owner)
135         Q_UNUSED(priority)
136         (*thread) = new RenderThread(function, data);
137         (*thread)->start();
138 }
139
140 static void onThreadJoin(mlt_properties owner, mlt_consumer self, RenderThread* thread)
141 {
142         Q_UNUSED(owner)
143         Q_UNUSED(self)
144         if (thread) {
145                 thread->wait();
146                 qApp->processEvents();
147                 delete thread;
148         }
149 }
150
151 #endif // Qt 5
152
153 static void onThreadStarted(mlt_properties owner, mlt_consumer consumer)
154 {
155         mlt_service service = MLT_CONSUMER_SERVICE(consumer);
156         mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer);
157         mlt_filter filter = (mlt_filter) mlt_properties_get_data(properties, "glslManager", NULL);
158         mlt_properties filter_properties = MLT_FILTER_PROPERTIES(filter);
159
160         mlt_log_debug(service, "%s\n", __FUNCTION__);
161 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
162         GLWidget *widget = (GLWidget*) mlt_properties_get_data(properties, "GLWidget", NULL);
163         if (widget->createRenderContext()) {
164 #else
165         {
166 #endif
167                 mlt_events_fire(filter_properties, "init glsl", NULL);
168                 if (!mlt_properties_get_int(filter_properties, "glsl_supported")) {
169                         mlt_log_fatal(service,
170                                 "OpenGL Shading Language rendering is not supported on this machine.\n" );
171                         mlt_events_fire(properties, "consumer-fatal-error", NULL);
172                 }
173         }
174 }
175
176 static void onThreadStopped(mlt_properties owner, mlt_consumer consumer)
177 {
178         mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer);
179         mlt_filter filter = (mlt_filter) mlt_properties_get_data(properties, "glslManager", NULL);
180         mlt_events_fire(MLT_FILTER_PROPERTIES(filter), "close glsl", NULL);
181 }
182
183 static void onCleanup(mlt_properties owner, mlt_consumer consumer)
184 {
185 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
186         GLWidget* widget = (GLWidget*) mlt_properties_get_data( MLT_CONSUMER_PROPERTIES(consumer), "GLWidget", NULL);
187         delete widget;
188         mlt_properties_set_data(MLT_CONSUMER_PROPERTIES(consumer), "GLWidget", NULL, 0, NULL, NULL);
189         qApp->processEvents();
190 #endif
191 }
192
193 extern "C" {
194
195 mlt_consumer consumer_qglsl_init( mlt_profile profile, mlt_service_type type, const char *id, char *arg )
196 {
197         mlt_consumer consumer = mlt_factory_consumer(profile, "multi", arg);
198         if (consumer) {
199                 mlt_filter filter = mlt_factory_filter(profile, "glsl.manager", 0);
200                 if (filter) {
201                         mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer);
202                         mlt_properties_set_data(properties, "glslManager", filter, 0, (mlt_destructor) mlt_filter_close, NULL);
203                         mlt_events_register( properties, "consumer-cleanup", NULL );
204                         mlt_events_listen(properties, consumer, "consumer-thread-started", (mlt_listener) onThreadStarted);
205                         mlt_events_listen(properties, consumer, "consumer-thread-stopped", (mlt_listener) onThreadStopped);
206                         mlt_events_listen(properties, consumer, "consumer-cleanup", (mlt_listener) onCleanup);
207 #if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
208                         XInitThreads();
209                         if ( getenv("DISPLAY") == 0 ) {
210                                 mlt_log_error(MLT_CONSUMER_SERVICE(consumer), "The qglsl consumer requires a X11 environment.\nPlease either run melt from an X session or use a fake X server like xvfb:\nxvfb-run -a melt (...)\n" );
211                         } else
212 #endif
213                         if (!qApp) {
214                                 int argc = 1;
215                                 char* argv[1];
216                                 argv[0] = (char*) "MLT qglsl consumer";
217                                 new QApplication(argc, argv);
218                                 const char *localename = mlt_properties_get_lcnumeric(properties);
219                                 QLocale::setDefault(QLocale(localename));
220                         }
221 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
222                         mlt_properties_set_data(properties, "GLWidget", new GLWidget, 0, NULL, NULL);
223 #else
224                         mlt_events_listen(properties, consumer, "consumer-thread-create", (mlt_listener) onThreadCreate);
225                         mlt_events_listen(properties, consumer, "consumer-thread-join", (mlt_listener) onThreadJoin);
226 #endif
227                         qApp->processEvents();
228                         return consumer;
229                 }
230                 mlt_consumer_close(consumer);
231         }
232         return NULL;
233 }
234
235 }