diff --git a/mapmap.pro b/mapmap.pro index e59a9f1..001f9e7 100644 --- a/mapmap.pro +++ b/mapmap.pro @@ -6,7 +6,7 @@ TEMPLATE = app VERSION = 0.6.3 TARGET = mapmap -DEFINES += UNICODE QT_THREAD_SUPPORT QT_CORE_LIB QT_GUI_LIB +DEFINES += UNICODE QT_THREAD_SUPPORT QT_CORE_LIB QT_GUI_LIB QT_MESSAGELOGCONTEXT include(src/core/core.pri) include(src/shape/shape.pri) diff --git a/src/app/MainApplication.cpp b/src/app/MainApplication.cpp index 864b178..9444169 100644 --- a/src/app/MainApplication.cpp +++ b/src/app/MainApplication.cpp @@ -27,10 +27,11 @@ MainApplication::MainApplication(int &argc, char *argv[]) : QApplication(argc, argv) { #ifdef Q_OS_WIN32 - // Set GStreamer plugins path on Windows - QString pluginPath = QCoreApplication::applicationDirPath() + "/plugins"; + // Set GStreamer plugins path on Windows + QString pluginPath = QCoreApplication::applicationDirPath() + "/plugin"; - _putenv_s("GST_PLUGIN_PATH", pluginPath.toLocal8Bit()); + if (QDir(pluginPath).exists()) + _putenv_s("GST_PLUGIN_PATH", pluginPath.toLocal8Bit()); // Set settings default format QSettings::setDefaultFormat(QSettings::IniFormat); diff --git a/src/app/MainApplication.h b/src/app/MainApplication.h index b3e5777..6741ab0 100644 --- a/src/app/MainApplication.h +++ b/src/app/MainApplication.h @@ -27,6 +27,7 @@ #include #include "MM.h" #include +#include namespace mmp { diff --git a/src/core/CameraImpl.cpp b/src/core/CameraImpl.cpp new file mode 100644 index 0000000..93dc6ac --- /dev/null +++ b/src/core/CameraImpl.cpp @@ -0,0 +1,76 @@ +/* + * CameraImpl.cpp + * + * (c) 2019 Dame Diongue -- baydamd(@)gmail(.)com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "CameraImpl.h" + +namespace mmp { + +CameraImpl::CameraImpl() : + _camera(nullptr), + _cameraSurface(nullptr) +{ + +} + +CameraImpl::~CameraImpl() +{ + _camera->stop(); + delete _camera; + delete _cameraSurface; +} + +bool CameraImpl::loadMovie(const QString &deviceName) +{ + VideoImpl::loadMovie(deviceName); + + _camera = new QCamera(deviceName.toLocal8Bit()); + + _cameraSurface = new CameraSurface(); + + _camera->setViewfinder(_cameraSurface); + + if (_camera->isAvailable()) + _camera->start(); + + if (_camera->state() == QCamera::ActiveState) + return true; + + if (_camera->error() != QCamera::NoError) + QMessageBox(QMessageBox::Critical, "Camera Error", + "Failed to start: " + _camera->errorString()).exec(); + + return false; +} + +int CameraImpl::getWidth() const +{ + return _cameraSurface->surfaceFormat().frameWidth(); +} + +int CameraImpl::getHeight() const +{ + return _cameraSurface->surfaceFormat().frameHeight(); +} + +const uchar *CameraImpl::getBits() +{ + return _cameraSurface->bits(); +} + +} diff --git a/src/core/CameraImpl.h b/src/core/CameraImpl.h new file mode 100644 index 0000000..b6bca55 --- /dev/null +++ b/src/core/CameraImpl.h @@ -0,0 +1,57 @@ +/* + * CameraImpl.h + * + * (c) 2019 Dame Diongue -- baydamd(@)gmail(.)com + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef CAMERAIMPL_H_ +#define CAMERAIMPL_H_ + +#include "CameraSurface.h" +#include "VideoImpl.h" + +#include +#include + +namespace mmp { + +class CameraImpl : public VideoImpl +{ +public: + CameraImpl(); + ~CameraImpl(); + + bool loadMovie(const QString& deviceName); + bool isLive() { return true; } + + int getWidth() const; + int getHeight() const; + + const uchar* getBits(); + + bool hasBits() const { return _cameraSurface->isActive(); } + + bool bitsHaveChanged() const { return true; } + +private: + QCamera *_camera; + CameraSurface *_cameraSurface; + +}; + +} + +#endif // CAMERAIMPL_H_ diff --git a/src/core/CameraSurface.cpp b/src/core/CameraSurface.cpp new file mode 100644 index 0000000..f62d6f2 --- /dev/null +++ b/src/core/CameraSurface.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "CameraSurface.h" + +#include +#include +#include + +namespace mmp { + +CameraSurface::CameraSurface(QObject *parent) + : QAbstractVideoSurface(parent) +{ +} + +CameraSurface::~CameraSurface() +{ +} + +QList CameraSurface::supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const +{ + + if (handleType == QAbstractVideoBuffer::NoHandle) { + return QList() + << QVideoFrame::Format_ARGB32 + << QVideoFrame::Format_ARGB32_Premultiplied + << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_RGB24 + ; + } else { + return QList(); + } +} + +bool CameraSurface::present(const QVideoFrame &frame) +{ + if (frame.isValid()) { + // Copy current frame. + QVideoFrame currentFrame(frame); + + if (currentFrame.map(QAbstractVideoBuffer::ReadOnly)) + { + QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(currentFrame.pixelFormat()); + if (imageFormat != QImage::Format_Invalid) { + _temporaryImage = QImage(currentFrame.bits(), + currentFrame.width(), + currentFrame.height(), + imageFormat); + } else { + int nbytes = currentFrame.mappedBytes(); + _temporaryImage = QImage::fromData(currentFrame.bits(), nbytes); + } + currentFrame.unmap(); + } + +#ifdef Q_OS_WIN + _temporaryImage = QGLWidget::convertToGLFormat(_temporaryImage); +#else + // Convert to OpenGLformat and apply transforms to straighten. + _temporaryImage = QGLWidget::convertToGLFormat(_temporaryImage) + .mirrored(true, false) + .transformed(QTransform().rotate(180)); +#endif + + return true; + } + + return false; +} + +const uchar* CameraSurface::bits() +{ + return _temporaryImage.bits(); +} + +} diff --git a/src/core/CameraSurface.h b/src/core/CameraSurface.h new file mode 100644 index 0000000..f890723 --- /dev/null +++ b/src/core/CameraSurface.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CAMERA_SURFACE_H_ +#define CAMERA_SURFACE_H_ + +#include +#include +#include +#include + +namespace mmp { + +class CameraSurface : public QAbstractVideoSurface +{ + Q_OBJECT +public: + CameraSurface(QObject *parent = nullptr); + ~CameraSurface() override; + + QList supportedPixelFormats( + QAbstractVideoBuffer::HandleType handleType) const override; + bool present(const QVideoFrame &frame) override; + + const uchar* bits(); + +private: + QImage _temporaryImage; +}; + +} + +#endif // CAMERA_SURFACE_H_ diff --git a/src/core/MM.h b/src/core/MM.h index a28f6b6..7116cd0 100644 --- a/src/core/MM.h +++ b/src/core/MM.h @@ -69,6 +69,9 @@ public: static const int ZOOM_TOOLBAR_ICON_SIZE = 16; static const int ZOOM_TOOLBAR_BUTTON_SIZE = 20; static const int MAPPING_LIST_ICON_SIZE = 16; + static const int MAPPING_LIST_HIDE_COLUMN = 24; + static const int MAPPING_LIST_NAME_COLUMN = 135; + static const int MAPPING_LIST_BUTTONS_COLUMN = 128; // OSC static const int DEFAULT_OSC_PORT = 12345; diff --git a/src/core/Mapping.h b/src/core/Mapping.h index 502d26f..2c1302f 100644 --- a/src/core/Mapping.h +++ b/src/core/Mapping.h @@ -109,7 +109,7 @@ public: } /// The type of the mapping (expressed as a string). - virtual QString getType() const = 0; + virtual MShape::ShapeType getType() const = 0; // Return copy of this mapping. virtual Mapping* clone() const = 0; @@ -189,8 +189,8 @@ public: /// Returns true iff paint is compatible with mapping. virtual bool paintIsCompatible(Paint::ptr paint) const; - virtual QString getType() const { - return getShape()->getType() + "_color"; + virtual MShape::ShapeType getType() const { + return getShape()->getType(); } }; @@ -228,8 +228,8 @@ public: /// Returns true iff paint is compatible with mapping. virtual bool paintIsCompatible(Paint::ptr paint) const; - virtual QString getType() const { - return getShape()->getType() + "_texture"; + virtual MShape::ShapeType getType() const { + return getShape()->getType(); } }; diff --git a/src/core/MappingManager.cpp b/src/core/MappingManager.cpp index f99c9cc..539f490 100644 --- a/src/core/MappingManager.cpp +++ b/src/core/MappingManager.cpp @@ -105,6 +105,7 @@ bool MappingManager::removePaint(uid paintId) Q_ASSERT(idx != -1); paintVector.remove(idx); paintMap.remove(paintId); + paint->~Paint(); // FIX ME: Explicit call of paint destructor in order add Camera more than once return true; } else diff --git a/src/core/Paint.cpp b/src/core/Paint.cpp index 98bc5e6..b3f99bb 100644 --- a/src/core/Paint.cpp +++ b/src/core/Paint.cpp @@ -21,7 +21,7 @@ #include "Paint.h" #include "VideoImpl.h" #include "VideoUriDecodeBinImpl.h" -#include "VideoV4l2SrcImpl.h" +#include "CameraImpl.h" #include "VideoShmSrcImpl.h" #include @@ -188,7 +188,7 @@ void Image::_doPlay() /* Implementation of the Video class */ Video::Video(int id) : Texture(id), _uri(""), - _impl(NULL) + _impl(nullptr) { _impl = new VideoUriDecodeBinImpl(); setRate(1); @@ -198,26 +198,24 @@ Video::Video(int id) : Texture(id), Video::Video(const QString uri_, VideoType type, double rate, uid id): Texture(id), _uri(""), - _impl(NULL) + _videoType(type), + _impl(nullptr) { switch (type) { case VIDEO_URI: _impl = new VideoUriDecodeBinImpl(); break; case VIDEO_WEBCAM: - _impl = new VideoV4l2SrcImpl(); + _impl = new CameraImpl(); break; case VIDEO_SHMSRC: _impl = new VideoShmSrcImpl(); break; - default: - fprintf (stderr, "Could not determine type for video source\n "); - break; } - //_impl = new VideoShmSrcImpl();//V4l2SrcImpl();//UriDecodeBinImpl(); setRate(rate); setVolume(1); setUri(uri_); + _videoType = type; } // vertigo @@ -306,11 +304,11 @@ bool Video::hasVideoSupport() bool Video::setUri(const QString &uri) { QSettings settings; - bool sameMediasource = settings.value("oscSameMediaSource").toBool(); + bool sameMediaSourceOSC = settings.value("oscSameMediaSource").toBool(); // Check if we're actually changing the uri. // In some case with OSC message the user may need to allow // the same media source (uri) - if (sameMediasource || uri != _uri) + if (sameMediaSourceOSC || uri != _uri) { // Try to load movie. if (!_impl->loadMovie(uri)) @@ -330,14 +328,18 @@ bool Video::setUri(const QString &uri) return false; } - if (!_generateThumbnail()) - qDebug() << "Could not generate thumbnail for " << uri << ": using generic icon." << endl; + if (_videoType != VIDEO_WEBCAM) { // Generated thumbnail if source type is not camera + if (!_generateThumbnail()) + qDebug() << "Could not generate thumbnail for " << uri << ": using generic icon." << endl; + } _emitPropertyChanged("uri"); + + // Return success. + return true; } - // Return success. - return true; + return false; } void Video::_doPlay() diff --git a/src/core/Paint.h b/src/core/Paint.h index 217850b..a106640 100644 --- a/src/core/Paint.h +++ b/src/core/Paint.h @@ -38,6 +38,8 @@ #include "Element.h" #include "Maths.h" +#include + namespace mmp { typedef enum { @@ -66,6 +68,11 @@ protected: Paint(uid id=NULL_UID); public: + + enum SourceType { + Video, Image, Color + }; + typedef QSharedPointer ptr; virtual ~Paint(); @@ -99,7 +106,7 @@ public: /// Unlocks mutex (default = no effect). virtual void unlockMutex() {} - virtual QString getType() const = 0; + virtual SourceType getSourceType() const = 0; protected: virtual void _doPlay() {} @@ -125,7 +132,7 @@ public: QColor getColor() const { return color; } void setColor(const QColor& color_) { color = color_; } - virtual QString getType() const { return "color"; } + virtual SourceType getSourceType() const { return SourceType::Color; } virtual QIcon getIcon() const { QPixmap pixmap(MM::MAPPING_LIST_ICON_SIZE, MM::MAPPING_LIST_ICON_SIZE); @@ -202,6 +209,11 @@ public: virtual void read(const QDomElement& obj); virtual void write(QDomElement& obj); + // Get Camera human-readable name from url + QString getCameraNameFromUri(const QString &uri) { + return QCameraInfo(uri.toLocal8Bit()).description(); + } + protected: // Lists QProperties that should NOT be parsed automatically. virtual QList _propertiesSpecial() const { return Paint::_propertiesSpecial() << "x" << "y"; } @@ -246,7 +258,7 @@ public: const QString getUri() const { return _uri; } bool setUri(const QString &uri); - virtual QString getType() const { return "image"; } + virtual SourceType getSourceType() const { return SourceType::Image; } bool isAnimation() const { return (_images.size() > 1); } @@ -312,7 +324,7 @@ public: /// Unlocks mutex (default = no effect). virtual void unlockMutex(); - virtual QString getType() const { return "media"; } + virtual SourceType getSourceType() const { return SourceType::Video; } virtual int getWidth() const; virtual int getHeight() const; @@ -353,6 +365,7 @@ protected: QString _uri; QIcon _icon; + VideoType _videoType; /** * Private implementation, so that GStreamer headers don't need diff --git a/src/core/ProjectReader.cpp b/src/core/ProjectReader.cpp index bffa2b7..96d3fd3 100644 --- a/src/core/ProjectReader.cpp +++ b/src/core/ProjectReader.cpp @@ -101,14 +101,14 @@ void ProjectReader::parseProject(const QDomElement& project) _window->addPaintItem(paint->getId(), paint->getIcon(), paint->getName()); // Locate media file if not found - if (paint->getType() == "media") + if (paint->getSourceType() == Paint::SourceType::Video) { QSharedPointer