]> git.sesse.net Git - vlc/blob - bindings/phonon/vlc/backend.cpp
d54832fb7f2ffd5220db7294bb11936b6498fada
[vlc] / bindings / phonon / vlc / backend.cpp
1 /*****************************************************************************
2  * VLC backend for the Phonon library                                        *
3  * Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>               *
4  * Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>                *
5  * Copyright (C) 2009 Fathi Boudra <fabo@kde.org>                            *
6  *                                                                           *
7  * This program is free software; you can redistribute it and/or             *
8  * modify it under the terms of the GNU Lesser General Public                *
9  * License as published by the Free Software Foundation; either              *
10  * version 3 of the License, or (at your option) any later version.          *
11  *                                                                           *
12  * This program 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  * Lesser General Public License for more details.                           *
16  *                                                                           *
17  * You should have received a copy of the GNU Lesser General Public          *
18  * License along with this package; if not, write to the Free Software       *
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA *
20  *****************************************************************************/
21
22 #include "backend.h"
23
24 #include "audiooutput.h"
25 #include "mediaobject.h"
26 #include "videowidget.h"
27 #include "devicemanager.h"
28 #include "effectmanager.h"
29 #include "effect.h"
30 #include "sinknode.h"
31 #include "vlcloader.h"
32 #include "vlcmediaobject.h"
33
34 #include <QtCore/QSet>
35 #include <QtCore/QVariant>
36 #include <QtCore/QtPlugin>
37
38 Q_EXPORT_PLUGIN2(phonon_vlc, Phonon::VLC::Backend)
39
40 namespace Phonon
41 {
42 namespace VLC {
43
44 Backend::Backend(QObject *parent, const QVariantList &)
45         : QObject(parent)
46         , m_deviceManager(0)
47         , m_effectManager(0)
48         , m_debugLevel(Debug)
49 {
50     bool wasInit = vlcInit();
51
52     setProperty("identifier",     QLatin1String("phonon_vlc"));
53     setProperty("backendName",    QLatin1String("VLC"));
54     setProperty("backendComment", QLatin1String("VLC plugin for Phonon"));
55     setProperty("backendVersion", QLatin1String("0.1"));
56     setProperty("backendWebsite", QLatin1String("http://multimedia.kde.org/"));
57
58     // Check if we should enable debug output
59     QString debugLevelString = qgetenv("PHONON_VLC_DEBUG");
60     int debugLevel = debugLevelString.toInt();
61     if (debugLevel > 3) // 3 is maximum
62         debugLevel = 3;
63     m_debugLevel = (DebugLevel)debugLevel;
64
65     if (wasInit) {
66         logMessage(QString("Using VLC version %0").arg(libvlc_get_version()));
67     } else {
68         qWarning("Phonon::VLC::vlcInit: Failed to initialize VLC");
69     }
70
71     m_deviceManager = new DeviceManager(this);
72     m_effectManager = new EffectManager(this);
73 }
74
75 Backend::~Backend()
76 {
77 //    vlcRelease();
78 }
79
80 QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
81 {
82     switch (c) {
83     case MediaObjectClass:
84         return new VLCMediaObject(parent);
85     case VolumeFaderEffectClass:
86 //        return new VolumeFaderEffect(parent);
87         logMessage("createObject() : VolumeFaderEffect not implemented");
88         break;
89     case AudioOutputClass: {
90         AudioOutput *ao = new AudioOutput(this, parent);
91         m_audioOutputs.append(ao);
92         return ao;
93     }
94     case AudioDataOutputClass:
95 //        return new AudioDataOutput(parent);
96         logMessage("createObject() : AudioDataOutput not implemented");
97         break;
98     case VisualizationClass:
99 //        return new Visualization(parent);
100         logMessage("createObject() : Visualization not implemented");
101         break;
102     case VideoDataOutputClass:
103 //        return new VideoDataOutput(parent);
104         logMessage("createObject() : VideoDataOutput not implemented");
105         break;
106     case EffectClass:
107         return new Effect(m_effectManager, args[0].toInt(), parent);
108     case VideoWidgetClass:
109         return new VideoWidget(qobject_cast<QWidget *>(parent));
110     default:
111         logMessage("createObject() : Backend object not available");
112     }
113     return 0;
114 }
115
116 bool Backend::supportsVideo() const
117 {
118     return true;
119 }
120
121 bool Backend::supportsOSD() const
122 {
123     return true;
124 }
125
126 bool Backend::supportsFourcc(quint32 fourcc) const
127 {
128     return true;
129 }
130
131 bool Backend::supportsSubtitles() const
132 {
133     return true;
134 }
135
136 QStringList Backend::availableMimeTypes() const
137 {
138     if (m_supportedMimeTypes.isEmpty()) {
139         const_cast<Backend *>(this)->m_supportedMimeTypes
140         << QLatin1String("application/ogg")
141         << QLatin1String("application/vnd.rn-realmedia")
142         << QLatin1String("application/x-annodex")
143         << QLatin1String("application/x-flash-video")
144         << QLatin1String("application/x-quicktimeplayer")
145         << QLatin1String("audio/168sv")
146         << QLatin1String("audio/8svx")
147         << QLatin1String("audio/aiff")
148         << QLatin1String("audio/basic")
149         << QLatin1String("audio/mp3")
150         << QLatin1String("audio/mp4")
151         << QLatin1String("audio/mpeg")
152         << QLatin1String("audio/mpeg2")
153         << QLatin1String("audio/mpeg3")
154         << QLatin1String("audio/vnd.rn-realaudio")
155         << QLatin1String("audio/wav")
156         << QLatin1String("audio/x-16sv")
157         << QLatin1String("audio/x-8svx")
158         << QLatin1String("audio/x-aiff")
159         << QLatin1String("audio/x-basic")
160         << QLatin1String("audio/x-m4a")
161         << QLatin1String("audio/x-mp3")
162         << QLatin1String("audio/x-mpeg")
163         << QLatin1String("audio/x-mpeg2")
164         << QLatin1String("audio/x-mpeg3")
165         << QLatin1String("audio/x-mpegurl")
166         << QLatin1String("audio/x-ms-wma")
167         << QLatin1String("audio/x-ogg")
168         << QLatin1String("audio/x-pn-aiff")
169         << QLatin1String("audio/x-pn-au")
170         << QLatin1String("audio/x-pn-realaudio-plugin")
171         << QLatin1String("audio/x-pn-wav")
172         << QLatin1String("audio/x-pn-windows-acm")
173         << QLatin1String("audio/x-real-audio")
174         << QLatin1String("audio/x-realaudio")
175         << QLatin1String("audio/x-speex+ogg")
176         << QLatin1String("audio/x-wav")
177         << QLatin1String("image/ilbm")
178         << QLatin1String("image/png")
179         << QLatin1String("image/x-ilbm")
180         << QLatin1String("image/x-png")
181         << QLatin1String("video/anim")
182         << QLatin1String("video/avi")
183         << QLatin1String("video/mkv")
184         << QLatin1String("video/mng")
185         << QLatin1String("video/mp4")
186         << QLatin1String("video/mpeg")
187         << QLatin1String("video/mpg")
188         << QLatin1String("video/msvideo")
189         << QLatin1String("video/quicktime")
190         << QLatin1String("video/x-anim")
191         << QLatin1String("video/x-flic")
192         << QLatin1String("video/x-mng")
193         << QLatin1String("video/x-mpeg")
194         << QLatin1String("video/x-ms-asf")
195         << QLatin1String("video/x-ms-wmv")
196         << QLatin1String("video/x-msvideo")
197         << QLatin1String("video/x-quicktime");
198     }
199     return m_supportedMimeTypes;
200 }
201
202 QList<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const
203 {
204     QList<int> list;
205
206     switch (type) {
207     case Phonon::AudioOutputDeviceType: {
208         QList<AudioDevice> deviceList = deviceManager()->audioOutputDevices();
209         for (int dev = 0 ; dev < deviceList.size() ; ++dev)
210             list.append(deviceList[dev].id);
211         break;
212     }
213     break;
214     case Phonon::EffectType: {
215         QList<EffectInfo*> effectList = effectManager()->effects();
216         for (int eff = 0; eff < effectList.size(); ++eff)
217             list.append(eff);
218         break;
219     }
220     break;
221     default:
222         break;
223     }
224
225     return list;
226 }
227
228 QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
229 {
230     QHash<QByteArray, QVariant> ret;
231
232     switch (type) {
233     case Phonon::AudioOutputDeviceType: {
234         QList<AudioDevice> audioDevices = deviceManager()->audioOutputDevices();
235         if (index >= 0 && index < audioDevices.size()) {
236             ret.insert("name", audioDevices[index].vlcId);
237             ret.insert("description", audioDevices[index].description);
238             ret.insert("icon", QLatin1String("audio-card"));
239         }
240     }
241     break;
242     case Phonon::EffectType: {
243         QList<EffectInfo*> effectList = effectManager()->effects();
244         if (index >= 0 && index <= effectList.size()) {
245             const EffectInfo *effect = effectList[ index ];
246             ret.insert("name", effect->name());
247             ret.insert("description", effect->description());
248             ret.insert("author", effect->author());
249         } else {
250             Q_ASSERT(1); // Since we use list position as ID, this should not happen
251         }
252     }
253     break;
254     default:
255         break;
256     }
257
258     return ret;
259 }
260
261 bool Backend::startConnectionChange(QSet<QObject *> objects)
262 {
263     foreach(QObject *object, objects) {
264         logMessage(QString("Object: %0").arg(object->metaObject()->className()));
265     }
266
267     // There is nothing we can do but hope the connection changes will not take too long
268     // so that buffers would underrun
269     // But we should be pretty safe the way xine works by not doing anything here.
270     return true;
271 }
272
273 bool Backend::connectNodes(QObject *source, QObject *sink)
274 {
275     logMessage(QString("Backend connected %0 to %1")
276                .arg(source->metaObject()->className())
277                .arg(sink->metaObject()->className()));
278
279     // Example:
280     // source = Phonon::VLC_MPlayer::MediaObject
281     // sink = Phonon::VLC_MPlayer::VideoWidget
282
283     // Example:
284     // source = Phonon::VLC_MPlayer::MediaObject
285     // sink = Phonon::VLC_MPlayer::AudioOutput
286
287     // Example:
288     // source = Phonon::VLC_MPlayer::MediaObject
289     // sink = Phonon::VLC_MPlayer::Effect
290
291     // Example:
292     // source = Phonon::VLC_MPlayer::Effect
293     // sink = Phonon::VLC_MPlayer::AudioOutput
294
295     SinkNode *sinkNode = qobject_cast<SinkNode *>(sink);
296     if (sinkNode) {
297         PrivateMediaObject *mediaObject = qobject_cast<PrivateMediaObject *>(source);
298         if (mediaObject) {
299             // Connect the SinkNode to a MediaObject
300             sinkNode->connectToMediaObject(mediaObject);
301             return true;
302         } else {
303             // FIXME try to find a better way...
304 //            Effect *effect = qobject_cast<Effect *>(source);
305             return true;
306         }
307     }
308
309     logMessage(QString("Linking %0 to %1 failed")
310                .arg(source->metaObject()->className())
311                .arg(sink->metaObject()->className()),
312                Warning);
313
314     return false;
315 }
316
317 bool Backend::disconnectNodes(QObject *source, QObject *sink)
318 {
319     SinkNode *sinkNode = qobject_cast<SinkNode *>(sink);
320     if (sinkNode) {
321         PrivateMediaObject *mediaObject = qobject_cast<PrivateMediaObject *>(source);
322         if (mediaObject) {
323             // Disconnect the SinkNode from a MediaObject
324             sinkNode->disconnectFromMediaObject(mediaObject);
325             return true;
326         } else {
327             // FIXME try to find a better way...
328 //            Effect *effect = qobject_cast<Effect *>(source);
329             return true;
330         }
331     }
332
333     return false;
334 }
335
336 bool Backend::endConnectionChange(QSet<QObject *> objects)
337 {
338     foreach(QObject *object, objects) {
339         logMessage(QString("Object: %0").arg(object->metaObject()->className()));
340     }
341
342     return true;
343 }
344
345 DeviceManager* Backend::deviceManager() const
346 {
347     return m_deviceManager;
348 }
349
350 EffectManager* Backend::effectManager() const
351 {
352     return m_effectManager;
353 }
354
355 /**
356  * Return a debuglevel that is determined by the
357  * PHONON_VLC_DEBUG environment variable.
358  *
359  *  Warning - important warnings
360  *  Info    - general info
361  *  Debug   - gives extra info
362  */
363 Backend::DebugLevel Backend::debugLevel() const
364 {
365     return m_debugLevel;
366 }
367
368 /**
369  * Print a conditional debug message based on the current debug level
370  * If obj is provided, classname and objectname will be printed as well
371  *
372  * see debugLevel()
373  */
374 void Backend::logMessage(const QString &message, int priority, QObject *obj) const
375 {
376     if (debugLevel() > 0) {
377         QString output;
378         if (obj) {
379             // Strip away namespace from className
380             QString className(obj->metaObject()->className());
381             int nameLength = className.length() - className.lastIndexOf(':') - 1;
382             className = className.right(nameLength);
383             output.sprintf("%s %s (%s %p)", message.toLatin1().constData(),
384                            obj->objectName().toLatin1().constData(),
385                            className.toLatin1().constData(), obj);
386         } else {
387             output = message;
388         }
389         if (priority <= (int)debugLevel()) {
390             qDebug() << QString("PVLC(%1): %2").arg(priority).arg(output);
391         }
392     }
393 }
394
395 }
396 } // Namespace Phonon::VLC