File indexing completed on 2024-04-28 16:01:48

0001 /*  This file is part of the KDE project
0002     Copyright (C) 2007 Matthias Kretz <kretz@kde.org>
0003 
0004     This library is free software; you can redistribute it and/or
0005     modify it under the terms of the GNU Lesser General Public
0006     License as published by the Free Software Foundation; either
0007     version 2.1 of the License, or (at your option) version 3, or any
0008     later version accepted by the membership of KDE e.V. (or its
0009     successor approved by the membership of KDE e.V.), Nokia Corporation
0010     (or its successors, if any) and the KDE Free Qt Foundation, which shall
0011     act as a proxy defined in Section 6 of version 3 of the license.
0012 
0013     This library is distributed in the hope that it will be useful,
0014     but WITHOUT ANY WARRANTY; without even the implied warranty of
0015     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0016     Lesser General Public License for more details.
0017 
0018     You should have received a copy of the GNU Lesser General Public
0019     License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0020 
0021 */
0022 
0023 #include "mediasource.h"
0024 #include "mediasource_p.h"
0025 #include "iodevicestream_p.h"
0026 #include "abstractmediastream_p.h"
0027 #include "globalconfig.h"
0028 
0029 #include <QFileInfo>
0030 #include <QFile>
0031 
0032 namespace Phonon
0033 {
0034 
0035 MediaSource::MediaSource(MediaSourcePrivate &dd)
0036     : d(&dd)
0037 {
0038 }
0039 
0040 MediaSource::MediaSource()
0041     : d(new MediaSourcePrivate(Empty))
0042 {
0043 }
0044 
0045 MediaSource::MediaSource(const QString &filename)
0046     : d(new MediaSourcePrivate(LocalFile))
0047 {
0048     if (filename.startsWith(QLatin1String(":/")) || filename.startsWith(QLatin1String("qrc:///"))) {
0049 #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
0050         d->url.setScheme("qrc");
0051         d->url.setPath(filename.mid(filename.startsWith(QLatin1Char(':')) ? 1 : 6));
0052 
0053         // QFile needs :/ syntax
0054         QString path(QLatin1Char(':') + d->url.path());
0055 
0056         if (QFile::exists(path)) {
0057             d->type = Stream;
0058             d->ioDevice = new QFile(path);
0059             d->setStream(new IODeviceStream(d->ioDevice, d->ioDevice));
0060         } else {
0061             d->type = Invalid;
0062         }
0063 #else
0064         d->type = Invalid;
0065 #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
0066     } else {
0067         const QFileInfo fileinfo(filename);
0068         if (fileinfo.exists()) {
0069             d->url = QUrl::fromLocalFile(fileinfo.absoluteFilePath());
0070             if (!d->url.host().isEmpty()) {
0071                 // filename points to a file on a network share (eg \\host\share\path)
0072                 d->type = Url;
0073             }
0074         } else {
0075             d->url = filename;
0076             if (d->url.isValid()) {
0077                 d->type = Url;
0078             } else {
0079                 d->type = Invalid;
0080             }
0081         }
0082     }
0083 }
0084 
0085 MediaSource::MediaSource(const QUrl &url)
0086     : d(new MediaSourcePrivate(Url))
0087 {
0088     if (url.isValid()) {
0089         if (url.scheme() == QLatin1String("qrc")) {
0090 #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
0091             // QFile needs :/ syntax
0092             QString path(QLatin1Char(':') + url.path());
0093 
0094             if (QFile::exists(path)) {
0095                 d->type = Stream;
0096                 d->ioDevice = new QFile(path);
0097                 d->setStream(new IODeviceStream(d->ioDevice, d->ioDevice));
0098             } else {
0099                 d->type = Invalid;
0100             }
0101 #else
0102             d->type = Invalid;
0103 #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
0104         }
0105         d->url = url;
0106     } else {
0107         d->type = Invalid;
0108     }
0109 }
0110 
0111 MediaSource::MediaSource(DiscType dt, const QString &deviceName)
0112     : d(new MediaSourcePrivate(Disc))
0113 {
0114     if (dt == NoDisc) {
0115         d->type = Invalid;
0116         return;
0117     }
0118     d->discType = dt;
0119     d->deviceName = deviceName;
0120 }
0121 
0122 // NOTE: this is deprecated
0123 MediaSource::MediaSource(const DeviceAccess &)
0124     : d(new MediaSourcePrivate(Invalid))
0125 {
0126 }
0127 
0128 #ifndef PHONON_NO_AUDIOCAPTURE
0129 MediaSource::MediaSource(const AudioCaptureDevice& device)
0130     : d(new MediaSourcePrivate(CaptureDevice))
0131 {
0132     d->setCaptureDevices(device, VideoCaptureDevice());
0133 }
0134 #endif //PHONON_NO_AUDIOCAPTURE
0135 
0136 #ifndef PHONON_NO_VIDEOCAPTURE
0137 MediaSource::MediaSource(const VideoCaptureDevice& device)
0138     : d(new MediaSourcePrivate(CaptureDevice))
0139 {
0140     d->setCaptureDevices(AudioCaptureDevice(), device);
0141 }
0142 #endif //PHONON_NO_VIDEOCAPTURE
0143 
0144 #if !defined(PHONON_NO_VIDEOCAPTURE) && !defined(PHONON_NO_AUDIOCAPTURE)
0145 MediaSource::MediaSource(CaptureCategory category)
0146     : d(new MediaSourcePrivate(AudioVideoCapture))
0147 {
0148     d->setCaptureDevices(category);
0149 }
0150 
0151 MediaSource::MediaSource(Capture::DeviceType deviceType, CaptureCategory category)
0152     : d(new MediaSourcePrivate(CaptureDevice))
0153 {
0154     d->setCaptureDevice(deviceType, category);
0155 }
0156 #endif // !PHONON_NO_VIDEOCAPTURE && !PHONON_NO_AUDIOCAPTURE
0157 
0158 #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
0159 MediaSource::MediaSource(AbstractMediaStream *stream)
0160     : d(new MediaSourcePrivate(Stream))
0161 {
0162     if (stream) {
0163         d->setStream(stream);
0164     } else {
0165         d->type = Invalid;
0166     }
0167 }
0168 
0169 MediaSource::MediaSource(QIODevice *ioDevice)
0170     : d(new MediaSourcePrivate(Stream))
0171 {
0172     if (ioDevice) {
0173         d->setStream(new IODeviceStream(ioDevice, ioDevice));
0174         d->ioDevice = ioDevice;
0175     } else {
0176         d->type = Invalid;
0177     }
0178 }
0179 #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
0180 
0181 /* post 4.0
0182 MediaSource::MediaSource(const QList<MediaSource> &mediaList)
0183     : d(new MediaSourcePrivate(Link))
0184 {
0185     d->linkedSources = mediaList;
0186     foreach (MediaSource ms, mediaList) {
0187         Q_ASSERT(ms.type() != Link);
0188     }
0189 }
0190 
0191 QList<MediaSource> MediaSource::substreams() const
0192 {
0193     return d->linkedSources;
0194 }
0195 */
0196 
0197 MediaSource::~MediaSource()
0198 {
0199 }
0200 
0201 MediaSourcePrivate::~MediaSourcePrivate()
0202 {
0203 #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
0204     if (autoDelete) {
0205         //here we use deleteLater because this object
0206         //might be destroyed from another thread
0207         if (stream)
0208             stream->deleteLater();
0209         if (ioDevice)
0210             ioDevice->deleteLater();
0211     }
0212 #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
0213 }
0214 
0215 MediaSource::MediaSource(const MediaSource &rhs)
0216     : d(rhs.d)
0217 {
0218 }
0219 
0220 MediaSource &MediaSource::operator=(const MediaSource &rhs)
0221 {
0222     d = rhs.d;
0223     return *this;
0224 }
0225 
0226 bool MediaSource::operator==(const MediaSource &rhs) const
0227 {
0228     return d == rhs.d;
0229 }
0230 
0231 void MediaSource::setAutoDelete(bool autoDelete)
0232 {
0233     d->autoDelete = autoDelete;
0234 }
0235 
0236 bool MediaSource::autoDelete() const
0237 {
0238     return d->autoDelete;
0239 }
0240 
0241 MediaSource::Type MediaSource::type() const
0242 {
0243 #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
0244     if (d->type == Stream && d->stream == nullptr) {
0245         return Invalid;
0246     }
0247 #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
0248     return d->type;
0249 }
0250 
0251 QString MediaSource::fileName() const
0252 {
0253     return d->url.toLocalFile();
0254 }
0255 
0256 Mrl MediaSource::mrl() const
0257 {
0258     return Mrl(d->url);
0259 }
0260 
0261 QUrl MediaSource::url() const
0262 {
0263     return d->url;
0264 }
0265 
0266 DiscType MediaSource::discType() const
0267 {
0268     return d->discType;
0269 }
0270 
0271 const DeviceAccessList& MediaSource::deviceAccessList() const
0272 {
0273 #ifndef PHONON_NO_AUDIOCAPTURE
0274     if (d->audioCaptureDevice.isValid())
0275         return d->audioDeviceAccessList;
0276 #endif
0277 
0278 #ifndef PHONON_NO_VIDEOCAPTURE
0279     if (d->videoCaptureDevice.isValid())
0280         return d->videoDeviceAccessList;
0281 #endif
0282 
0283     return d->audioDeviceAccessList;    // It should be invalid
0284 }
0285 
0286 const DeviceAccessList& MediaSource::audioDeviceAccessList() const
0287 {
0288     return d->audioDeviceAccessList;
0289 }
0290 
0291 const DeviceAccessList& MediaSource::videoDeviceAccessList() const
0292 {
0293     return d->videoDeviceAccessList;
0294 }
0295 
0296 QString MediaSource::deviceName() const
0297 {
0298     return d->deviceName;
0299 }
0300 
0301 #ifndef QT_NO_PHONON_ABSTRACTMEDIASTREAM
0302 AbstractMediaStream *MediaSource::stream() const
0303 {
0304     return d->stream;
0305 }
0306 
0307 void MediaSourcePrivate::setStream(AbstractMediaStream *s)
0308 {
0309     stream = s;
0310 }
0311 #endif //QT_NO_PHONON_ABSTRACTMEDIASTREAM
0312 
0313 #ifndef PHONON_NO_AUDIOCAPTURE
0314 AudioCaptureDevice MediaSource::audioCaptureDevice() const
0315 {
0316     return d->audioCaptureDevice;
0317 }
0318 #endif //PHONON_NO_AUDIOCAPTURE
0319 
0320 #ifndef PHONON_NO_VIDEOCAPTURE
0321 VideoCaptureDevice MediaSource::videoCaptureDevice() const
0322 {
0323     return d->videoCaptureDevice;
0324 }
0325 #endif //PHONON_NO_VIDEOCAPTURE
0326 
0327 #if !defined(PHONON_NO_VIDEOCAPTURE) && !defined(PHONON_NO_AUDIOCAPTURE)
0328 void MediaSourcePrivate::setCaptureDevice(Capture::DeviceType deviceType, CaptureCategory category)
0329 {
0330     switch (deviceType) {
0331         case Capture::VideoType: {
0332             setCaptureDevices(AudioCaptureDevice(),
0333                 VideoCaptureDevice::fromIndex(GlobalConfig().videoCaptureDeviceFor(category)));
0334             break;
0335         }
0336         case Capture::AudioType: {
0337             setCaptureDevices(
0338                 AudioCaptureDevice::fromIndex(GlobalConfig().audioCaptureDeviceFor(category)), VideoCaptureDevice());
0339             break;
0340         }
0341     }
0342 }
0343 
0344 void MediaSourcePrivate::setCaptureDevices(CaptureCategory category)
0345 {
0346     setCaptureDevices(
0347         AudioCaptureDevice::fromIndex(GlobalConfig().audioCaptureDeviceFor(category)),
0348         VideoCaptureDevice::fromIndex(GlobalConfig().videoCaptureDeviceFor(category)));
0349 }
0350 
0351 void MediaSourcePrivate::setCaptureDevices(const AudioCaptureDevice &audioDevice, const VideoCaptureDevice &videoDevice)
0352 {
0353     audioCaptureDevice = audioDevice;
0354     videoCaptureDevice = videoDevice;
0355 
0356     if (audioDevice.propertyNames().contains("deviceAccessList") &&
0357             !audioDevice.property("deviceAccessList").value<DeviceAccessList>().isEmpty()) {
0358         audioDeviceAccessList = audioDevice.property("deviceAccessList").value<DeviceAccessList>();
0359     }
0360 
0361     if (videoDevice.propertyNames().contains("deviceAccessList") &&
0362             !videoDevice.property("deviceAccessList").value<DeviceAccessList>().isEmpty()) {
0363         videoDeviceAccessList = videoDevice.property("deviceAccessList").value<DeviceAccessList>();
0364     }
0365 
0366     bool validAudio = !audioDeviceAccessList.isEmpty();
0367     bool validVideo = !videoDeviceAccessList.isEmpty();
0368     type = MediaSource::Invalid;
0369     if (validAudio && validVideo)
0370         type = MediaSource::AudioVideoCapture;
0371     else if (validAudio || validVideo)
0372         type = MediaSource::CaptureDevice;
0373 }
0374 #endif // !PHONON_NO_VIDEOCAPTURE && !PHONON_NO_AUDIOCAPTURE
0375 
0376 QDebug operator <<(QDebug dbg, const Phonon::MediaSource &source)
0377 {
0378     switch (source.type()) {
0379     case MediaSource::Invalid:
0380         dbg.nospace() << "Invalid()";
0381         break;
0382     case MediaSource::LocalFile:
0383         dbg.nospace() << "LocalFile(" << source.url() << ")";
0384         break;
0385     case MediaSource::Url:
0386         dbg.nospace() << "Url(" << source.url() << ")";
0387         break;
0388     case MediaSource::Disc:
0389         dbg.nospace() << "Disc(";
0390         switch (source.discType()) {
0391         case NoDisc:
0392             dbg.nospace() << "NoDisc";
0393             break;
0394         case Cd:
0395             dbg.nospace() << "Cd: " << source.deviceName();
0396             break;
0397         case Dvd:
0398             dbg.nospace() << "Dvd: " << source.deviceName();
0399             break;
0400         case Vcd:
0401             dbg.nospace() << "Vcd: " << source.deviceName();
0402             break;
0403         case BluRay:
0404             dbg.nospace() << "BluRay: " << source.deviceName();
0405             break;
0406         }
0407         dbg.nospace() << ")";
0408         break;
0409     case MediaSource::Stream: {
0410         dbg.nospace() << "Stream(IOAddr: " << source.d->ioDevice;
0411         QObject *qiodevice = qobject_cast<QObject *>(source.d->ioDevice);
0412         if (qiodevice)
0413             dbg.nospace() << " IOClass: " << qiodevice->metaObject()->className();
0414 
0415         dbg.nospace() << "; StreamAddr: " << source.stream();
0416         QObject *qstream = qobject_cast<QObject *>(source.stream());
0417         if (qstream)
0418             dbg.nospace() << " StreamClass: " << qstream->metaObject()->className();
0419 
0420         dbg.nospace() << ")";
0421         break;
0422     }
0423     case MediaSource::CaptureDevice:
0424     case MediaSource::AudioVideoCapture:
0425         dbg.nospace() << "AudioVideoCapture(A:" << source.audioCaptureDevice().name()
0426                       << "/V: " << source.videoCaptureDevice().name() << ")";
0427         break;
0428     case MediaSource::Empty:
0429         dbg.nospace() << "Empty()";
0430         break;
0431     }
0432 
0433     return dbg.maybeSpace();
0434 }
0435 
0436 } // namespace Phonon
0437 
0438 // vim: sw=4 sts=4 et tw=100