diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7395d18..f0b292d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,99 +1,95 @@ if (MSVC OR (WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")) set (CMAKE_MODULE_PATH ${CMAKE_INSTALL_PREFIX}/share/apps/cmake/modules) find_package(KDEWin) if (KDEWIN_FOUND) include_directories(${KDEWIN_INCLUDES}/msvc) link_libraries(${KDEWIN_LIBRARIES}) else (KDEWIN_FOUND) include(CheckIncludeFileCXX) check_include_file_cxx(inttypes.h HAVE_INTTYPES) check_include_file_cxx(stdint.h HAVE_STDINT) if ( NOT HAVE_STDINT AND NOT HAVE_INTTYPES ) message (FATAL_ERROR "You don't have stdint.h and inttypes.h\n\t get them from http://code.google.com/p/baseutils/source/browse/#svn/trunk/msvc,\n\t or get kdewin http://websvn.kde.org/trunk/kdesupport/kdewin/") endif ( NOT HAVE_STDINT AND NOT HAVE_INTTYPES ) endif (KDEWIN_FOUND) endif (MSVC OR (WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")) # NB: This is evaluated in the build system because the phonon headers # change behavior based on the defines, meaning the defines must already be set # by the time the headers are pre-processed! if(${PHONON_VERSION} VERSION_GREATER "4.9.50") message(STATUS "Building against Phonon 4.10 API") set(BACKEND_VERSION_DEFINE -DPHONON_BACKEND_VERSION_4_10) # Older not supported because backend doesn't build with older cmake rigging anwyay. endif() add_definitions(${BACKEND_VERSION_DEFINE}) # also automatically used for moc set(phonon_vlc_SRCS audio/audiooutput.cpp audio/audiodataoutput.cpp audio/volumefadereffect.cpp backend.cpp devicemanager.cpp effect.cpp effectmanager.cpp media.cpp mediacontroller.cpp mediaobject.cpp mediaplayer.cpp sinknode.cpp streamreader.cpp # video/videodataoutput.cpp video/videowidget.cpp video/videomemorystream.cpp utils/debug.cpp utils/libvlc.cpp ) if(NOT ${LIBVLC_VERSION} VERSION_LESS "2.2.0") list(APPEND phonon_vlc_SRCS equalizereffect.cpp) endif() -if(NOT PHONON_NO_GRAPHICSVIEW) - list(APPEND phonon_vlc_SRCS video/videographicsobject.cpp) -endif() - if(PHONON_EXPERIMENTAL) list(APPEND phonon_vlc_SRCS video/videodataoutput.cpp) endif() if(APPLE) list(APPEND phonon_vlc_SRCS video/mac/nsvideoview.mm video/mac/vlcmacwidget.mm) endif() ecm_create_qm_loader(phonon_vlc_SRCS phonon_vlc_qt) add_library(phonon_vlc MODULE ${phonon_vlc_SRCS}) target_include_directories(phonon_vlc PRIVATE # Extra include. We use some internal stuff for easy chroma conversion. ${LIBVLC_INCLUDE_DIR}/vlc/plugins ) target_link_libraries(phonon_vlc Phonon::phonon4qt5 Qt5::Core Qt5::Widgets LibVLC::Core LibVLC::LibVLC ) if(PHONON_EXPERIMENTAL) target_link_libraries(phonon_vlc Phonon::phonon4qt5experimental) endif() install(TARGETS phonon_vlc DESTINATION ${PHONON_BACKEND_DIR}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h @ONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/utils/mime.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/utils/mime.h @ONLY) # Instead of desktop files we are embedding the information into the plugin itself. # We have no KDE technology to help with finding the actual libraries anyway, so # we need to have the library path anyway. # Also see qtplugin/Q_PLUGIN_METADATA documentation. configure_file(${CMAKE_CURRENT_SOURCE_DIR}/phonon-vlc.json.in ${CMAKE_CURRENT_BINARY_DIR}/phonon-vlc.json @ONLY) diff --git a/src/backend.cpp b/src/backend.cpp index 94df7d2..75e91c4 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -1,376 +1,371 @@ /* Copyright (C) 2007-2008 Tanguy Krotoff Copyright (C) 2008 Lukas Durfina Copyright (C) 2009 Fathi Boudra Copyright (C) 2009-2011 vlc-phonon AUTHORS Copyright (C) 2011-2013 Harald Sitter This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "backend.h" #include #include #include #include #include #include #include #include #include #include "audio/audiooutput.h" #include "audio/audiodataoutput.h" #include "audio/volumefadereffect.h" #include "config.h" #include "devicemanager.h" #include "effect.h" #include "effectmanager.h" #include "mediaobject.h" #include "sinknode.h" #include "utils/debug.h" #include "utils/libvlc.h" #include "utils/mime.h" #ifdef PHONON_EXPERIMENTAL #include "video/videodataoutput.h" #endif -#ifndef PHONON_NO_GRAPHICSVIEW -#include "video/videographicsobject.h" -#endif #include "video/videowidget.h" #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) Q_EXPORT_PLUGIN2(phonon_vlc, Phonon::VLC::Backend) #endif namespace Phonon { namespace VLC { Backend *Backend::self; Backend::Backend(QObject *parent, const QVariantList &) : QObject(parent) , m_deviceManager(0) , m_effectManager(0) { self = this; // Backend information properties setProperty("identifier", QLatin1String("phonon_vlc")); setProperty("backendName", QLatin1String("VLC")); setProperty("backendComment", QLatin1String("VLC backend for Phonon")); setProperty("backendVersion", QLatin1String(PHONON_VLC_VERSION)); setProperty("backendIcon", QLatin1String("vlc")); setProperty("backendWebsite", QLatin1String("https://projects.kde.org/projects/kdesupport/phonon/phonon-vlc")); // Check if we should enable debug output int debugLevel = qgetenv("PHONON_BACKEND_DEBUG").toInt(); if (debugLevel > 3) // 3 is maximum debugLevel = 3; Debug::setMinimumDebugLevel((Debug::DebugLevel)((int) Debug::DEBUG_NONE - 1 - debugLevel)); debug() << "Constructing Phonon-VLC Version" << PHONON_VLC_VERSION; // Actual libVLC initialisation if (LibVLC::init()) { debug() << "Using VLC version" << libvlc_get_version(); if (!qApp->applicationName().isEmpty()) { QString userAgent = QString("%0/%1 (Phonon/%2; Phonon-VLC/%3)").arg( qApp->applicationName(), qApp->applicationVersion(), PHONON_VERSION_STR, PHONON_VLC_VERSION); libvlc_set_user_agent(pvlc_libvlc, qApp->applicationName().toUtf8().constData(), userAgent.toUtf8().constData()); } else { qWarning("WARNING: Setting the user agent for streaming and" " PulseAudio requires you to set QCoreApplication::applicationName()"); } PulseSupport::getInstance()->enable(true); const bool pulseActive = PulseSupport::getInstance()->isActive(); PulseSupport::getInstance()->enable(false); if (!qApp->applicationName().isEmpty()) { const QString id = QString("org.kde.phonon.%1").arg(qApp->applicationName()); const QString version = qApp->applicationVersion(); QString icon; #if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0) if (!qApp->windowIcon().isNull()){ // Try to get the fromTheme() name of the QIcon. icon = qApp->windowIcon().name(); } #endif if (icon.isEmpty()) { // If we failed to get a proper icon name, use the appname instead. icon = qApp->applicationName().toLower(); } libvlc_set_app_id(pvlc_libvlc, id.toUtf8().constData(), version.toUtf8().constData(), icon.toUtf8().constData()); } else if (pulseActive) { qWarning("WARNING: Setting PulseAudio context information requires you" " to set QCoreApplication::applicationName()," " QCoreApplication::applicationVersion() and" " QGuiApplication::windowIcon()."); } } else { #ifdef __GNUC__ #warning TODO - this error message is as useful as a knife at a gun fight #endif QMessageBox msg; msg.setIcon(QMessageBox::Critical); msg.setWindowTitle(tr("LibVLC Failed to Initialize")); msg.setText(tr("Phonon's VLC backend failed to start." "\n\n" "This usually means a problem with your VLC installation," " please report a bug with your distributor.")); msg.setDetailedText(LibVLC::errorMessage()); msg.exec(); fatal() << "Phonon::VLC::vlcInit: Failed to initialize VLC"; } #if (LIBVLC_VERSION_INT < LIBVLC_VERSION(2, 2, 2, 0)) // VLC 2.2 changed the stream creation order around internally which breaks // the Pulseaudio hijacking. Since VLC upstream doesn't feel like giving us // any more property control we now consider this feature unsupported. As // such whatever properties VLC sets will be what pulse knows about us. // Initialise PulseAudio support PulseSupport *pulse = PulseSupport::getInstance(); pulse->enable(true); connect(pulse, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)), SIGNAL(objectDescriptionChanged(ObjectDescriptionType))); #endif m_deviceManager = new DeviceManager(this); m_effectManager = new EffectManager(this); } Backend::~Backend() { if (LibVLC::self) delete LibVLC::self; if (GlobalAudioChannels::self) delete GlobalAudioChannels::self; if (GlobalSubtitles::self) delete GlobalSubtitles::self; PulseSupport::shutdown(); } QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList &args) { if (!LibVLC::self || !pvlc_libvlc) return 0; switch (c) { case MediaObjectClass: return new MediaObject(parent); case AudioOutputClass: return new AudioOutput(parent); #if (LIBVLC_VERSION_INT < LIBVLC_VERSION(2, 0, 0, 0)) // Broken >= 2.0 // https://trac.videolan.org/vlc/ticket/6992 case AudioDataOutputClass: return new AudioDataOutput(parent); #endif #ifdef PHONON_EXPERIMENTAL case VideoDataOutputClass: return new VideoDataOutput(parent); #endif -#ifndef PHONON_NO_GRAPHICSVIEW case VideoGraphicsObjectClass: - return new VideoGraphicsObject(parent); -#endif + return nullptr; // No longer supported case EffectClass: return effectManager()->createEffect(args[0].toInt(), parent); case VideoWidgetClass: return new VideoWidget(qobject_cast(parent)); // case VolumeFaderEffectClass: #ifdef __GNUC__ #warning VFE crashes and has volume bugs ... deactivated // return new VolumeFaderEffect(parent); #endif } warning() << "Backend class" << c << "is not supported by Phonon VLC :("; return 0; } QStringList Backend::availableMimeTypes() const { if (m_supportedMimeTypes.isEmpty()) const_cast(this)->m_supportedMimeTypes = mimeTypeList(); return m_supportedMimeTypes; } QList Backend::objectDescriptionIndexes(ObjectDescriptionType type) const { QList list; switch (type) { case Phonon::AudioChannelType: { list << GlobalAudioChannels::instance()->globalIndexes(); } break; case Phonon::AudioOutputDeviceType: case Phonon::AudioCaptureDeviceType: case Phonon::VideoCaptureDeviceType: { return deviceManager()->deviceIds(type); } break; case Phonon::EffectType: { QList effectList = effectManager()->effects(); for (int eff = 0; eff < effectList.size(); ++eff) { list.append(eff); } } break; case Phonon::SubtitleType: { list << GlobalSubtitles::instance()->globalIndexes(); } break; } return list; } QHash Backend::objectDescriptionProperties(ObjectDescriptionType type, int index) const { QHash ret; switch (type) { case Phonon::AudioChannelType: { const AudioChannelDescription description = GlobalAudioChannels::instance()->fromIndex(index); ret.insert("name", description.name()); ret.insert("description", description.description()); } break; case Phonon::AudioOutputDeviceType: case Phonon::AudioCaptureDeviceType: case Phonon::VideoCaptureDeviceType: { // Index should be unique, even for different categories return deviceManager()->deviceProperties(index); } break; case Phonon::EffectType: { const QList effectList = effectManager()->effects(); if (index >= 0 && index <= effectList.size()) { const EffectInfo &effect = effectList.at(index); ret.insert("name", effect.name()); ret.insert("description", effect.description()); ret.insert("author", effect.author()); } else { Q_ASSERT(1); // Since we use list position as ID, this should not happen } } break; case Phonon::SubtitleType: { const SubtitleDescription description = GlobalSubtitles::instance()->fromIndex(index); ret.insert("name", description.name()); ret.insert("description", description.description()); ret.insert("type", description.property("type")); } break; } return ret; } bool Backend::startConnectionChange(QSet objects) { //FIXME foreach(QObject * object, objects) { debug() << "Object:" << object->metaObject()->className(); } // There is nothing we can do but hope the connection changes will not take too long // so that buffers would underrun // But we should be pretty safe the way xine works by not doing anything here. return true; } bool Backend::connectNodes(QObject *source, QObject *sink) { debug() << "Backend connected" << source->metaObject()->className() << "to" << sink->metaObject()->className(); SinkNode *sinkNode = dynamic_cast(sink); if (sinkNode) { MediaObject *mediaObject = qobject_cast(source); if (mediaObject) { // Connect the SinkNode to a MediaObject sinkNode->connectToMediaObject(mediaObject); return true; } VolumeFaderEffect *effect = qobject_cast(source); if (effect) { sinkNode->connectToMediaObject(effect->mediaObject()); return true; } } warning() << "Linking" << source->metaObject()->className() << "to" << sink->metaObject()->className() << "failed"; return false; } bool Backend::disconnectNodes(QObject *source, QObject *sink) { SinkNode *sinkNode = dynamic_cast(sink); if (sinkNode) { MediaObject *const mediaObject = qobject_cast(source); if (mediaObject) { // Disconnect the SinkNode from a MediaObject sinkNode->disconnectFromMediaObject(mediaObject); return true; } VolumeFaderEffect *const effect = qobject_cast(source); if (effect) { sinkNode->disconnectFromMediaObject(effect->mediaObject()); return true; } } return false; } bool Backend::endConnectionChange(QSet objects) { foreach(QObject *object, objects) { debug() << "Object:" << object->metaObject()->className(); } return true; } DeviceManager *Backend::deviceManager() const { return m_deviceManager; } EffectManager *Backend::effectManager() const { return m_effectManager; } } // namespace VLC } // namespace Phonon diff --git a/src/config.h.cmake b/src/config.h.cmake index 9591bda..9c1f78d 100644 --- a/src/config.h.cmake +++ b/src/config.h.cmake @@ -1,28 +1,27 @@ /* Copyright (C) 2019 Harald Sitter This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #ifndef PHONON_VLC_CONFIG_H #define PHONON_VLC_CONFIG_H // I'd really love to have inline constexpr QStringViews here, I'm unsure what // that requires vis-a-vis compiler support though :( #cmakedefine PHONON_VLC_VERSION "@PHONON_VLC_VERSION@" -#cmakedefine PHONON_NO_GRAPHICSVIEW #cmakedefine PHONON_EXPERIMENTAL #endif // PHONON_VLC_CONFIG_H diff --git a/src/video/videographicsobject.cpp b/src/video/videographicsobject.cpp deleted file mode 100644 index 08304bb..0000000 --- a/src/video/videographicsobject.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/* - Copyright (C) 2011-2012 Harald Sitter - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. If not, see . -*/ - -#include "videographicsobject.h" - -#include - -#include "utils/debug.h" -#include "mediaobject.h" - -namespace Phonon { -namespace VLC { - -VideoGraphicsObject::VideoGraphicsObject(QObject *parent) : - QObject(parent), - m_chosenFormat(VideoFrame::Format_Invalid) -{ - DEBUG_BLOCK; - m_frame.format = VideoFrame::Format_Invalid; -} - -VideoGraphicsObject::~VideoGraphicsObject() -{ - DEBUG_BLOCK; - m_mutex.lock(); -} - -void VideoGraphicsObject::connectToMediaObject(MediaObject *mediaObject) -{ - DEBUG_BLOCK; - SinkNode::connectToMediaObject(mediaObject); - setCallbacks(m_player); -} - -void VideoGraphicsObject::disconnectFromMediaObject(MediaObject *mediaObject) -{ - // Try to prevent callbacks called after this object is being deleted - if (m_mediaObject) { - m_mediaObject->stop(); - } - - unsetCallbacks(m_player); - SinkNode::disconnectFromMediaObject(mediaObject); -} - -void VideoGraphicsObject::lock() -{ - m_mutex.lock(); -} - -bool VideoGraphicsObject::tryLock() -{ - return m_mutex.tryLock(); -} - -void VideoGraphicsObject::unlock() -{ - m_mutex.unlock(); -} - -QList VideoGraphicsObject::offering(QList offers) -{ - // FIXME: impl - return offers; -} - -void VideoGraphicsObject::choose(VideoFrame::Format format) -{ - // FIXME: review - m_chosenFormat = format; -} - -void *VideoGraphicsObject::lockCallback(void **planes) -{ - lock(); - - for (unsigned int i = 0; i < m_frame.planeCount; ++i) { - planes[i] = reinterpret_cast(m_frame.plane[i].data()); - } - - return 0; // There is only one buffer, so no need to identify it. -} - -void VideoGraphicsObject::unlockCallback(void *picture, void *const*planes) -{ - Q_UNUSED(picture); - Q_UNUSED(planes); - unlock(); - // To avoid thread polution do not call frameReady directly, but via the - // event loop. - QMetaObject::invokeMethod(this, "frameReady", Qt::QueuedConnection); -} - -void VideoGraphicsObject::displayCallback(void *picture) -{ - Q_UNUSED(picture); // There is only one buffer. -} - -unsigned int VideoGraphicsObject::formatCallback(char *chroma, - unsigned *width, unsigned *height, - unsigned *pitches, unsigned *lines) -{ - DEBUG_BLOCK; - debug() << "Format:" - << "chroma:" << chroma - << "width:" << *width - << "height:" << *height - << "pitches:" << *pitches - << "lines:" << *lines; - - if (m_chosenFormat == VideoFrame::Format_Invalid) - emit needFormat(); - - Q_ASSERT(m_chosenFormat != VideoFrame::Format_Invalid); - - const vlc_chroma_description_t *chromaDesc = 0; - switch(m_chosenFormat) { - case VideoFrame::Format_RGB32: - m_frame.format = VideoFrame::Format_RGB32; - qstrcpy(chroma, "RV32"); - chromaDesc = vlc_fourcc_GetChromaDescription(VLC_CODEC_RGB32); - break; - case VideoFrame::Format_YV12: - m_frame.format = VideoFrame::Format_YV12; - qstrcpy(chroma, "YV12"); - chromaDesc = vlc_fourcc_GetChromaDescription(VLC_CODEC_YV12); - break; - case VideoFrame::Format_I420: - m_frame.format = VideoFrame::Format_I420; - qstrcpy(chroma, "I420"); - chromaDesc = vlc_fourcc_GetChromaDescription(VLC_CODEC_I420); - break; - } - - Q_ASSERT(chromaDesc); - - m_frame.width = *width; - m_frame.height = *height; - m_frame.planeCount = chromaDesc->plane_count; - - debug() << chroma; - const unsigned int bufferSize = setPitchAndLines(chromaDesc, - *width, *height, - pitches, lines, - (unsigned *) &m_frame.visiblePitch, (unsigned *)&m_frame.visibleLines); - for (unsigned int i = 0; i < m_frame.planeCount; ++i) { - m_frame.pitch[i] = pitches[i]; - m_frame.lines[i] = lines[i]; - m_frame.plane[i].resize(pitches[i] * lines[i]); - } - return bufferSize; -} - -void VideoGraphicsObject::formatCleanUpCallback() -{ - DEBUG_BLOCK; - // To avoid thread polution do not call reset directly but via the event loop. - QMetaObject::invokeMethod(this, "reset", Qt::QueuedConnection); -} - -} // namespace VLC -} // namespace Phonon diff --git a/src/video/videographicsobject.h b/src/video/videographicsobject.h deleted file mode 100644 index d683a24..0000000 --- a/src/video/videographicsobject.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright (C) 2011-2012 Harald Sitter - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library. If not, see . -*/ - -#ifndef PHONON_VLC_VIDEOGRAPHICSOBJECT_H -#define PHONON_VLC_VIDEOGRAPHICSOBJECT_H - -#include -#include - -#include -#include - -#include - -#include "sinknode.h" -#include "videomemorystream.h" - -struct libvlc_media_t; - -namespace Phonon { -namespace VLC { - -class VideoGraphicsObject : public QObject, - public VideoGraphicsObjectInterface, - public SinkNode, - public VideoMemoryStream -{ - Q_OBJECT - Q_INTERFACES(Phonon::VideoGraphicsObjectInterface) -public: - explicit VideoGraphicsObject(QObject *parent = 0); - virtual ~VideoGraphicsObject(); - - virtual void connectToMediaObject(MediaObject *mediaObject); - virtual void disconnectFromMediaObject(MediaObject *mediaObject); - - void lock(); - bool tryLock(); - void unlock(); - - const VideoFrame *frame() const { return &m_frame; } - - Q_INVOKABLE QList offering(QList offers); - Q_INVOKABLE void choose(VideoFrame::Format format); - - virtual void *lockCallback(void **planes); - virtual void unlockCallback(void *picture,void *const *planes); - virtual void displayCallback(void *picture); - - virtual unsigned formatCallback(char *chroma, - unsigned *width, unsigned *height, - unsigned *pitches, - unsigned *lines); - virtual void formatCleanUpCallback(); - -signals: - void frameReady(); - void reset(); - - void needFormat(); - -protected: - QMutex m_mutex; - - Phonon::VideoFrame m_frame; - - Phonon::VideoFrame::Format m_chosenFormat; -}; - -} // namespace VLC -} // namespace Phonon - -#endif // PHONON_VLC_VIDEOGRAPHICSOBJECT_H