diff options
Diffstat (limited to 'src')
64 files changed, 822 insertions, 290 deletions
diff --git a/src/gsttools/gsttools.pro b/src/gsttools/gsttools.pro index edbf603e3..f5e3fd96f 100644 --- a/src/gsttools/gsttools.pro +++ b/src/gsttools/gsttools.pro @@ -1,7 +1,6 @@ -TEMPLATE = lib - -TARGET = qgsttools_p -QPRO_PWD = $$PWD +TARGET = QtMultimediaGstTools +MODULE = multimediagsttools +CONFIG += internal_module QT = core-private multimedia-private gui-private @@ -36,7 +35,8 @@ PRIVATE_HEADERS += \ qgstreamervideoprobecontrol_p.h \ qgstreameraudioprobecontrol_p.h \ qgstreamervideowindow_p.h \ - qgstreamervideooverlay_p.h + qgstreamervideooverlay_p.h \ + qgsttools_global_p.h SOURCES += \ qgstreamerbushelper.cpp \ @@ -101,7 +101,4 @@ qtConfig(gstreamer_app) { HEADERS += $$PRIVATE_HEADERS -DESTDIR = $$QT.multimedia.libs -target.path = $$[QT_INSTALL_LIBS] - -INSTALLS += target +load(qt_module) diff --git a/src/gsttools/qgstcodecsinfo.cpp b/src/gsttools/qgstcodecsinfo.cpp index 230dc581b..a05ee92aa 100644 --- a/src/gsttools/qgstcodecsinfo.cpp +++ b/src/gsttools/qgstcodecsinfo.cpp @@ -156,7 +156,7 @@ void QGstCodecsInfo::updateCodecs(ElementType elementType) GstRank rank = GstRank(gst_plugin_feature_get_rank(GST_PLUGIN_FEATURE(factory))); // If two elements provide the same codec, use the highest ranked one - QMap<QString, CodecInfo>::const_iterator it = m_codecInfo.find(codec); + QMap<QString, CodecInfo>::const_iterator it = m_codecInfo.constFind(codec); if (it == m_codecInfo.constEnd() || it->rank < rank) { if (it == m_codecInfo.constEnd()) m_codecs.append(codec); diff --git a/src/gsttools/qgstreameraudioinputselector.cpp b/src/gsttools/qgstreameraudioinputselector.cpp index 6d74feb1b..72d079cbc 100644 --- a/src/gsttools/qgstreameraudioinputselector.cpp +++ b/src/gsttools/qgstreameraudioinputselector.cpp @@ -104,7 +104,7 @@ void QGstreamerAudioInputSelector::update() m_descriptions.clear(); //use autoaudiosrc as the first default device - m_names.append("default:"); + m_names.append(QLatin1String("default:")); m_descriptions.append(tr("System default device")); updatePulseDevices(); @@ -150,12 +150,12 @@ void QGstreamerAudioInputSelector::updateAlsaDevices() void QGstreamerAudioInputSelector::updateOssDevices() { - QDir devDir("/dev"); + QDir devDir(QStringLiteral("/dev")); devDir.setFilter(QDir::System); - const QFileInfoList entries = devDir.entryInfoList(QStringList() << "dsp*"); + const QFileInfoList entries = devDir.entryInfoList(QStringList() << QLatin1String("dsp*")); for (const QFileInfo& entryInfo : entries) { m_names.append(QLatin1String("oss:")+entryInfo.filePath()); - m_descriptions.append(QString("OSS device %1").arg(entryInfo.fileName())); + m_descriptions.append(QString::fromLatin1("OSS device %1").arg(entryInfo.fileName())); } } @@ -163,8 +163,8 @@ void QGstreamerAudioInputSelector::updatePulseDevices() { GstElementFactory *factory = gst_element_factory_find("pulsesrc"); if (factory) { - m_names.append("pulseaudio:"); - m_descriptions.append("PulseAudio device."); + m_names.append(QLatin1String("pulseaudio:")); + m_descriptions.append(QLatin1String("PulseAudio device.")); gst_object_unref(GST_OBJECT(factory)); } } diff --git a/src/gsttools/qgstutils.cpp b/src/gsttools/qgstutils.cpp index 06181403e..6a573fa78 100644 --- a/src/gsttools/qgstutils.cpp +++ b/src/gsttools/qgstutils.cpp @@ -471,16 +471,16 @@ void QGstUtils::initializeGst() namespace { const char* getCodecAlias(const QString &codec) { - if (codec.startsWith("avc1.")) + if (codec.startsWith(QLatin1String("avc1."))) return "video/x-h264"; - if (codec.startsWith("mp4a.")) + if (codec.startsWith(QLatin1String("mp4a."))) return "audio/mpeg4"; - if (codec.startsWith("mp4v.20.")) + if (codec.startsWith(QLatin1String("mp4v.20."))) return "video/mpeg4"; - if (codec == "samr") + if (codec == QLatin1String("samr")) return "audio/amr"; return 0; @@ -488,14 +488,14 @@ namespace { const char* getMimeTypeAlias(const QString &mimeType) { - if (mimeType == "video/mp4") + if (mimeType == QLatin1String("video/mp4")) return "video/mpeg4"; - if (mimeType == "audio/mp4") + if (mimeType == QLatin1String("audio/mp4")) return "audio/mpeg4"; - if (mimeType == "video/ogg" - || mimeType == "audio/ogg") + if (mimeType == QLatin1String("video/ogg") + || mimeType == QLatin1String("audio/ogg")) return "application/ogg"; return 0; @@ -513,12 +513,12 @@ QMultimedia::SupportEstimate QGstUtils::hasSupport(const QString &mimeType, bool containsMimeType = supportedMimeTypeSet.contains(mimeTypeLowcase); if (!containsMimeType) { const char* mimeTypeAlias = getMimeTypeAlias(mimeTypeLowcase); - containsMimeType = supportedMimeTypeSet.contains(mimeTypeAlias); + containsMimeType = supportedMimeTypeSet.contains(QLatin1String(mimeTypeAlias)); if (!containsMimeType) { - containsMimeType = supportedMimeTypeSet.contains("video/" + mimeTypeLowcase) - || supportedMimeTypeSet.contains("video/x-" + mimeTypeLowcase) - || supportedMimeTypeSet.contains("audio/" + mimeTypeLowcase) - || supportedMimeTypeSet.contains("audio/x-" + mimeTypeLowcase); + containsMimeType = supportedMimeTypeSet.contains(QLatin1String("video/") + mimeTypeLowcase) + || supportedMimeTypeSet.contains(QLatin1String("video/x-") + mimeTypeLowcase) + || supportedMimeTypeSet.contains(QLatin1String("audio/") + mimeTypeLowcase) + || supportedMimeTypeSet.contains(QLatin1String("audio/x-") + mimeTypeLowcase); } } @@ -527,12 +527,12 @@ QMultimedia::SupportEstimate QGstUtils::hasSupport(const QString &mimeType, QString codecLowcase = codec.toLower(); const char* codecAlias = getCodecAlias(codecLowcase); if (codecAlias) { - if (supportedMimeTypeSet.contains(codecAlias)) + if (supportedMimeTypeSet.contains(QLatin1String(codecAlias))) supportedCodecCount++; - } else if (supportedMimeTypeSet.contains("video/" + codecLowcase) - || supportedMimeTypeSet.contains("video/x-" + codecLowcase) - || supportedMimeTypeSet.contains("audio/" + codecLowcase) - || supportedMimeTypeSet.contains("audio/x-" + codecLowcase)) { + } else if (supportedMimeTypeSet.contains(QLatin1String("video/") + codecLowcase) + || supportedMimeTypeSet.contains(QLatin1String("video/x-") + codecLowcase) + || supportedMimeTypeSet.contains(QLatin1String("audio/") + codecLowcase) + || supportedMimeTypeSet.contains(QLatin1String("audio/x-") + codecLowcase)) { supportedCodecCount++; } } @@ -769,8 +769,8 @@ QSet<QString> QGstUtils::supportedMimeTypes(bool (*isValidFactory)(GstElementFac GstElementFactory *factory; if (GST_IS_TYPE_FIND_FACTORY(feature)) { - QString name(gst_plugin_feature_get_name(feature)); - if (name.contains('/')) //filter out any string without '/' which is obviously not a mime type + QString name(QLatin1String(gst_plugin_feature_get_name(feature))); + if (name.contains(QLatin1Char('/'))) //filter out any string without '/' which is obviously not a mime type supportedMimeTypes.insert(name.toLower()); continue; } else if (!GST_IS_ELEMENT_FACTORY (feature) @@ -788,18 +788,18 @@ QSet<QString> QGstUtils::supportedMimeTypes(bool (*isValidFactory)(GstElementFac if (gst_caps_is_any(caps) || gst_caps_is_empty(caps)) { } else for (guint i = 0; i < gst_caps_get_size(caps); i++) { GstStructure *structure = gst_caps_get_structure(caps, i); - QString nameLowcase = QString(gst_structure_get_name(structure)).toLower(); + QString nameLowcase = QString::fromLatin1(gst_structure_get_name(structure)).toLower(); supportedMimeTypes.insert(nameLowcase); - if (nameLowcase.contains("mpeg")) { + if (nameLowcase.contains(QLatin1String("mpeg"))) { //Because mpeg version number is only included in the detail //description, it is necessary to manually extract this information //in order to match the mime type of mpeg4. const GValue *value = gst_structure_get_value(structure, "mpegversion"); if (value) { gchar *str = gst_value_serialize(value); - QString versions(str); - const QStringList elements = versions.split(QRegExp("\\D+"), QString::SkipEmptyParts); + QString versions = QLatin1String(str); + const QStringList elements = versions.split(QRegExp(QLatin1String("\\D+")), QString::SkipEmptyParts); for (const QString &e : elements) supportedMimeTypes.insert(nameLowcase + e); g_free(str); @@ -1239,7 +1239,7 @@ void QGstUtils::setMetaData(GstElement *element, const QMap<QByteArray, QVariant QMapIterator<QByteArray, QVariant> it(data); while (it.hasNext()) { it.next(); - const QString tagName = it.key(); + const QString tagName = QString::fromLatin1(it.key()); const QVariant tagValue = it.value(); switch (tagValue.type()) { @@ -1439,26 +1439,26 @@ QString QGstUtils::fileExtensionForMimeType(const QString &mimeType) { if (fileExtensionMap->isEmpty()) { //extension for containers hard to guess from mimetype - fileExtensionMap->insert("video/x-matroska", "mkv"); - fileExtensionMap->insert("video/quicktime", "mov"); - fileExtensionMap->insert("video/x-msvideo", "avi"); - fileExtensionMap->insert("video/msvideo", "avi"); - fileExtensionMap->insert("audio/mpeg", "mp3"); - fileExtensionMap->insert("application/x-shockwave-flash", "swf"); - fileExtensionMap->insert("application/x-pn-realmedia", "rm"); + fileExtensionMap->insert(QStringLiteral("video/x-matroska"), QLatin1String("mkv")); + fileExtensionMap->insert(QStringLiteral("video/quicktime"), QLatin1String("mov")); + fileExtensionMap->insert(QStringLiteral("video/x-msvideo"), QLatin1String("avi")); + fileExtensionMap->insert(QStringLiteral("video/msvideo"), QLatin1String("avi")); + fileExtensionMap->insert(QStringLiteral("audio/mpeg"), QLatin1String("mp3")); + fileExtensionMap->insert(QStringLiteral("application/x-shockwave-flash"), QLatin1String("swf")); + fileExtensionMap->insert(QStringLiteral("application/x-pn-realmedia"), QLatin1String("rm")); } //for container names like avi instead of video/x-msvideo, use it as extension - if (!mimeType.contains('/')) + if (!mimeType.contains(QLatin1Char('/'))) return mimeType; - QString format = mimeType.left(mimeType.indexOf(',')); + QString format = mimeType.left(mimeType.indexOf(QLatin1Char(','))); QString extension = fileExtensionMap->value(format); if (!extension.isEmpty() || format.isEmpty()) return extension; - QRegExp rx("[-/]([\\w]+)$"); + QRegExp rx(QStringLiteral("[-/]([\\w]+)$")); if (rx.indexIn(format) != -1) extension = rx.cap(1); diff --git a/src/imports/audioengine/qdeclarative_playvariation_p.cpp b/src/imports/audioengine/qdeclarative_playvariation_p.cpp index 36ffca668..e6d3697d0 100644 --- a/src/imports/audioengine/qdeclarative_playvariation_p.cpp +++ b/src/imports/audioengine/qdeclarative_playvariation_p.cpp @@ -41,6 +41,7 @@ #include "qdeclarative_audioengine_p.h" #include "qsoundinstance_p.h" #include "qdebug.h" +#include "qrandom.h" #define DEBUG_AUDIOENGINE @@ -272,7 +273,7 @@ void QDeclarativePlayVariation::setSampleObject(QDeclarativeAudioSample *sampleO void QDeclarativePlayVariation::applyParameters(QSoundInstance *soundInstance) { - qreal pitch = qreal(qrand() % 1001) * 0.001f * (m_maxPitch - m_minPitch) + m_minPitch; - qreal gain = qreal(qrand() % 1001) * 0.001f * (m_maxGain - m_minGain) + m_minGain; + qreal pitch = QRandomGenerator::global()->bounded(1001 * 0.001f) * (m_maxPitch - m_minPitch) + m_minPitch; + qreal gain = QRandomGenerator::global()->bounded(1001 * 0.001f) * (m_maxGain - m_minGain) + m_minGain; soundInstance->updateVariationParameters(pitch, gain, m_looping); } diff --git a/src/imports/audioengine/qdeclarative_sound_p.cpp b/src/imports/audioengine/qdeclarative_sound_p.cpp index 0849215be..a11490cea 100644 --- a/src/imports/audioengine/qdeclarative_sound_p.cpp +++ b/src/imports/audioengine/qdeclarative_sound_p.cpp @@ -43,6 +43,7 @@ #include "qdeclarative_soundinstance_p.h" #include "qdeclarative_audioengine_p.h" #include "qdebug.h" +#include "qrandom.h" #define DEBUG_AUDIOENGINE @@ -316,7 +317,7 @@ int QDeclarativeSound::genVariationIndex(int oldVariationIndex) case QDeclarativeSound::Random: { if (oldVariationIndex < 0) oldVariationIndex = 0; - return (oldVariationIndex + (qrand() % (m_playlist.count() + 1))) % m_playlist.count(); + return (oldVariationIndex + (QRandomGenerator::global()->bounded(m_playlist.count() + 1))) % m_playlist.count(); } default: return (oldVariationIndex + 1) % m_playlist.count(); diff --git a/src/multimedia/audio/qaudio.cpp b/src/multimedia/audio/qaudio.cpp index d4f89e898..dea9a05a5 100644 --- a/src/multimedia/audio/qaudio.cpp +++ b/src/multimedia/audio/qaudio.cpp @@ -79,13 +79,18 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterAudioMetaTypes) /*! \enum QAudio::State - \value ActiveState Audio data is being processed, this state is set after start() is called - and while audio data is available to be processed. - \value SuspendedState The audio device is in a suspended state, this state will only be entered - after suspend() is called. - \value StoppedState The audio device is closed, and is not processing any audio data - \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state - is set after start() is called and while no audio data is available to be processed. + \value ActiveState Audio data is being processed, this state is set after start() is called + and while audio data is available to be processed. + \value SuspendedState The audio stream is in a suspended state. Entered after suspend() is called + or when another stream takes control of the audio device. In the later case, + a call to resume will return control of the audio device to this stream. This + should usually only be done upon user request. + \value StoppedState The audio device is closed, and is not processing any audio data + \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state + is set after start() is called and while no audio data is available to be processed. + \value InterruptedState This stream is in a suspended state because another higher priority stream currently + has control of the audio device. Playback cannot resume until the higher priority + stream relinquishes control of the audio device. */ /*! @@ -285,6 +290,9 @@ QDebug operator<<(QDebug dbg, QAudio::State state) case QAudio::IdleState: dbg << "IdleState"; break; + case QAudio::InterruptedState: + dbg << "InterruptedState"; + break; } return dbg; } diff --git a/src/multimedia/audio/qaudio.h b/src/multimedia/audio/qaudio.h index 1c38e9f35..2603d71d1 100644 --- a/src/multimedia/audio/qaudio.h +++ b/src/multimedia/audio/qaudio.h @@ -55,7 +55,7 @@ class QString; namespace QAudio { enum Error { NoError, OpenError, IOError, UnderrunError, FatalError }; - enum State { ActiveState, SuspendedState, StoppedState, IdleState }; + enum State { ActiveState, SuspendedState, StoppedState, IdleState, InterruptedState }; enum Mode { AudioInput, AudioOutput }; enum Role { diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.cpp b/src/multimedia/audio/qsoundeffect_pulse_p.cpp index 1e9204598..bf647ea1f 100644 --- a/src/multimedia/audio/qsoundeffect_pulse_p.cpp +++ b/src/multimedia/audio/qsoundeffect_pulse_p.cpp @@ -73,20 +73,23 @@ inline pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format) spec.rate = format.sampleRate(); spec.channels = format.channelCount(); - - if (format.sampleSize() == 8) - spec.format = PA_SAMPLE_U8; - else if (format.sampleSize() == 16) { - switch (format.byteOrder()) { - case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S16BE; break; - case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S16LE; break; - } - } - else if (format.sampleSize() == 32) { - switch (format.byteOrder()) { - case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S32BE; break; - case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S32LE; break; + spec.format = PA_SAMPLE_INVALID; + const bool isBigEndian = (format.byteOrder() == QAudioFormat::BigEndian); + + if (format.sampleType() == QAudioFormat::UnSignedInt) { + if (format.sampleSize() == 8) + spec.format = PA_SAMPLE_U8; + } else if (format.sampleType() == QAudioFormat::SignedInt) { + if (format.sampleSize() == 16) { + spec.format = isBigEndian ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; + } else if (format.sampleSize() == 24) { + spec.format = isBigEndian ? PA_SAMPLE_S24BE : PA_SAMPLE_S24LE; + } else if (format.sampleSize() == 32) { + spec.format = isBigEndian ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE; } + } else if (format.sampleType() == QAudioFormat::Float) { + if (format.sampleSize() == 32) + spec.format = isBigEndian ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE; } return spec; @@ -190,7 +193,11 @@ private Q_SLOTS: pa_context_set_state_callback(m_context, context_state_callback, this); - if (pa_context_connect(m_context, 0, (pa_context_flags_t)0, 0) < 0) { + const QByteArray srvStrEnv = qgetenv("QT_PULSE_SERVER_STRING"); + const char *srvStr = srvStrEnv.isNull() ? 0 : srvStrEnv.constData(); + pa_context_flags_t flags = qEnvironmentVariableIsSet("QT_PULSE_NOAUTOSPAWN") ? PA_CONTEXT_NOAUTOSPAWN : (pa_context_flags_t)0; + + if (pa_context_connect(m_context, srvStr, flags, 0) < 0) { qWarning("PulseAudioService: pa_context_connect() failed"); pa_context_unref(m_context); unlock(); diff --git a/src/multimedia/camera/qcamera.h b/src/multimedia/camera/qcamera.h index 685298905..aebd1c013 100644 --- a/src/multimedia/camera/qcamera.h +++ b/src/multimedia/camera/qcamera.h @@ -262,7 +262,10 @@ QT_WARNING_DISABLE_CLANG("-Wfloat-equal") QT_WARNING_DISABLE_GCC("-Wfloat-equal") Q_DECL_CONSTEXPR Q_INLINE_TEMPLATE bool operator==(const QCamera::FrameRateRange &r1, const QCamera::FrameRateRange &r2) Q_DECL_NOTHROW -{ return r1.minimumFrameRate == r2.minimumFrameRate && r1.maximumFrameRate == r2.maximumFrameRate; } +{ + return qFuzzyCompare(r1.minimumFrameRate, r2.minimumFrameRate) + && qFuzzyCompare(r1.maximumFrameRate, r2.maximumFrameRate); +} QT_WARNING_POP diff --git a/src/multimedia/doc/qtmultimedia.qdocconf b/src/multimedia/doc/qtmultimedia.qdocconf index e3d3827c5..074fcb75e 100644 --- a/src/multimedia/doc/qtmultimedia.qdocconf +++ b/src/multimedia/doc/qtmultimedia.qdocconf @@ -43,6 +43,9 @@ qhp.QtMultimedia.subprojects.examples.sortPages = true exampledirs += ../../../examples \ snippets +manifestmeta.highlighted.names = "QtMultimedia/QML Video Shader Effects Example" \ + "QtMultimedia/Media Player Example" + headerdirs += ../.. imagedirs += src/images \ diff --git a/src/multimedia/gsttools_headers/gstvideoconnector_p.h b/src/multimedia/gsttools_headers/gstvideoconnector_p.h index 4fa1456c8..a38ca2e65 100644 --- a/src/multimedia/gsttools_headers/gstvideoconnector_p.h +++ b/src/multimedia/gsttools_headers/gstvideoconnector_p.h @@ -51,6 +51,8 @@ // We mean it. // +#include <private/qgsttools_global_p.h> + #include <gst/gst.h> G_BEGIN_DECLS @@ -69,7 +71,7 @@ G_BEGIN_DECLS typedef struct _GstVideoConnector GstVideoConnector; typedef struct _GstVideoConnectorClass GstVideoConnectorClass; -struct _GstVideoConnector { +struct Q_GSTTOOLS_EXPORT _GstVideoConnector { GstElement element; GstPad *srcpad; @@ -81,14 +83,14 @@ struct _GstVideoConnector { GstBuffer *latest_buffer; }; -struct _GstVideoConnectorClass { +struct Q_GSTTOOLS_EXPORT _GstVideoConnectorClass { GstElementClass parent_class; /* action signal to resend new segment */ void (*resend_new_segment) (GstElement * element, gboolean emitFailedSignal); }; -GType gst_video_connector_get_type (void); +GType Q_GSTTOOLS_EXPORT gst_video_connector_get_type (void); G_END_DECLS diff --git a/src/multimedia/gsttools_headers/qgstappsrc_p.h b/src/multimedia/gsttools_headers/qgstappsrc_p.h index e50915231..c7e87037d 100644 --- a/src/multimedia/gsttools_headers/qgstappsrc_p.h +++ b/src/multimedia/gsttools_headers/qgstappsrc_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <QtCore/qobject.h> #include <QtCore/qiodevice.h> @@ -63,7 +64,7 @@ QT_BEGIN_NAMESPACE -class QGstAppSrc : public QObject +class Q_GSTTOOLS_EXPORT QGstAppSrc : public QObject { Q_OBJECT public: diff --git a/src/multimedia/gsttools_headers/qgstbufferpoolinterface_p.h b/src/multimedia/gsttools_headers/qgstbufferpoolinterface_p.h index e03da1ab5..45e573262 100644 --- a/src/multimedia/gsttools_headers/qgstbufferpoolinterface_p.h +++ b/src/multimedia/gsttools_headers/qgstbufferpoolinterface_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <qabstractvideobuffer.h> #include <qvideosurfaceformat.h> #include <QtCore/qobject.h> @@ -65,7 +66,7 @@ const QLatin1String QGstBufferPoolPluginKey("bufferpool"); /*! Abstract interface for video buffers allocation. */ -class QGstBufferPoolInterface +class Q_GSTTOOLS_EXPORT QGstBufferPoolInterface { public: virtual ~QGstBufferPoolInterface() {} diff --git a/src/multimedia/gsttools_headers/qgstcodecsinfo_p.h b/src/multimedia/gsttools_headers/qgstcodecsinfo_p.h index af1a4486f..33ab3de4b 100644 --- a/src/multimedia/gsttools_headers/qgstcodecsinfo_p.h +++ b/src/multimedia/gsttools_headers/qgstcodecsinfo_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <QtCore/qmap.h> #include <QtCore/qstringlist.h> @@ -58,7 +59,7 @@ QT_BEGIN_NAMESPACE -class QGstCodecsInfo +class Q_GSTTOOLS_EXPORT QGstCodecsInfo { public: enum ElementType { AudioEncoder, VideoEncoder, Muxer }; diff --git a/src/multimedia/gsttools_headers/qgstreameraudioinputselector_p.h b/src/multimedia/gsttools_headers/qgstreameraudioinputselector_p.h index 1a961c6d9..0c193fda9 100644 --- a/src/multimedia/gsttools_headers/qgstreameraudioinputselector_p.h +++ b/src/multimedia/gsttools_headers/qgstreameraudioinputselector_p.h @@ -51,12 +51,13 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <qaudioinputselectorcontrol.h> #include <QtCore/qstringlist.h> QT_BEGIN_NAMESPACE -class QGstreamerAudioInputSelector : public QAudioInputSelectorControl +class Q_GSTTOOLS_EXPORT QGstreamerAudioInputSelector : public QAudioInputSelectorControl { Q_OBJECT public: diff --git a/src/multimedia/gsttools_headers/qgstreameraudioprobecontrol_p.h b/src/multimedia/gsttools_headers/qgstreameraudioprobecontrol_p.h index bacf8c71d..4fc5c7704 100644 --- a/src/multimedia/gsttools_headers/qgstreameraudioprobecontrol_p.h +++ b/src/multimedia/gsttools_headers/qgstreameraudioprobecontrol_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <gst/gst.h> #include <qmediaaudioprobecontrol.h> #include <QtCore/qmutex.h> @@ -61,7 +62,7 @@ QT_BEGIN_NAMESPACE -class QGstreamerAudioProbeControl +class Q_GSTTOOLS_EXPORT QGstreamerAudioProbeControl : public QMediaAudioProbeControl , public QGstreamerBufferProbe , public QSharedData diff --git a/src/multimedia/gsttools_headers/qgstreamerbufferprobe_p.h b/src/multimedia/gsttools_headers/qgstreamerbufferprobe_p.h index f7ba2bbd9..35644f934 100644 --- a/src/multimedia/gsttools_headers/qgstreamerbufferprobe_p.h +++ b/src/multimedia/gsttools_headers/qgstreamerbufferprobe_p.h @@ -51,13 +51,15 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <gst/gst.h> #include <QtCore/qglobal.h> + QT_BEGIN_NAMESPACE -class QGstreamerBufferProbe +class Q_GSTTOOLS_EXPORT QGstreamerBufferProbe { public: enum Flags diff --git a/src/multimedia/gsttools_headers/qgstreamerbushelper_p.h b/src/multimedia/gsttools_headers/qgstreamerbushelper_p.h index 3216c07da..c7d06faf8 100644 --- a/src/multimedia/gsttools_headers/qgstreamerbushelper_p.h +++ b/src/multimedia/gsttools_headers/qgstreamerbushelper_p.h @@ -51,9 +51,11 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <QObject> #include "qgstreamermessage_p.h" + #include <gst/gst.h> QT_BEGIN_NAMESPACE @@ -78,7 +80,7 @@ Q_DECLARE_INTERFACE(QGstreamerBusMessageFilter, QGstreamerBusMessageFilter_iid) class QGstreamerBusHelperPrivate; -class QGstreamerBusHelper : public QObject +class Q_GSTTOOLS_EXPORT QGstreamerBusHelper : public QObject { Q_OBJECT friend class QGstreamerBusHelperPrivate; diff --git a/src/multimedia/gsttools_headers/qgstreamermessage_p.h b/src/multimedia/gsttools_headers/qgstreamermessage_p.h index 5d832ccfa..2f9d1745c 100644 --- a/src/multimedia/gsttools_headers/qgstreamermessage_p.h +++ b/src/multimedia/gsttools_headers/qgstreamermessage_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <QMetaType> #include <gst/gst.h> @@ -60,7 +61,7 @@ QT_BEGIN_NAMESPACE // Required for QDoc workaround class QString; -class QGstreamerMessage +class Q_GSTTOOLS_EXPORT QGstreamerMessage { public: QGstreamerMessage(); diff --git a/src/multimedia/gsttools_headers/qgstreamervideoinputdevicecontrol_p.h b/src/multimedia/gsttools_headers/qgstreamervideoinputdevicecontrol_p.h index e1ac453c7..b660cc7b3 100644 --- a/src/multimedia/gsttools_headers/qgstreamervideoinputdevicecontrol_p.h +++ b/src/multimedia/gsttools_headers/qgstreamervideoinputdevicecontrol_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <qvideodeviceselectorcontrol.h> #include <QtCore/qstringlist.h> @@ -59,7 +60,7 @@ QT_BEGIN_NAMESPACE -class QGstreamerVideoInputDeviceControl : public QVideoDeviceSelectorControl +class Q_GSTTOOLS_EXPORT QGstreamerVideoInputDeviceControl : public QVideoDeviceSelectorControl { Q_OBJECT public: diff --git a/src/multimedia/gsttools_headers/qgstreamervideoprobecontrol_p.h b/src/multimedia/gsttools_headers/qgstreamervideoprobecontrol_p.h index b599b0e78..b15b6099c 100644 --- a/src/multimedia/gsttools_headers/qgstreamervideoprobecontrol_p.h +++ b/src/multimedia/gsttools_headers/qgstreamervideoprobecontrol_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <gst/gst.h> #include <gst/video/video.h> #include <qmediavideoprobecontrol.h> @@ -62,7 +63,7 @@ QT_BEGIN_NAMESPACE -class QGstreamerVideoProbeControl +class Q_GSTTOOLS_EXPORT QGstreamerVideoProbeControl : public QMediaVideoProbeControl , public QGstreamerBufferProbe , public QSharedData diff --git a/src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h b/src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h index 1d22e1125..2f0b80d45 100644 --- a/src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h +++ b/src/multimedia/gsttools_headers/qgstreamervideorenderer_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <qvideorenderercontrol.h> #include <private/qvideosurfacegstsink_p.h> #include <qabstractvideosurface.h> @@ -59,7 +60,7 @@ QT_BEGIN_NAMESPACE -class QGstreamerVideoRenderer : public QVideoRendererControl, public QGstreamerVideoRendererInterface +class Q_GSTTOOLS_EXPORT QGstreamerVideoRenderer : public QVideoRendererControl, public QGstreamerVideoRendererInterface { Q_OBJECT Q_INTERFACES(QGstreamerVideoRendererInterface) diff --git a/src/multimedia/gsttools_headers/qgstreamervideowidget_p.h b/src/multimedia/gsttools_headers/qgstreamervideowidget_p.h index b2dfece60..3e3240725 100644 --- a/src/multimedia/gsttools_headers/qgstreamervideowidget_p.h +++ b/src/multimedia/gsttools_headers/qgstreamervideowidget_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <qvideowidgetcontrol.h> #include "qgstreamervideorendererinterface_p.h" @@ -59,9 +60,9 @@ QT_BEGIN_NAMESPACE -class QGstreamerVideoWidget; +class Q_GSTTOOLS_EXPORT QGstreamerVideoWidget; -class QGstreamerVideoWidgetControl +class Q_GSTTOOLS_EXPORT QGstreamerVideoWidgetControl : public QVideoWidgetControl , public QGstreamerVideoRendererInterface , public QGstreamerSyncMessageFilter diff --git a/src/multimedia/gsttools_headers/qgstreamervideowindow_p.h b/src/multimedia/gsttools_headers/qgstreamervideowindow_p.h index b489650f9..5f893f10e 100644 --- a/src/multimedia/gsttools_headers/qgstreamervideowindow_p.h +++ b/src/multimedia/gsttools_headers/qgstreamervideowindow_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <qvideowindowcontrol.h> #include "qgstreamervideorendererinterface_p.h" @@ -61,7 +62,7 @@ QT_BEGIN_NAMESPACE class QAbstractVideoSurface; -class QGstreamerVideoWindow : +class Q_GSTTOOLS_EXPORT QGstreamerVideoWindow : public QVideoWindowControl, public QGstreamerVideoRendererInterface, public QGstreamerSyncMessageFilter, diff --git a/src/multimedia/gsttools_headers/qgsttools_global_p.h b/src/multimedia/gsttools_headers/qgsttools_global_p.h new file mode 100644 index 000000000..babcd3aaf --- /dev/null +++ b/src/multimedia/gsttools_headers/qgsttools_global_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2017 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGSTTOOLS_GLOBAL_H +#define QGSTTOOLS_GLOBAL_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +#ifndef QT_STATIC +# if defined(QT_BUILD_MULTIMEDIAGSTTOOLS_LIB) +# define Q_GSTTOOLS_EXPORT Q_DECL_EXPORT +# else +# define Q_GSTTOOLS_EXPORT Q_DECL_IMPORT +# endif +#else +# define Q_GSTTOOLS_EXPORT +#endif + +QT_END_NAMESPACE + +#endif // QGSTTOOLS_GLOBAL_H diff --git a/src/multimedia/gsttools_headers/qgstutils_p.h b/src/multimedia/gsttools_headers/qgstutils_p.h index 8b7de3661..24d3e889d 100644 --- a/src/multimedia/gsttools_headers/qgstutils_p.h +++ b/src/multimedia/gsttools_headers/qgstutils_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <QtCore/qmap.h> #include <QtCore/qset.h> #include <QtCore/qvector.h> @@ -85,7 +86,7 @@ class QImage; class QVideoSurfaceFormat; namespace QGstUtils { - struct CameraInfo + struct Q_GSTTOOLS_EXPORT CameraInfo { QString name; QString description; @@ -94,74 +95,74 @@ namespace QGstUtils { QByteArray driver; }; - QMap<QByteArray, QVariant> gstTagListToMap(const GstTagList *list); + Q_GSTTOOLS_EXPORT QMap<QByteArray, QVariant> gstTagListToMap(const GstTagList *list); - QSize capsResolution(const GstCaps *caps); - QSize capsCorrectedResolution(const GstCaps *caps); - QAudioFormat audioFormatForCaps(const GstCaps *caps); + Q_GSTTOOLS_EXPORT QSize capsResolution(const GstCaps *caps); + Q_GSTTOOLS_EXPORT QSize capsCorrectedResolution(const GstCaps *caps); + Q_GSTTOOLS_EXPORT QAudioFormat audioFormatForCaps(const GstCaps *caps); #if GST_CHECK_VERSION(1,0,0) - QAudioFormat audioFormatForSample(GstSample *sample); + Q_GSTTOOLS_EXPORT QAudioFormat audioFormatForSample(GstSample *sample); #else - QAudioFormat audioFormatForBuffer(GstBuffer *buffer); + Q_GSTTOOLS_EXPORT QAudioFormat audioFormatForBuffer(GstBuffer *buffer); #endif - GstCaps *capsForAudioFormat(const QAudioFormat &format); - void initializeGst(); - QMultimedia::SupportEstimate hasSupport(const QString &mimeType, + Q_GSTTOOLS_EXPORT GstCaps *capsForAudioFormat(const QAudioFormat &format); + Q_GSTTOOLS_EXPORT void initializeGst(); + Q_GSTTOOLS_EXPORT QMultimedia::SupportEstimate hasSupport(const QString &mimeType, const QStringList &codecs, const QSet<QString> &supportedMimeTypeSet); - QVector<CameraInfo> enumerateCameras(GstElementFactory *factory = 0); - QList<QByteArray> cameraDevices(GstElementFactory * factory = 0); - QString cameraDescription(const QString &device, GstElementFactory * factory = 0); - QCamera::Position cameraPosition(const QString &device, GstElementFactory * factory = 0); - int cameraOrientation(const QString &device, GstElementFactory * factory = 0); - QByteArray cameraDriver(const QString &device, GstElementFactory * factory = 0); + Q_GSTTOOLS_EXPORT QVector<CameraInfo> enumerateCameras(GstElementFactory *factory = 0); + Q_GSTTOOLS_EXPORT QList<QByteArray> cameraDevices(GstElementFactory * factory = 0); + Q_GSTTOOLS_EXPORT QString cameraDescription(const QString &device, GstElementFactory * factory = 0); + Q_GSTTOOLS_EXPORT QCamera::Position cameraPosition(const QString &device, GstElementFactory * factory = 0); + Q_GSTTOOLS_EXPORT int cameraOrientation(const QString &device, GstElementFactory * factory = 0); + Q_GSTTOOLS_EXPORT QByteArray cameraDriver(const QString &device, GstElementFactory * factory = 0); - QSet<QString> supportedMimeTypes(bool (*isValidFactory)(GstElementFactory *factory)); + Q_GSTTOOLS_EXPORT QSet<QString> supportedMimeTypes(bool (*isValidFactory)(GstElementFactory *factory)); #if GST_CHECK_VERSION(1,0,0) - QImage bufferToImage(GstBuffer *buffer, const GstVideoInfo &info); - QVideoSurfaceFormat formatForCaps( + Q_GSTTOOLS_EXPORT QImage bufferToImage(GstBuffer *buffer, const GstVideoInfo &info); + Q_GSTTOOLS_EXPORT QVideoSurfaceFormat formatForCaps( GstCaps *caps, GstVideoInfo *info = 0, QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle); #else - QImage bufferToImage(GstBuffer *buffer); - QVideoSurfaceFormat formatForCaps( + Q_GSTTOOLS_EXPORT QImage bufferToImage(GstBuffer *buffer); + Q_GSTTOOLS_EXPORT QVideoSurfaceFormat formatForCaps( GstCaps *caps, int *bytesPerLine = 0, QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle); #endif - GstCaps *capsForFormats(const QList<QVideoFrame::PixelFormat> &formats); + Q_GSTTOOLS_EXPORT GstCaps *capsForFormats(const QList<QVideoFrame::PixelFormat> &formats); void setFrameTimeStamps(QVideoFrame *frame, GstBuffer *buffer); - void setMetaData(GstElement *element, const QMap<QByteArray, QVariant> &data); - void setMetaData(GstBin *bin, const QMap<QByteArray, QVariant> &data); + Q_GSTTOOLS_EXPORT void setMetaData(GstElement *element, const QMap<QByteArray, QVariant> &data); + Q_GSTTOOLS_EXPORT void setMetaData(GstBin *bin, const QMap<QByteArray, QVariant> &data); - GstCaps *videoFilterCaps(); + Q_GSTTOOLS_EXPORT GstCaps *videoFilterCaps(); - QSize structureResolution(const GstStructure *s); - QVideoFrame::PixelFormat structurePixelFormat(const GstStructure *s, int *bpp = 0); - QSize structurePixelAspectRatio(const GstStructure *s); - QPair<qreal, qreal> structureFrameRateRange(const GstStructure *s); + Q_GSTTOOLS_EXPORT QSize structureResolution(const GstStructure *s); + Q_GSTTOOLS_EXPORT QVideoFrame::PixelFormat structurePixelFormat(const GstStructure *s, int *bpp = 0); + Q_GSTTOOLS_EXPORT QSize structurePixelAspectRatio(const GstStructure *s); + Q_GSTTOOLS_EXPORT QPair<qreal, qreal> structureFrameRateRange(const GstStructure *s); - QString fileExtensionForMimeType(const QString &mimeType); + Q_GSTTOOLS_EXPORT QString fileExtensionForMimeType(const QString &mimeType); } -void qt_gst_object_ref_sink(gpointer object); -GstCaps *qt_gst_pad_get_current_caps(GstPad *pad); -GstCaps *qt_gst_pad_get_caps(GstPad *pad); -GstStructure *qt_gst_structure_new_empty(const char *name); -gboolean qt_gst_element_query_position(GstElement *element, GstFormat format, gint64 *cur); -gboolean qt_gst_element_query_duration(GstElement *element, GstFormat format, gint64 *cur); -GstCaps *qt_gst_caps_normalize(GstCaps *caps); -const gchar *qt_gst_element_get_factory_name(GstElement *element); -gboolean qt_gst_caps_can_intersect(const GstCaps * caps1, const GstCaps * caps2); -GList *qt_gst_video_sinks(); -void qt_gst_util_double_to_fraction(gdouble src, gint *dest_n, gint *dest_d); - -QDebug operator <<(QDebug debug, GstCaps *caps); +Q_GSTTOOLS_EXPORT void qt_gst_object_ref_sink(gpointer object); +Q_GSTTOOLS_EXPORT GstCaps *qt_gst_pad_get_current_caps(GstPad *pad); +Q_GSTTOOLS_EXPORT GstCaps *qt_gst_pad_get_caps(GstPad *pad); +Q_GSTTOOLS_EXPORT GstStructure *qt_gst_structure_new_empty(const char *name); +Q_GSTTOOLS_EXPORT gboolean qt_gst_element_query_position(GstElement *element, GstFormat format, gint64 *cur); +Q_GSTTOOLS_EXPORT gboolean qt_gst_element_query_duration(GstElement *element, GstFormat format, gint64 *cur); +Q_GSTTOOLS_EXPORT GstCaps *qt_gst_caps_normalize(GstCaps *caps); +Q_GSTTOOLS_EXPORT const gchar *qt_gst_element_get_factory_name(GstElement *element); +Q_GSTTOOLS_EXPORT gboolean qt_gst_caps_can_intersect(const GstCaps * caps1, const GstCaps * caps2); +Q_GSTTOOLS_EXPORT GList *qt_gst_video_sinks(); +Q_GSTTOOLS_EXPORT void qt_gst_util_double_to_fraction(gdouble src, gint *dest_n, gint *dest_d); + +Q_GSTTOOLS_EXPORT QDebug operator <<(QDebug debug, GstCaps *caps); QT_END_NAMESPACE diff --git a/src/multimedia/gsttools_headers/qgstvideobuffer_p.h b/src/multimedia/gsttools_headers/qgstvideobuffer_p.h index d2802d9a2..c67c57021 100644 --- a/src/multimedia/gsttools_headers/qgstvideobuffer_p.h +++ b/src/multimedia/gsttools_headers/qgstvideobuffer_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <qabstractvideobuffer.h> #include <QtCore/qvariant.h> @@ -60,14 +61,14 @@ QT_BEGIN_NAMESPACE #if GST_CHECK_VERSION(1,0,0) -class QGstVideoBuffer : public QAbstractPlanarVideoBuffer +class Q_GSTTOOLS_EXPORT QGstVideoBuffer : public QAbstractPlanarVideoBuffer { public: QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info); QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info, HandleType handleType, const QVariant &handle); #else -class QGstVideoBuffer : public QAbstractVideoBuffer +class Q_GSTTOOLS_EXPORT QGstVideoBuffer : public QAbstractVideoBuffer { public: QGstVideoBuffer(GstBuffer *buffer, int bytesPerLine); diff --git a/src/multimedia/gsttools_headers/qgstvideorendererplugin_p.h b/src/multimedia/gsttools_headers/qgstvideorendererplugin_p.h index 6a0c4c6bd..df36dbe09 100644 --- a/src/multimedia/gsttools_headers/qgstvideorendererplugin_p.h +++ b/src/multimedia/gsttools_headers/qgstvideorendererplugin_p.h @@ -51,6 +51,7 @@ // We mean it. // +#include <private/qgsttools_global_p.h> #include <qabstractvideobuffer.h> #include <qvideosurfaceformat.h> #include <QtCore/qobject.h> @@ -64,7 +65,7 @@ class QAbstractVideoSurface; const QLatin1String QGstVideoRendererPluginKey("gstvideorenderer"); -class QGstVideoRenderer +class Q_GSTTOOLS_EXPORT QGstVideoRenderer { public: virtual ~QGstVideoRenderer() {} @@ -81,7 +82,7 @@ public: /* Abstract interface for video buffers allocation. */ -class QGstVideoRendererInterface +class Q_GSTTOOLS_EXPORT QGstVideoRendererInterface { public: virtual ~QGstVideoRendererInterface() {} @@ -92,7 +93,7 @@ public: #define QGstVideoRendererInterface_iid "org.qt-project.qt.gstvideorenderer/5.4" Q_DECLARE_INTERFACE(QGstVideoRendererInterface, QGstVideoRendererInterface_iid) -class QGstVideoRendererPlugin : public QObject, public QGstVideoRendererInterface +class Q_GSTTOOLS_EXPORT QGstVideoRendererPlugin : public QObject, public QGstVideoRendererInterface { Q_OBJECT Q_INTERFACES(QGstVideoRendererInterface) diff --git a/src/multimedia/multimedia.pro b/src/multimedia/multimedia.pro index 0f3f3ff6b..d5d8b40d3 100644 --- a/src/multimedia/multimedia.pro +++ b/src/multimedia/multimedia.pro @@ -72,9 +72,9 @@ ANDROID_JAR_DEPENDENCIES = \ jar/QtMultimedia.jar:org.qtproject.qt5.android.multimedia.QtMultimediaUtils ANDROID_LIB_DEPENDENCIES = \ plugins/mediaservice/libqtmedia_android.so \ - lib/libQt5MultimediaQuick_p.so:Qt5Quick + lib/libQt5MultimediaQuick.so:Qt5Quick ANDROID_BUNDLED_FILES += \ - lib/libQt5MultimediaQuick_p.so + lib/libQt5MultimediaQuick.so ANDROID_PERMISSIONS += \ android.permission.CAMERA \ android.permission.RECORD_AUDIO diff --git a/src/multimedia/playback/qmedianetworkplaylistprovider.cpp b/src/multimedia/playback/qmedianetworkplaylistprovider.cpp index a4ad97251..3f24d0f55 100644 --- a/src/multimedia/playback/qmedianetworkplaylistprovider.cpp +++ b/src/multimedia/playback/qmedianetworkplaylistprovider.cpp @@ -42,6 +42,7 @@ #include "qmediacontent.h" #include "qmediaobject_p.h" #include "qplaylistfileparser_p.h" +#include "qrandom.h" QT_BEGIN_NAMESPACE @@ -266,7 +267,7 @@ void QMediaNetworkPlaylistProvider::shuffle() QList<QMediaContent> resources; while (!d->resources.isEmpty()) { - resources.append(d->resources.takeAt(qrand() % d->resources.size())); + resources.append(d->resources.takeAt(QRandomGenerator::global()->bounded(d->resources.size()))); } d->resources = resources; diff --git a/src/multimedia/playback/qmediaplaylistnavigator.cpp b/src/multimedia/playback/qmediaplaylistnavigator.cpp index 192fd463c..0966c9396 100644 --- a/src/multimedia/playback/qmediaplaylistnavigator.cpp +++ b/src/multimedia/playback/qmediaplaylistnavigator.cpp @@ -43,6 +43,7 @@ #include "qmediaobject_p.h" #include <QtCore/qdebug.h> +#include <QtCore/qrandom.h> QT_BEGIN_NAMESPACE @@ -124,7 +125,7 @@ int QMediaPlaylistNavigatorPrivate::nextItemPos(int steps) const randomModePositions.append(-1); int res = randomModePositions[randomPositionsOffset+steps]; if (res<0 || res >= playlist->mediaCount()) { - res = qrand() % playlist->mediaCount(); + res = QRandomGenerator::global()->bounded(playlist->mediaCount()); randomModePositions[randomPositionsOffset+steps] = res; } @@ -177,7 +178,7 @@ int QMediaPlaylistNavigatorPrivate::previousItemPos(int steps) const int res = randomModePositions[randomPositionsOffset-steps]; if (res<0 || res >= playlist->mediaCount()) { - res = qrand() % playlist->mediaCount(); + res = QRandomGenerator::global()->bounded(playlist->mediaCount()); randomModePositions[randomPositionsOffset-steps] = res; } diff --git a/src/multimedia/qmediaobject.cpp b/src/multimedia/qmediaobject.cpp index a2f0d58aa..71b2d148c 100644 --- a/src/multimedia/qmediaobject.cpp +++ b/src/multimedia/qmediaobject.cpp @@ -55,7 +55,13 @@ void QMediaObjectPrivate::_q_notify() const QMetaObject* m = q->metaObject(); - for (int pi : qAsConst(notifyProperties)) { + // QTBUG-57045 + // we create a copy of notifyProperties container to ensure that if a property is removed + // from the original container as a result of invoking propertyChanged signal, the iterator + // won't become invalidated + QSet<int> properties = notifyProperties; + + for (int pi : qAsConst(properties)) { QMetaProperty p = m->property(pi); p.notifySignal().invoke( q, QGenericArgument(QMetaType::typeName(p.userType()), p.read(q).data())); diff --git a/src/multimediawidgets/multimediawidgets.pro b/src/multimediawidgets/multimediawidgets.pro index 8e4a78278..57d4194ec 100644 --- a/src/multimediawidgets/multimediawidgets.pro +++ b/src/multimediawidgets/multimediawidgets.pro @@ -28,4 +28,6 @@ qtConfig(graphicsview) { HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS +msvc:lessThan(QMAKE_MSC_VER, 1900): QMAKE_CXXFLAGS += -Zm200 + load(qt_module) diff --git a/src/multimediawidgets/qpaintervideosurface.cpp b/src/multimediawidgets/qpaintervideosurface.cpp index 214e5ec7e..6e93e150d 100644 --- a/src/multimediawidgets/qpaintervideosurface.cpp +++ b/src/multimediawidgets/qpaintervideosurface.cpp @@ -191,6 +191,10 @@ QAbstractVideoSurface::Error QVideoSurfaceGenericPainter::paint( m_imageSize.height(), m_frame.bytesPerLine(), m_imageFormat); + // Do not render into ARGB32 images using QPainter. + // Using QImage::Format_ARGB32_Premultiplied is significantly faster. + if (m_imageFormat == QImage::Format_ARGB32) + image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); const QTransform oldTransform = painter->transform(); QTransform transform = oldTransform; diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index a7f0254ee..15aa027e4 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -697,7 +697,7 @@ void QAndroidCameraSession::onCameraTakePictureFailed() void QAndroidCameraSession::onCameraPictureExposed() { - if (m_captureCanceled) + if (m_captureCanceled || !m_camera) return; emit imageExposed(m_currentImageCaptureId); @@ -706,7 +706,7 @@ void QAndroidCameraSession::onCameraPictureExposed() void QAndroidCameraSession::onLastPreviewFrameFetched(const QVideoFrame &frame) { - if (m_captureCanceled) + if (m_captureCanceled || !m_camera) return; QtConcurrent::run(this, &QAndroidCameraSession::processPreviewImage, @@ -730,6 +730,9 @@ void QAndroidCameraSession::processPreviewImage(int id, const QVideoFrame &frame void QAndroidCameraSession::onNewPreviewFrame(const QVideoFrame &frame) { + if (!m_camera) + return; + m_videoProbesMutex.lock(); for (QAndroidMediaVideoProbeControl *probe : qAsConst(m_videoProbes)) @@ -756,7 +759,8 @@ void QAndroidCameraSession::onCameraPictureCaptured(const QByteArray &data) m_captureCanceled = false; // Preview needs to be restarted after taking a picture - m_camera->startPreview(); + if (m_camera) + m_camera->startPreview(); } void QAndroidCameraSession::onCameraPreviewStarted() diff --git a/src/plugins/avfoundation/camera/avfcameraservice.mm b/src/plugins/avfoundation/camera/avfcameraservice.mm index 7fd04250e..71ea31e5b 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.mm +++ b/src/plugins/avfoundation/camera/avfcameraservice.mm @@ -37,7 +37,6 @@ ** ****************************************************************************/ -#include <QtCore/qoperatingsystemversion.h> #include <QtCore/qvariant.h> #include <QtCore/qdebug.h> @@ -95,9 +94,8 @@ AVFCameraService::AVFCameraService(QObject *parent): m_imageCaptureControl = new AVFImageCaptureControl(this); m_cameraFocusControl = new AVFCameraFocusControl(this); m_cameraExposureControl = 0; -#if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0) - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) - m_cameraExposureControl = new AVFCameraExposureControl(this); +#ifdef Q_OS_IOS + m_cameraExposureControl = new AVFCameraExposureControl(this); #endif m_cameraZoomControl = 0; diff --git a/src/plugins/avfoundation/camera/avfcamerautility.mm b/src/plugins/avfoundation/camera/avfcamerautility.mm index 872075e0f..22713d613 100644 --- a/src/plugins/avfoundation/camera/avfcamerautility.mm +++ b/src/plugins/avfoundation/camera/avfcamerautility.mm @@ -40,7 +40,6 @@ #include "avfcamerautility.h" #include "avfcameradebug.h" -#include <QtCore/qoperatingsystemversion.h> #include <QtCore/qvector.h> #include <QtCore/qpair.h> #include <private/qmultimediautils_p.h> @@ -180,12 +179,10 @@ QSize qt_device_format_high_resolution(AVCaptureDeviceFormat *format) { Q_ASSERT(format); QSize res; -#if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0) - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) { - const CMVideoDimensions hrDim(format.highResolutionStillImageDimensions); - res.setWidth(hrDim.width); - res.setHeight(hrDim.height); - } +#if defined(Q_OS_IOS) + const CMVideoDimensions hrDim(format.highResolutionStillImageDimensions); + res.setWidth(hrDim.width); + res.setHeight(hrDim.height); #endif return res; } diff --git a/src/plugins/avfoundation/camera/avfimageencodercontrol.mm b/src/plugins/avfoundation/camera/avfimageencodercontrol.mm index 8384ce6ae..e858d93c4 100644 --- a/src/plugins/avfoundation/camera/avfimageencodercontrol.mm +++ b/src/plugins/avfoundation/camera/avfimageencodercontrol.mm @@ -48,7 +48,6 @@ #include <QtMultimedia/qmediaencodersettings.h> -#include <QtCore/qoperatingsystemversion.h> #include <QtCore/qdebug.h> #include <AVFoundation/AVFoundation.h> @@ -94,17 +93,15 @@ QList<QSize> AVFImageEncoderControl::supportedResolutions(const QImageEncoderSet const QSize res(qt_device_format_resolution(format)); if (!res.isNull() && res.isValid()) resolutions << res; -#if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0) - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) { - // From Apple's docs (iOS): - // By default, AVCaptureStillImageOutput emits images with the same dimensions as - // its source AVCaptureDevice instance’s activeFormat.formatDescription. However, - // if you set this property to YES, the receiver emits still images at the capture - // device’s highResolutionStillImageDimensions value. - const QSize hrRes(qt_device_format_high_resolution(format)); - if (!hrRes.isNull() && hrRes.isValid()) - resolutions << res; - } +#ifdef Q_OS_IOS + // From Apple's docs (iOS): + // By default, AVCaptureStillImageOutput emits images with the same dimensions as + // its source AVCaptureDevice instance’s activeFormat.formatDescription. However, + // if you set this property to YES, the receiver emits still images at the capture + // device’s highResolutionStillImageDimensions value. + const QSize hrRes(qt_device_format_high_resolution(format)); + if (!hrRes.isNull() && hrRes.isValid()) + resolutions << res; #endif } @@ -133,17 +130,15 @@ QImageEncoderSettings AVFImageEncoderControl::imageSettings() const } QSize res(qt_device_format_resolution(captureDevice.activeFormat)); -#if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0) - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) { - if (!m_service->imageCaptureControl() || !m_service->imageCaptureControl()->stillImageOutput()) { - qDebugCamera() << Q_FUNC_INFO << "no still image output"; - return settings; - } - - AVCaptureStillImageOutput *stillImageOutput = m_service->imageCaptureControl()->stillImageOutput(); - if (stillImageOutput.highResolutionStillImageOutputEnabled) - res = qt_device_format_high_resolution(captureDevice.activeFormat); +#ifdef Q_OS_IOS + if (!m_service->imageCaptureControl() || !m_service->imageCaptureControl()->stillImageOutput()) { + qDebugCamera() << Q_FUNC_INFO << "no still image output"; + return settings; } + + AVCaptureStillImageOutput *stillImageOutput = m_service->imageCaptureControl()->stillImageOutput(); + if (stillImageOutput.highResolutionStillImageOutputEnabled) + res = qt_device_format_high_resolution(captureDevice.activeFormat); #endif if (res.isNull() || !res.isValid()) { qDebugCamera() << Q_FUNC_INFO << "failed to exctract the image resolution"; @@ -217,14 +212,12 @@ bool AVFImageEncoderControl::applySettings() activeFormatChanged = qt_set_active_format(captureDevice, match, true); -#if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0) - if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::IOS, 8)) { - AVCaptureStillImageOutput *imageOutput = m_service->imageCaptureControl()->stillImageOutput(); - if (res == qt_device_format_high_resolution(captureDevice.activeFormat)) - imageOutput.highResolutionStillImageOutputEnabled = YES; - else - imageOutput.highResolutionStillImageOutputEnabled = NO; - } +#ifdef Q_OS_IOS + AVCaptureStillImageOutput *imageOutput = m_service->imageCaptureControl()->stillImageOutput(); + if (res == qt_device_format_high_resolution(captureDevice.activeFormat)) + imageOutput.highResolutionStillImageOutputEnabled = YES; + else + imageOutput.highResolutionStillImageOutputEnabled = NO; #endif return activeFormatChanged; diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm index d657dc17d..0b31bd0bc 100644 --- a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm @@ -49,6 +49,7 @@ #include "avfmediacontainercontrol.h" #include "avfcamerautility.h" +#include <QtCore/qmath.h> #include <QtCore/qdebug.h> QT_USE_NAMESPACE @@ -273,14 +274,11 @@ void AVFMediaRecorderControlIOS::setState(QMediaRecorder::State state) else rotation = (screenOrientation + (360 - cameraInfo.orientation)) % 360; - // convert to radians - rotation *= M_PI / 180.f; - if ([m_writer setupWithFileURL:nsFileURL cameraService:m_service audioSettings:m_audioSettings videoSettings:m_videoSettings - transform:CGAffineTransformMakeRotation(rotation)]) { + transform:CGAffineTransformMakeRotation(qDegreesToRadians(rotation))]) { m_state = QMediaRecorder::RecordingState; m_lastStatus = QMediaRecorder::StartingStatus; diff --git a/src/plugins/common/evr/evrcustompresenter.cpp b/src/plugins/common/evr/evrcustompresenter.cpp index 38e8c3a8f..958204079 100644 --- a/src/plugins/common/evr/evrcustompresenter.cpp +++ b/src/plugins/common/evr/evrcustompresenter.cpp @@ -560,7 +560,6 @@ EVRCustomPresenter::EVRCustomPresenter(QAbstractVideoSurface *surface) , m_mediaType(0) , m_surface(0) , m_canRenderToSurface(false) - , m_sampleToPresent(0) { // Initial source rectangle = (0,0,1,1) m_sourceRect.top = 0; diff --git a/src/plugins/common/evr/evrcustompresenter.h b/src/plugins/common/evr/evrcustompresenter.h index 5c240ea95..199dee774 100644 --- a/src/plugins/common/evr/evrcustompresenter.h +++ b/src/plugins/common/evr/evrcustompresenter.h @@ -367,8 +367,6 @@ private: QAbstractVideoSurface *m_surface; bool m_canRenderToSurface; - - IMFSample *m_sampleToPresent; }; bool qt_evr_setCustomPresenter(IUnknown *evr, EVRCustomPresenter *presenter); diff --git a/src/plugins/common/evr/evrd3dpresentengine.cpp b/src/plugins/common/evr/evrd3dpresentengine.cpp index 043d0ad73..fd9ccdef1 100644 --- a/src/plugins/common/evr/evrd3dpresentengine.cpp +++ b/src/plugins/common/evr/evrd3dpresentengine.cpp @@ -49,7 +49,7 @@ #include <private/qmediaopenglhelper_p.h> #ifdef MAYBE_ANGLE -# include <qtgui/qguiapplication.h> +# include <qguiapplication.h> # include <qpa/qplatformnativeinterface.h> # include <qopenglfunctions.h> # include <EGL/eglext.h> diff --git a/src/plugins/directshow/directshow.pro b/src/plugins/directshow/directshow.pro index 2857f87d9..54d617166 100644 --- a/src/plugins/directshow/directshow.pro +++ b/src/plugins/directshow/directshow.pro @@ -8,7 +8,13 @@ win32:!qtHaveModule(opengl)|qtConfig(dynamicgl) { HEADERS += dsserviceplugin.h SOURCES += dsserviceplugin.cpp -mingw: DEFINES += NO_DSHOW_STRSAFE +# Remove WINVER/_WIN32_WINNT definitions added to qt_build_config.prf +# by qtbase/d57a7c41712f8627a462d893329dc3f0dbb52d32 since the multimedia +# headers of MinGW 5.3/7.1 are too broken to compile with 0x0601. +mingw { + DEFINES -= WINVER=0x0601 _WIN32_WINNT=0x0601 + DEFINES += NO_DSHOW_STRSAFE +} include(common/common.pri) qtConfig(directshow-player): include(player/player.pri) diff --git a/src/plugins/directshow/player/directshowplayerservice.cpp b/src/plugins/directshow/player/directshowplayerservice.cpp index 9cbb62969..8ee5d67a1 100644 --- a/src/plugins/directshow/player/directshowplayerservice.cpp +++ b/src/plugins/directshow/player/directshowplayerservice.cpp @@ -402,7 +402,6 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker) } else if (!m_resources.isEmpty()) { m_pendingTasks |= SetUrlSource; } else { - m_pendingTasks = 0; m_graphStatus = InvalidMedia; switch (hr) { @@ -1688,8 +1687,6 @@ void DirectShowPlayerService::run() QMutexLocker locker(&m_mutex); for (;;) { - ::ResetEvent(m_taskHandle); - while (m_pendingTasks == 0) { DWORD result = 0; diff --git a/src/plugins/gstreamer/common.pri b/src/plugins/gstreamer/common.pri index cbe87be4f..d0c5c7bdd 100644 --- a/src/plugins/gstreamer/common.pri +++ b/src/plugins/gstreamer/common.pri @@ -1,12 +1,10 @@ -QT += core-private multimedia-private network +QT += core-private multimedia-private multimediagsttools-private network qtHaveModule(widgets) { QT += widgets multimediawidgets-private DEFINES += HAVE_WIDGETS } -LIBS += -lqgsttools_p - QMAKE_USE += gstreamer qtConfig(resourcepolicy): \ diff --git a/src/plugins/pulseaudio/qpulsehelpers.cpp b/src/plugins/pulseaudio/qpulsehelpers.cpp index 17579bdd9..0604c97f5 100644 --- a/src/plugins/pulseaudio/qpulsehelpers.cpp +++ b/src/plugins/pulseaudio/qpulsehelpers.cpp @@ -49,30 +49,23 @@ pa_sample_spec audioFormatToSampleSpec(const QAudioFormat &format) spec.rate = format.sampleRate(); spec.channels = format.channelCount(); - - if (format.sampleSize() == 8) { - spec.format = PA_SAMPLE_U8; - } else if (format.sampleSize() == 16) { - switch (format.byteOrder()) { - case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S16BE; break; - case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S16LE; break; - } - } else if (format.sampleSize() == 24) { - switch (format.byteOrder()) { - case QAudioFormat::BigEndian: spec.format = PA_SAMPLE_S24BE; break; - case QAudioFormat::LittleEndian: spec.format = PA_SAMPLE_S24LE; break; - } - } else if (format.sampleSize() == 32) { - switch (format.byteOrder()) { - case QAudioFormat::BigEndian: - format.sampleType() == QAudioFormat::Float ? spec.format = PA_SAMPLE_FLOAT32BE : spec.format = PA_SAMPLE_S32BE; - break; - case QAudioFormat::LittleEndian: - format.sampleType() == QAudioFormat::Float ? spec.format = PA_SAMPLE_FLOAT32LE : spec.format = PA_SAMPLE_S32LE; - break; + spec.format = PA_SAMPLE_INVALID; + const bool isBigEndian = (format.byteOrder() == QAudioFormat::BigEndian); + + if (format.sampleType() == QAudioFormat::UnSignedInt) { + if (format.sampleSize() == 8) + spec.format = PA_SAMPLE_U8; + } else if (format.sampleType() == QAudioFormat::SignedInt) { + if (format.sampleSize() == 16) { + spec.format = isBigEndian ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; + } else if (format.sampleSize() == 24) { + spec.format = isBigEndian ? PA_SAMPLE_S24BE : PA_SAMPLE_S24LE; + } else if (format.sampleSize() == 32) { + spec.format = isBigEndian ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE; } - } else { - spec.format = PA_SAMPLE_INVALID; + } else if (format.sampleType() == QAudioFormat::Float) { + if (format.sampleSize() == 32) + spec.format = isBigEndian ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE; } return spec; diff --git a/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp b/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp index d08d01e6d..c4c09f543 100644 --- a/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp +++ b/src/plugins/qnx-audio/audio/qnxaudiooutput.cpp @@ -43,19 +43,24 @@ #include <private/qaudiohelpers_p.h> +#pragma GCC diagnostic ignored "-Wvla" + QT_BEGIN_NAMESPACE QnxAudioOutput::QnxAudioOutput() - : m_source(0), - m_pushSource(false), - m_notifyInterval(1000), - m_error(QAudio::NoError), - m_state(QAudio::StoppedState), - m_volume(1.0), - m_periodSize(0), - m_pcmHandle(0), - m_bytesWritten(0), - m_intervalOffset(0) + : m_source(0) + , m_pushSource(false) + , m_notifyInterval(1000) + , m_error(QAudio::NoError) + , m_state(QAudio::StoppedState) + , m_volume(1.0) + , m_periodSize(0) + , m_pcmHandle(0) + , m_bytesWritten(0) + , m_intervalOffset(0) +#if _NTO_VERSION >= 700 + , m_pcmNotifier(0) +#endif { m_timer.setSingleShot(false); m_timer.setInterval(20); @@ -124,20 +129,16 @@ void QnxAudioOutput::reset() void QnxAudioOutput::suspend() { - m_timer.stop(); snd_pcm_playback_pause(m_pcmHandle); - setState(QAudio::SuspendedState); + if (state() != QAudio::InterruptedState) + suspendInternal(QAudio::SuspendedState); } void QnxAudioOutput::resume() { snd_pcm_playback_resume(m_pcmHandle); - if (m_pushSource) - setState(QAudio::IdleState); - else { - setState(QAudio::ActiveState); - m_timer.start(); - } + if (state() != QAudio::InterruptedState) + resumeInternal(); } int QnxAudioOutput::bytesFree() const @@ -146,6 +147,7 @@ int QnxAudioOutput::bytesFree() const return 0; snd_pcm_channel_status_t status; + memset(&status, 0, sizeof(status)); status.channel = SND_PCM_CHANNEL_PLAYBACK; const int errorCode = snd_pcm_plugin_status(m_pcmHandle, &status); @@ -214,9 +216,21 @@ qreal QnxAudioOutput::volume() const return m_volume; } +void QnxAudioOutput::setCategory(const QString &category) +{ + m_category = category; +} + +QString QnxAudioOutput::category() const +{ + return m_category; +} + void QnxAudioOutput::pullData() { - if (m_state == QAudio::StoppedState || m_state == QAudio::SuspendedState) + if (m_state == QAudio::StoppedState + || m_state == QAudio::SuspendedState + || m_state == QAudio::InterruptedState) return; const int bytesAvailable = bytesFree(); @@ -290,6 +304,8 @@ bool QnxAudioOutput::open() return false; } + addPcmEventFilter(); + // Necessary so that bytesFree() which uses the "free" member of the status struct works snd_pcm_plugin_set_disable(m_pcmHandle, PLUGIN_MMAP); @@ -303,6 +319,7 @@ bool QnxAudioOutput::open() } snd_pcm_channel_params_t params = QnxAudioUtils::formatToChannelParams(m_format, QAudio::AudioOutput, info.max_fragment_size); + setTypeName(¶ms); if ((errorCode = snd_pcm_plugin_params(m_pcmHandle, ¶ms)) < 0) { qWarning("QnxAudioOutput: open error, couldn't set channel params (0x%x)", -errorCode); @@ -331,6 +348,8 @@ bool QnxAudioOutput::open() m_intervalOffset = 0; m_bytesWritten = 0; + createPcmNotifiers(); + return true; } @@ -338,6 +357,8 @@ void QnxAudioOutput::close() { m_timer.stop(); + destroyPcmNotifiers(); + if (m_pcmHandle) { snd_pcm_plugin_flush(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK); snd_pcm_close(m_pcmHandle); @@ -400,6 +421,109 @@ qint64 QnxAudioOutput::write(const char *data, qint64 len) } } +void QnxAudioOutput::suspendInternal(QAudio::State suspendState) +{ + m_timer.stop(); + setState(suspendState); +} + +void QnxAudioOutput::resumeInternal() +{ + if (m_pushSource) { + setState(QAudio::IdleState); + } else { + setState(QAudio::ActiveState); + m_timer.start(); + } +} + +#if _NTO_VERSION >= 700 + +QAudio::State suspendState(const snd_pcm_event_t &event) +{ + Q_ASSERT(event.type == SND_PCM_EVENT_AUDIOMGMT_STATUS); + Q_ASSERT(event.data.audiomgmt_status.new_status == SND_PCM_STATUS_SUSPENDED); + return event.data.audiomgmt_status.flags & SND_PCM_STATUS_EVENT_HARD_SUSPEND + ? QAudio::InterruptedState : QAudio::SuspendedState; +} + +void QnxAudioOutput::addPcmEventFilter() +{ + /* Enable PCM events */ + snd_pcm_filter_t filter; + memset(&filter, 0, sizeof(filter)); + filter.enable = (1<<SND_PCM_EVENT_AUDIOMGMT_STATUS) | + (1<<SND_PCM_EVENT_AUDIOMGMT_MUTE) | + (1<<SND_PCM_EVENT_OUTPUTCLASS); + snd_pcm_set_filter(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK, &filter); +} + +void QnxAudioOutput::createPcmNotifiers() +{ + // QSocketNotifier::Read for poll based event dispatcher. Exception for + // select based event dispatcher. + m_pcmNotifier = new QSocketNotifier(snd_pcm_file_descriptor(m_pcmHandle, + SND_PCM_CHANNEL_PLAYBACK), + QSocketNotifier::Read, this); + connect(m_pcmNotifier, &QSocketNotifier::activated, + this, &QnxAudioOutput::pcmNotifierActivated); +} + +void QnxAudioOutput::destroyPcmNotifiers() +{ + if (m_pcmNotifier) { + delete m_pcmNotifier; + m_pcmNotifier = 0; + } +} + +void QnxAudioOutput::setTypeName(snd_pcm_channel_params_t *params) +{ + if (m_category.isEmpty()) + return; + + QByteArray latin1Category = m_category.toLatin1(); + + if (QString::fromLatin1(latin1Category) != m_category) { + qWarning("QnxAudioOutput: audio category name isn't a Latin1 string."); + return; + } + + if (latin1Category.size() >= static_cast<int>(sizeof(params->audio_type_name))) { + qWarning("QnxAudioOutput: audio category name too long."); + return; + } + + strcpy(params->audio_type_name, latin1Category.constData()); +} + +void QnxAudioOutput::pcmNotifierActivated(int socket) +{ + Q_UNUSED(socket); + + snd_pcm_event_t pcm_event; + memset(&pcm_event, 0, sizeof(pcm_event)); + while (snd_pcm_channel_read_event(m_pcmHandle, SND_PCM_CHANNEL_PLAYBACK, &pcm_event) == 0) { + if (pcm_event.type == SND_PCM_EVENT_AUDIOMGMT_STATUS) { + if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_SUSPENDED) + suspendInternal(suspendState(pcm_event)); + else if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_RUNNING) + resumeInternal(); + else if (pcm_event.data.audiomgmt_status.new_status == SND_PCM_STATUS_PAUSED) + suspendInternal(QAudio::SuspendedState); + } + } +} + +#else + +void QnxAudioOutput::addPcmEventFilter() {} +void QnxAudioOutput::createPcmNotifiers() {} +void QnxAudioOutput::destroyPcmNotifiers() {} +void QnxAudioOutput::setTypeName(snd_pcm_channel_params_t *) {} + +#endif + QnxPushIODevice::QnxPushIODevice(QnxAudioOutput *output) : QIODevice(output), m_output(output) diff --git a/src/plugins/qnx-audio/audio/qnxaudiooutput.h b/src/plugins/qnx-audio/audio/qnxaudiooutput.h index 5ee69b542..85aadf4b9 100644 --- a/src/plugins/qnx-audio/audio/qnxaudiooutput.h +++ b/src/plugins/qnx-audio/audio/qnxaudiooutput.h @@ -45,8 +45,10 @@ #include <QTime> #include <QTimer> #include <QIODevice> +#include <QSocketNotifier> #include <sys/asoundlib.h> +#include <sys/neutrino.h> QT_BEGIN_NAMESPACE @@ -80,6 +82,8 @@ public: QAudioFormat format() const Q_DECL_OVERRIDE; void setVolume(qreal volume) Q_DECL_OVERRIDE; qreal volume() const Q_DECL_OVERRIDE; + void setCategory(const QString &category) Q_DECL_OVERRIDE; + QString category() const Q_DECL_OVERRIDE; private slots: void pullData(); @@ -90,6 +94,14 @@ private: void setError(QAudio::Error error); void setState(QAudio::State state); + void addPcmEventFilter(); + void createPcmNotifiers(); + void destroyPcmNotifiers(); + void setTypeName(snd_pcm_channel_params_t *params); + + void suspendInternal(QAudio::State suspendState); + void resumeInternal(); + friend class QnxPushIODevice; qint64 write(const char *data, qint64 len); @@ -102,6 +114,7 @@ private: QAudio::State m_state; QAudioFormat m_format; qreal m_volume; + QString m_category; int m_periodSize; snd_pcm_t *m_pcmHandle; @@ -109,6 +122,13 @@ private: QTime m_startTimeStamp; QTime m_intervalTimeStamp; qint64 m_intervalOffset; + +#if _NTO_VERSION >= 700 + QSocketNotifier *m_pcmNotifier; + +private slots: + void pcmNotifierActivated(int socket); +#endif }; class QnxPushIODevice : public QIODevice diff --git a/src/plugins/qnx/mediaplayer/mediaplayer.pri b/src/plugins/qnx/mediaplayer/mediaplayer.pri index 4c4363a91..71bb98827 100644 --- a/src/plugins/qnx/mediaplayer/mediaplayer.pri +++ b/src/plugins/qnx/mediaplayer/mediaplayer.pri @@ -1,6 +1,7 @@ INCLUDEPATH += $$PWD HEADERS += \ + $$PWD/mmrendereraudiorolecontrol.h \ $$PWD/mmrenderermediaplayercontrol.h \ $$PWD/mmrenderermediaplayerservice.h \ $$PWD/mmrenderermetadata.h \ @@ -11,6 +12,7 @@ HEADERS += \ $$PWD/mmreventmediaplayercontrol.h \ $$PWD/mmreventthread.h SOURCES += \ + $$PWD/mmrendereraudiorolecontrol.cpp \ $$PWD/mmrenderermediaplayercontrol.cpp \ $$PWD/mmrenderermediaplayerservice.cpp \ $$PWD/mmrenderermetadata.cpp \ diff --git a/src/plugins/qnx/mediaplayer/mmrendereraudiorolecontrol.cpp b/src/plugins/qnx/mediaplayer/mmrendereraudiorolecontrol.cpp new file mode 100644 index 000000000..e470ed4c5 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrendereraudiorolecontrol.cpp @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2017 QNX Software Systems. All rights reserved. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "mmrendereraudiorolecontrol.h" +#include "mmrendererutil.h" + +QT_BEGIN_NAMESPACE + +MmRendererAudioRoleControl::MmRendererAudioRoleControl(QObject *parent) + : QAudioRoleControl(parent) + , m_role(QAudio::UnknownRole) +{ +} + +QAudio::Role MmRendererAudioRoleControl::audioRole() const +{ + return m_role; +} + +void MmRendererAudioRoleControl::setAudioRole(QAudio::Role role) +{ + if (m_role != role) { + m_role = role; + emit audioRoleChanged(m_role); + } +} + +QList<QAudio::Role> MmRendererAudioRoleControl::supportedAudioRoles() const +{ + return qnxSupportedAudioRoles(); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrendereraudiorolecontrol.h b/src/plugins/qnx/mediaplayer/mmrendereraudiorolecontrol.h new file mode 100644 index 000000000..7458d3512 --- /dev/null +++ b/src/plugins/qnx/mediaplayer/mmrendereraudiorolecontrol.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2017 QNX Software Systems. All rights reserved. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef MMRENDERERAUDIOROLECONTROL_H +#define MMRENDERERAUDIOROLECONTROL_H + +#include <qaudiorolecontrol.h> + +QT_BEGIN_NAMESPACE + +class MmRendererAudioRoleControl : public QAudioRoleControl +{ + Q_OBJECT +public: + explicit MmRendererAudioRoleControl(QObject *parent = 0); + + QAudio::Role audioRole() const Q_DECL_OVERRIDE; + void setAudioRole(QAudio::Role role) Q_DECL_OVERRIDE; + + QList<QAudio::Role> supportedAudioRoles() const Q_DECL_OVERRIDE; + +private: + QAudio::Role m_role; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp index d8b0a3934..55116f642 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.cpp @@ -36,6 +36,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include "mmrendereraudiorolecontrol.h" #include "mmrenderermediaplayercontrol.h" #include "mmrenderermetadatareadercontrol.h" #include "mmrendererplayervideorenderercontrol.h" @@ -70,7 +71,6 @@ MmRendererMediaPlayerControl::MmRendererMediaPlayerControl(QObject *parent) m_mediaStatus(QMediaPlayer::NoMedia), m_playAfterMediaLoaded(false), m_inputAttached(false), - m_stopEventsToIgnore(0), m_bufferLevel(0) { m_loadingTimer.setSingleShot(true); @@ -109,30 +109,12 @@ void MmRendererMediaPlayerControl::openConnection() startMonitoring(); } -void MmRendererMediaPlayerControl::handleMmStatusUpdate(qint64 newPosition) -{ - // Prevent spurious position change events from overriding our own position, for example - // when setting the position to 0 in stop(). - // Also, don't change the position while we're loading the media, as then play() would - // set a wrong initial position. - if (m_state != QMediaPlayer::PlayingState || - m_mediaStatus == QMediaPlayer::LoadingMedia || - m_mediaStatus == QMediaPlayer::NoMedia || - m_mediaStatus == QMediaPlayer::InvalidMedia) - return; - - setMmPosition(newPosition); -} - void MmRendererMediaPlayerControl::handleMmStopped() { // Only react to stop events that happen when the end of the stream is reached and // playback is stopped because of this. - // Ignore other stop event sources, souch as calling mmr_stop() ourselves and - // mmr_input_attach(). - if (m_stopEventsToIgnore > 0) { - --m_stopEventsToIgnore; - } else { + // Ignore other stop event sources, such as calling mmr_stop() ourselves. + if (m_state != QMediaPlayer::StoppedState) { setMediaStatus(QMediaPlayer::EndOfMedia); stopInternal(IgnoreMmRenderer); } @@ -197,6 +179,17 @@ void MmRendererMediaPlayerControl::attach() return; } + if (m_audioId != -1 && m_audioRoleControl) { + QString audioType = qnxAudioType(m_audioRoleControl->audioRole()); + QByteArray latin1AudioType = audioType.toLatin1(); + if (!audioType.isEmpty() && latin1AudioType == audioType) { + strm_dict_t *dict = strm_dict_new(); + dict = strm_dict_set(dict, "audio_type", latin1AudioType.constData()); + if (mmr_output_parameters(m_context, m_audioId, dict) != 0) + emitMmError("mmr_output_parameters: Setting audio_type failed"); + } + } + const QByteArray resourcePath = resourcePathForUrl(m_media.canonicalUrl()); if (resourcePath.isEmpty()) { detach(); @@ -210,11 +203,6 @@ void MmRendererMediaPlayerControl::attach() return; } - // For whatever reason, the mmrenderer sends out a MMR_STOPPED event when calling - // mmr_input_attach() above. Ignore it, as otherwise we'll trigger stopping right after we - // started. - m_stopEventsToIgnore++; - m_inputAttached = true; setMediaStatus(QMediaPlayer::LoadedMedia); @@ -351,7 +339,6 @@ void MmRendererMediaPlayerControl::stopInternal(StopCommand stopCommand) if (m_state != QMediaPlayer::StoppedState) { if (stopCommand == StopMmRenderer) { - ++m_stopEventsToIgnore; mmr_stop(m_context); } @@ -519,7 +506,6 @@ void MmRendererMediaPlayerControl::play() return; } - m_stopEventsToIgnore = 0; // once playing, stop events must be proccessed setState( QMediaPlayer::PlayingState); } @@ -556,6 +542,11 @@ void MmRendererMediaPlayerControl::setMetaDataReaderControl(MmRendererMetaDataRe m_metaDataReaderControl = metaDataReaderControl; } +void MmRendererMediaPlayerControl::setAudioRoleControl(MmRendererAudioRoleControl *audioRoleControl) +{ + m_audioRoleControl = audioRoleControl; +} + void MmRendererMediaPlayerControl::setMmPosition(qint64 newPosition) { if (newPosition != 0 && newPosition != m_position) { diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h index 2edbd50e0..ffa80bd27 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayercontrol.h @@ -52,6 +52,7 @@ typedef struct strm_dict strm_dict_t; QT_BEGIN_NAMESPACE +class MmRendererAudioRoleControl; class MmRendererMetaDataReaderControl; class MmRendererPlayerVideoRendererControl; class MmRendererVideoWindowControl; @@ -103,6 +104,7 @@ public: MmRendererVideoWindowControl *videoWindowControl() const; void setVideoWindowControl(MmRendererVideoWindowControl *videoControl); void setMetaDataReaderControl(MmRendererMetaDataReaderControl *metaDataReaderControl); + void setAudioRoleControl(MmRendererAudioRoleControl *audioRoleControl); protected: virtual void startMonitoring() = 0; @@ -115,7 +117,6 @@ protected: void setMmBufferStatus(const QString &bufferStatus); void setMmBufferLevel(const QString &bufferLevel); void handleMmStopped(); - void handleMmStatusUpdate(qint64 position); void updateMetaData(const strm_dict_t *dict); // must be called from subclass dtors (calls virtual function stopMonitoring()) @@ -156,12 +157,12 @@ private: QPointer<MmRendererPlayerVideoRendererControl> m_videoRendererControl; QPointer<MmRendererVideoWindowControl> m_videoWindowControl; QPointer<MmRendererMetaDataReaderControl> m_metaDataReaderControl; + QPointer<MmRendererAudioRoleControl> m_audioRoleControl; MmRendererMetaData m_metaData; qint64 m_position; QMediaPlayer::MediaStatus m_mediaStatus; bool m_playAfterMediaLoaded; bool m_inputAttached; - int m_stopEventsToIgnore; int m_bufferLevel; QTimer m_loadingTimer; }; diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp index 1258d199c..257c437ce 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "mmrenderermediaplayerservice.h" +#include "mmrendereraudiorolecontrol.h" #include "mmrenderermediaplayercontrol.h" #include "mmrenderermetadatareadercontrol.h" #include "mmrendererplayervideorenderercontrol.h" @@ -66,6 +67,7 @@ MmRendererMediaPlayerService::~MmRendererMediaPlayerService() delete m_videoWindowControl; delete m_mediaPlayerControl; delete m_metaDataReaderControl; + delete m_audioRoleControl; } QMediaControl *MmRendererMediaPlayerService::requestControl(const char *name) @@ -76,15 +78,19 @@ QMediaControl *MmRendererMediaPlayerService::requestControl(const char *name) updateControls(); } return m_mediaPlayerControl; - } - else if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) { + } else if (qstrcmp(name, QMetaDataReaderControl_iid) == 0) { if (!m_metaDataReaderControl) { m_metaDataReaderControl = new MmRendererMetaDataReaderControl(); updateControls(); } return m_metaDataReaderControl; - } - else if (qstrcmp(name, QVideoRendererControl_iid) == 0) { + } else if (qstrcmp(name, QAudioRoleControl_iid) == 0) { + if (!m_audioRoleControl) { + m_audioRoleControl = new MmRendererAudioRoleControl(); + updateControls(); + } + return m_audioRoleControl; + } else if (qstrcmp(name, QVideoRendererControl_iid) == 0) { if (!m_appHasDrmPermissionChecked) { m_appHasDrmPermission = checkForDrmPermission(); m_appHasDrmPermissionChecked = true; @@ -102,8 +108,7 @@ QMediaControl *MmRendererMediaPlayerService::requestControl(const char *name) updateControls(); } return m_videoRendererControl; - } - else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { + } else if (qstrcmp(name, QVideoWindowControl_iid) == 0) { if (!m_videoWindowControl) { m_videoWindowControl = new MmRendererVideoWindowControl(); updateControls(); @@ -123,6 +128,8 @@ void MmRendererMediaPlayerService::releaseControl(QMediaControl *control) m_mediaPlayerControl = 0; if (control == m_metaDataReaderControl) m_metaDataReaderControl = 0; + if (control == m_audioRoleControl) + m_audioRoleControl = 0; delete control; } @@ -136,6 +143,9 @@ void MmRendererMediaPlayerService::updateControls() if (m_metaDataReaderControl && m_mediaPlayerControl) m_mediaPlayerControl->setMetaDataReaderControl(m_metaDataReaderControl); + + if (m_audioRoleControl && m_mediaPlayerControl) + m_mediaPlayerControl->setAudioRoleControl(m_audioRoleControl); } QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h index de85293cb..9434b85b2 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h +++ b/src/plugins/qnx/mediaplayer/mmrenderermediaplayerservice.h @@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE +class MmRendererAudioRoleControl; class MmRendererMediaPlayerControl; class MmRendererMetaDataReaderControl; class MmRendererPlayerVideoRendererControl; @@ -66,6 +67,7 @@ private: QPointer<MmRendererVideoWindowControl> m_videoWindowControl; QPointer<MmRendererMediaPlayerControl> m_mediaPlayerControl; QPointer<MmRendererMetaDataReaderControl> m_metaDataReaderControl; + QPointer<MmRendererAudioRoleControl> m_audioRoleControl; bool m_appHasDrmPermission : 1; bool m_appHasDrmPermissionChecked : 1; diff --git a/src/plugins/qnx/mediaplayer/mmrendererutil.cpp b/src/plugins/qnx/mediaplayer/mmrendererutil.cpp index 239d9d52e..7a9f6393b 100644 --- a/src/plugins/qnx/mediaplayer/mmrendererutil.cpp +++ b/src/plugins/qnx/mediaplayer/mmrendererutil.cpp @@ -41,6 +41,11 @@ #include <QDebug> #include <QDir> #include <QFile> +#include <QJsonDocument> +#include <QJsonObject> +#include <QJsonValue> +#include <QMutex> +#include <QMutex> #include <QString> #include <QXmlStreamReader> @@ -85,6 +90,91 @@ static const MmError mmErrors[] = { }; static const unsigned int numMmErrors = sizeof(mmErrors) / sizeof(MmError); +static QBasicMutex roleMapMutex; +static bool roleMapInitialized = false; +static QString roleMap[QAudio::GameRole + 1]; + +template <typename T, size_t N> +constexpr size_t countof(T (&)[N]) +{ + return N; +} + +constexpr bool inBounds(QAudio::Role r) +{ + return r >= 0 && r < countof(roleMap); +} + +QString keyValueMapsLocation() +{ + QByteArray qtKeyValueMaps = qgetenv("QT_KEY_VALUE_MAPS"); + if (qtKeyValueMaps.isNull()) + return QStringLiteral("/etc/qt/keyvaluemaps"); + else + return qtKeyValueMaps; +} + +QJsonObject loadMapObject(const QString &keyValueMapPath) +{ + QFile mapFile(keyValueMapsLocation() + keyValueMapPath); + if (mapFile.open(QIODevice::ReadOnly)) { + QByteArray mapFileContents = mapFile.readAll(); + QJsonDocument mapDocument = QJsonDocument::fromJson(mapFileContents); + if (mapDocument.isObject()) { + QJsonObject mapObject = mapDocument.object(); + return mapObject; + } + } + return QJsonObject(); +} + +static void loadRoleMap() +{ + QMutexLocker locker(&roleMapMutex); + + if (!roleMapInitialized) { + QJsonObject mapObject = loadMapObject("/QAudio/Role.json"); + if (!mapObject.isEmpty()) { + // Wrapping the loads in a switch like this ensures that anyone adding + // a new enumerator will be notified that this code must be updated. A + // compile error will occur because the enumerator is missing from the + // switch. A compile error will also occur if the enumerator used to + // size the mapping table isn't updated when a new enumerator is added. + // One or more enumerators will be outside the bounds of the array when + // the wrong enumerator is used to size the array. + // + // The code loads a mapping for each enumerator because role is set + // to UnknownRole and all the cases drop through to the next case. +#pragma GCC diagnostic push +#pragma GCC diagnostic error "-Wswitch" +#define loadRoleMapping(r) \ + case QAudio::r: \ + static_assert(inBounds(QAudio::r), #r " out-of-bounds." \ + " Do you need to change the enumerator used to size the mapping table" \ + " because you added new QAudio::Role enumerators?"); \ + roleMap[QAudio::r] = mapObject.value(QLatin1String(#r)).toString(); + + QAudio::Role role = QAudio::UnknownRole; + switch (role) { + loadRoleMapping(UnknownRole); + loadRoleMapping(MusicRole); + loadRoleMapping(VideoRole); + loadRoleMapping(VoiceCommunicationRole); + loadRoleMapping(AlarmRole); + loadRoleMapping(NotificationRole); + loadRoleMapping(RingtoneRole); + loadRoleMapping(AccessibilityRole); + loadRoleMapping(SonificationRole); + loadRoleMapping(GameRole); + } +#undef loadRoleMapping +#pragma GCC diagnostic pop + } + + roleMapInitialized = true; + } +} + QString mmErrorMessage(const QString &msg, mmr_context_t *context, int *errorCode) { const mmr_error_info_t * const mmError = mmr_error_info(context); @@ -124,4 +214,27 @@ bool checkForDrmPermission() return false; } +QString qnxAudioType(QAudio::Role role) +{ + loadRoleMap(); + + if (role >= 0 && role < countof(roleMap)) + return roleMap[role]; + else + return QString(); +} + +QList<QAudio::Role> qnxSupportedAudioRoles() +{ + loadRoleMap(); + + QList<QAudio::Role> result; + for (size_t i = 0; i < countof(roleMap); ++i) { + if (!roleMap[i].isEmpty() || (i == QAudio::UnknownRole)) + result.append(static_cast<QAudio::Role>(i)); + } + + return result; +} + QT_END_NAMESPACE diff --git a/src/plugins/qnx/mediaplayer/mmrendererutil.h b/src/plugins/qnx/mediaplayer/mmrendererutil.h index 8017b2690..ac6f73a7d 100644 --- a/src/plugins/qnx/mediaplayer/mmrendererutil.h +++ b/src/plugins/qnx/mediaplayer/mmrendererutil.h @@ -40,6 +40,7 @@ #define MMRENDERERUTIL_H #include <QtCore/qglobal.h> +#include <QtMultimedia/qaudio.h> typedef struct mmr_context mmr_context_t; @@ -51,6 +52,9 @@ QString mmErrorMessage(const QString &msg, mmr_context_t *context, int * errorCo bool checkForDrmPermission(); +QString qnxAudioType(QAudio::Role role); +QList<QAudio::Role> qnxSupportedAudioRoles(); + QT_END_NAMESPACE #endif diff --git a/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp b/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp index e1a46841d..53345dec8 100644 --- a/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp +++ b/src/plugins/wasapi/qwasapiaudiodeviceinfo.cpp @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(lcMmDeviceInfo, "qt.multimedia.deviceinfo") QWasapiAudioDeviceInfo::QWasapiAudioDeviceInfo(QByteArray dev, QAudio::Mode mode) - : m_deviceName(dev) + : m_deviceName(QString::fromLocal8Bit(dev)) { qCDebug(lcMmDeviceInfo) << __FUNCTION__ << dev << mode; m_interface = QWasapiUtils::createOrGetInterface(dev, mode); diff --git a/src/plugins/wasapi/qwasapiutils.cpp b/src/plugins/wasapi/qwasapiutils.cpp index 727c94c23..0d03982de 100644 --- a/src/plugins/wasapi/qwasapiutils.cpp +++ b/src/plugins/wasapi/qwasapiutils.cpp @@ -90,6 +90,26 @@ struct DeviceMapping { Q_GLOBAL_STATIC(DeviceMapping, gMapping) } +struct CoInitializer +{ + CoInitializer() + { + const bool isGuiThread = QCoreApplication::instance() && + QThread::currentThread() == QCoreApplication::instance()->thread(); + CoInitializeEx(NULL, isGuiThread ? COINIT_APARTMENTTHREADED : COINIT_MULTITHREADED); + } + + ~CoInitializer() + { + CoUninitialize(); + } +}; + +static void CoInitIfNeeded() +{ + static CoInitializer initializer; +} + AudioInterface::AudioInterface() { qCDebug(lcMmAudioInterface) << __FUNCTION__; @@ -182,6 +202,7 @@ QByteArray QWasapiUtils::defaultDevice(QAudio::Mode mode) { qCDebug(lcMmUtils) << __FUNCTION__ << mode; + CoInitIfNeeded(); QList<QByteArray> &deviceNames = mode == QAudio::AudioInput ? gMapping->inputDeviceNames : gMapping->outputDeviceNames; QList<QString> &deviceIds = mode == QAudio::AudioInput ? gMapping->inputDeviceIds : gMapping->outputDeviceIds; if (deviceNames.isEmpty() || deviceIds.isEmpty()) // Initialize @@ -214,6 +235,7 @@ QList<QByteArray> QWasapiUtils::availableDevices(QAudio::Mode mode) { qCDebug(lcMmUtils) << __FUNCTION__ << mode; + CoInitIfNeeded(); ComPtr<IDeviceInformationStatics> statics; HRESULT hr; @@ -290,6 +312,7 @@ Microsoft::WRL::ComPtr<AudioInterface> QWasapiUtils::createOrGetInterface(const { qCDebug(lcMmUtils) << __FUNCTION__ << dev << mode; Q_ASSERT((mode == QAudio::AudioInput ? gMapping->inputDeviceNames.indexOf(dev) : gMapping->outputDeviceNames.indexOf(dev)) != -1); + CoInitIfNeeded(); Microsoft::WRL::ComPtr<AudioInterface> result; HRESULT hr = QEventDispatcherWinRT::runOnXamlThread([dev, mode, &result]() { diff --git a/src/plugins/windowsaudio/qwindowsaudiooutput.h b/src/plugins/windowsaudio/qwindowsaudiooutput.h index 19b4b92af..f25475b02 100644 --- a/src/plugins/windowsaudio/qwindowsaudiooutput.h +++ b/src/plugins/windowsaudio/qwindowsaudiooutput.h @@ -116,7 +116,6 @@ private slots: private: QByteArray m_device; - bool resuming; int bytesAvailable; QTime timeStamp; qint64 elapsedTimeOffset; @@ -139,8 +138,6 @@ private: WAVEFORMATEXTENSIBLE wfx; HWAVEOUT hWaveOut; - MMRESULT result; - WAVEHDR header; WAVEHDR* waveBlocks; volatile bool finished; volatile int waveFreeBlockCount; diff --git a/src/plugins/wmf/mfstream.cpp b/src/plugins/wmf/mfstream.cpp index fd95bf20b..a98b5a704 100644 --- a/src/plugins/wmf/mfstream.cpp +++ b/src/plugins/wmf/mfstream.cpp @@ -231,6 +231,8 @@ STDMETHODIMP MFStream::Seek( qint64 pos = qint64(llSeekOffset); switch (SeekOrigin) { + case msoBegin: + break; case msoCurrent: pos += m_stream->pos(); break; diff --git a/src/plugins/wmf/player/mfmetadatacontrol.cpp b/src/plugins/wmf/player/mfmetadatacontrol.cpp index 01be95e84..ac57ccfb5 100644 --- a/src/plugins/wmf/player/mfmetadatacontrol.cpp +++ b/src/plugins/wmf/player/mfmetadatacontrol.cpp @@ -193,6 +193,11 @@ QVariant MFMetaDataControl::metaData(const QString &key) const if (m_content && SUCCEEDED(m_content->GetValue(PKEY_Video_FrameWidth, &var))) res.setWidth(convertValue(var).toUInt()); value = res; + } else if (key == QMediaMetaData::Orientation) { + uint orientation = 0; + if (m_content && SUCCEEDED(m_content->GetValue(PKEY_Video_Orientation, &var))) + orientation = convertValue(var).toUInt(); + value = orientation; } else if (key == QMediaMetaData::PixelAspectRatio) { QSize aspectRatio; aspectRatio.setWidth(value.toUInt()); @@ -352,6 +357,8 @@ void MFMetaDataControl::updateSource(IMFPresentationDescriptor* sourcePD, IMFMed m_availableMetaDatas.push_back(QMediaMetaData::ThumbnailImage); } else if (key == PKEY_Video_FrameHeight) { m_availableMetaDatas.push_back(QMediaMetaData::Resolution); + } else if (key == PKEY_Video_Orientation) { + m_availableMetaDatas.push_back(QMediaMetaData::Orientation); } else if (key == PKEY_Video_HorizontalAspectRatio) { m_availableMetaDatas.push_back(QMediaMetaData::PixelAspectRatio); } else if (key == PKEY_Video_FrameRate) { diff --git a/src/qtmultimediaquicktools/qtmultimediaquicktools.pro b/src/qtmultimediaquicktools/qtmultimediaquicktools.pro index e4e157a54..bffdc6ec2 100644 --- a/src/qtmultimediaquicktools/qtmultimediaquicktools.pro +++ b/src/qtmultimediaquicktools/qtmultimediaquicktools.pro @@ -1,4 +1,4 @@ -TARGET = QtMultimediaQuick_p +TARGET = QtMultimediaQuick QT = core quick multimedia-private CONFIG += internal_module |