diff options
56 files changed, 1034 insertions, 300 deletions
diff --git a/.qmake.conf b/.qmake.conf index 35dba5489..b3c7403c2 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -2,4 +2,4 @@ load(qt_build_config) DEFINES += QT_NO_FOREACH QT_NO_JAVA_STYLE_ITERATORS QT_NO_LINKED_LIST -MODULE_VERSION = 5.14.2 +MODULE_VERSION = 5.15.0 diff --git a/examples/multimedia/spectrum/app/engine.cpp b/examples/multimedia/spectrum/app/engine.cpp index fd977785b..d188259dc 100644 --- a/examples/multimedia/spectrum/app/engine.cpp +++ b/examples/multimedia/spectrum/app/engine.cpp @@ -569,15 +569,17 @@ bool Engine::selectFormat() sampleRatesList += m_audioInputDevice.supportedSampleRates(); sampleRatesList += m_audioOutputDevice.supportedSampleRates(); - sampleRatesList = sampleRatesList.toSet().toList(); // remove duplicates std::sort(sampleRatesList.begin(), sampleRatesList.end()); + const auto uniqueRatesEnd = std::unique(sampleRatesList.begin(), sampleRatesList.end()); + sampleRatesList.erase(uniqueRatesEnd, sampleRatesList.end()); ENGINE_DEBUG << "Engine::initialize frequenciesList" << sampleRatesList; QList<int> channelsList; channelsList += m_audioInputDevice.supportedChannelCounts(); channelsList += m_audioOutputDevice.supportedChannelCounts(); - channelsList = channelsList.toSet().toList(); std::sort(channelsList.begin(), channelsList.end()); + const auto uniqueChannelsEnd = std::unique(channelsList.begin(), channelsList.end()); + channelsList.erase(uniqueChannelsEnd, channelsList.end()); ENGINE_DEBUG << "Engine::initialize channelsList" << channelsList; QAudioFormat format; diff --git a/src/gsttools/gstvideoconnector.c b/src/gsttools/gstvideoconnector.c index b85f5bdbe..7f88a89af 100644 --- a/src/gsttools/gstvideoconnector.c +++ b/src/gsttools/gstvideoconnector.c @@ -116,13 +116,13 @@ gst_video_connector_class_init (GstVideoConnectorClass * klass) gst_video_connector_signals[SIGNAL_RESEND_NEW_SEGMENT] = g_signal_new ("resend-new-segment", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, - G_STRUCT_OFFSET (GstVideoConnectorClass, resend_new_segment), NULL, NULL, + G_STRUCT_OFFSET (GstVideoConnectorClass, resend_new_segment), nullptr, nullptr, g_cclosure_marshal_VOID__BOOLEAN, G_TYPE_NONE, 1, G_TYPE_BOOLEAN); gst_video_connector_signals[SIGNAL_CONNECTION_FAILED] = g_signal_new ("connection-failed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, - 0, NULL, NULL, + 0, nullptr, nullptr, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } @@ -159,7 +159,7 @@ gst_video_connector_init (GstVideoConnector *element, element->relinked = FALSE; element->failedSignalEmited = FALSE; gst_segment_init (&element->segment, GST_FORMAT_TIME); - element->latest_buffer = NULL; + element->latest_buffer = nullptr; } static void @@ -167,9 +167,9 @@ gst_video_connector_reset (GstVideoConnector * element) { element->relinked = FALSE; element->failedSignalEmited = FALSE; - if (element->latest_buffer != NULL) { + if (element->latest_buffer != nullptr) { gst_buffer_unref (element->latest_buffer); - element->latest_buffer = NULL; + element->latest_buffer = nullptr; } gst_segment_init (&element->segment, GST_FORMAT_UNDEFINED); } @@ -196,7 +196,7 @@ gst_video_connector_buffer_alloc (GstPad * pad, guint64 offset, guint size, if (!buf) return GST_FLOW_ERROR; - *buf = NULL; + *buf = nullptr; gboolean isFailed = FALSE; while (1) { @@ -265,7 +265,7 @@ gst_video_connector_setcaps (GstPad *pad, GstCaps *caps) /* forward-negotiate */ gboolean res = gst_pad_set_caps(element->srcpad, caps); - gchar * debugmsg = NULL; + gchar * debugmsg = nullptr; GST_DEBUG_OBJECT(element, "gst_video_connector_setcaps %s %i", debugmsg = gst_caps_to_string(caps), res); if (debugmsg) g_free(debugmsg); @@ -407,7 +407,7 @@ gst_video_connector_chain (GstPad * pad, GstBuffer * buf) if (element->latest_buffer) { gst_buffer_unref (element->latest_buffer); - element->latest_buffer = NULL; + element->latest_buffer = nullptr; } element->latest_buffer = gst_buffer_ref(buf); diff --git a/src/gsttools/qgstappsrc.cpp b/src/gsttools/qgstappsrc.cpp index d5c44ec08..f6ecd48be 100644 --- a/src/gsttools/qgstappsrc.cpp +++ b/src/gsttools/qgstappsrc.cpp @@ -69,7 +69,7 @@ bool QGstAppSrc::setup(GstElement* appsrc) gst_object_ref(G_OBJECT(m_appSrc)); gst_app_src_set_callbacks(m_appSrc, (GstAppSrcCallbacks*)&m_callbacks, this, (GDestroyNotify)&QGstAppSrc::destroy_notify); - g_object_get(G_OBJECT(m_appSrc), "max-bytes", &m_maxBytes, NULL); + g_object_get(G_OBJECT(m_appSrc), "max-bytes", &m_maxBytes, nullptr); if (m_sequential) m_streamType = GST_APP_STREAM_TYPE_STREAM; diff --git a/src/gsttools/qgstbufferpoolinterface_p.h b/src/gsttools/qgstbufferpoolinterface_p.h index 45e573262..f5cbc35aa 100644 --- a/src/gsttools/qgstbufferpoolinterface_p.h +++ b/src/gsttools/qgstbufferpoolinterface_p.h @@ -79,7 +79,7 @@ public: /*! Build an QAbstractVideoBuffer instance from GstBuffer. - Returns NULL if GstBuffer is not compatible with this buffer pool. + Returns nullptr if GstBuffer is not compatible with this buffer pool. This method is called from gstreamer video sink thread. */ @@ -105,7 +105,7 @@ public: /*! Build an QAbstractVideoBuffer instance from compatible GstBuffer. - Returns NULL if GstBuffer is not compatible with this buffer pool. + Returns nullptr if GstBuffer is not compatible with this buffer pool. This method is called from gstreamer video sink thread. */ diff --git a/src/gsttools/qgstcodecsinfo.cpp b/src/gsttools/qgstcodecsinfo.cpp index c6e61f824..2522ee19c 100644 --- a/src/gsttools/qgstcodecsinfo.cpp +++ b/src/gsttools/qgstcodecsinfo.cpp @@ -99,7 +99,7 @@ QStringList QGstCodecsInfo::codecOptions(const QString &codec) const if (elementName.isEmpty()) return options; - GstElement *element = gst_element_factory_make(elementName, NULL); + GstElement *element = gst_element_factory_make(elementName, nullptr); if (element) { guint numProperties; GParamSpec **properties = g_object_class_list_properties(G_OBJECT_GET_CLASS(element), @@ -174,7 +174,7 @@ void QGstCodecsInfo::updateCodecs(ElementType elementType) } } - GstCaps *newCaps = gst_caps_new_full(newStructure, NULL); + GstCaps *newCaps = gst_caps_new_full(newStructure, nullptr); gchar *capsString = gst_caps_to_string(newCaps); QString codec = QLatin1String(capsString); diff --git a/src/gsttools/qgstreameraudioinputselector.cpp b/src/gsttools/qgstreameraudioinputselector.cpp index 72d079cbc..3bf5538c2 100644 --- a/src/gsttools/qgstreameraudioinputselector.cpp +++ b/src/gsttools/qgstreameraudioinputselector.cpp @@ -124,24 +124,21 @@ void QGstreamerAudioInputSelector::updateAlsaDevices() } n = hints; - while (*n != NULL) { + while (*n != nullptr) { char *name = snd_device_name_get_hint(*n, "NAME"); char *descr = snd_device_name_get_hint(*n, "DESC"); char *io = snd_device_name_get_hint(*n, "IOID"); - if ((name != NULL) && (descr != NULL)) { - if ( io == NULL || qstrcmp(io,"Input") == 0 ) { + if ((name != nullptr) && (descr != nullptr)) { + if (io == nullptr || qstrcmp(io, "Input") == 0) { m_names.append(QLatin1String("alsa:")+QString::fromUtf8(name)); m_descriptions.append(QString::fromUtf8(descr)); } } - if (name != NULL) - free(name); - if (descr != NULL) - free(descr); - if (io != NULL) - free(io); + free(name); + free(descr); + free(io); n++; } snd_device_name_free_hint(hints); diff --git a/src/gsttools/qgstreamerbufferprobe.cpp b/src/gsttools/qgstreamerbufferprobe.cpp index d95de4c63..e2956eadd 100644 --- a/src/gsttools/qgstreamerbufferprobe.cpp +++ b/src/gsttools/qgstreamerbufferprobe.cpp @@ -70,11 +70,11 @@ void QGstreamerBufferProbe::addProbeToPad(GstPad *pad, bool downstream) : GST_PAD_PROBE_TYPE_EVENT_UPSTREAM, capsProbe, this, - NULL); + nullptr); } if (m_flags & ProbeBuffers) { m_bufferProbeId = gst_pad_add_probe( - pad, GST_PAD_PROBE_TYPE_BUFFER, bufferProbe, this, NULL); + pad, GST_PAD_PROBE_TYPE_BUFFER, bufferProbe, this, nullptr); } #else Q_UNUSED(downstream); diff --git a/src/gsttools/qgstreamerbushelper.cpp b/src/gsttools/qgstreamerbushelper.cpp index 5df046fde..1a4034eee 100644 --- a/src/gsttools/qgstreamerbushelper.cpp +++ b/src/gsttools/qgstreamerbushelper.cpp @@ -69,7 +69,7 @@ public: connect(m_intervalTimer, SIGNAL(timeout()), SLOT(interval())); m_intervalTimer->start(); } else { - m_tag = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT, busCallback, this, NULL); + m_tag = gst_bus_add_watch_full(bus, G_PRIORITY_DEFAULT, busCallback, this, nullptr); } } @@ -186,27 +186,27 @@ QGstreamerBusHelper::~QGstreamerBusHelper() void QGstreamerBusHelper::installMessageFilter(QObject *filter) { - QGstreamerSyncMessageFilter *syncFilter = qobject_cast<QGstreamerSyncMessageFilter*>(filter); + auto syncFilter = qobject_cast<QGstreamerSyncMessageFilter*>(filter); if (syncFilter) { QMutexLocker lock(&d->filterMutex); if (!d->syncFilters.contains(syncFilter)) d->syncFilters.append(syncFilter); } - QGstreamerBusMessageFilter *busFilter = qobject_cast<QGstreamerBusMessageFilter*>(filter); + auto busFilter = qobject_cast<QGstreamerBusMessageFilter*>(filter); if (busFilter && !d->busFilters.contains(busFilter)) d->busFilters.append(busFilter); } void QGstreamerBusHelper::removeMessageFilter(QObject *filter) { - QGstreamerSyncMessageFilter *syncFilter = qobject_cast<QGstreamerSyncMessageFilter*>(filter); + auto syncFilter = qobject_cast<QGstreamerSyncMessageFilter*>(filter); if (syncFilter) { QMutexLocker lock(&d->filterMutex); d->syncFilters.removeAll(syncFilter); } - QGstreamerBusMessageFilter *busFilter = qobject_cast<QGstreamerBusMessageFilter*>(filter); + auto busFilter = qobject_cast<QGstreamerBusMessageFilter*>(filter); if (busFilter) d->busFilters.removeAll(busFilter); } diff --git a/src/gsttools/qgstreamerplayersession.cpp b/src/gsttools/qgstreamerplayersession.cpp index ed3f16c5f..c6d2df810 100644 --- a/src/gsttools/qgstreamerplayersession.cpp +++ b/src/gsttools/qgstreamerplayersession.cpp @@ -118,7 +118,7 @@ QGstreamerPlayerSession::QGstreamerPlayerSession(QObject *parent) void QGstreamerPlayerSession::initPlaybin() { - m_playbin = gst_element_factory_make(QT_GSTREAMER_PLAYBIN_ELEMENT_NAME, NULL); + m_playbin = gst_element_factory_make(QT_GSTREAMER_PLAYBIN_ELEMENT_NAME, nullptr); if (m_playbin) { //GST_PLAY_FLAG_NATIVE_VIDEO omits configuration of ffmpegcolorspace and videoscale, //since those elements are included in the video output bin when necessary. @@ -131,7 +131,7 @@ void QGstreamerPlayerSession::initPlaybin() flags |= GST_PLAY_FLAG_NATIVE_VIDEO; #endif } - g_object_set(G_OBJECT(m_playbin), "flags", flags, NULL); + g_object_set(G_OBJECT(m_playbin), "flags", flags, nullptr); const QByteArray envAudioSink = qgetenv("QT_GSTREAMER_PLAYBIN_AUDIOSINK"); GstElement *audioSink = gst_element_factory_make(envAudioSink.isEmpty() ? "autoaudiosink" : envAudioSink, "audiosink"); @@ -144,7 +144,7 @@ void QGstreamerPlayerSession::initPlaybin() if (m_volumeElement) { m_audioSink = gst_bin_new("audio-output-bin"); - gst_bin_add_many(GST_BIN(m_audioSink), m_volumeElement, audioSink, NULL); + gst_bin_add_many(GST_BIN(m_audioSink), m_volumeElement, audioSink, nullptr); gst_element_link(m_volumeElement, audioSink); GstPad *pad = gst_element_get_static_pad(m_volumeElement, "sink"); @@ -156,13 +156,13 @@ void QGstreamerPlayerSession::initPlaybin() } } - g_object_set(G_OBJECT(m_playbin), "audio-sink", m_audioSink, NULL); + g_object_set(G_OBJECT(m_playbin), "audio-sink", m_audioSink, nullptr); addAudioBufferProbe(); } } #if GST_CHECK_VERSION(1,0,0) - m_videoIdentity = gst_element_factory_make("identity", NULL); // floating ref + m_videoIdentity = gst_element_factory_make("identity", nullptr); // floating ref #else m_videoIdentity = GST_ELEMENT(g_object_new(gst_video_connector_get_type(), 0)); // floating ref g_signal_connect(G_OBJECT(m_videoIdentity), "connection-failed", G_CALLBACK(insertColorSpaceElement), (gpointer)this); @@ -172,8 +172,8 @@ void QGstreamerPlayerSession::initPlaybin() qt_gst_object_ref_sink(GST_OBJECT(m_colorSpace)); #endif - m_nullVideoSink = gst_element_factory_make("fakesink", NULL); - g_object_set(G_OBJECT(m_nullVideoSink), "sync", true, NULL); + m_nullVideoSink = gst_element_factory_make("fakesink", nullptr); + g_object_set(G_OBJECT(m_nullVideoSink), "sync", true, nullptr); gst_object_ref(GST_OBJECT(m_nullVideoSink)); m_videoOutputBin = gst_bin_new("video-output-bin"); @@ -183,15 +183,15 @@ void QGstreamerPlayerSession::initPlaybin() GstElement *videoOutputSink = m_videoIdentity; #if QT_CONFIG(gstreamer_gl) if (QGstUtils::useOpenGL()) { - videoOutputSink = gst_element_factory_make("glupload", NULL); - GstElement *colorConvert = gst_element_factory_make("glcolorconvert", NULL); - gst_bin_add_many(GST_BIN(m_videoOutputBin), videoOutputSink, colorConvert, m_videoIdentity, m_nullVideoSink, NULL); - gst_element_link_many(videoOutputSink, colorConvert, m_videoIdentity, NULL); + videoOutputSink = gst_element_factory_make("glupload", nullptr); + GstElement *colorConvert = gst_element_factory_make("glcolorconvert", nullptr); + gst_bin_add_many(GST_BIN(m_videoOutputBin), videoOutputSink, colorConvert, m_videoIdentity, m_nullVideoSink, nullptr); + gst_element_link_many(videoOutputSink, colorConvert, m_videoIdentity, nullptr); } else { - gst_bin_add_many(GST_BIN(m_videoOutputBin), m_videoIdentity, m_nullVideoSink, NULL); + gst_bin_add_many(GST_BIN(m_videoOutputBin), m_videoIdentity, m_nullVideoSink, nullptr); } #else - gst_bin_add_many(GST_BIN(m_videoOutputBin), m_videoIdentity, m_nullVideoSink, NULL); + gst_bin_add_many(GST_BIN(m_videoOutputBin), m_videoIdentity, m_nullVideoSink, nullptr); #endif gst_element_link(m_videoIdentity, m_nullVideoSink); @@ -206,7 +206,7 @@ void QGstreamerPlayerSession::initPlaybin() // Sort out messages setBus(gst_element_get_bus(m_playbin)); - g_object_set(G_OBJECT(m_playbin), "video-sink", m_videoOutputBin, NULL); + g_object_set(G_OBJECT(m_playbin), "video-sink", m_videoOutputBin, nullptr); g_signal_connect(G_OBJECT(m_playbin), "notify::source", G_CALLBACK(playbinNotifySource), this); g_signal_connect(G_OBJECT(m_playbin), "element-added", G_CALLBACK(handleElementAdded), this); @@ -287,7 +287,7 @@ void QGstreamerPlayerSession::configureAppSrcElement(GObject* object, GObject *o return; GstElement *appsrc; - g_object_get(orig, "source", &appsrc, NULL); + g_object_get(orig, "source", &appsrc, nullptr); if (!self->appsrc()->setup(appsrc)) qWarning()<<"Could not setup appsrc element"; @@ -314,7 +314,7 @@ void QGstreamerPlayerSession::loadFromStream(const QNetworkRequest &request, QIO m_tags.clear(); emit tagsChanged(); - g_object_set(G_OBJECT(m_playbin), "uri", "appsrc://", NULL); + g_object_set(G_OBJECT(m_playbin), "uri", "appsrc://", nullptr); if (!m_streamTypes.isEmpty()) { m_streamProperties.clear(); @@ -346,7 +346,7 @@ void QGstreamerPlayerSession::loadFromUri(const QNetworkRequest &request) m_tags.clear(); emit tagsChanged(); - g_object_set(G_OBJECT(m_playbin), "uri", m_request.url().toEncoded().constData(), NULL); + g_object_set(G_OBJECT(m_playbin), "uri", m_request.url().toEncoded().constData(), nullptr); if (!m_streamTypes.isEmpty()) { m_streamProperties.clear(); @@ -497,7 +497,7 @@ void QGstreamerPlayerSession::setPlaybackRate(qreal rate) gst_element_seek(m_pipeline, rate, GST_FORMAT_TIME, GstSeekFlags(GST_SEEK_FLAG_FLUSH), GST_SEEK_TYPE_NONE,0, - GST_SEEK_TYPE_NONE,0 ); + GST_SEEK_TYPE_END, 0); } emit playbackRateChanged(m_playbackRate); } @@ -547,13 +547,13 @@ int QGstreamerPlayerSession::activeStream(QMediaStreamsControl::StreamType strea if (m_playbin) { switch (streamType) { case QMediaStreamsControl::AudioStream: - g_object_get(G_OBJECT(m_playbin), "current-audio", &streamNumber, NULL); + g_object_get(G_OBJECT(m_playbin), "current-audio", &streamNumber, nullptr); break; case QMediaStreamsControl::VideoStream: - g_object_get(G_OBJECT(m_playbin), "current-video", &streamNumber, NULL); + g_object_get(G_OBJECT(m_playbin), "current-video", &streamNumber, nullptr); break; case QMediaStreamsControl::SubPictureStream: - g_object_get(G_OBJECT(m_playbin), "current-text", &streamNumber, NULL); + g_object_get(G_OBJECT(m_playbin), "current-text", &streamNumber, nullptr); break; default: break; @@ -578,13 +578,13 @@ void QGstreamerPlayerSession::setActiveStream(QMediaStreamsControl::StreamType s if (m_playbin) { switch (streamType) { case QMediaStreamsControl::AudioStream: - g_object_set(G_OBJECT(m_playbin), "current-audio", streamNumber, NULL); + g_object_set(G_OBJECT(m_playbin), "current-audio", streamNumber, nullptr); break; case QMediaStreamsControl::VideoStream: - g_object_set(G_OBJECT(m_playbin), "current-video", streamNumber, NULL); + g_object_set(G_OBJECT(m_playbin), "current-video", streamNumber, nullptr); break; case QMediaStreamsControl::SubPictureStream: - g_object_set(G_OBJECT(m_playbin), "current-text", streamNumber, NULL); + g_object_set(G_OBJECT(m_playbin), "current-text", streamNumber, nullptr); break; default: break; @@ -666,9 +666,7 @@ void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput) } } - QGstreamerVideoRendererInterface* renderer = qobject_cast<QGstreamerVideoRendererInterface*>(videoOutput); - - m_renderer = renderer; + m_renderer = qobject_cast<QGstreamerVideoRendererInterface*>(videoOutput); emit rendererChanged(); // No sense to continue if custom pipeline requested. @@ -737,7 +735,7 @@ void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput) qDebug() << "Failed to connect video output, inserting the colorspace element."; #endif gst_bin_add(GST_BIN(m_videoOutputBin), m_colorSpace); - linked = gst_element_link_many(m_videoIdentity, m_colorSpace, m_videoSink, NULL); + linked = gst_element_link_many(m_videoIdentity, m_colorSpace, m_videoSink, nullptr); } #endif @@ -746,7 +744,7 @@ void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput) if (g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "show-preroll-frame") != 0) { gboolean value = m_displayPrerolledFrame; - g_object_set(G_OBJECT(m_videoSink), "show-preroll-frame", value, NULL); + g_object_set(G_OBJECT(m_videoSink), "show-preroll-frame", value, nullptr); } addVideoBufferProbe(); @@ -782,7 +780,7 @@ void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput) //block pads, async to avoid locking in paused state GstPad *srcPad = gst_element_get_static_pad(m_videoIdentity, "src"); #if GST_CHECK_VERSION(1,0,0) - this->pad_probe_id = gst_pad_add_probe(srcPad, (GstPadProbeType)(GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BLOCKING), block_pad_cb, this, NULL); + this->pad_probe_id = gst_pad_add_probe(srcPad, (GstPadProbeType)(GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_BLOCKING), block_pad_cb, this, nullptr); #else gst_pad_set_blocked_async(srcPad, true, &block_pad_cb, this); #endif @@ -815,7 +813,7 @@ void QGstreamerPlayerSession::finishVideoOutputChange() //pad is not blocked, it's possible to swap outputs only in the null state qWarning() << "Pad is not blocked yet, could not switch video sink"; GstState identityElementState = GST_STATE_NULL; - gst_element_get_state(m_videoIdentity, &identityElementState, NULL, GST_CLOCK_TIME_NONE); + gst_element_get_state(m_videoIdentity, &identityElementState, nullptr, GST_CLOCK_TIME_NONE); if (identityElementState != GST_STATE_NULL) { gst_object_unref(GST_OBJECT(srcPad)); return; //can't change vo yet, received async call from the previous change @@ -873,7 +871,7 @@ void QGstreamerPlayerSession::finishVideoOutputChange() qDebug() << "Failed to connect video output, inserting the colorspace element."; #endif gst_bin_add(GST_BIN(m_videoOutputBin), m_colorSpace); - linked = gst_element_link_many(m_videoIdentity, m_colorSpace, m_videoSink, NULL); + linked = gst_element_link_many(m_videoIdentity, m_colorSpace, m_videoSink, nullptr); } #endif @@ -964,7 +962,7 @@ void QGstreamerPlayerSession::insertColorSpaceElement(GstElement *element, gpoin gst_element_unlink(session->m_videoIdentity, session->m_videoSink); gst_bin_add(GST_BIN(session->m_videoOutputBin), session->m_colorSpace); - gst_element_link_many(session->m_videoIdentity, session->m_colorSpace, session->m_videoSink, NULL); + gst_element_link_many(session->m_videoIdentity, session->m_colorSpace, session->m_videoSink, nullptr); GstState state = GST_STATE_VOID_PENDING; @@ -1108,7 +1106,7 @@ void QGstreamerPlayerSession::setVolume(int volume) m_volume = volume; if (m_volumeElement) - g_object_set(G_OBJECT(m_volumeElement), "volume", m_volume / 100.0, NULL); + g_object_set(G_OBJECT(m_volumeElement), "volume", m_volume / 100.0, nullptr); emit volumeChanged(m_volume); } @@ -1123,7 +1121,7 @@ void QGstreamerPlayerSession::setMuted(bool muted) m_muted = muted; if (m_volumeElement) - g_object_set(G_OBJECT(m_volumeElement), "mute", m_muted ? TRUE : FALSE, NULL); + g_object_set(G_OBJECT(m_volumeElement), "mute", m_muted ? TRUE : FALSE, nullptr); emit mutedStateChanged(m_muted); } @@ -1455,9 +1453,9 @@ void QGstreamerPlayerSession::getStreamsInfo() gint videoStreamsCount = 0; gint textStreamsCount = 0; - g_object_get(G_OBJECT(m_playbin), "n-audio", &audioStreamsCount, NULL); - g_object_get(G_OBJECT(m_playbin), "n-video", &videoStreamsCount, NULL); - g_object_get(G_OBJECT(m_playbin), "n-text", &textStreamsCount, NULL); + g_object_get(G_OBJECT(m_playbin), "n-audio", &audioStreamsCount, nullptr); + g_object_get(G_OBJECT(m_playbin), "n-video", &videoStreamsCount, nullptr); + g_object_get(G_OBJECT(m_playbin), "n-text", &textStreamsCount, nullptr); haveAudio = audioStreamsCount > 0; haveVideo = videoStreamsCount > 0; @@ -1617,7 +1615,7 @@ void QGstreamerPlayerSession::playbinNotifySource(GObject *o, GParamSpec *p, gpo Q_UNUSED(p); GstElement *source = 0; - g_object_get(o, "source", &source, NULL); + g_object_get(o, "source", &source, nullptr); if (source == 0) return; @@ -1634,7 +1632,7 @@ void QGstreamerPlayerSession::playbinNotifySource(GObject *o, GParamSpec *p, gpo // defined in extra-headers if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "user-agent") != 0) { g_object_set(G_OBJECT(source), "user-agent", - self->m_request.rawHeader(userAgentString).constData(), NULL); + self->m_request.rawHeader(userAgentString).constData(), nullptr); } // The rest @@ -1659,7 +1657,7 @@ void QGstreamerPlayerSession::playbinNotifySource(GObject *o, GParamSpec *p, gpo } if (gst_structure_n_fields(extras) > 0) - g_object_set(G_OBJECT(source), "extra-headers", extras, NULL); + g_object_set(G_OBJECT(source), "extra-headers", extras, nullptr); gst_structure_free(extras); } @@ -1675,7 +1673,7 @@ void QGstreamerPlayerSession::playbinNotifySource(GObject *o, GParamSpec *p, gpo // Gst 0.10 -> microsecond convertedTimeout *= 1000000; #endif - g_object_set(G_OBJECT(source), "timeout", convertedTimeout, NULL); + g_object_set(G_OBJECT(source), "timeout", convertedTimeout, nullptr); self->m_sourceType = UDPSrc; //The udpsrc is always a live source. self->m_isLiveSource = true; @@ -1684,26 +1682,26 @@ void QGstreamerPlayerSession::playbinNotifySource(GObject *o, GParamSpec *p, gpo const QString var = QLatin1String("udpsrc.caps"); if (query.hasQueryItem(var)) { GstCaps *caps = gst_caps_from_string(query.queryItemValue(var).toLatin1().constData()); - g_object_set(G_OBJECT(source), "caps", caps, NULL); + g_object_set(G_OBJECT(source), "caps", caps, nullptr); gst_caps_unref(caps); } } else if (qstrcmp(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)), "GstSoupHTTPSrc") == 0) { //souphttpsrc timeout unit = second - g_object_set(G_OBJECT(source), "timeout", guint(timeout), NULL); + g_object_set(G_OBJECT(source), "timeout", guint(timeout), nullptr); self->m_sourceType = SoupHTTPSrc; //since gst_base_src_is_live is not reliable, so we check the source property directly gboolean isLive = false; - g_object_get(G_OBJECT(source), "is-live", &isLive, NULL); + g_object_get(G_OBJECT(source), "is-live", &isLive, nullptr); self->m_isLiveSource = isLive; } else if (qstrcmp(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)), "GstMMSSrc") == 0) { self->m_sourceType = MMSSrc; self->m_isLiveSource = gst_base_src_is_live(GST_BASE_SRC(source)); - g_object_set(G_OBJECT(source), "tcp-timeout", G_GUINT64_CONSTANT(timeout*1000000), NULL); + g_object_set(G_OBJECT(source), "tcp-timeout", G_GUINT64_CONSTANT(timeout*1000000), nullptr); } else if (qstrcmp(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)), "GstRTSPSrc") == 0) { //rtspsrc acts like a live source and will therefore only generate data in the PLAYING state. self->m_sourceType = RTSPSrc; self->m_isLiveSource = true; - g_object_set(G_OBJECT(source), "buffer-mode", 1, NULL); + g_object_set(G_OBJECT(source), "buffer-mode", 1, nullptr); } else { self->m_sourceType = UnknownSrc; self->m_isLiveSource = gst_base_src_is_live(GST_BASE_SRC(source)); @@ -1717,7 +1715,7 @@ void QGstreamerPlayerSession::playbinNotifySource(GObject *o, GParamSpec *p, gpo #endif if (self->m_videoSink) - g_object_set(G_OBJECT(self->m_videoSink), "sync", !self->m_isLiveSource, NULL); + g_object_set(G_OBJECT(self->m_videoSink), "sync", !self->m_isLiveSource, nullptr); gst_object_unref(source); } @@ -1738,7 +1736,7 @@ void QGstreamerPlayerSession::handleVolumeChange(GObject *o, GParamSpec *p, gpoi void QGstreamerPlayerSession::updateVolume() { double volume = 1.0; - g_object_get(m_playbin, "volume", &volume, NULL); + g_object_get(m_playbin, "volume", &volume, nullptr); if (m_volume != int(volume*100 + 0.5)) { m_volume = int(volume*100 + 0.5); @@ -1760,7 +1758,7 @@ void QGstreamerPlayerSession::handleMutedChange(GObject *o, GParamSpec *p, gpoin void QGstreamerPlayerSession::updateMuted() { gboolean muted = FALSE; - g_object_get(G_OBJECT(m_playbin), "mute", &muted, NULL); + g_object_get(G_OBJECT(m_playbin), "mute", &muted, nullptr); if (m_muted != muted) { m_muted = muted; #ifdef DEBUG_PLAYBIN @@ -1775,8 +1773,8 @@ static gboolean factory_can_src_any_caps (GstElementFactory *factory, const GstC { GList *templates; - g_return_val_if_fail(factory != NULL, FALSE); - g_return_val_if_fail(caps != NULL, FALSE); + g_return_val_if_fail(factory != nullptr, FALSE); + g_return_val_if_fail(caps != nullptr, FALSE); templates = factory->staticpadtemplates; @@ -1813,7 +1811,7 @@ GstAutoplugSelectResult QGstreamerPlayerSession::handleAutoplugSelect(GstBin *bi if (g_str_has_prefix(factoryName, "vaapi")) { GstPad *sinkPad = gst_element_get_static_pad(session->m_videoSink, "sink"); #if GST_CHECK_VERSION(1,0,0) - GstCaps *sinkCaps = gst_pad_query_caps(sinkPad, NULL); + GstCaps *sinkCaps = gst_pad_query_caps(sinkPad, nullptr); #else GstCaps *sinkCaps = gst_pad_get_caps(sinkPad); #endif @@ -1843,7 +1841,7 @@ void QGstreamerPlayerSession::handleElementAdded(GstBin *bin, GstElement *elemen if (g_str_has_prefix(elementName, "queue2")) { // Disable on-disk buffering. - g_object_set(G_OBJECT(element), "temp-template", NULL, NULL); + g_object_set(G_OBJECT(element), "temp-template", nullptr, nullptr); } else if (g_str_has_prefix(elementName, "uridecodebin") || #if GST_CHECK_VERSION(1,0,0) g_str_has_prefix(elementName, "decodebin")) { @@ -1851,7 +1849,7 @@ void QGstreamerPlayerSession::handleElementAdded(GstBin *bin, GstElement *elemen g_str_has_prefix(elementName, "decodebin2")) { if (g_str_has_prefix(elementName, "uridecodebin")) { // Add video/x-surface (VAAPI) to default raw formats - g_object_set(G_OBJECT(element), "caps", gst_static_caps_get(&static_RawCaps), NULL); + g_object_set(G_OBJECT(element), "caps", gst_static_caps_get(&static_RawCaps), nullptr); // listen for uridecodebin autoplug-select to skip VAAPI usage when the current // video sink doesn't support it g_signal_connect(element, "autoplug-select", G_CALLBACK(handleAutoplugSelect), session); @@ -1894,7 +1892,7 @@ void QGstreamerPlayerSession::showPrerollFrames(bool enabled) g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), "show-preroll-frame") != 0) { gboolean value = enabled; - g_object_set(G_OBJECT(m_videoSink), "show-preroll-frame", value, NULL); + g_object_set(G_OBJECT(m_videoSink), "show-preroll-frame", value, nullptr); m_displayPrerolledFrame = enabled; } } diff --git a/src/gsttools/qgstreamervideooverlay.cpp b/src/gsttools/qgstreamervideooverlay.cpp index 6b862e475..d410be7d9 100644 --- a/src/gsttools/qgstreamervideooverlay.cpp +++ b/src/gsttools/qgstreamervideooverlay.cpp @@ -122,7 +122,7 @@ public: { int brightness = 0; if (m_hasBrightness) - g_object_get(G_OBJECT(m_videoSink), "brightness", &brightness, NULL); + g_object_get(G_OBJECT(m_videoSink), "brightness", &brightness, nullptr); return brightness / 10; } @@ -131,7 +131,7 @@ public: { m_brightness = brightness; if (m_hasBrightness) - g_object_set(G_OBJECT(m_videoSink), "brightness", brightness * 10, NULL); + g_object_set(G_OBJECT(m_videoSink), "brightness", brightness * 10, nullptr); return m_hasBrightness; } @@ -140,7 +140,7 @@ public: { int contrast = 0; if (m_hasContrast) - g_object_get(G_OBJECT(m_videoSink), "contrast", &contrast, NULL); + g_object_get(G_OBJECT(m_videoSink), "contrast", &contrast, nullptr); return contrast / 10; } @@ -149,7 +149,7 @@ public: { m_contrast = contrast; if (m_hasContrast) - g_object_set(G_OBJECT(m_videoSink), "contrast", contrast * 10, NULL); + g_object_set(G_OBJECT(m_videoSink), "contrast", contrast * 10, nullptr); return m_hasContrast; } @@ -158,7 +158,7 @@ public: { int hue = 0; if (m_hasHue) - g_object_get(G_OBJECT(m_videoSink), "hue", &hue, NULL); + g_object_get(G_OBJECT(m_videoSink), "hue", &hue, nullptr); return hue / 10; } @@ -167,7 +167,7 @@ public: { m_hue = hue; if (m_hasHue) - g_object_set(G_OBJECT(m_videoSink), "hue", hue * 10, NULL); + g_object_set(G_OBJECT(m_videoSink), "hue", hue * 10, nullptr); return m_hasHue; } @@ -176,7 +176,7 @@ public: { int saturation = 0; if (m_hasSaturation) - g_object_get(G_OBJECT(m_videoSink), "saturation", &saturation, NULL); + g_object_get(G_OBJECT(m_videoSink), "saturation", &saturation, nullptr); return saturation / 10; } @@ -185,7 +185,7 @@ public: { m_saturation = saturation; if (m_hasSaturation) - g_object_set(G_OBJECT(m_videoSink), "saturation", saturation * 10, NULL); + g_object_set(G_OBJECT(m_videoSink), "saturation", saturation * 10, nullptr); return m_hasSaturation; } @@ -195,7 +195,7 @@ public: Qt::AspectRatioMode mode = Qt::KeepAspectRatio; if (m_hasForceAspectRatio) { gboolean forceAR = false; - g_object_get(G_OBJECT(m_videoSink), "force-aspect-ratio", &forceAR, NULL); + g_object_get(G_OBJECT(m_videoSink), "force-aspect-ratio", &forceAR, nullptr); if (!forceAR) mode = Qt::IgnoreAspectRatio; } @@ -210,7 +210,7 @@ public: g_object_set(G_OBJECT(m_videoSink), "force-aspect-ratio", (mode == Qt::KeepAspectRatio), - (const char*)NULL); + nullptr); } } @@ -245,7 +245,7 @@ public: { gfloat brightness = 0; if (m_hasBrightness) - g_object_get(G_OBJECT(m_videoSink), "brightness", &brightness, NULL); + g_object_get(G_OBJECT(m_videoSink), "brightness", &brightness, nullptr); return brightness * 100; // [-1,1] -> [-100,100] } @@ -255,7 +255,7 @@ public: m_brightness = brightness; if (m_hasBrightness) { gfloat v = brightness / 100.0; // [-100,100] -> [-1,1] - g_object_set(G_OBJECT(m_videoSink), "brightness", v, NULL); + g_object_set(G_OBJECT(m_videoSink), "brightness", v, nullptr); } return m_hasBrightness; @@ -265,7 +265,7 @@ public: { gfloat contrast = 1; if (m_hasContrast) - g_object_get(G_OBJECT(m_videoSink), "contrast", &contrast, NULL); + g_object_get(G_OBJECT(m_videoSink), "contrast", &contrast, nullptr); return (contrast - 1) * 100; // [0,2] -> [-100,100] } @@ -275,7 +275,7 @@ public: m_contrast = contrast; if (m_hasContrast) { gfloat v = (contrast / 100.0) + 1; // [-100,100] -> [0,2] - g_object_set(G_OBJECT(m_videoSink), "contrast", v, NULL); + g_object_set(G_OBJECT(m_videoSink), "contrast", v, nullptr); } return m_hasContrast; @@ -285,7 +285,7 @@ public: { gfloat hue = 0; if (m_hasHue) - g_object_get(G_OBJECT(m_videoSink), "hue", &hue, NULL); + g_object_get(G_OBJECT(m_videoSink), "hue", &hue, nullptr); return hue / 180 * 100; // [-180,180] -> [-100,100] } @@ -295,7 +295,7 @@ public: m_hue = hue; if (m_hasHue) { gfloat v = hue / 100.0 * 180; // [-100,100] -> [-180,180] - g_object_set(G_OBJECT(m_videoSink), "hue", v, NULL); + g_object_set(G_OBJECT(m_videoSink), "hue", v, nullptr); } return m_hasHue; @@ -305,7 +305,7 @@ public: { gfloat saturation = 1; if (m_hasSaturation) - g_object_get(G_OBJECT(m_videoSink), "saturation", &saturation, NULL); + g_object_get(G_OBJECT(m_videoSink), "saturation", &saturation, nullptr); return (saturation - 1) * 100; // [0,2] -> [-100,100] } @@ -315,7 +315,7 @@ public: m_saturation = saturation; if (m_hasSaturation) { gfloat v = (saturation / 100.0) + 1; // [-100,100] -> [0,2] - g_object_set(G_OBJECT(m_videoSink), "saturation", v, NULL); + g_object_set(G_OBJECT(m_videoSink), "saturation", v, nullptr); } return m_hasSaturation; @@ -350,7 +350,7 @@ static GstElement *findBestVideoSink() continue; #endif if (platform == QLatin1String(elementMap[i].qtPlatform) - && (choice = gst_element_factory_make(elementMap[i].gstreamerElement, NULL))) { + && (choice = gst_element_factory_make(elementMap[i].gstreamerElement, nullptr))) { if (qt_gst_element_is_functioning(choice)) return choice; @@ -363,13 +363,13 @@ static GstElement *findBestVideoSink() // If none of the known video sinks are available, try to find one that implements the // GstVideoOverlay interface and has autoplugging rank. GList *list = qt_gst_video_sinks(); - for (GList *item = list; item != NULL; item = item->next) { + for (GList *item = list; item != nullptr; item = item->next) { GstElementFactory *f = GST_ELEMENT_FACTORY(item->data); if (!gst_element_factory_has_interface(f, QT_GSTREAMER_VIDEOOVERLAY_INTERFACE_NAME)) continue; - if (GstElement *el = gst_element_factory_create(f, NULL)) { + if (GstElement *el = gst_element_factory_create(f, nullptr)) { if (qt_gst_element_is_functioning(el)) { choice = el; break; @@ -390,7 +390,7 @@ QGstreamerVideoOverlay::QGstreamerVideoOverlay(QObject *parent, const QByteArray { GstElement *sink = nullptr; if (!elementName.isEmpty()) - sink = gst_element_factory_make(elementName.constData(), NULL); + sink = gst_element_factory_make(elementName.constData(), nullptr); else sink = findBestVideoSink(); @@ -567,7 +567,7 @@ void QGstreamerVideoOverlay::updateIsActive() gboolean showPreroll = true; if (m_sinkProperties->hasShowPrerollFrame()) - g_object_get(G_OBJECT(m_videoSink), "show-preroll-frame", &showPreroll, NULL); + g_object_get(G_OBJECT(m_videoSink), "show-preroll-frame", &showPreroll, nullptr); bool newIsActive = (state == GST_STATE_PLAYING || (state == GST_STATE_PAUSED && showPreroll)); diff --git a/src/gsttools/qgstutils.cpp b/src/gsttools/qgstutils.cpp index f8a9d79c1..f998c4309 100644 --- a/src/gsttools/qgstutils.cpp +++ b/src/gsttools/qgstutils.cpp @@ -424,7 +424,7 @@ GstCaps *QGstUtils::capsForAudioFormat(const QAudioFormat &format) "format" , G_TYPE_STRING, gst_audio_format_to_string(qt_audioLookup[i].format), "rate" , G_TYPE_INT , format.sampleRate(), "channels", G_TYPE_INT , format.channelCount(), - NULL); + nullptr); } return 0; #else @@ -432,29 +432,29 @@ GstCaps *QGstUtils::capsForAudioFormat(const QAudioFormat &format) if (format.isValid()) { if (format.sampleType() == QAudioFormat::SignedInt || format.sampleType() == QAudioFormat::UnSignedInt) { - structure = gst_structure_new("audio/x-raw-int", NULL); + structure = gst_structure_new("audio/x-raw-int", nullptr); } else if (format.sampleType() == QAudioFormat::Float) { - structure = gst_structure_new("audio/x-raw-float", NULL); + structure = gst_structure_new("audio/x-raw-float", nullptr); } } GstCaps *caps = 0; if (structure) { - gst_structure_set(structure, "rate", G_TYPE_INT, format.sampleRate(), NULL); - gst_structure_set(structure, "channels", G_TYPE_INT, format.channelCount(), NULL); - gst_structure_set(structure, "width", G_TYPE_INT, format.sampleSize(), NULL); - gst_structure_set(structure, "depth", G_TYPE_INT, format.sampleSize(), NULL); + gst_structure_set(structure, "rate", G_TYPE_INT, format.sampleRate(), nullptr); + gst_structure_set(structure, "channels", G_TYPE_INT, format.channelCount(), nullptr); + gst_structure_set(structure, "width", G_TYPE_INT, format.sampleSize(), nullptr); + gst_structure_set(structure, "depth", G_TYPE_INT, format.sampleSize(), nullptr); if (format.byteOrder() == QAudioFormat::LittleEndian) - gst_structure_set(structure, "endianness", G_TYPE_INT, 1234, NULL); + gst_structure_set(structure, "endianness", G_TYPE_INT, 1234, nullptr); else if (format.byteOrder() == QAudioFormat::BigEndian) - gst_structure_set(structure, "endianness", G_TYPE_INT, 4321, NULL); + gst_structure_set(structure, "endianness", G_TYPE_INT, 4321, nullptr); if (format.sampleType() == QAudioFormat::SignedInt) - gst_structure_set(structure, "signed", G_TYPE_BOOLEAN, TRUE, NULL); + gst_structure_set(structure, "signed", G_TYPE_BOOLEAN, TRUE, nullptr); else if (format.sampleType() == QAudioFormat::UnSignedInt) - gst_structure_set(structure, "signed", G_TYPE_BOOLEAN, FALSE, NULL); + gst_structure_set(structure, "signed", G_TYPE_BOOLEAN, FALSE, nullptr); caps = gst_caps_new_empty(); Q_ASSERT(caps); @@ -470,7 +470,7 @@ void QGstUtils::initializeGst() static bool initialized = false; if (!initialized) { initialized = true; - gst_init(NULL, NULL); + gst_init(nullptr, nullptr); } } @@ -606,8 +606,8 @@ QVector<QGstUtils::CameraInfo> QGstUtils::enumerateCameras(GstElementFactory *fa // no-op } else for (int i = 0; i < 2; ++i) { gint orientation = 0; - g_object_set(G_OBJECT(camera), "camera-device", i, NULL); - g_object_get(G_OBJECT(camera), "sensor-mount-angle", &orientation, NULL); + g_object_set(G_OBJECT(camera), "camera-device", i, nullptr); + g_object_get(G_OBJECT(camera), "sensor-mount-angle", &orientation, nullptr); devices[i].orientation = (720 - orientation) % 360; } @@ -807,7 +807,7 @@ QSet<QString> QGstUtils::supportedMimeTypes(bool (*isValidFactory)(GstElementFac QSet<QString> supportedMimeTypes; //enumerate supported mime types - gst_init(NULL, NULL); + gst_init(nullptr, nullptr); #if GST_CHECK_VERSION(1,0,0) GstRegistry *registry = gst_registry_get(); @@ -829,7 +829,7 @@ QSet<QString> QGstUtils::supportedMimeTypes(bool (*isValidFactory)(GstElementFac GList *orig_features = gst_registry_get_feature_list_by_plugin( registry, gst_plugin_get_name(plugin)); for (GList *features = orig_features; features; features = g_list_next(features)) { - if (G_UNLIKELY(features->data == NULL)) + if (G_UNLIKELY(features->data == nullptr)) continue; GstPluginFeature *feature = GST_PLUGIN_FEATURE(features->data); @@ -1238,7 +1238,7 @@ GstCaps *QGstUtils::capsForFormats(const QList<QVideoFrame::PixelFormat> &format gst_caps_append_structure(caps, gst_structure_new( "video/x-raw", "format" , G_TYPE_STRING, gst_video_format_to_string(qt_videoFormatLookup[index].gstFormat), - NULL)); + nullptr)); } } #else @@ -1249,7 +1249,7 @@ GstCaps *QGstUtils::capsForFormats(const QList<QVideoFrame::PixelFormat> &format gst_caps_append_structure(caps, gst_structure_new( "video/x-raw-yuv", "format", GST_TYPE_FOURCC, qt_yuvColorLookup[index].fourcc, - NULL)); + nullptr)); continue; } @@ -1265,11 +1265,11 @@ GstCaps *QGstUtils::capsForFormats(const QList<QVideoFrame::PixelFormat> &format "red_mask" , G_TYPE_INT, qt_rgbColorLookup[i].red, "green_mask", G_TYPE_INT, qt_rgbColorLookup[i].green, "blue_mask" , G_TYPE_INT, qt_rgbColorLookup[i].blue, - NULL); + nullptr); if (qt_rgbColorLookup[i].alpha != 0) { gst_structure_set( - structure, "alpha_mask", G_TYPE_INT, qt_rgbColorLookup[i].alpha, NULL); + structure, "alpha_mask", G_TYPE_INT, qt_rgbColorLookup[i].alpha, nullptr); } gst_caps_append_structure(caps, structure); } @@ -1282,7 +1282,7 @@ GstCaps *QGstUtils::capsForFormats(const QList<QVideoFrame::PixelFormat> &format "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, INT_MAX, 1, "width" , GST_TYPE_INT_RANGE, 1, INT_MAX, "height" , GST_TYPE_INT_RANGE, 1, INT_MAX, - NULL); + nullptr); return caps; } @@ -1317,7 +1317,7 @@ void QGstUtils::setMetaData(GstElement *element, const QMap<QByteArray, QVariant GST_TAG_MERGE_REPLACE, tagName.toUtf8().constData(), tagValue.toString().toUtf8().constData(), - NULL); + nullptr); break; case QVariant::Int: case QVariant::LongLong: @@ -1325,14 +1325,14 @@ void QGstUtils::setMetaData(GstElement *element, const QMap<QByteArray, QVariant GST_TAG_MERGE_REPLACE, tagName.toUtf8().constData(), tagValue.toInt(), - NULL); + nullptr); break; case QVariant::Double: gst_tag_setter_add_tags(GST_TAG_SETTER(element), GST_TAG_MERGE_REPLACE, tagName.toUtf8().constData(), tagValue.toDouble(), - NULL); + nullptr); break; #if GST_CHECK_VERSION(0, 10, 31) case QVariant::DateTime: { @@ -1343,7 +1343,7 @@ void QGstUtils::setMetaData(GstElement *element, const QMap<QByteArray, QVariant gst_date_time_new_local_time( date.date().year(), date.date().month(), date.date().day(), date.time().hour(), date.time().minute(), date.time().second()), - NULL); + nullptr); break; } #endif @@ -1604,7 +1604,7 @@ GstCaps *qt_gst_pad_get_current_caps(GstPad *pad) GstCaps *qt_gst_pad_get_caps(GstPad *pad) { #if GST_CHECK_VERSION(1,0,0) - return gst_pad_query_caps(pad, NULL); + return gst_pad_query_caps(pad, nullptr); #elif GST_CHECK_VERSION(0, 10, 26) return gst_pad_get_caps_reffed(pad); #else @@ -1617,7 +1617,7 @@ GstStructure *qt_gst_structure_new_empty(const char *name) #if GST_CHECK_VERSION(1,0,0) return gst_structure_new_empty(name); #else - return gst_structure_new(name, NULL); + return gst_structure_new(name, nullptr); #endif } @@ -1709,7 +1709,7 @@ static gint qt_gst_compare_ranks(GstPluginFeature *f1, GstPluginFeature *f2) GList *qt_gst_video_sinks() { - GList *list = NULL; + GList *list = nullptr; #if GST_CHECK_VERSION(0, 10, 31) list = gst_element_factory_list_get_elements(GST_ELEMENT_FACTORY_TYPE_SINK | GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO, @@ -1717,7 +1717,7 @@ GList *qt_gst_video_sinks() #else list = gst_registry_feature_filter(gst_registry_get_default(), (GstPluginFeatureFilter)qt_gst_videosink_factory_filter, - FALSE, NULL); + FALSE, nullptr); list = g_list_sort(list, (GCompareFunc)qt_gst_compare_ranks); #endif diff --git a/src/gsttools/qgstvideorenderersink.cpp b/src/gsttools/qgstvideorenderersink.cpp index 3b458a978..9eb2531a1 100644 --- a/src/gsttools/qgstvideorenderersink.cpp +++ b/src/gsttools/qgstvideorenderersink.cpp @@ -170,8 +170,8 @@ QVideoSurfaceGstDelegate::QVideoSurfaceGstDelegate(QAbstractVideoSurface *surfac { const auto instances = rendererLoader()->instances(QGstVideoRendererPluginKey); for (QObject *instance : instances) { - QGstVideoRendererInterface* plugin = qobject_cast<QGstVideoRendererInterface*>(instance); - if (QGstVideoRenderer *renderer = plugin ? plugin->createRenderer() : 0) + auto plugin = qobject_cast<QGstVideoRendererInterface*>(instance); + if (QGstVideoRenderer *renderer = plugin ? plugin->createRenderer() : nullptr) m_renderers.append(renderer); } @@ -304,7 +304,7 @@ GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer) #if QT_CONFIG(gstreamer_gl) static GstGLContext *gstGLDisplayContext(QAbstractVideoSurface *surface) { - QOpenGLContext *glContext = qobject_cast<QOpenGLContext*>(surface->property("GLContext").value<QObject*>()); + auto glContext = qobject_cast<QOpenGLContext*>(surface->property("GLContext").value<QObject*>()); // Context is not ready yet. if (!glContext) return nullptr; @@ -360,7 +360,7 @@ static GstGLContext *gstGLDisplayContext(QAbstractVideoSurface *surface) qWarning() << "Could not create wrappped context for platform:" << glPlatform; GstGLContext *displayContext = nullptr; - GError *error = NULL; + GError *error = nullptr; gst_gl_display_create_context(display, appContext, &displayContext, &error); if (error) { qWarning() << "Could not create display context:" << error->message; @@ -393,14 +393,14 @@ bool QVideoSurfaceGstDelegate::query(GstQuery *query) if (!m_gstGLDisplayContext) return false; - GstContext *context = NULL; + GstContext *context = nullptr; gst_query_parse_context(query, &context); context = context ? gst_context_copy(context) : gst_context_new(type, FALSE); GstStructure *structure = gst_context_writable_structure(context); #if GST_CHECK_VERSION(1,11,1) - gst_structure_set(structure, "context", GST_TYPE_GL_CONTEXT, m_gstGLDisplayContext, NULL); + gst_structure_set(structure, "context", GST_TYPE_GL_CONTEXT, m_gstGLDisplayContext, nullptr); #else - gst_structure_set(structure, "context", GST_GL_TYPE_CONTEXT, m_gstGLDisplayContext, NULL); + gst_structure_set(structure, "context", GST_GL_TYPE_CONTEXT, m_gstGLDisplayContext, nullptr); #endif gst_query_set_context(query, context); gst_context_unref(context); @@ -583,10 +583,10 @@ GType QGstVideoRendererSink::get_type() { sizeof(QGstVideoRendererSinkClass), // class_size base_init, // base_init - NULL, // base_finalize + nullptr, // base_finalize class_init, // class_init - NULL, // class_finalize - NULL, // class_data + nullptr, // class_finalize + nullptr, // class_data sizeof(QGstVideoRendererSink), // instance_size 0, // n_preallocs instance_init, // instance_init @@ -694,12 +694,12 @@ void QGstVideoRendererSink::handleShowPrerollChange(GObject *o, GParamSpec *p, g QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>(d); gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default - g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, NULL); + g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, nullptr); if (!showPrerollFrame) { GstState state = GST_STATE_VOID_PENDING; GstClockTime timeout = 10000000; // 10 ms - gst_element_get_state(GST_ELEMENT(sink), &state, NULL, timeout); + gst_element_get_state(GST_ELEMENT(sink), &state, nullptr, timeout); // show-preroll-frame being set to 'false' while in GST_STATE_PAUSED means // the QMediaPlayer was stopped from the paused state. // We need to flush the current frame. @@ -714,7 +714,7 @@ GstStateChangeReturn QGstVideoRendererSink::change_state( QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>(element); gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default - g_object_get(G_OBJECT(element), "show-preroll-frame", &showPrerollFrame, NULL); + g_object_get(G_OBJECT(element), "show-preroll-frame", &showPrerollFrame, nullptr); // If show-preroll-frame is 'false' when transitioning from GST_STATE_PLAYING to // GST_STATE_PAUSED, it means the QMediaPlayer was stopped. diff --git a/src/gsttools/qvideosurfacegstsink.cpp b/src/gsttools/qvideosurfacegstsink.cpp index c63eea9a6..c6951bdef 100644 --- a/src/gsttools/qvideosurfacegstsink.cpp +++ b/src/gsttools/qvideosurfacegstsink.cpp @@ -69,7 +69,7 @@ QVideoSurfaceGstDelegate::QVideoSurfaceGstDelegate( if (m_surface) { const auto instances = bufferPoolLoader()->instances(QGstBufferPoolPluginKey); for (QObject *instance : instances) { - QGstBufferPoolInterface* plugin = qobject_cast<QGstBufferPoolInterface*>(instance); + auto plugin = qobject_cast<QGstBufferPoolInterface*>(instance); if (plugin) { m_pools.append(plugin); @@ -356,10 +356,10 @@ GType QVideoSurfaceGstSink::get_type() { sizeof(QVideoSurfaceGstSinkClass), // class_size base_init, // base_init - NULL, // base_finalize + nullptr, // base_finalize class_init, // class_init - NULL, // class_finalize - NULL, // class_data + nullptr, // class_finalize + nullptr, // class_data sizeof(QVideoSurfaceGstSink), // instance_size 0, // n_preallocs instance_init, // instance_init @@ -460,11 +460,11 @@ void QVideoSurfaceGstSink::handleShowPrerollChange(GObject *o, GParamSpec *p, gp QVideoSurfaceGstSink *sink = reinterpret_cast<QVideoSurfaceGstSink *>(d); gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default - g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, NULL); + g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, nullptr); if (!showPrerollFrame) { GstState state = GST_STATE_VOID_PENDING; - gst_element_get_state(GST_ELEMENT(sink), &state, NULL, GST_CLOCK_TIME_NONE); + gst_element_get_state(GST_ELEMENT(sink), &state, nullptr, GST_CLOCK_TIME_NONE); // show-preroll-frame being set to 'false' while in GST_STATE_PAUSED means // the QMediaPlayer was stopped from the paused state. // We need to flush the current frame. @@ -478,7 +478,7 @@ GstStateChangeReturn QVideoSurfaceGstSink::change_state(GstElement *element, Gst QVideoSurfaceGstSink *sink = reinterpret_cast<QVideoSurfaceGstSink *>(element); gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default - g_object_get(G_OBJECT(element), "show-preroll-frame", &showPrerollFrame, NULL); + g_object_get(G_OBJECT(element), "show-preroll-frame", &showPrerollFrame, nullptr); // If show-preroll-frame is 'false' when transitioning from GST_STATE_PLAYING to // GST_STATE_PAUSED, it means the QMediaPlayer was stopped. @@ -576,7 +576,7 @@ GstFlowReturn QVideoSurfaceGstSink::buffer_alloc( if (!buffer) return GST_FLOW_ERROR; - *buffer = NULL; + *buffer = nullptr; if (!sink->delegate->pool()) return GST_FLOW_OK; @@ -694,7 +694,7 @@ GstFlowReturn QVideoSurfaceGstSink::preroll(GstBaseSink *base, GstBuffer *buffer { VO_SINK(base); gboolean showPrerollFrame = true; - g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, NULL); + g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, nullptr); if (showPrerollFrame) return sink->delegate->render(buffer); diff --git a/src/imports/multimedia/multimedia.cpp b/src/imports/multimedia/multimedia.cpp index 8aed83d33..0bbe9cae3 100644 --- a/src/imports/multimedia/multimedia.cpp +++ b/src/imports/multimedia/multimedia.cpp @@ -60,6 +60,7 @@ #include "qdeclarativecameraimageprocessing_p.h" #include "qdeclarativecameraviewfinder_p.h" #include "qdeclarativetorch_p.h" +#include <QAbstractVideoSurface> QML_DECLARE_TYPE(QSoundEffect) @@ -160,6 +161,11 @@ public: // 5.13 types qmlRegisterType<QDeclarativeVideoOutput, 13>(uri, 5, 13, "VideoOutput"); + // 5.15 types + qmlRegisterType<QDeclarativeAudio, 15>(uri, 5, 15, "MediaPlayer"); + qmlRegisterType<QDeclarativeVideoOutput, 15>(uri, 5, 15, "VideoOutput"); + qmlRegisterType<QAbstractVideoSurface>(); + // Auto-increment the import to stay in sync with ALL future QtQuick minor versions from 5.11 onward qmlRegisterModule(uri, 5, QT_VERSION_MINOR); } diff --git a/src/imports/multimedia/qdeclarativeaudio.cpp b/src/imports/multimedia/qdeclarativeaudio.cpp index 9d41c77fa..fcba6257d 100644 --- a/src/imports/multimedia/qdeclarativeaudio.cpp +++ b/src/imports/multimedia/qdeclarativeaudio.cpp @@ -45,12 +45,14 @@ #include <qmediaservice.h> #include <private/qmediaserviceprovider_p.h> +#include <private/qdeclarativevideooutput_p.h> #include <qmetadatareadercontrol.h> #include <qmediaavailabilitycontrol.h> #include "qdeclarativeplaylist_p.h" #include "qdeclarativemediametadata_p.h" +#include <QAbstractVideoSurface> #include <QTimerEvent> #include <QtQml/qqmlengine.h> @@ -130,6 +132,63 @@ QDeclarativeAudio::~QDeclarativeAudio() } /*! + \since 5.15 + \qmlproperty url QtMultimedia::MediaPlayer::videoOutput + + This property holds the target video output. + Accepts one or an array of QAbstractVideoSurface or VideoOutput elements. + + \snippet multimedia-snippets/multiple-videooutputs.qml complete + + \sa QMediaPlayer::setVideoOutput() +*/ + +QVariant QDeclarativeAudio::videoOutput() const +{ + return m_videoOutput; +} + +void QDeclarativeAudio::setVideoOutput(const QVariant &v) +{ + if (m_videoOutput == v) + return; + + QAbstractVideoSurface *surface = nullptr; + auto vo = v.value<QDeclarativeVideoOutput *>(); + if (vo) + surface = vo->videoSurface(); + else + surface = v.value<QAbstractVideoSurface *>(); + + // If only one object has been passed. + if (surface) { + m_player->setVideoOutput(surface); + } else { + QVector<QAbstractVideoSurface *> surfaces; + // Check if it is an array. + auto arr = v.value<QJSValue>(); + if (!arr.isNull()) { + const int len = arr.property("length").toInt(); + for (int i = 0; i < len; ++i) { + auto &&v = arr.property(i); + if (v.isQObject()) { + auto obj = v.toQObject(); + vo = qobject_cast<QDeclarativeVideoOutput *>(obj); + surface = vo ? vo->videoSurface() : qobject_cast<QAbstractVideoSurface *>(obj); + if (surface) + surfaces.append(surface); + } + } + } + + m_player->setVideoOutput(surfaces); + } + + m_videoOutput = v; + emit videoOutputChanged(); +} + +/*! \qmlproperty enumeration QtMultimedia::Audio::availability Returns the availability state of the media player. diff --git a/src/imports/multimedia/qdeclarativeaudio_p.h b/src/imports/multimedia/qdeclarativeaudio_p.h index 043b36042..dc8800695 100644 --- a/src/imports/multimedia/qdeclarativeaudio_p.h +++ b/src/imports/multimedia/qdeclarativeaudio_p.h @@ -97,6 +97,7 @@ class QDeclarativeAudio : public QObject, public QQmlParserStatus Q_PROPERTY(AudioRole audioRole READ audioRole WRITE setAudioRole NOTIFY audioRoleChanged REVISION 1) Q_PROPERTY(QString customAudioRole READ customAudioRole WRITE setCustomAudioRole NOTIFY customAudioRoleChanged REVISION 3) Q_PROPERTY(int notifyInterval READ notifyInterval WRITE setNotifyInterval NOTIFY notifyIntervalChanged REVISION 2) + Q_PROPERTY(QVariant videoOutput READ videoOutput WRITE setVideoOutput NOTIFY videoOutputChanged REVISION 15) Q_ENUMS(Status) Q_ENUMS(Error) Q_ENUMS(Loop) @@ -164,6 +165,9 @@ public: QDeclarativeAudio(QObject *parent = 0); ~QDeclarativeAudio(); + QVariant videoOutput() const; + void setVideoOutput(const QVariant &); + bool hasAudio() const; bool hasVideo() const; @@ -269,6 +273,7 @@ Q_SIGNALS: void mediaObjectChanged(); Q_REVISION(2) void notifyIntervalChanged(); + Q_REVISION(15) void videoOutputChanged(); private Q_SLOTS: void _q_error(QMediaPlayer::Error); @@ -305,6 +310,7 @@ private: QMediaPlayer *m_player; int m_notifyInterval; + QVariant m_videoOutput; friend class QDeclarativeMediaBaseAnimation; }; diff --git a/src/multimedia/doc/snippets/multimedia-snippets/multimedia-snippets.pro b/src/multimedia/doc/snippets/multimedia-snippets/multimedia-snippets.pro index c13090a79..a46b20bd0 100644 --- a/src/multimedia/doc/snippets/multimedia-snippets/multimedia-snippets.pro +++ b/src/multimedia/doc/snippets/multimedia-snippets/multimedia-snippets.pro @@ -22,4 +22,5 @@ SOURCES += \ OTHER_FILES += \ soundeffect.qml \ - qtvideosink.qml + qtvideosink.qml \ + multiple-videooutputs.qml diff --git a/src/multimedia/video/qvideoframe_p.h b/src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml index d7b9dd348..e3c1587f6 100644 --- a/src/multimedia/video/qvideoframe_p.h +++ b/src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. @@ -37,27 +37,31 @@ ** ****************************************************************************/ -#ifndef QVIDEOFRAME_P_H -#define QVIDEOFRAME_P_H +import QtQuick 2.0 +import QtQuick.Window 2.2 +import QtMultimedia 5.15 -#include <QtMultimedia/qvideoframe.h> +//! [complete] +Item { + MediaPlayer { + id: mediaplayer + autoPlay: true + source: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4" + videoOutput: [v1, v2] + } -// -// 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. -// - -QT_BEGIN_NAMESPACE - -Q_MULTIMEDIA_EXPORT QImage qt_imageFromVideoFrame(const QVideoFrame &frame); - -QT_END_NAMESPACE - -#endif // QVIDEOFRAME_P_H + VideoOutput { + id: v1 + anchors.fill: parent + } + Window { + visible: true + width: 480; height: 320 + VideoOutput { + id: v2 + anchors.fill: parent + } + } +} +//! [complete] diff --git a/src/multimedia/doc/snippets/multimedia-snippets/video.cpp b/src/multimedia/doc/snippets/multimedia-snippets/video.cpp index 3c14f7009..46327e3d6 100644 --- a/src/multimedia/doc/snippets/multimedia-snippets/video.cpp +++ b/src/multimedia/doc/snippets/multimedia-snippets/video.cpp @@ -117,6 +117,7 @@ public: void VideoWidget(); void VideoWindowControl(); void VideoWidgetControl(); + void VideoSurface(); private: // Common naming @@ -163,6 +164,28 @@ void VideoExample::VideoWidget() //! [Setting surface in player] } +void VideoExample::VideoSurface() +{ + //! [Widget Surface] + QImage img = QImage("images/qt-logo.png").convertToFormat(QImage::Format_ARGB32); + QVideoSurfaceFormat format(img.size(), QVideoFrame::Format_ARGB32); + videoWidget = new QVideoWidget; + videoWidget->videoSurface()->start(format); + videoWidget->videoSurface()->present(img); + videoWidget->show(); + //! [Widget Surface] + + //! [GraphicsVideoItem Surface] + QGraphicsVideoItem *item = new QGraphicsVideoItem; + graphicsView->scene()->addItem(item); + graphicsView->show(); + QImage img = QImage("images/qt-logo.png").convertToFormat(QImage::Format_ARGB32); + QVideoSurfaceFormat format(img.size(), QVideoFrame::Format_ARGB32); + item->videoSurface()->start(format); + item->videoSurface()->present(img); + //! [GraphicsVideoItem Surface] +} + void VideoExample::VideoWidgetControl() { //! [Video widget control] diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp index 48db0335e..153794801 100644 --- a/src/multimedia/playback/qmediaplayer.cpp +++ b/src/multimedia/playback/qmediaplayer.cpp @@ -38,6 +38,7 @@ ****************************************************************************/ #include "qmediaplayer.h" +#include "qvideosurfaces_p.h" #include "qvideosurfaceoutput_p.h" #include "qmediaobject_p.h" @@ -555,7 +556,7 @@ static QMediaService *playerService(QMediaPlayer::Flags flags) { QMediaServiceProvider *provider = QMediaServiceProvider::defaultServiceProvider(); if (flags) { - QMediaServiceProviderHint::Features features = 0; + QMediaServiceProviderHint::Features features; if (flags & QMediaPlayer::LowLatency) features |= QMediaServiceProviderHint::LowLatencyPlayback; @@ -1168,6 +1169,24 @@ void QMediaPlayer::setVideoOutput(QAbstractVideoSurface *surface) } } +/*! + \since 5.15 + Sets multiple video surfaces as the video output of a media player. + This allows the media player to render video frames on different surfaces. + + All video surfaces must support at least one shared \c QVideoFrame::PixelFormat. + + If a video output has already been set on the media player the new surfaces + will replace it. + + \sa QAbstractVideoSurface::supportedPixelFormats +*/ + +void QMediaPlayer::setVideoOutput(const QVector<QAbstractVideoSurface *> &surfaces) +{ + setVideoOutput(!surfaces.empty() ? new QVideoSurfaces(surfaces, this) : nullptr); +} + /*! \reimp */ QMultimedia::AvailabilityStatus QMediaPlayer::availability() const { @@ -1542,7 +1561,7 @@ QStringList QMediaPlayer::supportedCustomAudioRoles() const This value is a multiplier applied to the media's standard play rate. By default this value is 1.0, indicating that the media is playing at the standard pace. Values higher than 1.0 will increase the rate of play. - Values less than zero can be set and indicate the media will rewind at the + Values less than zero can be set and indicate the media should rewind at the multiplier of the standard pace. Not all playback services support change of the playback rate. It is diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h index 5d9a393e1..7ebed84da 100644 --- a/src/multimedia/playback/qmediaplayer.h +++ b/src/multimedia/playback/qmediaplayer.h @@ -131,6 +131,7 @@ public: void setVideoOutput(QVideoWidget *); void setVideoOutput(QGraphicsVideoItem *); void setVideoOutput(QAbstractVideoSurface *surface); + void setVideoOutput(const QVector<QAbstractVideoSurface *> &surfaces); QMediaContent media() const; const QIODevice *mediaStream() const; diff --git a/src/multimedia/qmediaserviceprovider.cpp b/src/multimedia/qmediaserviceprovider.cpp index d8ffe42ae..93b560d8c 100644 --- a/src/multimedia/qmediaserviceprovider.cpp +++ b/src/multimedia/qmediaserviceprovider.cpp @@ -56,7 +56,7 @@ class QMediaServiceProviderHintPrivate : public QSharedData { public: QMediaServiceProviderHintPrivate(QMediaServiceProviderHint::Type type) - :type(type), cameraPosition(QCamera::UnspecifiedPosition), features(nullptr) + : type(type) { } @@ -77,7 +77,7 @@ public: QMediaServiceProviderHint::Type type; QByteArray device; - QCamera::Position cameraPosition; + QCamera::Position cameraPosition = QCamera::UnspecifiedPosition; QString mimeType; QStringList codecs; QMediaServiceProviderHint::Features features; @@ -712,7 +712,7 @@ QMediaServiceProviderHint::Features QMediaServiceProvider::supportedFeatures(con { Q_UNUSED(service); - return QMediaServiceProviderHint::Features(nullptr); + return {}; } /*! diff --git a/src/multimedia/video/qvideoframe.cpp b/src/multimedia/video/qvideoframe.cpp index 5e2d6df39..fd7b74075 100644 --- a/src/multimedia/video/qvideoframe.cpp +++ b/src/multimedia/video/qvideoframe.cpp @@ -39,7 +39,6 @@ #include "qvideoframe.h" -#include "qvideoframe_p.h" #include "qimagevideobuffer_p.h" #include "qmemoryvideobuffer_p.h" #include "qvideoframeconversionhelper_p.h" @@ -1112,11 +1111,12 @@ static void qInitConvertFuncsAsm() } /*! - \internal + Based on the pixel format converts current video frame to image. + \since 5.15 */ -QImage qt_imageFromVideoFrame(const QVideoFrame &f) +QImage QVideoFrame::image() const { - QVideoFrame &frame = const_cast<QVideoFrame&>(f); + QVideoFrame frame = *this; QImage result; if (!frame.isValid() || !frame.map(QAbstractVideoBuffer::ReadOnly)) diff --git a/src/multimedia/video/qvideoframe.h b/src/multimedia/video/qvideoframe.h index 8fcf47fc4..d043442a3 100644 --- a/src/multimedia/video/qvideoframe.h +++ b/src/multimedia/video/qvideoframe.h @@ -166,6 +166,8 @@ public: QVariant metaData(const QString &key) const; void setMetaData(const QString &key, const QVariant &value); + QImage image() const; + static PixelFormat pixelFormatFromImageFormat(QImage::Format format); static QImage::Format imageFormatFromPixelFormat(PixelFormat format); diff --git a/src/multimedia/video/qvideosurfaces.cpp b/src/multimedia/video/qvideosurfaces.cpp new file mode 100644 index 000000000..793879382 --- /dev/null +++ b/src/multimedia/video/qvideosurfaces.cpp @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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$ +** +****************************************************************************/ + +#include "qvideosurfaces_p.h" + +QT_BEGIN_NAMESPACE + +QVideoSurfaces::QVideoSurfaces(const QVector<QAbstractVideoSurface *> &s, QObject *parent) + : QAbstractVideoSurface(parent) + , m_surfaces(s) +{ + for (auto a : s) { + connect(a, &QAbstractVideoSurface::supportedFormatsChanged, this, [this, a] { + auto context = property("GLContext").value<QObject *>(); + if (!context) + setProperty("GLContext", a->property("GLContext")); + + emit supportedFormatsChanged(); + }); + } +} + +QVideoSurfaces::~QVideoSurfaces() +{ +} + +QList<QVideoFrame::PixelFormat> QVideoSurfaces::supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const +{ + QList<QVideoFrame::PixelFormat> result; + QMap<QVideoFrame::PixelFormat, int> formats; + for (auto &s : m_surfaces) { + for (auto &p : s->supportedPixelFormats(type)) { + if (++formats[p] == m_surfaces.size()) + result << p; + } + } + + return result; +} + +bool QVideoSurfaces::start(const QVideoSurfaceFormat &format) +{ + bool result = true; + for (auto &s : m_surfaces) + result &= s->start(format); + + return result && QAbstractVideoSurface::start(format); +} + +void QVideoSurfaces::stop() +{ + for (auto &s : m_surfaces) + s->stop(); + + QAbstractVideoSurface::stop(); +} + +bool QVideoSurfaces::present(const QVideoFrame &frame) +{ + bool result = true; + for (auto &s : m_surfaces) + result &= s->present(frame); + + return result; +} + +QT_END_NAMESPACE diff --git a/src/multimedia/video/qvideosurfaces_p.h b/src/multimedia/video/qvideosurfaces_p.h new file mode 100644 index 000000000..67831e74e --- /dev/null +++ b/src/multimedia/video/qvideosurfaces_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 QVIDEOSURFACES_P_H +#define QVIDEOSURFACES_P_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 <QAbstractVideoSurface> +#include <QVector> + +QT_BEGIN_NAMESPACE + +class QVideoSurfaces : public QAbstractVideoSurface +{ +public: + QVideoSurfaces(const QVector<QAbstractVideoSurface *> &surfaces, QObject *parent = nullptr); + ~QVideoSurfaces(); + + QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType type) const override; + bool start(const QVideoSurfaceFormat &format) override; + void stop() override; + bool present(const QVideoFrame &frame) override; + +private: + QVector<QAbstractVideoSurface *> m_surfaces; + Q_DISABLE_COPY(QVideoSurfaces) +}; + +QT_END_NAMESPACE + +#endif // QVIDEOSURFACES_P_H diff --git a/src/multimedia/video/video.pri b/src/multimedia/video/video.pri index e5fa697ce..a3668ba4a 100644 --- a/src/multimedia/video/video.pri +++ b/src/multimedia/video/video.pri @@ -15,8 +15,8 @@ PRIVATE_HEADERS += \ video/qmemoryvideobuffer_p.h \ video/qvideooutputorientationhandler_p.h \ video/qvideosurfaceoutput_p.h \ - video/qvideoframe_p.h \ - video/qvideoframeconversionhelper_p.h + video/qvideoframeconversionhelper_p.h \ + video/qvideosurfaces_p.h SOURCES += \ video/qabstractvideobuffer.cpp \ @@ -29,7 +29,8 @@ SOURCES += \ video/qvideosurfaceoutput.cpp \ video/qvideoprobe.cpp \ video/qabstractvideofilter.cpp \ - video/qvideoframeconversionhelper.cpp + video/qvideoframeconversionhelper.cpp \ + video/qvideosurfaces.cpp SSE2_SOURCES += video/qvideoframeconversionhelper_sse2.cpp SSSE3_SOURCES += video/qvideoframeconversionhelper_ssse3.cpp diff --git a/src/multimediawidgets/qgraphicsvideoitem.cpp b/src/multimediawidgets/qgraphicsvideoitem.cpp index 2db8987fb..fae1f9048 100644 --- a/src/multimediawidgets/qgraphicsvideoitem.cpp +++ b/src/multimediawidgets/qgraphicsvideoitem.cpp @@ -232,6 +232,22 @@ QMediaObject *QGraphicsVideoItem::mediaObject() const } /*! + \since 5.15 + \property QGraphicsVideoItem::videoSurface + \brief Returns the underlying video surface that can render video frames + to the current item. + This property is never \c nullptr. + Example of how to render video frames to QGraphicsVideoItem: + \snippet multimedia-snippets/video.cpp GraphicsVideoItem Surface + \sa QMediaPlayer::setVideoOutput +*/ + +QAbstractVideoSurface *QGraphicsVideoItem::videoSurface() const +{ + return d_func()->surface; +} + +/*! \internal */ bool QGraphicsVideoItem::setMediaObject(QMediaObject *object) diff --git a/src/multimediawidgets/qgraphicsvideoitem.h b/src/multimediawidgets/qgraphicsvideoitem.h index 5aa3bd75c..5c71ee651 100644 --- a/src/multimediawidgets/qgraphicsvideoitem.h +++ b/src/multimediawidgets/qgraphicsvideoitem.h @@ -60,11 +60,13 @@ class Q_MULTIMEDIAWIDGETS_EXPORT QGraphicsVideoItem : public QGraphicsObject, pu Q_PROPERTY(QPointF offset READ offset WRITE setOffset) Q_PROPERTY(QSizeF size READ size WRITE setSize) Q_PROPERTY(QSizeF nativeSize READ nativeSize NOTIFY nativeSizeChanged) + Q_PROPERTY(QAbstractVideoSurface* videoSurface READ videoSurface CONSTANT) public: explicit QGraphicsVideoItem(QGraphicsItem *parent = nullptr); ~QGraphicsVideoItem(); QMediaObject *mediaObject() const override; + QAbstractVideoSurface *videoSurface() const; Qt::AspectRatioMode aspectRatioMode() const; void setAspectRatioMode(Qt::AspectRatioMode mode); diff --git a/src/multimediawidgets/qpaintervideosurface.cpp b/src/multimediawidgets/qpaintervideosurface.cpp index 944ea23a7..1c8e2dd63 100644 --- a/src/multimediawidgets/qpaintervideosurface.cpp +++ b/src/multimediawidgets/qpaintervideosurface.cpp @@ -1473,29 +1473,28 @@ void QPainterVideoSurface::stop() bool QPainterVideoSurface::present(const QVideoFrame &frame) { if (!m_ready) { - if (!isActive()) + if (!isActive()) { setError(StoppedError); + return false; + } } else if (frame.isValid() && (frame.pixelFormat() != m_pixelFormat || frame.size() != m_frameSize)) { setError(IncorrectFormatError); stop(); + return false; } else { QAbstractVideoSurface::Error error = m_painter->setCurrentFrame(frame); - if (error != QAbstractVideoSurface::NoError) { setError(error); - stop(); - } else { - m_ready = false; - - emit frameChanged(); - - return true; + return false; } + + m_ready = false; + emit frameChanged(); } - return false; + return true; } /*! diff --git a/src/multimediawidgets/qvideowidget.cpp b/src/multimediawidgets/qvideowidget.cpp index a7d3665f8..723a9bbb3 100644 --- a/src/multimediawidgets/qvideowidget.cpp +++ b/src/multimediawidgets/qvideowidget.cpp @@ -145,7 +145,8 @@ QRendererVideoWidgetBackend::QRendererVideoWidgetBackend( connect(m_surface, SIGNAL(surfaceFormatChanged(QVideoSurfaceFormat)), this, SLOT(formatChanged(QVideoSurfaceFormat))); - m_rendererControl->setSurface(m_surface); + if (m_rendererControl) + m_rendererControl->setSurface(m_surface); } QRendererVideoWidgetBackend::~QRendererVideoWidgetBackend() @@ -153,14 +154,21 @@ QRendererVideoWidgetBackend::~QRendererVideoWidgetBackend() delete m_surface; } +QAbstractVideoSurface *QRendererVideoWidgetBackend::videoSurface() const +{ + return m_surface; +} + void QRendererVideoWidgetBackend::releaseControl() { - m_service->releaseControl(m_rendererControl); + if (m_service && m_rendererControl) + m_service->releaseControl(m_rendererControl); } void QRendererVideoWidgetBackend::clearSurface() { - m_rendererControl->setSurface(0); + if (m_rendererControl) + m_rendererControl->setSurface(0); } void QRendererVideoWidgetBackend::setBrightness(int brightness) @@ -469,7 +477,7 @@ void QVideoWidgetPrivate::clearService() delete rendererBackend; rendererBackend = 0; - } else { + } else if (windowBackend) { windowBackend->releaseControl(); delete windowBackend; @@ -515,18 +523,15 @@ bool QVideoWidgetPrivate::createWindowBackend() bool QVideoWidgetPrivate::createRendererBackend() { - if (QMediaControl *control = service->requestControl(QVideoRendererControl_iid)) { - if (QVideoRendererControl *rendererControl = qobject_cast<QVideoRendererControl *>(control)) { - rendererBackend = new QRendererVideoWidgetBackend(service, rendererControl, q_func()); - currentBackend = rendererBackend; - - setCurrentControl(rendererBackend); + QMediaControl *control = service + ? service->requestControl(QVideoRendererControl_iid) + : nullptr; + rendererBackend = new QRendererVideoWidgetBackend(service, + qobject_cast<QVideoRendererControl *>(control), q_func()); + currentBackend = rendererBackend; + setCurrentControl(rendererBackend); - return true; - } - service->releaseControl(control); - } - return false; + return !service || (service && control); } void QVideoWidgetPrivate::_q_serviceDestroyed() @@ -611,7 +616,7 @@ void QVideoWidgetPrivate::_q_dimensionsChanged() The \a parent is passed to QWidget. */ QVideoWidget::QVideoWidget(QWidget *parent) - : QWidget(parent, 0) + : QWidget(parent, {}) , d_ptr(new QVideoWidgetPrivate) { d_ptr->q_ptr = this; @@ -621,7 +626,7 @@ QVideoWidget::QVideoWidget(QWidget *parent) \internal */ QVideoWidget::QVideoWidget(QVideoWidgetPrivate &dd, QWidget *parent) - : QWidget(parent, 0) + : QWidget(parent, {}) , d_ptr(&dd) { d_ptr->q_ptr = this; @@ -696,6 +701,29 @@ bool QVideoWidget::setMediaObject(QMediaObject *object) } /*! + \since 5.15 + \property QVideoWidget::videoSurface + \brief Returns the underlaying video surface that can render video frames + to the current widget. + This property is never \c nullptr. + Example of how to render video frames to QVideoWidget: + \snippet multimedia-snippets/video.cpp Widget Surface + \sa QMediaPlayer::setVideoOutput +*/ + +QAbstractVideoSurface *QVideoWidget::videoSurface() const +{ + auto d = const_cast<QVideoWidgetPrivate *>(d_func()); + + if (!d->rendererBackend) { + d->clearService(); + d->createRendererBackend(); + } + + return d->rendererBackend->videoSurface(); +} + +/*! \property QVideoWidget::aspectRatioMode \brief how video is scaled with respect to its aspect ratio. */ diff --git a/src/multimediawidgets/qvideowidget.h b/src/multimediawidgets/qvideowidget.h index fff1153ca..fdf93330b 100644 --- a/src/multimediawidgets/qvideowidget.h +++ b/src/multimediawidgets/qvideowidget.h @@ -51,6 +51,7 @@ QT_BEGIN_NAMESPACE class QMediaObject; class QVideoWidgetPrivate; +class QAbstractVideoSurface; class Q_MULTIMEDIAWIDGETS_EXPORT QVideoWidget : public QWidget, public QMediaBindableInterface { Q_OBJECT @@ -62,12 +63,14 @@ class Q_MULTIMEDIAWIDGETS_EXPORT QVideoWidget : public QWidget, public QMediaBin Q_PROPERTY(int contrast READ contrast WRITE setContrast NOTIFY contrastChanged) Q_PROPERTY(int hue READ hue WRITE setHue NOTIFY hueChanged) Q_PROPERTY(int saturation READ saturation WRITE setSaturation NOTIFY saturationChanged) + Q_PROPERTY(QAbstractVideoSurface* videoSurface READ videoSurface CONSTANT) public: explicit QVideoWidget(QWidget *parent = nullptr); ~QVideoWidget(); QMediaObject *mediaObject() const override; + QAbstractVideoSurface *videoSurface() const; #ifdef Q_QDOC bool isFullScreen() const; diff --git a/src/multimediawidgets/qvideowidget_p.h b/src/multimediawidgets/qvideowidget_p.h index ef417b222..1db91f3f9 100644 --- a/src/multimediawidgets/qvideowidget_p.h +++ b/src/multimediawidgets/qvideowidget_p.h @@ -131,6 +131,8 @@ public: QRendererVideoWidgetBackend(QMediaService *service, QVideoRendererControl *control, QWidget *widget); ~QRendererVideoWidgetBackend(); + QAbstractVideoSurface *videoSurface() const; + void releaseControl(); void clearSurface(); @@ -222,40 +224,21 @@ class QVideoWidgetPrivate { Q_DECLARE_PUBLIC(QVideoWidget) public: - QVideoWidgetPrivate() - : q_ptr(0) - , mediaObject(0) - , service(0) - , widgetBackend(0) - , windowBackend(0) - , rendererBackend(0) - , currentControl(0) - , currentBackend(0) - , brightness(0) - , contrast(0) - , hue(0) - , saturation(0) - , aspectRatioMode(Qt::KeepAspectRatio) - , nonFullScreenFlags(0) - , wasFullScreen(false) - { - } - - QVideoWidget *q_ptr; + QVideoWidget *q_ptr = nullptr; QPointer<QMediaObject> mediaObject; - QMediaService *service; - QVideoWidgetControlBackend *widgetBackend; - QWindowVideoWidgetBackend *windowBackend; - QRendererVideoWidgetBackend *rendererBackend; - QVideoWidgetControlInterface *currentControl; - QVideoWidgetBackend *currentBackend; - int brightness; - int contrast; - int hue; - int saturation; - Qt::AspectRatioMode aspectRatioMode; + QMediaService *service = nullptr; + QVideoWidgetControlBackend *widgetBackend = nullptr; + QWindowVideoWidgetBackend *windowBackend = nullptr; + QRendererVideoWidgetBackend *rendererBackend = nullptr; + QVideoWidgetControlInterface *currentControl = nullptr; + QVideoWidgetBackend *currentBackend = nullptr; + int brightness = 0; + int contrast = 0; + int hue = 0; + int saturation = 0; + Qt::AspectRatioMode aspectRatioMode = Qt::KeepAspectRatio; Qt::WindowFlags nonFullScreenFlags; - bool wasFullScreen; + bool wasFullScreen = false; bool createWidgetBackend(); bool createWindowBackend(); diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index f3ad84836..a0f809376 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -53,7 +53,6 @@ #include <qdebug.h> #include <qvideoframe.h> #include <private/qmemoryvideobuffer_p.h> -#include <private/qvideoframe_p.h> #include <QtCore/private/qjnihelpers_p.h> QT_BEGIN_NAMESPACE @@ -749,7 +748,7 @@ void QAndroidCameraSession::processPreviewImage(int id, const QVideoFrame &frame transform.scale(-1, 1); transform.rotate(rotation); - emit imageCaptured(id, qt_imageFromVideoFrame(frame).transformed(transform)); + emit imageCaptured(id, frame.image().transformed(transform)); } void QAndroidCameraSession::onNewPreviewFrame(const QVideoFrame &frame) diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm index dbaf3ed41..55a20b1bd 100644 --- a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm +++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm @@ -48,7 +48,6 @@ #include <QtCore/qbuffer.h> #include <QtConcurrent/qtconcurrentrun.h> #include <QtGui/qimagereader.h> -#include <private/qvideoframe_p.h> QT_USE_NAMESPACE @@ -214,7 +213,7 @@ void AVFImageCaptureControl::makeCapturePreview(CaptureRequest request, QTransform transform; transform.rotate(rotation); - Q_EMIT imageCaptured(request.captureId, qt_imageFromVideoFrame(frame).transformed(transform)); + Q_EMIT imageCaptured(request.captureId, frame.image().transformed(transform)); request.previewReady->release(); } diff --git a/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm b/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm index e06ddc4b0..63bdee4f5 100644 --- a/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm +++ b/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm @@ -177,7 +177,11 @@ void AVFVideoRendererControl::setSurface(QAbstractVideoSurface *surface) #endif //Check for needed formats to render as OpenGL Texture - m_enableOpenGL = m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).contains(QVideoFrame::Format_BGR32); + auto handleGlEnabled = [this] { + m_enableOpenGL = m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).contains(QVideoFrame::Format_BGR32); + }; + handleGlEnabled(); + connect(m_surface, &QAbstractVideoSurface::supportedFormatsChanged, this, handleGlEnabled); //If we already have a layer, but changed surfaces start rendering again if (m_playerLayer && !m_displayLink->isActive()) { diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index a0c120816..cee3e9c56 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -44,7 +44,6 @@ #include <QtMultimedia/qvideosurfaceformat.h> #include <QtMultimedia/qcameraimagecapture.h> #include <private/qmemoryvideobuffer_p.h> -#include <private/qvideoframe_p.h> #include "dscamerasession.h" #include "dsvideorenderer.h" @@ -637,7 +636,7 @@ void DSCameraSession::presentFrame() if (m_capturedFrame.isValid()) { - captureImage = qt_imageFromVideoFrame(m_capturedFrame); + captureImage = m_capturedFrame.image(); const bool needsVerticalMirroring = m_previewSurfaceFormat.scanLineDirection() != QVideoSurfaceFormat::TopToBottom; captureImage = captureImage.mirrored(m_needsHorizontalMirroring, needsVerticalMirroring); // also causes a deep copy of the data diff --git a/src/plugins/gstreamer/camerabin/camerabinzoom.cpp b/src/plugins/gstreamer/camerabin/camerabinzoom.cpp index bb3659493..401e13207 100644 --- a/src/plugins/gstreamer/camerabin/camerabinzoom.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinzoom.cpp @@ -51,7 +51,9 @@ CameraBinZoom::CameraBinZoom(CameraBinSession *session) , m_requestedOpticalZoom(1.0) , m_requestedDigitalZoom(1.0) { - + GstElement *camerabin = m_session->cameraBin(); + g_signal_connect(G_OBJECT(camerabin), "notify::zoom", G_CALLBACK(updateZoom), this); + g_signal_connect(G_OBJECT(camerabin), "notify::max-zoom", G_CALLBACK(updateMaxZoom), this); } CameraBinZoom::~CameraBinZoom() @@ -114,4 +116,32 @@ void CameraBinZoom::zoomTo(qreal optical, qreal digital) emit currentDigitalZoomChanged(digital); } +void CameraBinZoom::updateZoom(GObject *o, GParamSpec *p, gpointer d) +{ + Q_UNUSED(p); + + gfloat zoomFactor = 1.0; + g_object_get(o, ZOOM_PROPERTY, &zoomFactor, NULL); + + CameraBinZoom *zoom = reinterpret_cast<CameraBinZoom *>(d); + + QMetaObject::invokeMethod(zoom, "currentDigitalZoomChanged", + Qt::QueuedConnection, + Q_ARG(qreal, zoomFactor)); +} + +void CameraBinZoom::updateMaxZoom(GObject *o, GParamSpec *p, gpointer d) +{ + Q_UNUSED(p); + + gfloat zoomFactor = 1.0; + g_object_get(o, MAX_ZOOM_PROPERTY, &zoomFactor, NULL); + + CameraBinZoom *zoom = reinterpret_cast<CameraBinZoom *>(d); + + QMetaObject::invokeMethod(zoom, "maximumDigitalZoomChanged", + Qt::QueuedConnection, + Q_ARG(qreal, zoomFactor)); +} + QT_END_NAMESPACE diff --git a/src/plugins/gstreamer/camerabin/camerabinzoom.h b/src/plugins/gstreamer/camerabin/camerabinzoom.h index 8ad4764b2..858ada2da 100644 --- a/src/plugins/gstreamer/camerabin/camerabinzoom.h +++ b/src/plugins/gstreamer/camerabin/camerabinzoom.h @@ -41,6 +41,7 @@ #define CAMERABINZOOMCONTROL_H #include <qcamerazoomcontrol.h> +#include <gst/gst.h> QT_BEGIN_NAMESPACE @@ -64,6 +65,9 @@ public: void zoomTo(qreal optical, qreal digital) override; private: + static void updateZoom(GObject *o, GParamSpec *p, gpointer d); + static void updateMaxZoom(GObject *o, GParamSpec *p, gpointer d); + CameraBinSession *m_session; qreal m_requestedOpticalZoom; qreal m_requestedDigitalZoom; diff --git a/src/plugins/m3u/qm3uhandler.cpp b/src/plugins/m3u/qm3uhandler.cpp index 017c32d92..5e05994ef 100644 --- a/src/plugins/m3u/qm3uhandler.cpp +++ b/src/plugins/m3u/qm3uhandler.cpp @@ -163,7 +163,7 @@ public: virtual bool writeItem(const QMediaContent& item) { - *m_textStream << item.request().url().toString() << endl; + *m_textStream << item.request().url().toString() << Qt::endl; return true; } diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp index 32166502d..81dc3fcb3 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp @@ -138,6 +138,7 @@ QDeclarativeVideoOutput::QDeclarativeVideoOutput(QQuickItem *parent) : { initResource(); setFlag(ItemHasContents, true); + createBackend(nullptr); } QDeclarativeVideoOutput::~QDeclarativeVideoOutput() @@ -148,6 +149,22 @@ QDeclarativeVideoOutput::~QDeclarativeVideoOutput() } /*! + \qmlproperty object QtMultimedia::VideoOutput::videoSurface + \since 5.15 + + This property holds the underlaying video surface that can be used + to render the video frames to this VideoOutput element. + It is similar to setting a QObject with \c videoSurface property as a source, + where this video surface will be set. + \sa setSource +*/ + +QAbstractVideoSurface *QDeclarativeVideoOutput::videoSurface() const +{ + return m_backend ? m_backend->videoSurface() : nullptr; +} + +/*! \qmlproperty variant QtMultimedia::VideoOutput::source This property holds the source item providing the video frames like MediaPlayer or Camera. @@ -206,21 +223,10 @@ void QDeclarativeVideoOutput::setSource(QObject *source) } m_sourceType = MediaObjectSource; -#if QT_CONFIG(opengl) } else if (metaObject->indexOfProperty("videoSurface") != -1) { - // Make sure our backend is a QDeclarativeVideoRendererBackend - m_backend.reset(); - createBackend(0); - Q_ASSERT(m_backend); -#ifndef QT_NO_DYNAMIC_CAST - Q_ASSERT(dynamic_cast<QDeclarativeVideoRendererBackend *>(m_backend.data())); -#endif - QAbstractVideoSurface * const surface = m_backend->videoSurface(); - Q_ASSERT(surface); m_source.data()->setProperty("videoSurface", - QVariant::fromValue<QAbstractVideoSurface*>(surface)); + QVariant::fromValue<QAbstractVideoSurface *>(videoSurface())); m_sourceType = VideoSurfaceSource; -#endif } else { m_sourceType = NoSource; } @@ -242,7 +248,8 @@ bool QDeclarativeVideoOutput::createBackend(QMediaService *service) const auto instances = videoBackendFactoryLoader()->instances(QLatin1String("declarativevideobackend")); for (QObject *instance : instances) { if (QDeclarativeVideoBackendFactoryInterface *plugin = qobject_cast<QDeclarativeVideoBackendFactoryInterface*>(instance)) { - m_backend.reset(plugin->create(this)); + if (!m_backend) + m_backend.reset(plugin->create(this)); if (m_backend && m_backend->init(service)) { backendAvailable = true; break; @@ -251,7 +258,8 @@ bool QDeclarativeVideoOutput::createBackend(QMediaService *service) } #if QT_CONFIG(opengl) if (!backendAvailable) { - m_backend.reset(new QDeclarativeVideoRendererBackend(this)); + if (!m_backend) + m_backend.reset(new QDeclarativeVideoRendererBackend(this)); if (m_backend->init(service)) backendAvailable = true; } @@ -293,9 +301,6 @@ void QDeclarativeVideoOutput::_q_updateMediaObject() if (m_mediaObject.data() == mediaObject) return; - if (m_sourceType != VideoSurfaceSource) - m_backend.reset(); - m_mediaObject.clear(); m_service.clear(); diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_p.h b/src/qtmultimediaquicktools/qdeclarativevideooutput_p.h index 8ea0dc338..d14731c91 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput_p.h +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_p.h @@ -67,6 +67,7 @@ class QMediaObject; class QMediaService; class QDeclarativeVideoBackend; class QVideoOutputOrientationHandler; +class QAbstractVideoSurface; class Q_MULTIMEDIAQUICK_EXPORT QDeclarativeVideoOutput : public QQuickItem { @@ -80,6 +81,7 @@ class Q_MULTIMEDIAQUICK_EXPORT QDeclarativeVideoOutput : public QQuickItem Q_PROPERTY(QRectF contentRect READ contentRect NOTIFY contentRectChanged) Q_PROPERTY(QQmlListProperty<QAbstractVideoFilter> filters READ filters); Q_PROPERTY(FlushMode flushMode READ flushMode WRITE setFlushMode NOTIFY flushModeChanged REVISION 13) + Q_PROPERTY(QAbstractVideoSurface* videoSurface READ videoSurface CONSTANT REVISION 15) Q_ENUMS(FlushMode) Q_ENUMS(FillMode) @@ -102,6 +104,8 @@ public: QDeclarativeVideoOutput(QQuickItem *parent = 0); ~QDeclarativeVideoOutput(); + QAbstractVideoSurface *videoSurface() const; + QObject *source() const { return m_source.data(); } void setSource(QObject *source); diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp index 863cefa4e..bdfa23dfb 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp @@ -46,7 +46,6 @@ #include <QtCore/qloggingcategory.h> #include <private/qmediapluginloader_p.h> #include <private/qsgvideonode_p.h> -#include <private/qvideoframe_p.h> #include <QtGui/QOpenGLContext> #include <QtQuick/QQuickWindow> @@ -304,7 +303,7 @@ QSGNode *QDeclarativeVideoRendererBackend::updatePaintNode(QSGNode *oldNode, if (!runnable) continue; - QVideoFilterRunnable::RunFlags flags = 0; + QVideoFilterRunnable::RunFlags flags; if (i == m_filters.count() - 1) flags |= QVideoFilterRunnable::LastInChain; @@ -363,7 +362,7 @@ QSGNode *QDeclarativeVideoRendererBackend::updatePaintNode(QSGNode *oldNode, videoNode->setTexturedRectGeometry(m_renderedRect, m_sourceTextureRect, qNormalizedOrientation(q->orientation())); if (m_frameChanged) { - QSGVideoNode::FrameFlags flags = 0; + QSGVideoNode::FrameFlags flags; if (isFrameModified) flags |= QSGVideoNode::FrameFiltered; videoNode->setCurrentFrame(m_frame, flags); @@ -372,7 +371,7 @@ QSGNode *QDeclarativeVideoRendererBackend::updatePaintNode(QSGNode *oldNode, || q->flushMode() == QDeclarativeVideoOutput::LastFrame) { m_frameOnFlush = m_surfaceFormat.handleType() == QAbstractVideoBuffer::NoHandle ? m_frame - : qt_imageFromVideoFrame(m_frame); + : m_frame.image(); } //don't keep the frame for more than really necessary diff --git a/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp b/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp index 894486230..27fc014aa 100644 --- a/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp +++ b/tests/auto/integration/qcamerabackend/tst_qcamerabackend.cpp @@ -49,7 +49,6 @@ #include <qcameraimagecapture.h> #include <qvideorenderercontrol.h> #include <private/qmediaserviceprovider_p.h> -#include <private/qvideoframe_p.h> QT_USE_NAMESPACE @@ -451,7 +450,7 @@ void tst_QCameraBackend::testCaptureToBuffer() QCOMPARE(imageAvailableSignal.first().first().toInt(), id); QVideoFrame frame = imageAvailableSignal.first().last().value<QVideoFrame>(); - QVERIFY(!qt_imageFromVideoFrame(frame).isNull()); + QVERIFY(!frame.image().isNull()); frame = QVideoFrame(); capturedSignal.clear(); @@ -509,7 +508,7 @@ void tst_QCameraBackend::testCaptureToBuffer() QCOMPARE(imageAvailableSignal.first().first().toInt(), id); frame = imageAvailableSignal.first().last().value<QVideoFrame>(); - QVERIFY(!qt_imageFromVideoFrame(frame).isNull()); + QVERIFY(!frame.image().isNull()); QString fileName = savedSignal.first().last().toString(); QVERIFY(QFileInfo(fileName).exists()); diff --git a/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp b/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp index 798b63f96..27c7d85de 100644 --- a/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp +++ b/tests/auto/integration/qdeclarativevideooutput/tst_qdeclarativevideooutput.cpp @@ -32,6 +32,7 @@ #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcomponent.h> +#include <QQuickView> #include "private/qdeclarativevideooutput_p.h" @@ -109,6 +110,7 @@ private slots: void flushMode(); void orientation(); void surfaceSource(); + void paintSurface(); void sourceRect(); void contentRect(); @@ -349,6 +351,45 @@ void tst_QDeclarativeVideoOutput::surfaceSource() delete videoOutput2; } +static const uchar rgb32ImageData[] = +{// B G R A + 0x00, 0x01, 0x02, 0xff, 0x03, 0x04, 0x05, 0xff, + 0x06, 0x07, 0x08, 0xff, 0x09, 0x0a, 0x0b, 0xff +}; + +void tst_QDeclarativeVideoOutput::paintSurface() +{ + QQuickView window; + window.setSource(QUrl("qrc:/main.qml")); + window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); + + auto videoOutput = qobject_cast<QDeclarativeVideoOutput *>(window.rootObject()); + QVERIFY(videoOutput); + + auto surface = videoOutput->property("videoSurface").value<QAbstractVideoSurface *>(); + QVERIFY(surface); + QVERIFY(!surface->isActive()); + videoOutput->setSize(QSize(2, 2)); + QVideoSurfaceFormat format(QSize(2, 2), QVideoFrame::Format_RGB32); + QVERIFY(surface->isFormatSupported(format)); + QVERIFY(surface->start(format)); + QVERIFY(surface->isActive()); + + QImage img(rgb32ImageData, 2, 2, 8, QImage::Format_RGB32); + QVERIFY(surface->present(img)); + + if (QGuiApplication::platformName() == QLatin1String("offscreen") + || QGuiApplication::platformName() == QLatin1String("minimal")) + return; + + QImage capture = window.grabWindow(); + QCOMPARE(capture.pixelColor(0, 0), QColor(rgb32ImageData[2], rgb32ImageData[1], rgb32ImageData[0], rgb32ImageData[3])); + QCOMPARE(capture.pixelColor(1, 0), QColor(rgb32ImageData[6], rgb32ImageData[5], rgb32ImageData[4], rgb32ImageData[7])); + QCOMPARE(capture.pixelColor(0, 1), QColor(rgb32ImageData[10], rgb32ImageData[9], rgb32ImageData[8], rgb32ImageData[11])); + QCOMPARE(capture.pixelColor(1, 1), QColor(rgb32ImageData[14], rgb32ImageData[13], rgb32ImageData[12], rgb32ImageData[15])); +} + void tst_QDeclarativeVideoOutput::sourceRect() { QQmlComponent component(&m_engine); diff --git a/tests/auto/integration/qmediaplayerbackend/BLACKLIST b/tests/auto/integration/qmediaplayerbackend/BLACKLIST index c2833f1f7..e91f47755 100644 --- a/tests/auto/integration/qmediaplayerbackend/BLACKLIST +++ b/tests/auto/integration/qmediaplayerbackend/BLACKLIST @@ -5,6 +5,7 @@ windows-7 windows-7sp1 windows-10 msvc-2015 windows-10 msvc-2017 +windows-10 msvc-2019 # Media player plugin not built at the moment on this platform opensuse-13.1 64bit diff --git a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp index 9cd3b7fa9..f1be070e8 100644 --- a/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp +++ b/tests/auto/integration/qmediaplayerbackend/tst_qmediaplayerbackend.cpp @@ -78,6 +78,7 @@ private slots: void playlistObject(); void surfaceTest_data(); void surfaceTest(); + void multipleSurfaces(); void metadata(); void playerStateAtEOS(); @@ -1393,6 +1394,33 @@ void tst_QMediaPlayerBackend::surfaceTest() QVERIFY2(surface.m_totalFrames >= 25, qPrintable(QString("Expected >= 25, got %1").arg(surface.m_totalFrames))); } +void tst_QMediaPlayerBackend::multipleSurfaces() +{ + if (localVideoFile.isNull()) + QSKIP("No supported video file"); + + QList<QVideoFrame::PixelFormat> formats1; + formats1 << QVideoFrame::Format_RGB32 + << QVideoFrame::Format_ARGB32; + QList<QVideoFrame::PixelFormat> formats2; + formats2 << QVideoFrame::Format_YUV420P + << QVideoFrame::Format_RGB32; + + TestVideoSurface surface1(false); + surface1.setSupportedFormats(formats1); + TestVideoSurface surface2(false); + surface2.setSupportedFormats(formats2); + + QMediaPlayer player; + player.setVideoOutput(QVector<QAbstractVideoSurface *>() << &surface1 << &surface2); + player.setMedia(localVideoFile); + player.play(); + QTRY_VERIFY(player.position() >= 1000); + QVERIFY2(surface1.m_totalFrames >= 25, qPrintable(QString("Expected >= 25, got %1").arg(surface1.m_totalFrames))); + QVERIFY2(surface2.m_totalFrames >= 25, qPrintable(QString("Expected >= 25, got %1").arg(surface2.m_totalFrames))); + QCOMPARE(surface1.m_totalFrames, surface2.m_totalFrames); +} + void tst_QMediaPlayerBackend::metadata() { if (localFileWithMetadata.isNull()) diff --git a/tests/auto/unit/qdeclarativeaudio/qdeclarativeaudio.pro b/tests/auto/unit/qdeclarativeaudio/qdeclarativeaudio.pro index f59027bc2..6d8b3c215 100644 --- a/tests/auto/unit/qdeclarativeaudio/qdeclarativeaudio.pro +++ b/tests/auto/unit/qdeclarativeaudio/qdeclarativeaudio.pro @@ -1,7 +1,7 @@ CONFIG += testcase TARGET = tst_qdeclarativeaudio -QT += multimedia-private qml testlib +QT += multimedia-private qml testlib qtmultimediaquicktools-private HEADERS += \ ../../../../src/imports/multimedia/qdeclarativeaudio_p.h \ diff --git a/tests/auto/unit/qdeclarativeaudio/tst_qdeclarativeaudio.cpp b/tests/auto/unit/qdeclarativeaudio/tst_qdeclarativeaudio.cpp index 87c72521c..ded188d72 100644 --- a/tests/auto/unit/qdeclarativeaudio/tst_qdeclarativeaudio.cpp +++ b/tests/auto/unit/qdeclarativeaudio/tst_qdeclarativeaudio.cpp @@ -40,7 +40,9 @@ #include <qmediaplayercontrol.h> #include <qmediaservice.h> #include <private/qmediaserviceprovider_p.h> +#include <private/qdeclarativevideooutput_p.h> #include <qmetadatareadercontrol.h> +#include <QAbstractVideoSurface> #include <QtGui/qguiapplication.h> #include <QtQml/qqmlengine.h> @@ -75,6 +77,7 @@ private slots: void loops(); void audioRole(); void customAudioRole(); + void videoOutput(); private: void enumerator(const QMetaObject *object, const char *name, QMetaEnum *result); @@ -1201,6 +1204,52 @@ int tst_QDeclarativeAudio::keyToValue(const QMetaEnum &enumeration, const char * return result; } +struct Surface : QAbstractVideoSurface +{ + Surface(QObject *parent = nullptr) : QAbstractVideoSurface(parent) { } + QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType) const override + { + return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_RGB32; + } + + bool present(const QVideoFrame &) override { return true; } +}; + +void tst_QDeclarativeAudio::videoOutput() +{ + QtTestMediaPlayerControl playerControl; + QtTestMediaServiceProvider provider(&playerControl, 0); + + QDeclarativeAudio audio; + QSignalSpy spy(&audio, &QDeclarativeAudio::videoOutputChanged); + + audio.classBegin(); + audio.componentComplete(); + + QVERIFY(audio.videoOutput().isNull()); + + QVariant surface; + surface.setValue(new Surface(this)); + audio.setVideoOutput(surface); + QCOMPARE(audio.videoOutput(), surface); + QCOMPARE(spy.count(), 1); + + QQmlEngine engine; + QJSValue jsArray = engine.newArray(5); + jsArray.setProperty(0, engine.newQObject(new Surface(this))); + jsArray.setProperty(1, engine.newQObject(new Surface(this))); + QDeclarativeVideoOutput output; + jsArray.setProperty(2, engine.newQObject(&output)); + jsArray.setProperty(3, 123); + jsArray.setProperty(4, QLatin1String("ignore this")); + + QVariant surfaces; + surfaces.setValue(jsArray); + audio.setVideoOutput(surfaces); + QCOMPARE(audio.videoOutput(), surfaces); + QCOMPARE(spy.count(), 2); +} + QTEST_MAIN(tst_QDeclarativeAudio) #include "tst_qdeclarativeaudio.moc" diff --git a/tests/auto/unit/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp b/tests/auto/unit/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp index f4759bbf7..41805f49a 100644 --- a/tests/auto/unit/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp +++ b/tests/auto/unit/qgraphicsvideoitem/tst_qgraphicsvideoitem.cpp @@ -70,6 +70,7 @@ private slots: void boundingRect(); void paint(); + void paintSurface(); }; Q_DECLARE_METATYPE(const uchar *) @@ -656,6 +657,48 @@ void tst_QGraphicsVideoItem::paint() QCOMPARE(surface->isReady(), true); } +void tst_QGraphicsVideoItem::paintSurface() +{ + QtTestGraphicsVideoItem *item = new QtTestGraphicsVideoItem; + QVERIFY(item->videoSurface()); + + QGraphicsScene graphicsScene; + graphicsScene.addItem(item); + QGraphicsView graphicsView(&graphicsScene); + graphicsView.show(); + QVERIFY(item->waitForPaint(1)); + + QPainterVideoSurface *surface = qobject_cast<QPainterVideoSurface *>( + item->videoSurface()); + if (!surface) + QSKIP("QGraphicsVideoItem is not QPainterVideoSurface based"); + + QVideoSurfaceFormat format(QSize(2, 2), QVideoFrame::Format_RGB32); + + QVERIFY(surface->start(format)); + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); + + QVERIFY(item->waitForPaint(1)); + + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); + + QVideoFrame frame(sizeof(rgb32ImageData), QSize(2, 2), 8, QVideoFrame::Format_RGB32); + + frame.map(QAbstractVideoBuffer::WriteOnly); + memcpy(frame.bits(), rgb32ImageData, frame.mappedBytes()); + frame.unmap(); + + QVERIFY(surface->present(frame)); + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), false); + + QVERIFY(item->waitForPaint(1)); + + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); +} QTEST_MAIN(tst_QGraphicsVideoItem) diff --git a/tests/auto/unit/qmediaserviceprovider/mockserviceplugin2/mockserviceplugin2.cpp b/tests/auto/unit/qmediaserviceprovider/mockserviceplugin2/mockserviceplugin2.cpp index 66ace2045..4167b18ea 100644 --- a/tests/auto/unit/qmediaserviceprovider/mockserviceplugin2/mockserviceplugin2.cpp +++ b/tests/auto/unit/qmediaserviceprovider/mockserviceplugin2/mockserviceplugin2.cpp @@ -75,10 +75,10 @@ public: QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const { + QMediaServiceProviderHint::Features result; if (service == QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)) - return QMediaServiceProviderHint::LowLatencyPlayback; - else - return 0; + result |= QMediaServiceProviderHint::LowLatencyPlayback; + return result; } }; diff --git a/tests/auto/unit/qmediaserviceprovider/mockserviceplugin4/mockserviceplugin4.cpp b/tests/auto/unit/qmediaserviceprovider/mockserviceplugin4/mockserviceplugin4.cpp index 92707169c..6a7725fee 100644 --- a/tests/auto/unit/qmediaserviceprovider/mockserviceplugin4/mockserviceplugin4.cpp +++ b/tests/auto/unit/qmediaserviceprovider/mockserviceplugin4/mockserviceplugin4.cpp @@ -75,10 +75,10 @@ public: QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const { + QMediaServiceProviderHint::Features result; if (service == QByteArray(Q_MEDIASERVICE_MEDIAPLAYER)) - return QMediaServiceProviderHint::StreamPlayback; - else - return 0; + result |= QMediaServiceProviderHint::StreamPlayback; + return result; } }; diff --git a/tests/auto/unit/qpaintervideosurface/tst_qpaintervideosurface.cpp b/tests/auto/unit/qpaintervideosurface/tst_qpaintervideosurface.cpp index 7ba631e58..6aaeab855 100644 --- a/tests/auto/unit/qpaintervideosurface/tst_qpaintervideosurface.cpp +++ b/tests/auto/unit/qpaintervideosurface/tst_qpaintervideosurface.cpp @@ -481,8 +481,7 @@ void tst_QPainterVideoSurface::present() QCOMPARE(surface.isActive(), true); QCOMPARE(surface.isReady(), false); - // Not ready. - QVERIFY(!surface.present(frameA)); + QVERIFY(surface.present(frameA)); QCOMPARE(frameSpy.count(), 1); surface.setReady(true); @@ -1093,8 +1092,9 @@ void tst_QPainterVideoSurface::shaderPresent() QCOMPARE(surface.isActive(), true); QCOMPARE(surface.isReady(), false); - // Not ready. - QVERIFY(!surface.present(frameA)); + // If present() fails for any other reason the surface should immediately enter the stopped state + // and an error() value will be set. + QVERIFY(surface.present(frameA)); QCOMPARE(frameSpy.count(), 1); surface.setReady(true); diff --git a/tests/auto/unit/qvideoframe/tst_qvideoframe.cpp b/tests/auto/unit/qvideoframe/tst_qvideoframe.cpp index 6be039108..943051435 100644 --- a/tests/auto/unit/qvideoframe/tst_qvideoframe.cpp +++ b/tests/auto/unit/qvideoframe/tst_qvideoframe.cpp @@ -33,6 +33,7 @@ #include <qvideoframe.h> #include <QtGui/QImage> #include <QtCore/QPointer> +#include <QtMultimedia/private/qtmultimedia-config_p.h> // Adds an enum, and the stringized version #define ADD_ENUM_TEST(x) \ @@ -85,6 +86,9 @@ private slots: void isMapped(); void isReadable(); void isWritable(); + + void image_data(); + void image(); }; Q_DECLARE_METATYPE(QImage::Format) @@ -1128,6 +1132,173 @@ void tst_QVideoFrame::isWritable() frame.unmap(); } +void tst_QVideoFrame::image_data() +{ + QTest::addColumn<QSize>("size"); + QTest::addColumn<QVideoFrame::PixelFormat>("pixelFormat"); + QTest::addColumn<int>("bytes"); + QTest::addColumn<int>("bytesPerLine"); + QTest::addColumn<QImage::Format>("imageFormat"); + + QTest::newRow("64x64 ARGB32") + << QSize(64, 64) + << QVideoFrame::Format_ARGB32 + << 16384 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 ARGB32_Premultiplied") + << QSize(64, 64) + << QVideoFrame::Format_ARGB32_Premultiplied + << 16384 + << 256 + << QImage::Format_ARGB32_Premultiplied; + + QTest::newRow("64x64 RGB32") + << QSize(64, 64) + << QVideoFrame::Format_RGB32 + << 16384 + << 256 + << QImage::Format_RGB32; + + QTest::newRow("64x64 RGB24") + << QSize(64, 64) + << QVideoFrame::Format_RGB24 + << 16384 + << 192 + << QImage::Format_RGB888; + + QTest::newRow("64x64 RGB565") + << QSize(64, 64) + << QVideoFrame::Format_RGB565 + << 16384 + << 128 + << QImage::Format_RGB16; + + QTest::newRow("64x64 RGB555") + << QSize(64, 64) + << QVideoFrame::Format_RGB555 + << 16384 + << 128 + << QImage::Format_RGB555; + + QTest::newRow("64x64 BGRA32") + << QSize(64, 64) + << QVideoFrame::Format_BGRA32 + << 16384 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 BGRA32_Premultiplied") + << QSize(64, 64) + << QVideoFrame::Format_BGRA32_Premultiplied + << 16384 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 BGR32") + << QSize(64, 64) + << QVideoFrame::Format_BGR32 + << 16384 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 BGR24") + << QSize(64, 64) + << QVideoFrame::Format_BGR24 + << 16384 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 BGR565") + << QSize(64, 64) + << QVideoFrame::Format_BGR565 + << 16384 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 BGR555") + << QSize(64, 64) + << QVideoFrame::Format_BGR555 + << 16384 + << 256 + << QImage::Format_ARGB32; +#if !QT_CONFIG(directshow) + QTest::newRow("64x64 AYUV444") + << QSize(64, 64) + << QVideoFrame::Format_AYUV444 + << 16384 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 YUV444") + << QSize(64, 64) + << QVideoFrame::Format_YUV444 + << 16384 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 YUV420P") + << QSize(64, 64) + << QVideoFrame::Format_YUV420P + << 13288 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 YV12") + << QSize(64, 64) + << QVideoFrame::Format_YV12 + << 16384 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 UYVY") + << QSize(64, 64) + << QVideoFrame::Format_UYVY + << 16384 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 YUYV") + << QSize(64, 64) + << QVideoFrame::Format_YUYV + << 16384 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 NV12") + << QSize(64, 64) + << QVideoFrame::Format_NV12 + << 16384 + << 256 + << QImage::Format_ARGB32; + + QTest::newRow("64x64 NV21") + << QSize(64, 64) + << QVideoFrame::Format_NV21 + << 16384 + << 256 + << QImage::Format_ARGB32; +#endif +} + +void tst_QVideoFrame::image() +{ + QFETCH(QSize, size); + QFETCH(QVideoFrame::PixelFormat, pixelFormat); + QFETCH(int, bytes); + QFETCH(int, bytesPerLine); + QFETCH(QImage::Format, imageFormat); + + QVideoFrame frame(bytes, size, bytesPerLine, pixelFormat); + QImage img = frame.image(); + + QVERIFY(!img.isNull()); + QCOMPARE(img.format(), imageFormat); + QCOMPARE(img.size(), size); + QCOMPARE(img.bytesPerLine(), bytesPerLine); +} + QTEST_MAIN(tst_QVideoFrame) #include "tst_qvideoframe.moc" diff --git a/tests/auto/unit/qvideowidget/tst_qvideowidget.cpp b/tests/auto/unit/qvideowidget/tst_qvideowidget.cpp index 3baa72281..bcc4acb3a 100644 --- a/tests/auto/unit/qvideowidget/tst_qvideowidget.cpp +++ b/tests/auto/unit/qvideowidget/tst_qvideowidget.cpp @@ -100,6 +100,7 @@ private slots: void saturationRendererControl(); void paintRendererControl(); + void paintSurface(); private: void sizeHint_data(); @@ -1609,6 +1610,34 @@ void tst_QVideoWidget::paintRendererControl() QCOMPARE(surface->isReady(), true); } +void tst_QVideoWidget::paintSurface() +{ + QtTestVideoWidget widget; + widget.resize(640,480); + widget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&widget)); + + QVERIFY(widget.videoSurface()); + auto surface = qobject_cast<QPainterVideoSurface *>( + widget.videoSurface()); + QVERIFY(surface); + + QVideoSurfaceFormat format(QSize(2, 2), QVideoFrame::Format_RGB32); + QVERIFY(surface->start(format)); + QCOMPARE(surface->isActive(), true); + + QVideoFrame frame(sizeof(rgb32ImageData), QSize(2, 2), 8, QVideoFrame::Format_RGB32); + frame.map(QAbstractVideoBuffer::WriteOnly); + memcpy(frame.bits(), rgb32ImageData, frame.mappedBytes()); + frame.unmap(); + + QVERIFY(surface->present(frame)); + QCOMPARE(surface->isReady(), false); + QTRY_COMPARE(surface->isReady(), true); + QCOMPARE(surface->isActive(), true); + QCOMPARE(surface->isReady(), true); +} + QTEST_MAIN(tst_QVideoWidget) #include "tst_qvideowidget.moc" |