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> *
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. *
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. *
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 *****************************************************************************/
24 #include "audiooutput.h"
25 #include "mediaobject.h"
26 #include "videowidget.h"
27 #include "devicemanager.h"
28 #include "effectmanager.h"
31 #include "vlcloader.h"
32 #include "vlcmediaobject.h"
34 #ifdef PHONON_PULSESUPPORT
35 # include <phonon/pulsesupport.h>
38 #include <QtCore/QSet>
39 #include <QtCore/QVariant>
40 #include <QtCore/QtPlugin>
42 Q_EXPORT_PLUGIN2(phonon_vlc, Phonon::VLC::Backend)
48 Backend::Backend(QObject *parent, const QVariantList &)
50 , m_deviceManager(NULL)
51 , m_effectManager(NULL)
54 #ifdef PHONON_PULSESUPPORT
55 // Initialise PulseAudio support
56 PulseSupport *pulse = PulseSupport::getInstance();
58 connect(pulse, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)), SIGNAL(objectDescriptionChanged(ObjectDescriptionType)));
61 bool wasInit = vlcInit();
63 setProperty("identifier", QLatin1String("phonon_vlc"));
64 setProperty("backendName", QLatin1String("VLC"));
65 setProperty("backendComment", QLatin1String("VLC plugin for Phonon"));
66 setProperty("backendVersion", QLatin1String("0.1"));
67 setProperty("backendWebsite", QLatin1String("http://multimedia.kde.org/"));
69 // Check if we should enable debug output
70 QString debugLevelString = qgetenv("PHONON_VLC_DEBUG");
71 int debugLevel = debugLevelString.toInt();
72 if (debugLevel > 3) // 3 is maximum
74 m_debugLevel = (DebugLevel)debugLevel;
77 logMessage(QString("Using VLC version %0").arg(libvlc_get_version()));
79 qWarning("Phonon::VLC::vlcInit: Failed to initialize VLC");
82 m_deviceManager = new DeviceManager(this);
83 m_effectManager = new EffectManager(this);
91 QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
94 case MediaObjectClass:
95 return new VLCMediaObject(parent);
96 case VolumeFaderEffectClass:
97 // return new VolumeFaderEffect(parent);
98 logMessage("createObject() : VolumeFaderEffect not implemented");
100 case AudioOutputClass: {
101 AudioOutput *ao = new AudioOutput(this, parent);
102 m_audioOutputs.append(ao);
105 case AudioDataOutputClass:
106 // return new AudioDataOutput(parent);
107 logMessage("createObject() : AudioDataOutput not implemented");
109 case VisualizationClass:
110 // return new Visualization(parent);
111 logMessage("createObject() : Visualization not implemented");
113 case VideoDataOutputClass:
114 // return new VideoDataOutput(parent);
115 logMessage("createObject() : VideoDataOutput not implemented");
118 return new Effect(m_effectManager, args[0].toInt(), parent);
119 case VideoWidgetClass:
120 return new VideoWidget(qobject_cast<QWidget *>(parent));
122 logMessage("createObject() : Backend object not available");
127 bool Backend::supportsVideo() const
132 bool Backend::supportsOSD() const
137 bool Backend::supportsFourcc(quint32 fourcc) const
142 bool Backend::supportsSubtitles() const
147 QStringList Backend::availableMimeTypes() const
149 if (m_supportedMimeTypes.isEmpty()) {
150 const_cast<Backend *>(this)->m_supportedMimeTypes
151 << QLatin1String("application/ogg")
152 << QLatin1String("application/vnd.rn-realmedia")
153 << QLatin1String("application/x-annodex")
154 << QLatin1String("application/x-flash-video")
155 << QLatin1String("application/x-quicktimeplayer")
156 << QLatin1String("audio/168sv")
157 << QLatin1String("audio/8svx")
158 << QLatin1String("audio/aiff")
159 << QLatin1String("audio/basic")
160 << QLatin1String("audio/mp3")
161 << QLatin1String("audio/mp4")
162 << QLatin1String("audio/mpeg")
163 << QLatin1String("audio/mpeg2")
164 << QLatin1String("audio/mpeg3")
165 << QLatin1String("audio/vnd.rn-realaudio")
166 << QLatin1String("audio/wav")
167 << QLatin1String("audio/x-16sv")
168 << QLatin1String("audio/x-8svx")
169 << QLatin1String("audio/x-aiff")
170 << QLatin1String("audio/x-basic")
171 << QLatin1String("audio/x-m4a")
172 << QLatin1String("audio/x-mp3")
173 << QLatin1String("audio/x-mpeg")
174 << QLatin1String("audio/x-mpeg2")
175 << QLatin1String("audio/x-mpeg3")
176 << QLatin1String("audio/x-mpegurl")
177 << QLatin1String("audio/x-ms-wma")
178 << QLatin1String("audio/x-ogg")
179 << QLatin1String("audio/x-pn-aiff")
180 << QLatin1String("audio/x-pn-au")
181 << QLatin1String("audio/x-pn-realaudio-plugin")
182 << QLatin1String("audio/x-pn-wav")
183 << QLatin1String("audio/x-pn-windows-acm")
184 << QLatin1String("audio/x-real-audio")
185 << QLatin1String("audio/x-realaudio")
186 << QLatin1String("audio/x-speex+ogg")
187 << QLatin1String("audio/x-wav")
188 << QLatin1String("image/ilbm")
189 << QLatin1String("image/png")
190 << QLatin1String("image/x-ilbm")
191 << QLatin1String("image/x-png")
192 << QLatin1String("video/anim")
193 << QLatin1String("video/avi")
194 << QLatin1String("video/mkv")
195 << QLatin1String("video/mng")
196 << QLatin1String("video/mp4")
197 << QLatin1String("video/mpeg")
198 << QLatin1String("video/mpg")
199 << QLatin1String("video/msvideo")
200 << QLatin1String("video/quicktime")
201 << QLatin1String("video/x-anim")
202 << QLatin1String("video/x-flic")
203 << QLatin1String("video/x-mng")
204 << QLatin1String("video/x-mpeg")
205 << QLatin1String("video/x-ms-asf")
206 << QLatin1String("video/x-ms-wmv")
207 << QLatin1String("video/x-msvideo")
208 << QLatin1String("video/x-quicktime");
210 return m_supportedMimeTypes;
213 QList<int> Backend::objectDescriptionIndexes(ObjectDescriptionType type) const
218 case Phonon::AudioOutputDeviceType: {
219 QList<AudioDevice> deviceList = deviceManager()->audioOutputDevices();
220 for (int dev = 0 ; dev < deviceList.size() ; ++dev)
221 list.append(deviceList[dev].id);
225 case Phonon::EffectType: {
226 QList<EffectInfo*> effectList = effectManager()->effects();
227 for (int eff = 0; eff < effectList.size(); ++eff)
239 QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const
241 QHash<QByteArray, QVariant> ret;
244 case Phonon::AudioOutputDeviceType: {
245 QList<AudioDevice> audioDevices = deviceManager()->audioOutputDevices();
246 if (index >= 0 && index < audioDevices.size()) {
247 ret.insert("name", audioDevices[index].vlcId);
248 ret.insert("description", audioDevices[index].description);
249 ret.insert("icon", QLatin1String("audio-card"));
253 case Phonon::EffectType: {
254 QList<EffectInfo*> effectList = effectManager()->effects();
255 if (index >= 0 && index <= effectList.size()) {
256 const EffectInfo *effect = effectList[ index ];
257 ret.insert("name", effect->name());
258 ret.insert("description", effect->description());
259 ret.insert("author", effect->author());
261 Q_ASSERT(1); // Since we use list position as ID, this should not happen
272 bool Backend::startConnectionChange(QSet<QObject *> objects)
274 foreach(QObject *object, objects) {
275 logMessage(QString("Object: %0").arg(object->metaObject()->className()));
278 // There is nothing we can do but hope the connection changes will not take too long
279 // so that buffers would underrun
280 // But we should be pretty safe the way xine works by not doing anything here.
284 bool Backend::connectNodes(QObject *source, QObject *sink)
286 logMessage(QString("Backend connected %0 to %1")
287 .arg(source->metaObject()->className())
288 .arg(sink->metaObject()->className()));
291 // source = Phonon::VLC_MPlayer::MediaObject
292 // sink = Phonon::VLC_MPlayer::VideoWidget
295 // source = Phonon::VLC_MPlayer::MediaObject
296 // sink = Phonon::VLC_MPlayer::AudioOutput
299 // source = Phonon::VLC_MPlayer::MediaObject
300 // sink = Phonon::VLC_MPlayer::Effect
303 // source = Phonon::VLC_MPlayer::Effect
304 // sink = Phonon::VLC_MPlayer::AudioOutput
306 SinkNode *sinkNode = qobject_cast<SinkNode *>(sink);
308 PrivateMediaObject *mediaObject = qobject_cast<PrivateMediaObject *>(source);
310 // Connect the SinkNode to a MediaObject
311 sinkNode->connectToMediaObject(mediaObject);
314 // FIXME try to find a better way...
315 // Effect *effect = qobject_cast<Effect *>(source);
320 logMessage(QString("Linking %0 to %1 failed")
321 .arg(source->metaObject()->className())
322 .arg(sink->metaObject()->className()),
328 bool Backend::disconnectNodes(QObject *source, QObject *sink)
330 SinkNode *sinkNode = qobject_cast<SinkNode *>(sink);
332 PrivateMediaObject *mediaObject = qobject_cast<PrivateMediaObject *>(source);
334 // Disconnect the SinkNode from a MediaObject
335 sinkNode->disconnectFromMediaObject(mediaObject);
338 // FIXME try to find a better way...
339 // Effect *effect = qobject_cast<Effect *>(source);
347 bool Backend::endConnectionChange(QSet<QObject *> objects)
349 foreach(QObject *object, objects) {
350 logMessage(QString("Object: %0").arg(object->metaObject()->className()));
356 DeviceManager* Backend::deviceManager() const
358 return m_deviceManager;
361 EffectManager* Backend::effectManager() const
363 return m_effectManager;
367 * Return a debuglevel that is determined by the
368 * PHONON_VLC_DEBUG environment variable.
370 * Warning - important warnings
371 * Info - general info
372 * Debug - gives extra info
374 Backend::DebugLevel Backend::debugLevel() const
380 * Print a conditional debug message based on the current debug level
381 * If obj is provided, classname and objectname will be printed as well
385 void Backend::logMessage(const QString &message, int priority, QObject *obj) const
387 if (debugLevel() > 0) {
390 // Strip away namespace from className
391 QString className(obj->metaObject()->className());
392 int nameLength = className.length() - className.lastIndexOf(':') - 1;
393 className = className.right(nameLength);
394 output.sprintf("%s %s (%s %p)", message.toLatin1().constData(),
395 obj->objectName().toLatin1().constData(),
396 className.toLatin1().constData(), obj);
400 if (priority <= (int)debugLevel()) {
401 qDebug() << QString("PVLC(%1): %2").arg(priority).arg(output);
407 } // Namespace Phonon::VLC