summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gsttools/qgstappsrc.cpp2
-rw-r--r--src/gsttools/qgstbufferpoolinterface_p.h4
-rw-r--r--src/gsttools/qgstcodecsinfo.cpp4
-rw-r--r--src/gsttools/qgstreameraudioinputselector.cpp15
-rw-r--r--src/gsttools/qgstreamerbufferprobe.cpp4
-rw-r--r--src/gsttools/qgstreamerbushelper.cpp10
-rw-r--r--src/gsttools/qgstreamerplayercontrol.cpp6
-rw-r--r--src/gsttools/qgstreamerplayersession.cpp138
-rw-r--r--src/gsttools/qgstreamervideooverlay.cpp46
-rw-r--r--src/gsttools/qgstreamervideowidget.cpp4
-rw-r--r--src/gsttools/qgstutils.cpp60
-rw-r--r--src/gsttools/qgstvideorenderersink.cpp39
-rw-r--r--src/gsttools/qvideosurfacegstsink.cpp18
-rw-r--r--src/imports/multimedia/Video.qml19
-rw-r--r--src/imports/multimedia/multimedia.cpp6
-rw-r--r--src/imports/multimedia/plugins.qmltypes36
-rw-r--r--src/imports/multimedia/qdeclarativeaudio.cpp59
-rw-r--r--src/imports/multimedia/qdeclarativeaudio_p.h6
-rw-r--r--src/imports/multimedia/qdeclarativecamera.cpp17
-rw-r--r--src/imports/multimedia/qdeclarativecamera_p.h5
-rw-r--r--src/multimedia/audio/qaudiohelpers.cpp6
-rw-r--r--src/multimedia/audio/qsamplecache_p.cpp2
-rw-r--r--src/multimedia/audio/qsoundeffect_pulse_p.cpp19
-rw-r--r--src/multimedia/camera/qcamera.cpp11
-rw-r--r--src/multimedia/camera/qcamera.h3
-rw-r--r--src/multimedia/camera/qcameraimagecapture.cpp9
-rw-r--r--src/multimedia/configure.json19
-rw-r--r--src/multimedia/controls/qaudiodecodercontrol.cpp1
-rw-r--r--src/multimedia/controls/qaudioencodersettingscontrol.cpp1
-rw-r--r--src/multimedia/controls/qaudioinputselectorcontrol.cpp1
-rw-r--r--src/multimedia/controls/qaudiooutputselectorcontrol.cpp1
-rw-r--r--src/multimedia/controls/qaudiorolecontrol.cpp1
-rw-r--r--src/multimedia/controls/qcameracapturebufferformatcontrol.cpp1
-rw-r--r--src/multimedia/controls/qcameracapturedestinationcontrol.cpp1
-rw-r--r--src/multimedia/controls/qcameracontrol.cpp1
-rw-r--r--src/multimedia/controls/qcameraexposurecontrol.cpp1
-rw-r--r--src/multimedia/controls/qcamerafeedbackcontrol.cpp1
-rw-r--r--src/multimedia/controls/qcameraflashcontrol.cpp1
-rw-r--r--src/multimedia/controls/qcamerafocuscontrol.cpp1
-rw-r--r--src/multimedia/controls/qcameraimagecapturecontrol.cpp1
-rw-r--r--src/multimedia/controls/qcameraimageprocessingcontrol.cpp1
-rw-r--r--src/multimedia/controls/qcamerainfocontrol.cpp1
-rw-r--r--src/multimedia/controls/qcameralockscontrol.cpp1
-rw-r--r--src/multimedia/controls/qcameraviewfindersettingscontrol.cpp1
-rw-r--r--src/multimedia/controls/qcamerazoomcontrol.cpp1
-rw-r--r--src/multimedia/controls/qcustomaudiorolecontrol.cpp1
-rw-r--r--src/multimedia/controls/qimageencodercontrol.cpp1
-rw-r--r--src/multimedia/controls/qmediaaudioprobecontrol.cpp1
-rw-r--r--src/multimedia/controls/qmediaavailabilitycontrol.cpp1
-rw-r--r--src/multimedia/controls/qmediacontainercontrol.cpp1
-rw-r--r--src/multimedia/controls/qmediagaplessplaybackcontrol.cpp1
-rw-r--r--src/multimedia/controls/qmedianetworkaccesscontrol.cpp7
-rw-r--r--src/multimedia/controls/qmedianetworkaccesscontrol.h15
-rw-r--r--src/multimedia/controls/qmediaplayercontrol.cpp1
-rw-r--r--src/multimedia/controls/qmediarecordercontrol.cpp1
-rw-r--r--src/multimedia/controls/qmediastreamscontrol.cpp1
-rw-r--r--src/multimedia/controls/qmediavideoprobecontrol.cpp1
-rw-r--r--src/multimedia/controls/qmetadatareadercontrol.cpp1
-rw-r--r--src/multimedia/controls/qmetadatawritercontrol.cpp1
-rw-r--r--src/multimedia/controls/qradiodatacontrol.cpp1
-rw-r--r--src/multimedia/controls/qradiotunercontrol.cpp2
-rw-r--r--src/multimedia/controls/qvideodeviceselectorcontrol.cpp1
-rw-r--r--src/multimedia/controls/qvideoencodersettingscontrol.cpp1
-rw-r--r--src/multimedia/controls/qvideorenderercontrol.cpp1
-rw-r--r--src/multimedia/controls/qvideowindowcontrol.cpp1
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/media.cpp31
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/multimedia-snippets.pro3
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/multiple-videooutputs.qml (renamed from src/multimedia/video/qvideoframe_p.h)48
-rw-r--r--src/multimedia/doc/snippets/multimedia-snippets/video.cpp23
-rw-r--r--src/multimedia/doc/src/cameraoverview.qdoc2
-rw-r--r--src/multimedia/doc/src/platform-notes-windows.qdoc5
-rw-r--r--src/multimedia/doc/src/qtmultimedia-index.qdoc3
-rw-r--r--src/multimedia/playback/qmediaplayer.cpp73
-rw-r--r--src/multimedia/playback/qmediaplayer.h31
-rw-r--r--src/multimedia/playback/qplaylistfileparser.cpp2
-rw-r--r--src/multimedia/qmediacontrol.cpp1
-rw-r--r--src/multimedia/qmediapluginloader.cpp2
-rw-r--r--src/multimedia/qmediaservice.cpp1
-rw-r--r--src/multimedia/qmediaserviceprovider.cpp6
-rw-r--r--src/multimedia/video/qabstractvideobuffer.cpp5
-rw-r--r--src/multimedia/video/qabstractvideobuffer.h1
-rw-r--r--src/multimedia/video/qmemoryvideobuffer.cpp2
-rw-r--r--src/multimedia/video/qvideoframe.cpp8
-rw-r--r--src/multimedia/video/qvideoframe.h2
-rw-r--r--src/multimedia/video/qvideosurfaces.cpp103
-rw-r--r--src/multimedia/video/qvideosurfaces_p.h77
-rw-r--r--src/multimedia/video/video.pri7
-rw-r--r--src/multimediawidgets/qgraphicsvideoitem.cpp20
-rw-r--r--src/multimediawidgets/qgraphicsvideoitem.h2
-rw-r--r--src/multimediawidgets/qpaintervideosurface.cpp109
-rw-r--r--src/multimediawidgets/qpaintervideosurface_p.h13
-rw-r--r--src/multimediawidgets/qvideowidget.cpp65
-rw-r--r--src/multimediawidgets/qvideowidget.h3
-rw-r--r--src/multimediawidgets/qvideowidget_p.h49
-rw-r--r--src/plugins/alsa/qalsaaudiodeviceinfo.h18
-rw-r--r--src/plugins/alsa/qalsaaudioinput.h44
-rw-r--r--src/plugins/alsa/qalsaaudiooutput.cpp2
-rw-r--r--src/plugins/alsa/qalsaaudiooutput.h44
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcamerasession.cpp3
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcapturesession.cpp56
-rw-r--r--src/plugins/android/src/mediacapture/qandroidcapturesession.h3
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp8
-rw-r--r--src/plugins/android/src/wrappers/jni/androidcamera.cpp6
-rw-r--r--src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp2
-rw-r--r--src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp26
-rw-r--r--src/plugins/android/src/wrappers/jni/androidmediarecorder.h2
-rw-r--r--src/plugins/avfoundation/camera/avfcameraflashcontrol.mm26
-rw-r--r--src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm7
-rw-r--r--src/plugins/avfoundation/camera/avfcameraservice.h5
-rw-r--r--src/plugins/avfoundation/camera/avfcameraservice.mm29
-rw-r--r--src/plugins/avfoundation/camera/avfcamerasession.h3
-rw-r--r--src/plugins/avfoundation/camera/avfcamerasession.mm33
-rw-r--r--src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm43
-rw-r--r--src/plugins/avfoundation/camera/avfcamerawindowcontrol.h129
-rw-r--r--src/plugins/avfoundation/camera/avfcamerawindowcontrol.mm262
-rw-r--r--src/plugins/avfoundation/camera/avfcapturedestinationcontrol.h63
-rw-r--r--src/plugins/avfoundation/camera/avfcapturedestinationcontrol.mm62
-rw-r--r--src/plugins/avfoundation/camera/avfimagecapturecontrol.mm34
-rw-r--r--src/plugins/avfoundation/camera/camera.pro8
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h6
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm137
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.h67
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.mm330
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfvideoframerenderer_ios.h113
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfvideoframerenderer_ios.mm261
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.h5
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm138
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfvideowidget.mm17
-rw-r--r--src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm9
-rw-r--r--src/plugins/avfoundation/mediaplayer/mediaplayer.pro38
-rw-r--r--src/plugins/common/evr/evrcustompresenter.cpp36
-rw-r--r--src/plugins/common/evr/evrcustompresenter.h3
-rw-r--r--src/plugins/common/evr/evrd3dpresentengine.cpp7
-rw-r--r--src/plugins/common/evr/evrd3dpresentengine.h3
-rw-r--r--src/plugins/common/evr/evrvideowindowcontrol.cpp24
-rw-r--r--src/plugins/common/evr/evrvideowindowcontrol.h3
-rw-r--r--src/plugins/coreaudio/coreaudiodeviceinfo.mm13
-rw-r--r--src/plugins/coreaudio/coreaudioinput.mm5
-rw-r--r--src/plugins/coreaudio/coreaudiooutput.mm7
-rw-r--r--src/plugins/coreaudio/coreaudiosessionmanager.mm5
-rw-r--r--src/plugins/directshow/camera/dscamerasession.cpp78
-rw-r--r--src/plugins/directshow/camera/dscamerasession.h2
-rw-r--r--src/plugins/directshow/common/directshowmediatype.cpp9
-rw-r--r--src/plugins/directshow/common/directshowmediatypeenum.cpp3
-rw-r--r--src/plugins/directshow/common/directshowutils.cpp29
-rw-r--r--src/plugins/directshow/common/directshowutils.h2
-rw-r--r--src/plugins/directshow/player/directshowioreader.cpp2
-rw-r--r--src/plugins/directshow/player/directshowmetadatacontrol.cpp2
-rw-r--r--src/plugins/gstreamer/camerabin/camerabinfocus.cpp2
-rw-r--r--src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp5
-rw-r--r--src/plugins/gstreamer/camerabin/camerabinsession.cpp22
-rw-r--r--src/plugins/gstreamer/camerabin/camerabinzoom.cpp32
-rw-r--r--src/plugins/gstreamer/camerabin/camerabinzoom.h4
-rw-r--r--src/plugins/m3u/qm3uhandler.cpp12
-rw-r--r--src/plugins/m3u/qm3uhandler.h12
-rw-r--r--src/plugins/pulseaudio/qaudiodeviceinfo_pulse.h18
-rw-r--r--src/plugins/pulseaudio/qaudioinput_pulse.cpp8
-rw-r--r--src/plugins/pulseaudio/qaudioinput_pulse.h46
-rw-r--r--src/plugins/pulseaudio/qaudiooutput_pulse.cpp36
-rw-r--r--src/plugins/pulseaudio/qaudiooutput_pulse.h52
-rw-r--r--src/plugins/pulseaudio/qpulseaudioplugin.h10
-rw-r--r--src/plugins/qnx-audio/audio/audio.pro1
-rw-r--r--src/plugins/qnx-audio/audio/qnxaudioinput.cpp2
-rw-r--r--src/plugins/qnx/common/windowgrabber.cpp8
-rw-r--r--src/plugins/videonode/imx6/imx6.pro8
-rw-r--r--src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp23
-rw-r--r--src/plugins/videonode/imx6/qsgvivantevideomaterial.h2
-rw-r--r--src/plugins/videonode/videonode.pro2
-rw-r--r--src/plugins/windowsaudio/qwindowsaudiooutput.cpp2
-rw-r--r--src/plugins/winrt/qwinrtcameracontrol.cpp2
-rw-r--r--src/plugins/wmf/player/mfplayersession.cpp21
-rw-r--r--src/plugins/wmf/player/mftvideo.cpp2
-rw-r--r--src/plugins/wmf/player/mfvideorenderercontrol.cpp24
-rw-r--r--src/plugins/wmf/player/mfvideorenderercontrol.h5
-rw-r--r--src/plugins/wmf/sourceresolver.cpp2
-rw-r--r--src/qtmultimediaquicktools/qdeclarativevideooutput.cpp49
-rw-r--r--src/qtmultimediaquicktools/qdeclarativevideooutput_p.h4
-rw-r--r--src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp7
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_texture.cpp147
-rw-r--r--src/qtmultimediaquicktools/qsgvideonode_texture_p.h2
-rw-r--r--src/qtmultimediaquicktools/qtmultimediaquicktools.qrc5
-rw-r--r--src/qtmultimediaquicktools/shaders/rectsampler.vert10
-rw-r--r--src/qtmultimediaquicktools/shaders/rectsampler_core.vert11
-rw-r--r--src/qtmultimediaquicktools/shaders/rectsampler_rgb.frag8
-rw-r--r--src/qtmultimediaquicktools/shaders/rectsampler_rgb_core.frag10
185 files changed, 2794 insertions, 1417 deletions
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/qgstreamerplayercontrol.cpp b/src/gsttools/qgstreamerplayercontrol.cpp
index 165978288..689467db8 100644
--- a/src/gsttools/qgstreamerplayercontrol.cpp
+++ b/src/gsttools/qgstreamerplayercontrol.cpp
@@ -439,8 +439,10 @@ void QGstreamerPlayerControl::updateSessionState(QMediaPlayer::State state)
}
m_pendingSeekPosition = -1;
- if (m_currentState == QMediaPlayer::PlayingState)
- m_session->play();
+ if (m_currentState == QMediaPlayer::PlayingState) {
+ if (m_bufferProgress == -1 || m_bufferProgress == 100)
+ m_session->play();
+ }
}
updateMediaStatus();
diff --git a/src/gsttools/qgstreamerplayersession.cpp b/src/gsttools/qgstreamerplayersession.cpp
index ed3f16c5f..d36f73b2a 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,21 @@ 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
+ static const auto convDesc = qEnvironmentVariable("QT_GSTREAMER_PLAYBIN_CONVERT");
+ GError *err = nullptr;
+ auto convPipeline = !convDesc.isEmpty() ? convDesc.toLatin1().constData() : "identity";
+ auto convElement = gst_parse_launch(convPipeline, &err);
+ if (err) {
+ qWarning() << "Error:" << convDesc << ":" << QLatin1String(err->message);
+ g_clear_error(&err);
+ }
+ m_videoIdentity = convElement;
#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 +180,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 +191,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 +214,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 +295,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 +322,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 +354,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();
@@ -494,10 +502,12 @@ void QGstreamerPlayerSession::setPlaybackRate(qreal rate)
if (!qFuzzyCompare(m_playbackRate, rate)) {
m_playbackRate = rate;
if (m_pipeline && m_seekable) {
+ qint64 from = rate > 0 ? position() : 0;
+ qint64 to = rate > 0 ? duration() : position();
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_SET, from * 1000000,
+ GST_SEEK_TYPE_SET, to * 1000000);
}
emit playbackRateChanged(m_playbackRate);
}
@@ -547,13 +557,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 +588,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 +676,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 +745,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 +754,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 +790,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 +823,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 +881,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 +972,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;
@@ -1080,15 +1088,13 @@ bool QGstreamerPlayerSession::seek(qint64 ms)
//seek locks when the video output sink is changing and pad is blocked
if (m_pipeline && !m_pendingVideoSink && m_state != QMediaPlayer::StoppedState && m_seekable) {
ms = qMax(ms,qint64(0));
- gint64 position = ms * 1000000;
- bool isSeeking = gst_element_seek(m_pipeline,
- m_playbackRate,
- GST_FORMAT_TIME,
+ qint64 from = m_playbackRate > 0 ? ms : 0;
+ qint64 to = m_playbackRate > 0 ? duration() : ms;
+
+ bool isSeeking = gst_element_seek(m_pipeline, m_playbackRate, GST_FORMAT_TIME,
GstSeekFlags(GST_SEEK_FLAG_FLUSH),
- GST_SEEK_TYPE_SET,
- position,
- GST_SEEK_TYPE_NONE,
- 0);
+ GST_SEEK_TYPE_SET, from * 1000000,
+ GST_SEEK_TYPE_SET, to * 1000000);
if (isSeeking)
m_lastPosition = ms;
@@ -1108,7 +1114,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 +1129,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 +1461,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;
@@ -1581,7 +1587,7 @@ void QGstreamerPlayerSession::updateVideoResolutionTag()
void QGstreamerPlayerSession::updateDuration()
{
gint64 gstDuration = 0;
- int duration = 0;
+ qint64 duration = 0;
if (m_pipeline && qt_gst_element_query_duration(m_pipeline, GST_FORMAT_TIME, &gstDuration))
duration = gstDuration / 1000000;
@@ -1617,7 +1623,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 +1640,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 +1665,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 +1681,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 +1690,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 +1723,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 +1744,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 +1766,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 +1781,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 +1819,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 +1849,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 +1857,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 +1900,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/qgstreamervideowidget.cpp b/src/gsttools/qgstreamervideowidget.cpp
index 164e62f86..4137aff32 100644
--- a/src/gsttools/qgstreamervideowidget.cpp
+++ b/src/gsttools/qgstreamervideowidget.cpp
@@ -38,6 +38,7 @@
****************************************************************************/
#include "qgstreamervideowidget_p.h"
+#include "qgstutils_p.h"
#include <QtCore/qcoreevent.h>
#include <QtCore/qdebug.h>
@@ -170,7 +171,8 @@ bool QGstreamerVideoWidgetControl::eventFilter(QObject *object, QEvent *e)
if (e->type() == QEvent::Paint) {
// Update overlay by new size if any.
- m_videoOverlay.setRenderRectangle(QRect(0, 0, m_widget->width(), m_widget->height()));
+ if (QGstUtils::useOpenGL())
+ m_videoOverlay.setRenderRectangle(QRect(0, 0, m_widget->width(), m_widget->height()));
if (m_videoOverlay.isActive())
m_videoOverlay.expose(); // triggers a repaint of the last frame
else
diff --git a/src/gsttools/qgstutils.cpp b/src/gsttools/qgstutils.cpp
index f8a9d79c1..3f68244ba 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);
@@ -866,7 +866,7 @@ QSet<QString> QGstUtils::supportedMimeTypes(bool (*isValidFactory)(GstElementFac
if (value) {
gchar *str = gst_value_serialize(value);
QString versions = QLatin1String(str);
- const QStringList elements = versions.split(QRegularExpression(QLatin1String("\\D+")), QString::SkipEmptyParts);
+ const QStringList elements = versions.split(QRegularExpression(QLatin1String("\\D+")), Qt::SkipEmptyParts);
for (const QString &e : elements)
supportedMimeTypes.insert(nameLowcase + e);
g_free(str);
@@ -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..4000f2178 100644
--- a/src/gsttools/qgstvideorenderersink.cpp
+++ b/src/gsttools/qgstvideorenderersink.cpp
@@ -141,6 +141,19 @@ bool QGstDefaultVideoRenderer::present(QAbstractVideoSurface *surface, GstBuffer
if (!videoBuffer)
videoBuffer = new QGstVideoBuffer(buffer, m_videoInfo);
+ auto meta = gst_buffer_get_video_crop_meta (buffer);
+ if (meta) {
+ QRect vp(meta->x, meta->y, meta->width, meta->height);
+ if (m_format.viewport() != vp) {
+#ifdef DEBUG_VIDEO_SURFACE_SINK
+ qDebug() << Q_FUNC_INFO << " Update viewport on Metadata: [" << meta->height << "x" << meta->width << " | " << meta->x << "x" << meta->y << "]";
+#endif
+ //Update viewport if data is not the same
+ m_format.setViewport(vp);
+ surface->start(m_format);
+ }
+ }
+
QVideoFrame frame(
videoBuffer,
m_format.frameSize(),
@@ -170,8 +183,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 +317,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 +373,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 +406,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 +596,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 +707,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 +727,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/Video.qml b/src/imports/multimedia/Video.qml
index 19c437869..24fde22e1 100644
--- a/src/imports/multimedia/Video.qml
+++ b/src/imports/multimedia/Video.qml
@@ -38,7 +38,7 @@
****************************************************************************/
import QtQuick 2.0
-import QtMultimedia 5.11
+import QtMultimedia 5.13
/*!
\qmltype Video
@@ -125,6 +125,23 @@ Item {
property alias fillMode: videoOut.fillMode
/*!
+ \qmlproperty enumeration Video::flushMode
+
+ Set this property to define what \c Video should show
+ when playback is finished or stopped.
+
+ \list
+ \li VideoOutput.EmptyFrame - clears video output.
+ \li VideoOutput.FirstFrame - shows the first valid frame.
+ \li VideoOutput.LastFrame - shows the last valid frame.
+ \endlist
+
+ The default flush mode is EmptyFrame.
+ \since 5.15
+ */
+ property alias flushMode: videoOut.flushMode
+
+ /*!
\qmlproperty int Video::orientation
The orientation of the \c Video in degrees. Only multiples of 90
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/plugins.qmltypes b/src/imports/multimedia/plugins.qmltypes
index 870544160..06fb8918b 100644
--- a/src/imports/multimedia/plugins.qmltypes
+++ b/src/imports/multimedia/plugins.qmltypes
@@ -4,7 +4,7 @@ import QtQuick.tooling 1.2
// It is used for QML tooling purposes only.
//
// This file was auto-generated by:
-// 'qmlplugindump -nonrelocatable QtMultimedia 5.14'
+// 'qmlplugindump -nonrelocatable QtMultimedia 5.15'
Module {
dependencies: ["QtQuick 2.0"]
@@ -288,6 +288,24 @@ Module {
Property { name: "active"; type: "bool" }
}
Component {
+ name: "QAbstractVideoSurface"
+ prototype: "QObject"
+ Property { name: "nativeResolution"; type: "QSize"; isReadonly: true }
+ Signal {
+ name: "activeChanged"
+ Parameter { name: "active"; type: "bool" }
+ }
+ Signal {
+ name: "surfaceFormatChanged"
+ Parameter { name: "format"; type: "QVideoSurfaceFormat" }
+ }
+ Signal { name: "supportedFormatsChanged" }
+ Signal {
+ name: "nativeResolutionChanged"
+ Parameter { name: "resolution"; type: "QSize" }
+ }
+ }
+ Component {
name: "QCamera"
prototype: "QMediaObject"
Enum {
@@ -427,10 +445,11 @@ Module {
"QtMultimedia/Audio 5.9",
"QtMultimedia/MediaPlayer 5.0",
"QtMultimedia/MediaPlayer 5.11",
+ "QtMultimedia/MediaPlayer 5.15",
"QtMultimedia/MediaPlayer 5.6",
"QtMultimedia/MediaPlayer 5.9"
]
- exportMetaObjectRevisions: [0, 3, 1, 2, 0, 3, 1, 2]
+ exportMetaObjectRevisions: [0, 3, 1, 2, 0, 3, 15, 1, 2]
Enum {
name: "Status"
values: {
@@ -524,6 +543,7 @@ Module {
Property { name: "audioRole"; revision: 1; type: "AudioRole" }
Property { name: "customAudioRole"; revision: 3; type: "string" }
Property { name: "notifyInterval"; revision: 2; type: "int" }
+ Property { name: "videoOutput"; revision: 15; type: "QVariant" }
Signal { name: "playlistChanged"; revision: 1 }
Signal { name: "loopCountChanged" }
Signal { name: "paused" }
@@ -541,6 +561,7 @@ Module {
Parameter { name: "errorString"; type: "string" }
}
Signal { name: "notifyIntervalChanged"; revision: 2 }
+ Signal { name: "videoOutputChanged"; revision: 15 }
Method { name: "play" }
Method { name: "pause" }
Method { name: "stop" }
@@ -2025,9 +2046,10 @@ Module {
exports: [
"QtMultimedia/VideoOutput 5.0",
"QtMultimedia/VideoOutput 5.13",
+ "QtMultimedia/VideoOutput 5.15",
"QtMultimedia/VideoOutput 5.2"
]
- exportMetaObjectRevisions: [0, 13, 2]
+ exportMetaObjectRevisions: [0, 13, 15, 2]
Enum {
name: "FlushMode"
values: {
@@ -2052,6 +2074,13 @@ Module {
Property { name: "contentRect"; type: "QRectF"; isReadonly: true }
Property { name: "filters"; type: "QAbstractVideoFilter"; isList: true; isReadonly: true }
Property { name: "flushMode"; revision: 13; type: "FlushMode" }
+ Property {
+ name: "videoSurface"
+ revision: 15
+ type: "QAbstractVideoSurface"
+ isReadonly: true
+ isPointer: true
+ }
Signal {
name: "fillModeChanged"
Parameter { type: "QDeclarativeVideoOutput::FillMode" }
@@ -2124,6 +2153,7 @@ Module {
Parameter { name: "availability"; type: "QMultimedia::AvailabilityStatus" }
}
}
+ Component { name: "QSGVideoItemSurface"; prototype: "QAbstractVideoSurface" }
Component {
name: "QSoundEffect"
prototype: "QObject"
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/imports/multimedia/qdeclarativecamera.cpp b/src/imports/multimedia/qdeclarativecamera.cpp
index 7730c9900..3a9bc8fa2 100644
--- a/src/imports/multimedia/qdeclarativecamera.cpp
+++ b/src/imports/multimedia/qdeclarativecamera.cpp
@@ -59,9 +59,10 @@
QT_BEGIN_NAMESPACE
-void QDeclarativeCamera::_q_error(QCamera::Error errorCode)
+void QDeclarativeCamera::_q_errorOccurred(QCamera::Error errorCode)
{
emit error(Error(errorCode), errorString());
+ emit errorOccurred(Error(errorCode), errorString());
emit errorChanged();
}
@@ -197,7 +198,7 @@ QDeclarativeCamera::QDeclarativeCamera(QObject *parent) :
this, SIGNAL(lockStatusChanged()));
connect(m_camera, &QCamera::stateChanged, this, &QDeclarativeCamera::_q_updateState);
connect(m_camera, SIGNAL(statusChanged(QCamera::Status)), this, SIGNAL(cameraStatusChanged()));
- connect(m_camera, SIGNAL(error(QCamera::Error)), this, SLOT(_q_error(QCamera::Error)));
+ connect(m_camera, SIGNAL(errorOccurred(QCamera::Error)), this, SLOT(_q_errorOccurred(QCamera::Error)));
connect(m_camera, SIGNAL(availabilityChanged(QMultimedia::AvailabilityStatus)),
this, SLOT(_q_availabilityChanged(QMultimedia::AvailabilityStatus)));
@@ -420,7 +421,7 @@ QDeclarativeCamera::Error QDeclarativeCamera::errorCode() const
This property holds the last error string, if any.
- \sa error, errorCode
+ \sa errorOccurred, errorCode
*/
QString QDeclarativeCamera::errorString() const
{
@@ -752,11 +753,19 @@ void QDeclarativeCamera::setDigitalZoom(qreal value)
\value Camera.NotSupportedFeatureError
The feature is not supported.
- \sa error, errorString
+ \sa errorOccurred, errorString
*/
/*!
\qmlsignal QtMultimedia::Camera::error(errorCode, errorString)
+ \obsolete
+
+ Use errorOccurred() instead.
+*/
+
+/*!
+ \qmlsignal QtMultimedia::Camera::errorOccurred(errorCode, errorString)
+ \since 5.15
This signal is emitted when an error specified by \a errorCode occurs.
A descriptive string value is available in \a errorString.
diff --git a/src/imports/multimedia/qdeclarativecamera_p.h b/src/imports/multimedia/qdeclarativecamera_p.h
index 97afa5b53..41203ac80 100644
--- a/src/imports/multimedia/qdeclarativecamera_p.h
+++ b/src/imports/multimedia/qdeclarativecamera_p.h
@@ -308,7 +308,10 @@ public Q_SLOTS:
Q_SIGNALS:
void errorChanged();
+#if QT_DEPRECATED_SINCE(5,15)
void error(QDeclarativeCamera::Error errorCode, const QString &errorString);
+#endif
+ Q_REVISION(15) void errorOccurred(QDeclarativeCamera::Error errorCode, const QString &errorString);
Q_REVISION(1) void deviceIdChanged();
Q_REVISION(1) void positionChanged();
@@ -332,7 +335,7 @@ Q_SIGNALS:
private Q_SLOTS:
void _q_updateState(QCamera::State);
- void _q_error(QCamera::Error);
+ void _q_errorOccurred(QCamera::Error);
void _q_availabilityChanged(QMultimedia::AvailabilityStatus);
protected:
diff --git a/src/multimedia/audio/qaudiohelpers.cpp b/src/multimedia/audio/qaudiohelpers.cpp
index fae591477..1cd189d6e 100644
--- a/src/multimedia/audio/qaudiohelpers.cpp
+++ b/src/multimedia/audio/qaudiohelpers.cpp
@@ -103,19 +103,19 @@ template<class T> struct signedVersion {};
template<> struct signedVersion<quint8>
{
typedef qint8 TS;
- enum {offset = 0x80};
+ static constexpr int offset = 0x80;
};
template<> struct signedVersion<quint16>
{
typedef qint16 TS;
- enum {offset = 0x8000};
+ static constexpr int offset = 0x8000;
};
template<> struct signedVersion<quint32>
{
typedef qint32 TS;
- enum {offset = 0x80000000};
+ static constexpr uint offset = 0x80000000;
};
template<class T> void adjustUnsignedSamples(qreal factor, const void *src, void *dst, int samples)
diff --git a/src/multimedia/audio/qsamplecache_p.cpp b/src/multimedia/audio/qsamplecache_p.cpp
index 8c4fdc210..b293946cc 100644
--- a/src/multimedia/audio/qsamplecache_p.cpp
+++ b/src/multimedia/audio/qsamplecache_p.cpp
@@ -397,7 +397,7 @@ void QSample::load()
qDebug() << "QSample: load [" << m_url << "]";
#endif
m_stream = m_parent->networkAccessManager().get(QNetworkRequest(m_url));
- connect(m_stream, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(decoderError()));
+ connect(m_stream, SIGNAL(errorOccurred(QNetworkReply::NetworkError)), SLOT(decoderError()));
m_waveDecoder = new QWaveDecoder(m_stream);
connect(m_waveDecoder, SIGNAL(formatKnown()), SLOT(decoderReady()));
connect(m_waveDecoder, SIGNAL(parsingError()), SLOT(decoderError()));
diff --git a/src/multimedia/audio/qsoundeffect_pulse_p.cpp b/src/multimedia/audio/qsoundeffect_pulse_p.cpp
index 0855c1f67..a141f7e36 100644
--- a/src/multimedia/audio/qsoundeffect_pulse_p.cpp
+++ b/src/multimedia/audio/qsoundeffect_pulse_p.cpp
@@ -528,6 +528,21 @@ qreal QSoundEffectPrivate::volume() const
return m_volume;
}
+static void volume_stream_flush_callback(pa_stream *s, int success, void *userdata)
+{
+ Q_UNUSED(s);
+ QSoundEffectRef *ref = reinterpret_cast<QSoundEffectRef *>(userdata);
+ QSoundEffectPrivate *self = ref->soundEffect();
+ ref->release();
+ if (!self)
+ return;
+
+ if (!success)
+ qWarning("QSoundEffect(pulseaudio): failed to drain");
+
+ QMetaObject::invokeMethod(self, "prepare", Qt::QueuedConnection);
+}
+
void QSoundEffectPrivate::setVolume(qreal volume)
{
QMutexLocker locker(&m_volumeLock);
@@ -537,6 +552,10 @@ void QSoundEffectPrivate::setVolume(qreal volume)
m_volume = qBound(qreal(0), volume, qreal(1));
locker.unlock();
+ if (!m_playing && m_pulseStream) {
+ PulseDaemonLocker locker;
+ pa_stream_flush(m_pulseStream, volume_stream_flush_callback, m_ref->getRef());
+ }
emit volumeChanged();
}
diff --git a/src/multimedia/camera/qcamera.cpp b/src/multimedia/camera/qcamera.cpp
index 40441f332..79412b961 100644
--- a/src/multimedia/camera/qcamera.cpp
+++ b/src/multimedia/camera/qcamera.cpp
@@ -109,6 +109,7 @@ void QCameraPrivate::_q_error(int error, const QString &errorString)
this->error = QCamera::Error(error);
this->errorString = errorString;
+ emit q->errorOccurred(this->error);
emit q->error(this->error);
}
@@ -823,7 +824,7 @@ void QCamera::setCaptureMode(QCamera::CaptureModes mode)
Starts the camera.
State is changed to QCamera::ActiveState if camera is started
- successfully, otherwise error() signal is emitted.
+ successfully, otherwise errorOccurred() signal is emitted.
While the camera state is changed to QCamera::ActiveState,
starting the camera service can be asynchronous with the actual
@@ -1271,6 +1272,14 @@ void QCamera::unlock()
/*!
\fn void QCamera::error(QCamera::Error value)
+ \obsolete
+
+ Use errorOccurred() instead.
+*/
+
+/*!
+ \fn void QCamera::errorOccurred(QCamera::Error value)
+ \since 5.15
Signal emitted when error state changes to \a value.
*/
diff --git a/src/multimedia/camera/qcamera.h b/src/multimedia/camera/qcamera.h
index b2582cd19..97cf4509b 100644
--- a/src/multimedia/camera/qcamera.h
+++ b/src/multimedia/camera/qcamera.h
@@ -242,7 +242,10 @@ Q_SIGNALS:
void lockStatusChanged(QCamera::LockStatus status, QCamera::LockChangeReason reason);
void lockStatusChanged(QCamera::LockType lock, QCamera::LockStatus status, QCamera::LockChangeReason reason);
+#if QT_DEPRECATED_SINCE(5,15)
void error(QCamera::Error);
+#endif
+ void errorOccurred(QCamera::Error);
private:
Q_DISABLE_COPY(QCamera)
diff --git a/src/multimedia/camera/qcameraimagecapture.cpp b/src/multimedia/camera/qcameraimagecapture.cpp
index 502812f76..7eb67daed 100644
--- a/src/multimedia/camera/qcameraimagecapture.cpp
+++ b/src/multimedia/camera/qcameraimagecapture.cpp
@@ -618,7 +618,8 @@ void QCameraImageCapture::cancelCapture()
/*!
\fn QCameraImageCapture::imageCaptured(int id, const QImage &preview);
- Signal emitted when the frame with request \a id was captured, but not processed and saved yet.
+ Signal emitted when QAbstractVideoSurface is used as a viewfinder and
+ the frame with request \a id was captured, but not processed and saved yet.
Frame \a preview can be displayed to user.
*/
@@ -634,13 +635,15 @@ void QCameraImageCapture::cancelCapture()
/*!
\fn QCameraImageCapture::imageAvailable(int id, const QVideoFrame &frame)
- Signal emitted when the \a frame with request \a id is available.
+ Signal emitted when QCameraImageCapture::CaptureToBuffer is set and
+ the \a frame with request \a id is available.
*/
/*!
\fn QCameraImageCapture::imageSaved(int id, const QString &fileName)
- Signal emitted when the frame with request \a id was saved to \a fileName.
+ Signal emitted when QCameraImageCapture::CaptureToFile is set and
+ the frame with request \a id was saved to \a fileName.
*/
QT_END_NAMESPACE
diff --git a/src/multimedia/configure.json b/src/multimedia/configure.json
index e9480dfc5..7f9b5d064 100644
--- a/src/multimedia/configure.json
+++ b/src/multimedia/configure.json
@@ -54,7 +54,7 @@
"test": "gstreamer",
"sources": [
{ "type": "pkgConfig",
- "args": "gstreamer-1.0 gstreamer-base-1.0 gstreamer-audio-1.0 gstreamer-video-1.0 gstreamer-pbutils-1.0" },
+ "args": "gstreamer-1.0 gstreamer-base-1.0 gstreamer-audio-1.0 gstreamer-video-1.0 gstreamer-pbutils-1.0 gstreamer-allocators-1.0" },
{ "libs": "-lgstreamer-1.0 -lgstbase-1.0 -lgstaudio-1.0 -lgstvideo-1.0 -lgstpbutils-1.0 -lglib-2.0 -lgobject-2.0",
"condition": "config.win32 || config.macos" },
{ "libs": "", "condition": "config.android && input.gstreamer != ''" }
@@ -109,18 +109,6 @@
{ "type": "pkgConfig", "args": "gstreamer-gl-1.0" }
]
},
- "gstreamer_imxcommon": {
- "label": "GStreamer i.MX common",
- "export": "gstreamer_imxcommon",
- "test": {
- "include": "gst/allocators/imx/phys_mem_meta.h"
- },
- "use": "gstreamer_1_0",
- "sources": [
- { "type": "pkgConfig",
- "args": "gstimxcommon" }
- ]
- },
"libresourceqt5": {
"label": "libresourceqt5",
"test": "resourcepolicy",
@@ -260,11 +248,6 @@
"condition": "features.opengl && features.gstreamer_1_0 && libs.gstreamer_gl_1_0",
"output": [ "privateFeature" ]
},
- "gstreamer_imxcommon": {
- "label": "GStreamer i.MX common",
- "condition": "(features.gstreamer_1_0 && libs.gstreamer_imxcommon)",
- "output": [ "privateFeature" ]
- },
"gpu_vivante": {
"label": "Vivante GPU",
"condition": "features.gui && features.opengles2 && tests.gpu_vivante",
diff --git a/src/multimedia/controls/qaudiodecodercontrol.cpp b/src/multimedia/controls/qaudiodecodercontrol.cpp
index 4d6d36a2f..711303174 100644
--- a/src/multimedia/controls/qaudiodecodercontrol.cpp
+++ b/src/multimedia/controls/qaudiodecodercontrol.cpp
@@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QAudioDecoderControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qaudioencodersettingscontrol.cpp b/src/multimedia/controls/qaudioencodersettingscontrol.cpp
index 42f20201c..5ae473178 100644
--- a/src/multimedia/controls/qaudioencodersettingscontrol.cpp
+++ b/src/multimedia/controls/qaudioencodersettingscontrol.cpp
@@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QAudioEncoderSettingsControl
+ \obsolete
\inmodule QtMultimedia
\ingroup multimedia_control
diff --git a/src/multimedia/controls/qaudioinputselectorcontrol.cpp b/src/multimedia/controls/qaudioinputselectorcontrol.cpp
index 0f8843808..649891225 100644
--- a/src/multimedia/controls/qaudioinputselectorcontrol.cpp
+++ b/src/multimedia/controls/qaudioinputselectorcontrol.cpp
@@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QAudioInputSelectorControl
+ \obsolete
\brief The QAudioInputSelectorControl class provides an audio input selector media control.
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qaudiooutputselectorcontrol.cpp b/src/multimedia/controls/qaudiooutputselectorcontrol.cpp
index 20c792f8d..64886e4c9 100644
--- a/src/multimedia/controls/qaudiooutputselectorcontrol.cpp
+++ b/src/multimedia/controls/qaudiooutputselectorcontrol.cpp
@@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QAudioOutputSelectorControl
+ \obsolete
\brief The QAudioOutputSelectorControl class provides an audio output selector media control.
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qaudiorolecontrol.cpp b/src/multimedia/controls/qaudiorolecontrol.cpp
index 7b2341846..01e60a914 100644
--- a/src/multimedia/controls/qaudiorolecontrol.cpp
+++ b/src/multimedia/controls/qaudiorolecontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QAudioRoleControl
+ \obsolete
\inmodule QtMultimedia
\ingroup multimedia_control
\since 5.6
diff --git a/src/multimedia/controls/qcameracapturebufferformatcontrol.cpp b/src/multimedia/controls/qcameracapturebufferformatcontrol.cpp
index 553414681..8f0c3e6e9 100644
--- a/src/multimedia/controls/qcameracapturebufferformatcontrol.cpp
+++ b/src/multimedia/controls/qcameracapturebufferformatcontrol.cpp
@@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QCameraCaptureBufferFormatControl
+ \obsolete
\brief The QCameraCaptureBufferFormatControl class provides a control for setting the capture buffer format.
diff --git a/src/multimedia/controls/qcameracapturedestinationcontrol.cpp b/src/multimedia/controls/qcameracapturedestinationcontrol.cpp
index e037ab5a9..a9a54a3b8 100644
--- a/src/multimedia/controls/qcameracapturedestinationcontrol.cpp
+++ b/src/multimedia/controls/qcameracapturedestinationcontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QCameraCaptureDestinationControl
+ \obsolete
\brief The QCameraCaptureDestinationControl class provides a control for setting capture destination.
diff --git a/src/multimedia/controls/qcameracontrol.cpp b/src/multimedia/controls/qcameracontrol.cpp
index 03a7a073c..d33fa94c9 100644
--- a/src/multimedia/controls/qcameracontrol.cpp
+++ b/src/multimedia/controls/qcameracontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QCameraControl
+ \obsolete
diff --git a/src/multimedia/controls/qcameraexposurecontrol.cpp b/src/multimedia/controls/qcameraexposurecontrol.cpp
index 1434f0976..2095c9cfa 100644
--- a/src/multimedia/controls/qcameraexposurecontrol.cpp
+++ b/src/multimedia/controls/qcameraexposurecontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QCameraExposureControl
+ \obsolete
\brief The QCameraExposureControl class allows controlling camera exposure parameters.
diff --git a/src/multimedia/controls/qcamerafeedbackcontrol.cpp b/src/multimedia/controls/qcamerafeedbackcontrol.cpp
index 07074d83d..42cd7d661 100644
--- a/src/multimedia/controls/qcamerafeedbackcontrol.cpp
+++ b/src/multimedia/controls/qcamerafeedbackcontrol.cpp
@@ -44,6 +44,7 @@
/*!
\class QCameraFeedbackControl
+ \obsolete
\brief The QCameraFeedbackControl class allows controlling feedback (sounds etc) during camera operation.
diff --git a/src/multimedia/controls/qcameraflashcontrol.cpp b/src/multimedia/controls/qcameraflashcontrol.cpp
index d5d9b564f..658e2d56c 100644
--- a/src/multimedia/controls/qcameraflashcontrol.cpp
+++ b/src/multimedia/controls/qcameraflashcontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QCameraFlashControl
+ \obsolete
\brief The QCameraFlashControl class allows controlling a camera's flash.
diff --git a/src/multimedia/controls/qcamerafocuscontrol.cpp b/src/multimedia/controls/qcamerafocuscontrol.cpp
index d963c95d4..b216882b4 100644
--- a/src/multimedia/controls/qcamerafocuscontrol.cpp
+++ b/src/multimedia/controls/qcamerafocuscontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QCameraFocusControl
+ \obsolete
\brief The QCameraFocusControl class supplies control for
diff --git a/src/multimedia/controls/qcameraimagecapturecontrol.cpp b/src/multimedia/controls/qcameraimagecapturecontrol.cpp
index 3c110eb68..0e089d01b 100644
--- a/src/multimedia/controls/qcameraimagecapturecontrol.cpp
+++ b/src/multimedia/controls/qcameraimagecapturecontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QCameraImageCaptureControl
+ \obsolete
\brief The QCameraImageCaptureControl class provides a control interface
for image capture services.
diff --git a/src/multimedia/controls/qcameraimageprocessingcontrol.cpp b/src/multimedia/controls/qcameraimageprocessingcontrol.cpp
index a39846642..fba4bf400 100644
--- a/src/multimedia/controls/qcameraimageprocessingcontrol.cpp
+++ b/src/multimedia/controls/qcameraimageprocessingcontrol.cpp
@@ -51,6 +51,7 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterCameraImageProcessingControlMetaTypes)
/*!
\class QCameraImageProcessingControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qcamerainfocontrol.cpp b/src/multimedia/controls/qcamerainfocontrol.cpp
index de6dc4277..8a4ef3b44 100644
--- a/src/multimedia/controls/qcamerainfocontrol.cpp
+++ b/src/multimedia/controls/qcamerainfocontrol.cpp
@@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QCameraInfoControl
+ \obsolete
\since 5.3
\brief The QCameraInfoControl class provides a camera info media control.
diff --git a/src/multimedia/controls/qcameralockscontrol.cpp b/src/multimedia/controls/qcameralockscontrol.cpp
index 436b3b9c9..27b68cf2c 100644
--- a/src/multimedia/controls/qcameralockscontrol.cpp
+++ b/src/multimedia/controls/qcameralockscontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QCameraLocksControl
+ \obsolete
diff --git a/src/multimedia/controls/qcameraviewfindersettingscontrol.cpp b/src/multimedia/controls/qcameraviewfindersettingscontrol.cpp
index 6fa0ded82..bd5c7a73b 100644
--- a/src/multimedia/controls/qcameraviewfindersettingscontrol.cpp
+++ b/src/multimedia/controls/qcameraviewfindersettingscontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QCameraViewfinderSettingsControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qcamerazoomcontrol.cpp b/src/multimedia/controls/qcamerazoomcontrol.cpp
index 9c8d8d289..1f0835224 100644
--- a/src/multimedia/controls/qcamerazoomcontrol.cpp
+++ b/src/multimedia/controls/qcamerazoomcontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QCameraZoomControl
+ \obsolete
\brief The QCameraZoomControl class supplies control for
diff --git a/src/multimedia/controls/qcustomaudiorolecontrol.cpp b/src/multimedia/controls/qcustomaudiorolecontrol.cpp
index 046219687..f1b89eda5 100644
--- a/src/multimedia/controls/qcustomaudiorolecontrol.cpp
+++ b/src/multimedia/controls/qcustomaudiorolecontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QCustomAudioRoleControl
+ \obsolete
\inmodule QtMultimedia
\ingroup multimedia_control
\since 5.11
diff --git a/src/multimedia/controls/qimageencodercontrol.cpp b/src/multimedia/controls/qimageencodercontrol.cpp
index c29a61662..6223c33c7 100644
--- a/src/multimedia/controls/qimageencodercontrol.cpp
+++ b/src/multimedia/controls/qimageencodercontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QImageEncoderControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qmediaaudioprobecontrol.cpp b/src/multimedia/controls/qmediaaudioprobecontrol.cpp
index 296f01888..e22135903 100644
--- a/src/multimedia/controls/qmediaaudioprobecontrol.cpp
+++ b/src/multimedia/controls/qmediaaudioprobecontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QMediaAudioProbeControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qmediaavailabilitycontrol.cpp b/src/multimedia/controls/qmediaavailabilitycontrol.cpp
index 1a6d73a8a..68b404369 100644
--- a/src/multimedia/controls/qmediaavailabilitycontrol.cpp
+++ b/src/multimedia/controls/qmediaavailabilitycontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QMediaAvailabilityControl
+ \obsolete
\brief The QMediaAvailabilityControl class supplies a control for reporting availability of a service.
diff --git a/src/multimedia/controls/qmediacontainercontrol.cpp b/src/multimedia/controls/qmediacontainercontrol.cpp
index b15c8acdc..2b2c8b78b 100644
--- a/src/multimedia/controls/qmediacontainercontrol.cpp
+++ b/src/multimedia/controls/qmediacontainercontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QMediaContainerControl
+ \obsolete
\brief The QMediaContainerControl class provides access to the output container format of a QMediaService.
diff --git a/src/multimedia/controls/qmediagaplessplaybackcontrol.cpp b/src/multimedia/controls/qmediagaplessplaybackcontrol.cpp
index b76274972..c9f531454 100644
--- a/src/multimedia/controls/qmediagaplessplaybackcontrol.cpp
+++ b/src/multimedia/controls/qmediagaplessplaybackcontrol.cpp
@@ -42,6 +42,7 @@
/*!
\class QMediaGaplessPlaybackControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qmedianetworkaccesscontrol.cpp b/src/multimedia/controls/qmedianetworkaccesscontrol.cpp
index 9e9ad239d..bd289cc29 100644
--- a/src/multimedia/controls/qmedianetworkaccesscontrol.cpp
+++ b/src/multimedia/controls/qmedianetworkaccesscontrol.cpp
@@ -39,11 +39,15 @@
#include "qmedianetworkaccesscontrol.h"
+#ifndef QT_NO_BEARERMANAGEMENT
+
QT_BEGIN_NAMESPACE
/*!
\class QMediaNetworkAccessControl
+ \obsolete
\brief The QMediaNetworkAccessControl class allows the setting of the Network Access Point for media related activities.
+ \obsolete
\inmodule QtMultimedia
@@ -92,10 +96,13 @@ QMediaNetworkAccessControl::~QMediaNetworkAccessControl()
/*!
\fn QMediaNetworkAccessControl::configurationChanged(const QNetworkConfiguration &configuration)
+
This signal is emitted when the current active network configuration changes
to \a configuration.
*/
QT_END_NAMESPACE
+#endif
+
#include "moc_qmedianetworkaccesscontrol.cpp"
diff --git a/src/multimedia/controls/qmedianetworkaccesscontrol.h b/src/multimedia/controls/qmedianetworkaccesscontrol.h
index daae4f389..681ef61b6 100644
--- a/src/multimedia/controls/qmedianetworkaccesscontrol.h
+++ b/src/multimedia/controls/qmedianetworkaccesscontrol.h
@@ -41,17 +41,25 @@
#ifndef QMEDIANETWORKACCESSCONTROL_H
#define QMEDIANETWORKACCESSCONTROL_H
+#if 0
+#pragma qt_class(QMediaNetworkAccessControl)
+#endif
+
#include <QtMultimedia/qmediacontrol.h>
#include <QtCore/qlist.h>
#include <QtNetwork/qnetworkconfiguration.h>
+#ifndef QT_NO_BEARERMANAGEMENT
+
QT_BEGIN_NAMESPACE
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+
// Required for QDoc workaround
class QString;
-
-class Q_MULTIMEDIA_EXPORT QMediaNetworkAccessControl : public QMediaControl
+class QT_DEPRECATED_VERSION_5_15 Q_MULTIMEDIA_EXPORT QMediaNetworkAccessControl : public QMediaControl
{
Q_OBJECT
public:
@@ -71,7 +79,10 @@ protected:
#define QMediaNetworkAccessControl_iid "org.qt-project.qt.medianetworkaccesscontrol/5.0"
Q_MEDIA_DECLARE_CONTROL(QMediaNetworkAccessControl, QMediaNetworkAccessControl_iid)
+QT_WARNING_POP
+
QT_END_NAMESPACE
+#endif
#endif
diff --git a/src/multimedia/controls/qmediaplayercontrol.cpp b/src/multimedia/controls/qmediaplayercontrol.cpp
index 28b217af8..a180413b9 100644
--- a/src/multimedia/controls/qmediaplayercontrol.cpp
+++ b/src/multimedia/controls/qmediaplayercontrol.cpp
@@ -46,6 +46,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QMediaPlayerControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qmediarecordercontrol.cpp b/src/multimedia/controls/qmediarecordercontrol.cpp
index f078073ef..87ace7017 100644
--- a/src/multimedia/controls/qmediarecordercontrol.cpp
+++ b/src/multimedia/controls/qmediarecordercontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QMediaRecorderControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qmediastreamscontrol.cpp b/src/multimedia/controls/qmediastreamscontrol.cpp
index aa5fe007d..2db9eb6fc 100644
--- a/src/multimedia/controls/qmediastreamscontrol.cpp
+++ b/src/multimedia/controls/qmediastreamscontrol.cpp
@@ -52,6 +52,7 @@ Q_CONSTRUCTOR_FUNCTION(qRegisterMediaStreamControlMetaTypes)
/*!
\class QMediaStreamsControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qmediavideoprobecontrol.cpp b/src/multimedia/controls/qmediavideoprobecontrol.cpp
index ea27ab057..4a85d56d0 100644
--- a/src/multimedia/controls/qmediavideoprobecontrol.cpp
+++ b/src/multimedia/controls/qmediavideoprobecontrol.cpp
@@ -44,6 +44,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QMediaVideoProbeControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qmetadatareadercontrol.cpp b/src/multimedia/controls/qmetadatareadercontrol.cpp
index e728353f6..f01ffec38 100644
--- a/src/multimedia/controls/qmetadatareadercontrol.cpp
+++ b/src/multimedia/controls/qmetadatareadercontrol.cpp
@@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QMetaDataReaderControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qmetadatawritercontrol.cpp b/src/multimedia/controls/qmetadatawritercontrol.cpp
index 053597b88..6221edaa1 100644
--- a/src/multimedia/controls/qmetadatawritercontrol.cpp
+++ b/src/multimedia/controls/qmetadatawritercontrol.cpp
@@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QMetaDataWriterControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qradiodatacontrol.cpp b/src/multimedia/controls/qradiodatacontrol.cpp
index df0046b5e..27e192674 100644
--- a/src/multimedia/controls/qradiodatacontrol.cpp
+++ b/src/multimedia/controls/qradiodatacontrol.cpp
@@ -46,6 +46,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QRadioDataControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qradiotunercontrol.cpp b/src/multimedia/controls/qradiotunercontrol.cpp
index ea2126319..20897150b 100644
--- a/src/multimedia/controls/qradiotunercontrol.cpp
+++ b/src/multimedia/controls/qradiotunercontrol.cpp
@@ -46,9 +46,9 @@ QT_BEGIN_NAMESPACE
/*!
\class QRadioTunerControl
+ \obsolete
\inmodule QtMultimedia
-
\ingroup multimedia_control
diff --git a/src/multimedia/controls/qvideodeviceselectorcontrol.cpp b/src/multimedia/controls/qvideodeviceselectorcontrol.cpp
index 8c4ee7ba4..420ba9150 100644
--- a/src/multimedia/controls/qvideodeviceselectorcontrol.cpp
+++ b/src/multimedia/controls/qvideodeviceselectorcontrol.cpp
@@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QVideoDeviceSelectorControl
+ \obsolete
\brief The QVideoDeviceSelectorControl class provides an video device selector media control.
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qvideoencodersettingscontrol.cpp b/src/multimedia/controls/qvideoencodersettingscontrol.cpp
index 52ae51382..64643f6db 100644
--- a/src/multimedia/controls/qvideoencodersettingscontrol.cpp
+++ b/src/multimedia/controls/qvideoencodersettingscontrol.cpp
@@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QVideoEncoderSettingsControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/controls/qvideorenderercontrol.cpp b/src/multimedia/controls/qvideorenderercontrol.cpp
index e722dfa38..eee20d59e 100644
--- a/src/multimedia/controls/qvideorenderercontrol.cpp
+++ b/src/multimedia/controls/qvideorenderercontrol.cpp
@@ -45,6 +45,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QVideoRendererControl
+ \obsolete
\inmodule QtMultimedia
\brief The QVideoRendererControl class provides a media control for rendering video to a QAbstractVideoSurface.
diff --git a/src/multimedia/controls/qvideowindowcontrol.cpp b/src/multimedia/controls/qvideowindowcontrol.cpp
index e971a6925..a6b2bf407 100644
--- a/src/multimedia/controls/qvideowindowcontrol.cpp
+++ b/src/multimedia/controls/qvideowindowcontrol.cpp
@@ -43,6 +43,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QVideoWindowControl
+ \obsolete
\inmodule QtMultimedia
diff --git a/src/multimedia/doc/snippets/multimedia-snippets/media.cpp b/src/multimedia/doc/snippets/multimedia-snippets/media.cpp
index 8ec7cb072..7fd6259ea 100644
--- a/src/multimedia/doc/snippets/multimedia-snippets/media.cpp
+++ b/src/multimedia/doc/snippets/multimedia-snippets/media.cpp
@@ -56,6 +56,7 @@
#include "qaudioprobe.h"
#include "qaudiorecorder.h"
#include "qvideoprobe.h"
+#include <QAbstractVideoSurface>
class MediaExample : public QObject {
Q_OBJECT
@@ -197,6 +198,36 @@ void MediaExample::MediaPlayer()
player->play();
//! [Pipeline]
+ //! [Pipeline Surface]
+ class Surface : public QAbstractVideoSurface
+ {
+ public:
+ Surface(QObject *p) : QAbstractVideoSurface(p) { }
+ QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType) const override
+ {
+ // Make sure that the driver supports this pixel format.
+ return QList<QVideoFrame::PixelFormat>() << QVideoFrame::Format_YUYV;
+ }
+
+ // Video frames are handled here.
+ bool present(const QVideoFrame &) override { return true; }
+ };
+
+ player = new QMediaPlayer;
+ player->setVideoOutput(new Surface(player));
+ player->setMedia(QUrl("gst-pipeline: videotestsrc ! qtvideosink"));
+ player->play();
+ //! [Pipeline Surface]
+
+ //! [Pipeline Widget]
+ player = new QMediaPlayer;
+ videoWidget = new QVideoWidget;
+ videoWidget->show();
+ player->setVideoOutput(videoWidget);
+ player->setMedia(QUrl("gst-pipeline: videotestsrc ! xvimagesink name=\"qtvideosink\""));
+ player->play();
+ //! [Pipeline Widget]
+
//! [Pipeline appsrc]
QImage img("images/qt-logo.png");
img = img.convertToFormat(QImage::Format_ARGB32);
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/doc/src/cameraoverview.qdoc b/src/multimedia/doc/src/cameraoverview.qdoc
index 6962c2c48..69631fdab 100644
--- a/src/multimedia/doc/src/cameraoverview.qdoc
+++ b/src/multimedia/doc/src/cameraoverview.qdoc
@@ -286,7 +286,7 @@ for all of these, so you shouldn't need to adjust them unless the user wants a s
If you're taking a series of images (for example, to stitch them together for
a panoramic image), you should lock the image processing settings so that all the
-images taken appear similar with \e {QCamera::lock(QCamera::LockWhiteBalance)}/
+images taken appear similar with \e {QCamera::searchAndLock(QCamera::LockWhiteBalance)}/
\section3 Canceling Asynchronous Operations
diff --git a/src/multimedia/doc/src/platform-notes-windows.qdoc b/src/multimedia/doc/src/platform-notes-windows.qdoc
index e86d6a276..a69e96d99 100644
--- a/src/multimedia/doc/src/platform-notes-windows.qdoc
+++ b/src/multimedia/doc/src/platform-notes-windows.qdoc
@@ -42,6 +42,11 @@ was introduced in Windows Vista as a replacement for DirectShow and other
multimedia APIs. Consequently, WMF plugin in Qt is supported only for
Windows Vista and later versions of the operating system.
+The environment variable \c QT_MULTIMEDIA_PREFERRED_PLUGINS can be used to
+control the priority of the plugins. For example, setting it to
+"windowsmediafoundation" or "directshow" will cause the corresponding plugin
+to be the preferred one.
+
\section1 Limitations
The WMF plugin in Qt does not currently provide a camera backend. Instead,
diff --git a/src/multimedia/doc/src/qtmultimedia-index.qdoc b/src/multimedia/doc/src/qtmultimedia-index.qdoc
index c2734f4a9..abd6a62cc 100644
--- a/src/multimedia/doc/src/qtmultimedia-index.qdoc
+++ b/src/multimedia/doc/src/qtmultimedia-index.qdoc
@@ -132,9 +132,6 @@
\li QMediaPlaylist
\li List of media to be played.
\row
- \li QRadioTuner
- \li Access radio device.
- \row
\li QAbstractVideoSurface
\li Base class for video presentation.
\endtable
diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp
index 44e91912b..382d8b30b 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"
@@ -115,7 +116,9 @@ public:
, audioRoleControl(nullptr)
, customAudioRoleControl(nullptr)
, playlist(nullptr)
+#ifndef QT_NO_BEARERMANAGEMENT
, networkAccessControl(nullptr)
+#endif
, state(QMediaPlayer::StoppedState)
, status(QMediaPlayer::UnknownMediaStatus)
, error(QMediaPlayer::NoError)
@@ -132,7 +135,12 @@ public:
QPointer<QObject> videoOutput;
QMediaPlaylist *playlist;
+#ifndef QT_NO_BEARERMANAGEMENT
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
QMediaNetworkAccessControl *networkAccessControl;
+QT_WARNING_POP
+#endif
QVideoSurfaceOutput surfaceOutput;
QMediaContent qrcMedia;
QScopedPointer<QFile> qrcFile;
@@ -563,7 +571,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;
@@ -598,7 +606,12 @@ QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags):
d->error = ServiceMissingError;
} else {
d->control = qobject_cast<QMediaPlayerControl*>(d->service->requestControl(QMediaPlayerControl_iid));
+#ifndef QT_NO_BEARERMANAGEMENT
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
d->networkAccessControl = qobject_cast<QMediaNetworkAccessControl*>(d->service->requestControl(QMediaNetworkAccessControl_iid));
+QT_WARNING_POP
+#endif
if (d->control != nullptr) {
connect(d->control, SIGNAL(mediaChanged(QMediaContent)), SLOT(_q_handleMediaChanged(QMediaContent)));
connect(d->control, SIGNAL(stateChanged(QMediaPlayer::State)), SLOT(_q_stateChanged(QMediaPlayer::State)));
@@ -642,10 +655,15 @@ QMediaPlayer::QMediaPlayer(QObject *parent, QMediaPlayer::Flags flags):
}
}
}
+#ifndef QT_NO_BEARERMANAGEMENT
if (d->networkAccessControl != nullptr) {
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
connect(d->networkAccessControl, &QMediaNetworkAccessControl::configurationChanged,
this, &QMediaPlayer::networkConfigurationChanged);
+QT_WARNING_POP
}
+#endif
}
}
@@ -730,7 +748,12 @@ void QMediaPlayer::setPlaylist(QMediaPlaylist *playlist)
setMedia(m);
}
+#ifndef QT_NO_BEARERMANAGEMENT
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
/*!
+ \obsolete
+
Sets the network access points for remote media playback.
\a configurations contains, in ascending preferential order, a list of
configuration that can be used for network access.
@@ -744,6 +767,8 @@ void QMediaPlayer::setNetworkConfigurations(const QList<QNetworkConfiguration> &
if (d->networkAccessControl)
d->networkAccessControl->setConfigurations(configurations);
}
+QT_WARNING_POP
+#endif
QMediaPlayer::State QMediaPlayer::state() const
{
@@ -869,7 +894,12 @@ QString QMediaPlayer::errorString() const
return d_func()->errorString;
}
+#ifndef QT_NO_BEARERMANAGEMENT
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
/*!
+ \obsolete
+
Returns the current network access point in use.
If a default contructed QNetworkConfiguration is returned
this feature is not available or that none of the
@@ -884,6 +914,8 @@ QNetworkConfiguration QMediaPlayer::currentNetworkConfiguration() const
return QNetworkConfiguration();
}
+QT_WARNING_POP
+#endif
//public Q_SLOTS:
/*!
@@ -1005,8 +1037,9 @@ void QMediaPlayer::setPlaybackRate(qreal rate)
Sets the current \a media source.
If a \a stream is supplied; media data will be read from it instead of resolving the media
- source. In this case the media source may still be used to resolve additional information
+ source. In this case the url should be provided to resolve additional information
about the media such as mime type. The \a stream must be open and readable.
+ For macOS the \a stream should be also seekable.
Setting the media to a null QMediaContent will cause the player to discard all
information relating to the current media source and to cease all I/O operations related
@@ -1022,8 +1055,17 @@ void QMediaPlayer::setPlaybackRate(qreal rate)
\snippet multimedia-snippets/media.cpp Pipeline
- If the pipeline contains a video sink element named \c qtvideosink,
- current QVideoWidget can be used to render the video.
+ If QAbstractVideoSurface is used as the video output,
+ \c qtvideosink can be used as a video sink element directly in the pipeline.
+ After that the surface will receive the video frames in QAbstractVideoSurface::present().
+
+ \snippet multimedia-snippets/media.cpp Pipeline Surface
+
+ If QVideoWidget is used as the video output
+ and the pipeline contains a video sink element named \c qtvideosink,
+ current QVideoWidget will be used to render the video.
+
+ \snippet multimedia-snippets/media.cpp Pipeline Widget
If the pipeline contains appsrc element, it will be used to push data from \a stream.
@@ -1176,6 +1218,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
{
@@ -1289,7 +1349,7 @@ QStringList QMediaPlayer::supportedCustomAudioRoles() const
Defines the status of a media player's current media.
\value UnknownMediaStatus The status of the media cannot be determined.
- \value NoMedia The is no current media. The player is in the StoppedState.
+ \value NoMedia There is no current media. The player is in the StoppedState.
\value LoadingMedia The current media is being loaded. The player may be in any state.
\value LoadedMedia The current media has been loaded. The player is in the StoppedState.
\value StalledMedia Playback of the current media has stalled due to insufficient buffering or
@@ -1550,7 +1610,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
@@ -1635,6 +1695,7 @@ QStringList QMediaPlayer::supportedCustomAudioRoles() const
/*!
\fn void QMediaPlayer::networkConfigurationChanged(const QNetworkConfiguration &configuration)
+ \obsolete
Signal that the active in use network access point has been changed to \a configuration and all subsequent network access will use this \a configuration.
*/
diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h
index 5d9a393e1..c579c7f40 100644
--- a/src/multimedia/playback/qmediaplayer.h
+++ b/src/multimedia/playback/qmediaplayer.h
@@ -40,6 +40,7 @@
#ifndef QMEDIAPLAYER_H
#define QMEDIAPLAYER_H
+#include <QtMultimedia/qtmultimediaglobal.h>
#include <QtMultimedia/qmediaobject.h>
#include <QtMultimedia/qmediacontent.h>
#include <QtMultimedia/qmediaenumdebug.h>
@@ -131,6 +132,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;
@@ -156,7 +158,12 @@ public:
Error error() const;
QString errorString() const;
- QNetworkConfiguration currentNetworkConfiguration() const;
+#ifndef QT_NO_BEARERMANAGEMENT
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+ QT_DEPRECATED_VERSION_5_15 QNetworkConfiguration currentNetworkConfiguration() const;
+QT_WARNING_POP
+#endif
QMultimedia::AvailabilityStatus availability() const override;
@@ -181,7 +188,16 @@ public Q_SLOTS:
void setMedia(const QMediaContent &media, QIODevice *stream = nullptr);
void setPlaylist(QMediaPlaylist *playlist);
- void setNetworkConfigurations(const QList<QNetworkConfiguration> &configurations);
+#ifndef QT_NO_BEARERMANAGEMENT
+#ifndef Q_MOC_RUN // moc fails to parse the expanded macro
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+#endif
+ QT_DEPRECATED_VERSION_5_15 void setNetworkConfigurations(const QList<QNetworkConfiguration> &configurations);
+#ifndef Q_MOC_RUN // moc fails to parse the expanded macro
+QT_WARNING_POP
+#endif
+#endif
Q_SIGNALS:
void mediaChanged(const QMediaContent &media);
@@ -208,7 +224,16 @@ Q_SIGNALS:
void error(QMediaPlayer::Error error);
- void networkConfigurationChanged(const QNetworkConfiguration &configuration);
+#ifndef QT_NO_BEARERMANAGEMENT
+#ifndef Q_MOC_RUN // moc fails to parse the expanded macro
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+#endif
+ QT_DEPRECATED_VERSION_5_15 void networkConfigurationChanged(const QNetworkConfiguration &configuration);
+#ifndef Q_MOC_RUN // moc fails to parse the expanded macro
+QT_WARNING_POP
+#endif
+#endif
public:
bool bind(QObject *) override;
void unbind(QObject *) override;
diff --git a/src/multimedia/playback/qplaylistfileparser.cpp b/src/multimedia/playback/qplaylistfileparser.cpp
index 9af447032..d3cd60476 100644
--- a/src/multimedia/playback/qplaylistfileparser.cpp
+++ b/src/multimedia/playback/qplaylistfileparser.cpp
@@ -552,7 +552,7 @@ void QPlaylistFileParser::start(const QNetworkRequest& request, const QString &m
d->m_source.reset(d->m_mgr.get(request));
connect(d->m_source.data(), SIGNAL(readyRead()), this, SLOT(handleData()));
connect(d->m_source.data(), SIGNAL(finished()), this, SLOT(handleData()));
- connect(d->m_source.data(), SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(handleError()));
+ connect(d->m_source.data(), SIGNAL(errorOccurred(QNetworkReply::NetworkError)), this, SLOT(handleError()));
if (url.isLocalFile())
d->handleData();
diff --git a/src/multimedia/qmediacontrol.cpp b/src/multimedia/qmediacontrol.cpp
index b8f980aa0..6f0a980a2 100644
--- a/src/multimedia/qmediacontrol.cpp
+++ b/src/multimedia/qmediacontrol.cpp
@@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QMediaControl
+ \obsolete
\inmodule QtMultimedia
\ingroup multimedia
diff --git a/src/multimedia/qmediapluginloader.cpp b/src/multimedia/qmediapluginloader.cpp
index 88bd591c2..3e9e6cc21 100644
--- a/src/multimedia/qmediapluginloader.cpp
+++ b/src/multimedia/qmediapluginloader.cpp
@@ -104,7 +104,7 @@ QList<QObject*> QMediaPluginLoader::instances(QString const &key)
static const bool showDebug = qEnvironmentVariableIntValue("QT_DEBUG_PLUGINS");
static const QStringList preferredPlugins =
- qEnvironmentVariable("QT_MULTIMEDIA_PREFERRED_PLUGINS").split(QLatin1Char(','), QString::SkipEmptyParts);
+ qEnvironmentVariable("QT_MULTIMEDIA_PREFERRED_PLUGINS").split(QLatin1Char(','), Qt::SkipEmptyParts);
for (int i = preferredPlugins.size() - 1; i >= 0; --i) {
auto name = preferredPlugins[i];
bool found = false;
diff --git a/src/multimedia/qmediaservice.cpp b/src/multimedia/qmediaservice.cpp
index 7ea24c6dc..ad543acae 100644
--- a/src/multimedia/qmediaservice.cpp
+++ b/src/multimedia/qmediaservice.cpp
@@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QMediaService
+ \obsolete
\brief The QMediaService class provides a common base class for media
service implementations.
\ingroup multimedia
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/qabstractvideobuffer.cpp b/src/multimedia/video/qabstractvideobuffer.cpp
index f0dd6d2eb..8762150d0 100644
--- a/src/multimedia/video/qabstractvideobuffer.cpp
+++ b/src/multimedia/video/qabstractvideobuffer.cpp
@@ -96,12 +96,15 @@ int QAbstractVideoBufferPrivate::map(
Identifies the type of a video buffers handle.
\value NoHandle The buffer has no handle, its data can only be accessed by mapping the buffer.
- \value GLTextureHandle The handle of the buffer is an OpenGL texture ID.
+ \value GLTextureHandle The handle of the buffer is an OpenGL texture ID
+ of an undefined and platform dependent target type.
\value XvShmImageHandle The handle contains pointer to shared memory XVideo image.
\value CoreImageHandle The handle contains pointer to \macos CIImage.
\value QPixmapHandle The handle of the buffer is a QPixmap.
\value EGLImageHandle The handle of the buffer is an EGLImageKHR.
\value UserHandle Start value for user defined handle types.
+ \value GLTextureRectangleHandle The handle of the buffer is an OpenGL texture ID
+ of target type \c GL_TEXTURE_RECTANGLE.
\sa handleType()
*/
diff --git a/src/multimedia/video/qabstractvideobuffer.h b/src/multimedia/video/qabstractvideobuffer.h
index 2352c0f3d..a3afc18e4 100644
--- a/src/multimedia/video/qabstractvideobuffer.h
+++ b/src/multimedia/video/qabstractvideobuffer.h
@@ -64,6 +64,7 @@ public:
CoreImageHandle,
QPixmapHandle,
EGLImageHandle,
+ GLTextureRectangleHandle,
UserHandle = 1000
};
diff --git a/src/multimedia/video/qmemoryvideobuffer.cpp b/src/multimedia/video/qmemoryvideobuffer.cpp
index e05210d9d..febcd66c8 100644
--- a/src/multimedia/video/qmemoryvideobuffer.cpp
+++ b/src/multimedia/video/qmemoryvideobuffer.cpp
@@ -101,7 +101,7 @@ uchar *QMemoryVideoBuffer::map(MapMode mode, int *numBytes, int *bytesPerLine)
{
Q_D(QMemoryVideoBuffer);
- if (d->mapMode == NotMapped && d->data.data() && mode != NotMapped) {
+ if (d->mapMode == NotMapped && d->data.size() && mode != NotMapped) {
d->mapMode = mode;
if (numBytes)
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..7c0521471 100644
--- a/src/multimediawidgets/qgraphicsvideoitem.cpp
+++ b/src/multimediawidgets/qgraphicsvideoitem.cpp
@@ -49,7 +49,7 @@
#include <QtCore/qpointer.h>
#if QT_CONFIG(opengl)
-#include <QtOpenGL/qgl.h>
+#include <QOpenGLContext>
#endif
QT_BEGIN_NAMESPACE
@@ -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)
@@ -379,7 +395,7 @@ void QGraphicsVideoItem::paint(
if (painter->paintEngine()->type() == QPaintEngine::OpenGL
|| painter->paintEngine()->type() == QPaintEngine::OpenGL2)
{
- d->surface->setGLContext(const_cast<QGLContext *>(QGLContext::currentContext()));
+ d->surface->updateGLContext();
if (d->surface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) {
d->surface->setShaderType(QPainterVideoSurface::GlslShader);
} else {
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..5fe76d869 100644
--- a/src/multimediawidgets/qpaintervideosurface.cpp
+++ b/src/multimediawidgets/qpaintervideosurface.cpp
@@ -47,9 +47,9 @@
#include <private/qmediaopenglhelper_p.h>
#if QT_CONFIG(opengl)
-#include <qglshaderprogram.h>
-#include <QtGui/QOpenGLContext>
-#include <QtGui/QOpenGLFunctions>
+#include <QOpenGLContext>
+#include <QOpenGLFunctions>
+#include <QOpenGLShaderProgram>
#include <QtGui/QWindow>
#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812F
@@ -57,15 +57,6 @@
#ifndef GL_RGB8
#define GL_RGB8 0x8051
#endif
-
-static void makeCurrent(QGLContext *context)
-{
- context->makeCurrent();
-
- auto handle = context->contextHandle();
- if (handle && QOpenGLContext::currentContext() != handle)
- handle->makeCurrent(handle->surface());
-}
#endif
#include <QtDebug>
@@ -264,7 +255,7 @@ void QVideoSurfaceGenericPainter::updateColors(int, int, int, int)
class QVideoSurfaceGLPainter : public QVideoSurfacePainter, protected QOpenGLFunctions
{
public:
- QVideoSurfaceGLPainter(QGLContext *context);
+ QVideoSurfaceGLPainter(QOpenGLContext *context);
~QVideoSurfaceGLPainter();
QList<QVideoFrame::PixelFormat> supportedPixelFormats(
QAbstractVideoBuffer::HandleType handleType) const override;
@@ -292,17 +283,12 @@ protected:
|| format.pixelFormat() == QVideoFrame::Format_ARGB32);
}
-#if !defined(QT_OPENGL_ES) && !defined(QT_OPENGL_DYNAMIC)
- typedef void (APIENTRY *_glActiveTexture) (GLenum);
- _glActiveTexture glActiveTexture;
-#endif
-
QList<QVideoFrame::PixelFormat> m_imagePixelFormats;
QList<QVideoFrame::PixelFormat> m_glPixelFormats;
QMatrix4x4 m_colorMatrix;
QVideoFrame m_frame;
- QGLContext *m_context;
+ QOpenGLContext *m_context;
QAbstractVideoBuffer::HandleType m_handleType;
QVideoSurfaceFormat::Direction m_scanLineDirection;
bool m_mirrored;
@@ -320,7 +306,7 @@ protected:
bool m_yuv;
};
-QVideoSurfaceGLPainter::QVideoSurfaceGLPainter(QGLContext *context)
+QVideoSurfaceGLPainter::QVideoSurfaceGLPainter(QOpenGLContext *context)
: m_context(context)
, m_handleType(QAbstractVideoBuffer::NoHandle)
, m_scanLineDirection(QVideoSurfaceFormat::TopToBottom)
@@ -332,10 +318,6 @@ QVideoSurfaceGLPainter::QVideoSurfaceGLPainter(QGLContext *context)
, m_textureCount(0)
, m_yuv(false)
{
-#if !defined(QT_OPENGL_ES) && !defined(QT_OPENGL_DYNAMIC)
- glActiveTexture = (_glActiveTexture)m_context->getProcAddress(QLatin1String("glActiveTexture"));
-#endif
-
memset(m_textureIds, 0, sizeof(m_textureIds));
memset(m_textureWidths, 0, sizeof(m_textureWidths));
memset(m_textureHeights, 0, sizeof(m_textureHeights));
@@ -404,8 +386,6 @@ QAbstractVideoSurface::Error QVideoSurfaceGLPainter::setCurrentFrame(const QVide
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) {
- makeCurrent(m_context);
-
for (int i = 0; i < m_textureCount; ++i) {
glBindTexture(GL_TEXTURE_2D, m_textureIds[i]);
glTexImage2D(
@@ -680,7 +660,7 @@ static const char *qt_arbfp_ayuvShaderProgram =
class QVideoSurfaceArbFpPainter : public QVideoSurfaceGLPainter
{
public:
- QVideoSurfaceArbFpPainter(QGLContext *context);
+ QVideoSurfaceArbFpPainter(QOpenGLContext *context);
QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format) override;
void stop() override;
@@ -707,20 +687,20 @@ private:
QSize m_frameSize;
};
-QVideoSurfaceArbFpPainter::QVideoSurfaceArbFpPainter(QGLContext *context)
+QVideoSurfaceArbFpPainter::QVideoSurfaceArbFpPainter(QOpenGLContext *context)
: QVideoSurfaceGLPainter(context)
, m_programId(0)
{
glProgramStringARB = (_glProgramStringARB) m_context->getProcAddress(
- QLatin1String("glProgramStringARB"));
+ QByteArray("glProgramStringARB"));
glBindProgramARB = (_glBindProgramARB) m_context->getProcAddress(
- QLatin1String("glBindProgramARB"));
+ QByteArray("glBindProgramARB"));
glDeleteProgramsARB = (_glDeleteProgramsARB) m_context->getProcAddress(
- QLatin1String("glDeleteProgramsARB"));
+ QByteArray("glDeleteProgramsARB"));
glGenProgramsARB = (_glGenProgramsARB) m_context->getProcAddress(
- QLatin1String("glGenProgramsARB"));
+ QByteArray("glGenProgramsARB"));
glProgramLocalParameter4fARB = (_glProgramLocalParameter4fARB) m_context->getProcAddress(
- QLatin1String("glProgramLocalParameter4fARB"));
+ QByteArray("glProgramLocalParameter4fARB"));
m_imagePixelFormats
<< QVideoFrame::Format_RGB32
@@ -746,8 +726,6 @@ QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::start(const QVideoSurfac
QAbstractVideoSurface::Error error = QAbstractVideoSurface::NoError;
- makeCurrent(m_context);
-
const char *program = 0;
if (format.handleType() == QAbstractVideoBuffer::NoHandle) {
@@ -871,8 +849,6 @@ QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::start(const QVideoSurfac
void QVideoSurfaceArbFpPainter::stop()
{
if (m_context) {
- makeCurrent(m_context);
-
if (m_handleType != QAbstractVideoBuffer::GLTextureHandle)
glDeleteTextures(m_textureCount, m_textureIds);
glDeleteProgramsARB(1, &m_programId);
@@ -1079,7 +1055,7 @@ static const char *qt_glsl_ayuvShaderProgram =
class QVideoSurfaceGlslPainter : public QVideoSurfaceGLPainter
{
public:
- QVideoSurfaceGlslPainter(QGLContext *context);
+ QVideoSurfaceGlslPainter(QOpenGLContext *context);
QAbstractVideoSurface::Error start(const QVideoSurfaceFormat &format) override;
void stop() override;
@@ -1088,11 +1064,11 @@ public:
const QRectF &target, QPainter *painter, const QRectF &source) override;
private:
- QGLShaderProgram m_program;
+ QOpenGLShaderProgram m_program;
QSize m_frameSize;
};
-QVideoSurfaceGlslPainter::QVideoSurfaceGlslPainter(QGLContext *context)
+QVideoSurfaceGlslPainter::QVideoSurfaceGlslPainter(QOpenGLContext *context)
: QVideoSurfaceGLPainter(context)
, m_program(context)
{
@@ -1100,7 +1076,7 @@ QVideoSurfaceGlslPainter::QVideoSurfaceGlslPainter(QGLContext *context)
<< QVideoFrame::Format_RGB32
<< QVideoFrame::Format_BGR32
<< QVideoFrame::Format_ARGB32;
- if (!context->contextHandle()->isOpenGLES()) {
+ if (!context->isOpenGLES()) {
m_imagePixelFormats
<< QVideoFrame::Format_RGB24
<< QVideoFrame::Format_BGR24;
@@ -1124,8 +1100,6 @@ QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::start(const QVideoSurface
QAbstractVideoSurface::Error error = QAbstractVideoSurface::NoError;
- makeCurrent(m_context);
-
const char *fragmentProgram = 0;
if (format.handleType() == QAbstractVideoBuffer::NoHandle) {
@@ -1143,13 +1117,13 @@ QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::start(const QVideoSurface
fragmentProgram = qt_glsl_argbShaderProgram;
break;
case QVideoFrame::Format_RGB24:
- if (!m_context->contextHandle()->isOpenGLES()) {
+ if (!m_context->isOpenGLES()) {
initRgbTextureInfo(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize());
fragmentProgram = qt_glsl_rgbShaderProgram;
}
break;
case QVideoFrame::Format_BGR24:
- if (!m_context->contextHandle()->isOpenGLES()) {
+ if (!m_context->isOpenGLES()) {
initRgbTextureInfo(GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE, format.frameSize());
fragmentProgram = qt_glsl_argbShaderProgram;
}
@@ -1202,11 +1176,11 @@ QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::start(const QVideoSurface
if (!fragmentProgram) {
error = QAbstractVideoSurface::UnsupportedFormatError;
- } else if (!m_program.addShaderFromSourceCode(QGLShader::Vertex, qt_glsl_vertexShaderProgram)) {
+ } else if (!m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, qt_glsl_vertexShaderProgram)) {
qWarning("QPainterVideoSurface: Vertex shader compile error %s",
qPrintable(m_program.log()));
error = QAbstractVideoSurface::ResourceError;
- } else if (!m_program.addShaderFromSourceCode(QGLShader::Fragment, fragmentProgram)) {
+ } else if (!m_program.addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentProgram)) {
qWarning("QPainterVideoSurface: Shader compile error %s", qPrintable(m_program.log()));
error = QAbstractVideoSurface::ResourceError;
m_program.removeAllShaders();
@@ -1231,8 +1205,6 @@ QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::start(const QVideoSurface
void QVideoSurfaceGlslPainter::stop()
{
if (m_context) {
- makeCurrent(m_context);
-
if (m_handleType != QAbstractVideoBuffer::GLTextureHandle)
glDeleteTextures(m_textureCount, m_textureIds);
}
@@ -1473,29 +1445,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;
}
/*!
@@ -1612,35 +1583,33 @@ void QPainterVideoSurface::paint(QPainter *painter, const QRectF &target, const
/*!
*/
-const QGLContext *QPainterVideoSurface::glContext() const
+const QOpenGLContext *QPainterVideoSurface::glContext() const
{
return m_glContext;
}
/*!
*/
-void QPainterVideoSurface::setGLContext(QGLContext *context)
+void QPainterVideoSurface::updateGLContext()
{
- if (m_glContext == context)
+ auto oldContext = m_glContext;
+ m_glContext = QOpenGLContext::currentContext();
+ if (oldContext == m_glContext)
return;
- m_glContext = context;
-
m_shaderTypes = NoShaders;
if (m_glContext) {
//Set a dynamic property to access the OpenGL context
- this->setProperty("GLContext", QVariant::fromValue<QObject*>(m_glContext->contextHandle()));
-
- makeCurrent(m_glContext);
+ this->setProperty("GLContext", QVariant::fromValue<QObject *>(m_glContext));
const QByteArray extensions(reinterpret_cast<const char *>(
- context->contextHandle()->functions()->glGetString(GL_EXTENSIONS)));
+ m_glContext->functions()->glGetString(GL_EXTENSIONS)));
#if !defined(QT_OPENGL_ES) && !defined(QT_OPENGL_DYNAMIC)
if (extensions.contains("ARB_fragment_program"))
m_shaderTypes |= FragmentProgramShader;
#endif
- if (QGLShaderProgram::hasOpenGLShaderPrograms(m_glContext)
+ if (QOpenGLShaderProgram::hasOpenGLShaderPrograms(m_glContext)
#if !defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_DYNAMIC)
&& extensions.contains("ARB_shader_objects")
#endif
@@ -1743,13 +1712,11 @@ void QPainterVideoSurface::createPainter()
#if !defined(QT_OPENGL_ES) && !defined(QT_OPENGL_DYNAMIC)
case FragmentProgramShader:
Q_ASSERT(m_glContext);
- makeCurrent(m_glContext);
m_painter = new QVideoSurfaceArbFpPainter(m_glContext);
break;
#endif // !QT_OPENGL_ES && !QT_OPENGL_DYNAMIC
case GlslShader:
Q_ASSERT(m_glContext);
- makeCurrent(m_glContext);
m_painter = new QVideoSurfaceGlslPainter(m_glContext);
break;
default:
diff --git a/src/multimediawidgets/qpaintervideosurface_p.h b/src/multimediawidgets/qpaintervideosurface_p.h
index 990d20cbe..582d6944c 100644
--- a/src/multimediawidgets/qpaintervideosurface_p.h
+++ b/src/multimediawidgets/qpaintervideosurface_p.h
@@ -59,11 +59,6 @@
#include <qabstractvideosurface.h>
#include <qvideoframe.h>
-QT_BEGIN_NAMESPACE
-
-class QGLContext;
-QT_END_NAMESPACE
-
QT_USE_NAMESPACE
QT_BEGIN_NAMESPACE
@@ -90,7 +85,7 @@ public:
virtual void viewportDestroyed() {}
};
-
+class QOpenGLContext;
class Q_AUTOTEST_EXPORT QPainterVideoSurface : public QAbstractVideoSurface
{
Q_OBJECT
@@ -126,8 +121,8 @@ public:
void paint(QPainter *painter, const QRectF &target, const QRectF &source = QRectF(0, 0, 1, 1));
#if QT_CONFIG(opengl)
- const QGLContext *glContext() const;
- void setGLContext(QGLContext *context);
+ const QOpenGLContext *glContext() const;
+ void updateGLContext();
enum ShaderType
{
@@ -155,7 +150,7 @@ private:
QVideoSurfacePainter *m_painter;
#if QT_CONFIG(opengl)
- QGLContext *m_glContext;
+ QOpenGLContext *m_glContext;
ShaderTypes m_shaderTypes;
ShaderType m_shaderType;
#endif
diff --git a/src/multimediawidgets/qvideowidget.cpp b/src/multimediawidgets/qvideowidget.cpp
index a7d3665f8..5158b2f35 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)
@@ -220,7 +228,6 @@ void QRendererVideoWidgetBackend::hideEvent(QHideEvent *)
{
#if QT_CONFIG(opengl)
m_updatePaintDevice = true;
- m_surface->setGLContext(0);
#endif
}
@@ -257,7 +264,7 @@ void QRendererVideoWidgetBackend::paintEvent(QPaintEvent *event)
|| painter.paintEngine()->type() == QPaintEngine::OpenGL2)) {
m_updatePaintDevice = false;
- m_surface->setGLContext(const_cast<QGLContext *>(QGLContext::currentContext()));
+ m_surface->updateGLContext();
if (m_surface->supportedShaderTypes() & QPainterVideoSurface::GlslShader) {
m_surface->setShaderType(QPainterVideoSurface::GlslShader);
} else {
@@ -469,7 +476,7 @@ void QVideoWidgetPrivate::clearService()
delete rendererBackend;
rendererBackend = 0;
- } else {
+ } else if (windowBackend) {
windowBackend->releaseControl();
delete windowBackend;
@@ -515,18 +522,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 +615,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 +625,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 +700,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..a3e687488 100644
--- a/src/multimediawidgets/qvideowidget_p.h
+++ b/src/multimediawidgets/qvideowidget_p.h
@@ -55,7 +55,7 @@
#include "qvideowidget.h"
#ifndef QT_NO_OPENGL
-#include <QGLWidget>
+#include <QOpenGLWidget>
#endif
#include "qpaintervideosurface_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/alsa/qalsaaudiodeviceinfo.h b/src/plugins/alsa/qalsaaudiodeviceinfo.h
index 65675df54..cdf08bfab 100644
--- a/src/plugins/alsa/qalsaaudiodeviceinfo.h
+++ b/src/plugins/alsa/qalsaaudiodeviceinfo.h
@@ -79,15 +79,15 @@ public:
bool testSettings(const QAudioFormat& format) const;
void updateLists();
- QAudioFormat preferredFormat() const;
- bool isFormatSupported(const QAudioFormat& format) const;
- QString deviceName() const;
- QStringList supportedCodecs();
- QList<int> supportedSampleRates();
- QList<int> supportedChannelCounts();
- QList<int> supportedSampleSizes();
- QList<QAudioFormat::Endian> supportedByteOrders();
- QList<QAudioFormat::SampleType> supportedSampleTypes();
+ QAudioFormat preferredFormat() const override;
+ bool isFormatSupported(const QAudioFormat& format) const override;
+ QString deviceName() const override;
+ QStringList supportedCodecs() override;
+ QList<int> supportedSampleRates() override;
+ QList<int> supportedChannelCounts() override;
+ QList<int> supportedSampleSizes() override;
+ QList<QAudioFormat::Endian> supportedByteOrders() override;
+ QList<QAudioFormat::SampleType> supportedSampleTypes() override;
static QByteArray defaultDevice(QAudio::Mode mode);
static QList<QByteArray> availableDevices(QAudio::Mode);
static QString deviceFromCardName(const QString &card);
diff --git a/src/plugins/alsa/qalsaaudioinput.h b/src/plugins/alsa/qalsaaudioinput.h
index fa9c954d7..62e1be039 100644
--- a/src/plugins/alsa/qalsaaudioinput.h
+++ b/src/plugins/alsa/qalsaaudioinput.h
@@ -103,26 +103,26 @@ public:
qint64 read(char* data, qint64 len);
- void start(QIODevice* device);
- QIODevice* start();
- void stop();
- void reset();
- void suspend();
- void resume();
- int bytesReady() const;
- int periodSize() const;
- void setBufferSize(int value);
- int bufferSize() const;
- void setNotifyInterval(int milliSeconds);
- int notifyInterval() const;
- qint64 processedUSecs() const;
- qint64 elapsedUSecs() const;
- QAudio::Error error() const;
- QAudio::State state() const;
- void setFormat(const QAudioFormat& fmt);
- QAudioFormat format() const;
- void setVolume(qreal);
- qreal volume() const;
+ void start(QIODevice* device) override;
+ QIODevice* start() override;
+ void stop() override;
+ void reset() override;
+ void suspend() override;
+ void resume() override;
+ int bytesReady() const override;
+ int periodSize() const override;
+ void setBufferSize(int value) override;
+ int bufferSize() const override;
+ void setNotifyInterval(int milliSeconds) override;
+ int notifyInterval() const override;
+ qint64 processedUSecs() const override;
+ qint64 elapsedUSecs() const override;
+ QAudio::Error error() const override;
+ QAudio::State state() const override;
+ void setFormat(const QAudioFormat& fmt) override;
+ QAudioFormat format() const override;
+ void setVolume(qreal) override;
+ qreal volume() const override;
bool resuming;
snd_pcm_t* handle;
qint64 totalTimeValue;
@@ -171,8 +171,8 @@ public:
AlsaInputPrivate(QAlsaAudioInput* audio);
~AlsaInputPrivate();
- qint64 readData( char* data, qint64 len);
- qint64 writeData(const char* data, qint64 len);
+ qint64 readData( char* data, qint64 len) override;
+ qint64 writeData(const char* data, qint64 len) override;
void trigger();
private:
diff --git a/src/plugins/alsa/qalsaaudiooutput.cpp b/src/plugins/alsa/qalsaaudiooutput.cpp
index 5c8ae171c..ee5aee989 100644
--- a/src/plugins/alsa/qalsaaudiooutput.cpp
+++ b/src/plugins/alsa/qalsaaudiooutput.cpp
@@ -707,7 +707,7 @@ bool QAlsaAudioOutput::deviceReady()
if(l > 0) {
// Got some data to output
- if(deviceState != QAudio::ActiveState)
+ if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
return true;
qint64 bytesWritten = write(audioBuffer,l);
if (bytesWritten != l)
diff --git a/src/plugins/alsa/qalsaaudiooutput.h b/src/plugins/alsa/qalsaaudiooutput.h
index 8002322cb..72b9c2e4c 100644
--- a/src/plugins/alsa/qalsaaudiooutput.h
+++ b/src/plugins/alsa/qalsaaudiooutput.h
@@ -77,26 +77,26 @@ public:
qint64 write( const char *data, qint64 len );
- void start(QIODevice* device);
- QIODevice* start();
- void stop();
- void reset();
- void suspend();
- void resume();
- int bytesFree() const;
- int periodSize() const;
- void setBufferSize(int value);
- int bufferSize() const;
- void setNotifyInterval(int milliSeconds);
- int notifyInterval() const;
- qint64 processedUSecs() const;
- qint64 elapsedUSecs() const;
- QAudio::Error error() const;
- QAudio::State state() const;
- void setFormat(const QAudioFormat& fmt);
- QAudioFormat format() const;
- void setVolume(qreal);
- qreal volume() const;
+ void start(QIODevice* device) override;
+ QIODevice* start() override;
+ void stop() override;
+ void reset() override;
+ void suspend() override;
+ void resume() override;
+ int bytesFree() const override;
+ int periodSize() const override;
+ void setBufferSize(int value) override;
+ int bufferSize() const override;
+ void setNotifyInterval(int milliSeconds) override;
+ int notifyInterval() const override;
+ qint64 processedUSecs() const override;
+ qint64 elapsedUSecs() const override;
+ QAudio::Error error() const override;
+ QAudio::State state() const override;
+ void setFormat(const QAudioFormat& fmt) override;
+ QAudioFormat format() const override;
+ void setVolume(qreal) override;
+ qreal volume() const override;
QIODevice* audioSource;
@@ -151,8 +151,8 @@ public:
AlsaOutputPrivate(QAlsaAudioOutput* audio);
~AlsaOutputPrivate();
- qint64 readData( char* data, qint64 len);
- qint64 writeData(const char* data, qint64 len);
+ qint64 readData( char* data, qint64 len) override;
+ qint64 writeData(const char* data, qint64 len) override;
private:
QAlsaAudioOutput *audioDevice;
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/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
index 7cc3ad619..c0484a139 100644
--- a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
+++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp
@@ -188,19 +188,30 @@ void QAndroidCaptureSession::setState(QMediaRecorder::State state)
start();
break;
case QMediaRecorder::PausedState:
- // Not supported by Android API
- qWarning("QMediaRecorder::PausedState is not supported on Android");
+ pause();
break;
}
}
void QAndroidCaptureSession::start()
{
- if (m_state == QMediaRecorder::RecordingState || m_status != QMediaRecorder::LoadedStatus)
+ if (m_state == QMediaRecorder::RecordingState
+ || (m_status != QMediaRecorder::LoadedStatus && m_status != QMediaRecorder::PausedStatus))
return;
setStatus(QMediaRecorder::StartingStatus);
+ if (m_state == QMediaRecorder::PausedState) {
+ if (!m_mediaRecorder || !m_mediaRecorder->resume()) {
+ emit error(QMediaRecorder::FormatError, QLatin1String("Unable to resume the media recorder."));
+ if (m_cameraSession)
+ restartViewfinder();
+ } else {
+ updateStartState();
+ }
+ return;
+ }
+
if (m_mediaRecorder) {
m_mediaRecorder->release();
delete m_mediaRecorder;
@@ -289,7 +300,11 @@ void QAndroidCaptureSession::start()
restartViewfinder();
return;
}
+ updateStartState();
+}
+void QAndroidCaptureSession::updateStartState()
+{
m_elapsedTime.start();
m_notifyTimer.start();
updateDuration();
@@ -302,9 +317,20 @@ void QAndroidCaptureSession::start()
m_cameraSession->camera()->setupPreviewFrameCallback();
}
+ QMediaRecorder::State oldState = m_state;
+ QMediaRecorder::Status oldStatus = m_status;
+
m_state = QMediaRecorder::RecordingState;
- emit stateChanged(m_state);
- setStatus(QMediaRecorder::RecordingStatus);
+ m_status = QMediaRecorder::RecordingStatus;
+
+ m_actualOutputLocation = m_usedOutputLocation;
+ emit actualLocationChanged(m_actualOutputLocation);
+
+ if (m_state != oldState)
+ emit stateChanged(m_state);
+
+ if (m_status != oldStatus)
+ emit statusChanged(m_status);
}
void QAndroidCaptureSession::stop(bool error)
@@ -317,6 +343,7 @@ void QAndroidCaptureSession::stop(bool error)
m_mediaRecorder->stop();
m_notifyTimer.stop();
updateDuration();
+ m_previousElapsedTime = 0;
m_elapsedTime.invalidate();
m_mediaRecorder->release();
delete m_mediaRecorder;
@@ -347,6 +374,23 @@ void QAndroidCaptureSession::stop(bool error)
setStatus(QMediaRecorder::LoadedStatus);
}
+void QAndroidCaptureSession::pause()
+{
+ if (m_state == QMediaRecorder::PausedState || m_mediaRecorder == 0)
+ return;
+
+ setStatus(QMediaRecorder::PausedStatus);
+
+ m_mediaRecorder->pause();
+ m_notifyTimer.stop();
+ updateDuration();
+ m_previousElapsedTime = m_duration;
+ m_elapsedTime.invalidate();
+
+ m_state = QMediaRecorder::PausedState;
+ emit stateChanged(m_state);
+}
+
void QAndroidCaptureSession::setStatus(QMediaRecorder::Status status)
{
if (m_status == status)
@@ -503,7 +547,7 @@ void QAndroidCaptureSession::restartViewfinder()
void QAndroidCaptureSession::updateDuration()
{
if (m_elapsedTime.isValid())
- m_duration = m_elapsedTime.elapsed();
+ m_duration = m_elapsedTime.elapsed() + m_previousElapsedTime;
emit durationChanged(m_duration);
}
diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.h b/src/plugins/android/src/mediacapture/qandroidcapturesession.h
index 8cfb9ad2a..cee148a4c 100644
--- a/src/plugins/android/src/mediacapture/qandroidcapturesession.h
+++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.h
@@ -136,7 +136,9 @@ private:
CaptureProfile getProfile(int id);
void start();
+ void updateStartState();
void stop(bool error = false);
+ void pause();
void setStatus(QMediaRecorder::Status status);
@@ -154,6 +156,7 @@ private:
QElapsedTimer m_elapsedTime;
QTimer m_notifyTimer;
qint64 m_duration;
+ qint64 m_previousElapsedTime = 0;
QMediaRecorder::State m_state;
QMediaRecorder::Status m_status;
diff --git a/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp
index ef86af896..66eafc765 100644
--- a/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp
+++ b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp
@@ -176,12 +176,12 @@ void QAndroidMetaDataReaderControl::extractMetadata(QAndroidMetaDataReaderContro
if (!string.isNull()) {
metadata.insert(isVideo ? QMediaMetaData::LeadPerformer
: QMediaMetaData::ContributingArtist,
- string.split('/', QString::SkipEmptyParts));
+ string.split('/', Qt::SkipEmptyParts));
}
string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Author);
if (!string.isNull())
- metadata.insert(QMediaMetaData::Author, string.split('/', QString::SkipEmptyParts));
+ metadata.insert(QMediaMetaData::Author, string.split('/', Qt::SkipEmptyParts));
string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Bitrate);
if (!string.isNull()) {
@@ -196,7 +196,7 @@ void QAndroidMetaDataReaderControl::extractMetadata(QAndroidMetaDataReaderContro
string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Composer);
if (!string.isNull())
- metadata.insert(QMediaMetaData::Composer, string.split('/', QString::SkipEmptyParts));
+ metadata.insert(QMediaMetaData::Composer, string.split('/', Qt::SkipEmptyParts));
string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Date);
if (!string.isNull())
@@ -231,7 +231,7 @@ void QAndroidMetaDataReaderControl::extractMetadata(QAndroidMetaDataReaderContro
string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Writer);
if (!string.isNull())
- metadata.insert(QMediaMetaData::Writer, string.split('/', QString::SkipEmptyParts));
+ metadata.insert(QMediaMetaData::Writer, string.split('/', Qt::SkipEmptyParts));
string = retriever.extractMetadata(AndroidMediaMetadataRetriever::Year);
if (!string.isNull())
diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp
index 3ea7bc773..50baaed21 100644
--- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp
+++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp
@@ -797,6 +797,12 @@ void AndroidCamera::getCameraInfo(int id, AndroidCameraInfo *info)
default:
break;
}
+ // Add a number to allow correct access to cameras on systems with two
+ // (and more) front/back cameras
+ if (id > 1) {
+ info->name.append(QByteArray::number(id));
+ info->description.append(QString(" %1").arg(id));
+ }
}
void AndroidCamera::startPreview()
diff --git a/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp b/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp
index f899481f0..de8422b86 100644
--- a/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp
+++ b/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp
@@ -271,7 +271,7 @@ void AndroidMediaPlayer::setAudioRole(QAudio::Role role)
void AndroidMediaPlayer::setCustomAudioRole(const QString &role)
{
- QStringList roles = role.split(",", QString::SkipEmptyParts);
+ QStringList roles = role.split(",", Qt::SkipEmptyParts);
int type = 0; // CONTENT_TYPE_UNKNOWN
int usage = 0; // USAGE_UNKNOWN
diff --git a/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp b/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp
index d607ab806..10508a358 100644
--- a/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp
+++ b/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp
@@ -213,6 +213,32 @@ void AndroidMediaRecorder::stop()
}
}
+void AndroidMediaRecorder::pause()
+{
+ QJNIEnvironmentPrivate env;
+ m_mediaRecorder.callMethod<void>("pause");
+ if (env->ExceptionCheck()) {
+#ifdef QT_DEBUG
+ env->ExceptionDescribe();
+#endif
+ env->ExceptionClear();
+ }
+}
+
+bool AndroidMediaRecorder::resume()
+{
+ QJNIEnvironmentPrivate env;
+ m_mediaRecorder.callMethod<void>("resume");
+ if (env->ExceptionCheck()) {
+#ifdef QT_DEBUG
+ env->ExceptionDescribe();
+#endif
+ env->ExceptionClear();
+ return false;
+ }
+ return true;
+}
+
void AndroidMediaRecorder::setAudioChannels(int numChannels)
{
m_mediaRecorder.callMethod<void>("setAudioChannels", "(I)V", numChannels);
diff --git a/src/plugins/android/src/wrappers/jni/androidmediarecorder.h b/src/plugins/android/src/wrappers/jni/androidmediarecorder.h
index e4b3a80ea..55b370cf1 100644
--- a/src/plugins/android/src/wrappers/jni/androidmediarecorder.h
+++ b/src/plugins/android/src/wrappers/jni/androidmediarecorder.h
@@ -138,6 +138,8 @@ public:
bool start();
void stop();
+ void pause();
+ bool resume();
void setAudioChannels(int numChannels);
void setAudioEncoder(AudioEncoder encoder);
diff --git a/src/plugins/avfoundation/camera/avfcameraflashcontrol.mm b/src/plugins/avfoundation/camera/avfcameraflashcontrol.mm
index 42303ce17..1e27dc472 100644
--- a/src/plugins/avfoundation/camera/avfcameraflashcontrol.mm
+++ b/src/plugins/avfoundation/camera/avfcameraflashcontrol.mm
@@ -171,6 +171,20 @@ bool AVFCameraFlashControl::applyFlashSettings()
return false;
}
+ auto setAvTorchModeSafe = [&captureDevice](AVCaptureTorchMode avTorchMode) {
+ if ([captureDevice isTorchModeSupported:avTorchMode])
+ captureDevice.torchMode = avTorchMode;
+ else
+ qDebugCamera() << Q_FUNC_INFO << "Attempt to setup unsupported torch mode " << avTorchMode;
+ };
+
+ auto setAvFlashModeSafe = [&captureDevice](AVCaptureFlashMode avFlashMode) {
+ if ([captureDevice isFlashModeSupported:avFlashMode])
+ captureDevice.flashMode = avFlashMode;
+ else
+ qDebugCamera() << Q_FUNC_INFO << "Attempt to setup unsupported flash mode " << avFlashMode;
+ };
+
if (!isFlashModeSupported(m_flashMode)) {
qDebugCamera() << Q_FUNC_INFO << "unsupported mode" << m_flashMode;
return false;
@@ -192,7 +206,7 @@ bool AVFCameraFlashControl::applyFlashSettings()
return false;
}
#endif
- captureDevice.torchMode = AVCaptureTorchModeOff;
+ setAvTorchModeSafe(AVCaptureTorchModeOff);
}
#ifdef Q_OS_IOS
if (![captureDevice isFlashAvailable]) {
@@ -209,7 +223,7 @@ bool AVFCameraFlashControl::applyFlashSettings()
return false;
}
#endif
- captureDevice.flashMode = AVCaptureFlashModeOff;
+ setAvFlashModeSafe(AVCaptureFlashModeOff);
}
#ifdef Q_OS_IOS
@@ -221,13 +235,13 @@ bool AVFCameraFlashControl::applyFlashSettings()
}
if (m_flashMode == QCameraExposure::FlashOff)
- captureDevice.flashMode = AVCaptureFlashModeOff;
+ setAvFlashModeSafe(AVCaptureFlashModeOff);
else if (m_flashMode == QCameraExposure::FlashOn)
- captureDevice.flashMode = AVCaptureFlashModeOn;
+ setAvFlashModeSafe(AVCaptureFlashModeOn);
else if (m_flashMode == QCameraExposure::FlashAuto)
- captureDevice.flashMode = AVCaptureFlashModeAuto;
+ setAvFlashModeSafe(AVCaptureFlashModeAuto);
else if (m_flashMode == QCameraExposure::FlashVideoLight)
- captureDevice.torchMode = AVCaptureTorchModeOn;
+ setAvTorchModeSafe(AVCaptureTorchModeOn);
return true;
}
diff --git a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm
index 0359f5d0a..7bf9de071 100644
--- a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm
+++ b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm
@@ -278,7 +278,8 @@ AVFCameraRendererControl::AVFCameraRendererControl(QObject *parent)
AVFCameraRendererControl::~AVFCameraRendererControl()
{
- [m_cameraSession->captureSession() removeOutput:m_videoDataOutput];
+ if ([m_cameraSession->captureSession().outputs containsObject:m_videoDataOutput])
+ [m_cameraSession->captureSession() removeOutput:m_videoDataOutput];
[m_viewfinderFramesDelegate release];
if (m_delegateQueue)
dispatch_release(m_delegateQueue);
@@ -297,11 +298,9 @@ void AVFCameraRendererControl::setSurface(QAbstractVideoSurface *surface)
{
if (m_surface != surface) {
m_surface = surface;
-#ifdef Q_OS_IOS
m_supportsTextures = m_surface
- ? m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).contains(QVideoFrame::Format_BGRA32)
+ ? !m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty()
: false;
-#endif
Q_EMIT surfaceChanged(surface);
}
}
diff --git a/src/plugins/avfoundation/camera/avfcameraservice.h b/src/plugins/avfoundation/camera/avfcameraservice.h
index 2969882b0..1397a7dee 100644
--- a/src/plugins/avfoundation/camera/avfcameraservice.h
+++ b/src/plugins/avfoundation/camera/avfcameraservice.h
@@ -70,6 +70,8 @@ class AVFMediaRecorderControlIOS;
class AVFAudioEncoderSettingsControl;
class AVFVideoEncoderSettingsControl;
class AVFMediaContainerControl;
+class AVFCameraWindowControl;
+class AVFCaptureDestinationControl;
class AVFCameraService : public QMediaService
{
@@ -99,6 +101,7 @@ public:
AVFAudioEncoderSettingsControl *audioEncoderSettingsControl() const { return m_audioEncoderSettingsControl; }
AVFVideoEncoderSettingsControl *videoEncoderSettingsControl() const {return m_videoEncoderSettingsControl; }
AVFMediaContainerControl *mediaContainerControl() const { return m_mediaContainerControl; }
+ AVFCaptureDestinationControl *captureDestinationControl() const { return m_captureDestinationControl; }
private:
AVFCameraSession *m_session;
@@ -120,6 +123,8 @@ private:
AVFAudioEncoderSettingsControl *m_audioEncoderSettingsControl;
AVFVideoEncoderSettingsControl *m_videoEncoderSettingsControl;
AVFMediaContainerControl *m_mediaContainerControl;
+ AVFCameraWindowControl *m_captureWindowControl;
+ AVFCaptureDestinationControl *m_captureDestinationControl;
};
QT_END_NAMESPACE
diff --git a/src/plugins/avfoundation/camera/avfcameraservice.mm b/src/plugins/avfoundation/camera/avfcameraservice.mm
index 33b4b72aa..79bf73910 100644
--- a/src/plugins/avfoundation/camera/avfcameraservice.mm
+++ b/src/plugins/avfoundation/camera/avfcameraservice.mm
@@ -61,6 +61,8 @@
#include "avfaudioencodersettingscontrol.h"
#include "avfvideoencodersettingscontrol.h"
#include "avfmediacontainercontrol.h"
+#include "avfcapturedestinationcontrol.h"
+#include "avfcamerawindowcontrol.h"
#ifdef Q_OS_IOS
#include "avfcamerazoomcontrol.h"
@@ -74,7 +76,8 @@ QT_USE_NAMESPACE
AVFCameraService::AVFCameraService(QObject *parent):
QMediaService(parent),
- m_videoOutput(nullptr)
+ m_videoOutput(nullptr),
+ m_captureWindowControl(nullptr)
{
m_session = new AVFCameraSession(this);
m_cameraControl = new AVFCameraControl(this);
@@ -109,6 +112,7 @@ AVFCameraService::AVFCameraService(QObject *parent):
m_audioEncoderSettingsControl = new AVFAudioEncoderSettingsControl(this);
m_videoEncoderSettingsControl = new AVFVideoEncoderSettingsControl(this);
m_mediaContainerControl = new AVFMediaContainerControl(this);
+ m_captureDestinationControl = new AVFCaptureDestinationControl;
}
AVFCameraService::~AVFCameraService()
@@ -119,6 +123,12 @@ AVFCameraService::~AVFCameraService()
delete m_recorderControl;
#endif
+ if (m_captureWindowControl) {
+ m_session->setCapturePreviewOutput(nullptr);
+ delete m_captureWindowControl;
+ m_captureWindowControl = nullptr;
+ }
+
if (m_videoOutput) {
m_session->setVideoOutput(nullptr);
delete m_videoOutput;
@@ -143,6 +153,7 @@ AVFCameraService::~AVFCameraService()
delete m_audioEncoderSettingsControl;
delete m_videoEncoderSettingsControl;
delete m_mediaContainerControl;
+ delete m_captureDestinationControl;
delete m_session;
}
@@ -210,6 +221,17 @@ QMediaControl *AVFCameraService::requestControl(const char *name)
return m_cameraZoomControl;
#endif
+ if (qstrcmp(name, QCameraCaptureDestinationControl_iid) == 0)
+ return m_captureDestinationControl;
+
+ if (!m_captureWindowControl) {
+ if (qstrcmp(name, QVideoWindowControl_iid) == 0) {
+ m_captureWindowControl = new AVFCameraWindowControl(this);
+ m_session->setCapturePreviewOutput(m_captureWindowControl);
+ return m_captureWindowControl;
+ }
+ }
+
if (!m_videoOutput) {
if (qstrcmp(name, QVideoRendererControl_iid) == 0)
m_videoOutput = new AVFCameraRendererControl(this);
@@ -234,6 +256,11 @@ void AVFCameraService::releaseControl(QMediaControl *control)
delete m_videoOutput;
m_videoOutput = nullptr;
}
+ else if (m_captureWindowControl == control) {
+ m_session->setCapturePreviewOutput(nullptr);
+ delete m_captureWindowControl;
+ m_captureWindowControl = nullptr;
+ }
}
diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h
index 103ec0e17..a449bb806 100644
--- a/src/plugins/avfoundation/camera/avfcamerasession.h
+++ b/src/plugins/avfoundation/camera/avfcamerasession.h
@@ -54,6 +54,7 @@ class AVFCameraControl;
class AVFCameraService;
class AVFCameraRendererControl;
class AVFMediaVideoProbeControl;
+class AVFCameraWindowControl;
struct AVFCameraInfo
{
@@ -79,6 +80,7 @@ public:
AVFCameraInfo activeCameraInfo() const { return m_activeCameraInfo; }
void setVideoOutput(AVFCameraRendererControl *output);
+ void setCapturePreviewOutput(AVFCameraWindowControl *output);
AVCaptureSession *captureSession() const { return m_captureSession; }
AVCaptureDevice *videoCaptureDevice() const;
@@ -122,6 +124,7 @@ private:
AVFCameraService *m_service;
AVFCameraRendererControl *m_videoOutput;
+ AVFCameraWindowControl *m_capturePreviewWindowOutput;
QCamera::State m_state;
bool m_active;
diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm
index 3c5f8f09a..6ee9c2636 100644
--- a/src/plugins/avfoundation/camera/avfcamerasession.mm
+++ b/src/plugins/avfoundation/camera/avfcamerasession.mm
@@ -48,6 +48,7 @@
#include "avfcameraviewfindersettingscontrol.h"
#include "avfimageencodercontrol.h"
#include "avfcamerautility.h"
+#include "avfcamerawindowcontrol.h"
#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/Foundation.h>
@@ -146,6 +147,7 @@ QList<AVFCameraInfo> AVFCameraSession::m_cameraDevices;
AVFCameraSession::AVFCameraSession(AVFCameraService *service, QObject *parent)
: QObject(parent)
, m_service(service)
+ , m_capturePreviewWindowOutput(nullptr)
, m_state(QCamera::UnloadedState)
, m_active(false)
, m_videoInput(nil)
@@ -160,6 +162,10 @@ AVFCameraSession::AVFCameraSession(AVFCameraService *service, QObject *parent)
AVFCameraSession::~AVFCameraSession()
{
+ if (m_capturePreviewWindowOutput) {
+ m_capturePreviewWindowOutput->setLayer(nil);
+ }
+
if (m_videoInput) {
[m_captureSession removeInput:m_videoInput];
[m_videoInput release];
@@ -257,6 +263,29 @@ void AVFCameraSession::setVideoOutput(AVFCameraRendererControl *output)
output->configureAVCaptureSession(this);
}
+void AVFCameraSession::setCapturePreviewOutput(AVFCameraWindowControl *output)
+{
+#ifdef QT_DEBUG_AVF
+ qDebug() << Q_FUNC_INFO << output;
+#endif
+
+ if (m_capturePreviewWindowOutput == output)
+ return;
+
+ if (m_capturePreviewWindowOutput)
+ m_capturePreviewWindowOutput->setLayer(nil);
+
+ m_capturePreviewWindowOutput = output;
+
+ if (m_capturePreviewWindowOutput) {
+ AVCaptureVideoPreviewLayer *previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:m_captureSession];
+ m_capturePreviewWindowOutput->setLayer(previewLayer);
+ if (AVFCameraViewfinderSettingsControl2 *vfControl = m_service->viewfinderSettingsControl2()) {
+ m_capturePreviewWindowOutput->setNativeSize(vfControl->viewfinderSettings().resolution());
+ }
+ }
+}
+
AVCaptureDevice *AVFCameraSession::videoCaptureDevice() const
{
if (m_videoInput)
@@ -409,6 +438,10 @@ bool AVFCameraSession::applyViewfinderSettings()
}
vfControl->applySettings(vfSettings);
+
+ if (m_capturePreviewWindowOutput)
+ m_capturePreviewWindowOutput->setNativeSize(vfControl->viewfinderSettings().resolution());
+
return !vfSettings.isNull();
}
diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm
index 0f7a0560b..dd0393f96 100644
--- a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm
+++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm
@@ -341,7 +341,10 @@ bool AVFCameraViewfinderSettingsControl2::convertPixelFormatIfSupported(QVideoFr
if (m_service->videoOutput()->surface()) {
const QAbstractVideoSurface *surface = m_service->videoOutput()->surface();
- if (!surface->supportedPixelFormats().contains(qtFormat))
+ QAbstractVideoBuffer::HandleType h = m_service->videoOutput()->supportsTextures()
+ ? QAbstractVideoBuffer::GLTextureHandle
+ : QAbstractVideoBuffer::NoHandle;
+ if (!surface->supportedPixelFormats(h).contains(qtFormat))
return false;
}
@@ -389,21 +392,19 @@ bool AVFCameraViewfinderSettingsControl2::applySettings(const QCameraViewfinderS
// format, or if no surface is set, the preferred capture device format
const QVector<QVideoFrame::PixelFormat> deviceFormats = viewfinderPixelFormats();
- QVideoFrame::PixelFormat pickedFormat = deviceFormats.first();
-
QAbstractVideoSurface *surface = m_service->videoOutput()->surface();
+ QVideoFrame::PixelFormat pickedFormat = deviceFormats.first();
if (surface) {
- if (m_service->videoOutput()->supportsTextures()) {
- pickedFormat = QVideoFrame::Format_ARGB32;
- } else {
- QList<QVideoFrame::PixelFormat> surfaceFormats = surface->supportedPixelFormats();
-
- for (int i = 0; i < surfaceFormats.count(); ++i) {
- const QVideoFrame::PixelFormat surfaceFormat = surfaceFormats.at(i);
- if (deviceFormats.contains(surfaceFormat)) {
- pickedFormat = surfaceFormat;
- break;
- }
+ pickedFormat = QVideoFrame::Format_Invalid;
+ QAbstractVideoBuffer::HandleType h = m_service->videoOutput()->supportsTextures()
+ ? QAbstractVideoBuffer::GLTextureHandle
+ : QAbstractVideoBuffer::NoHandle;
+ QList<QVideoFrame::PixelFormat> surfaceFormats = surface->supportedPixelFormats(h);
+ for (int i = 0; i < surfaceFormats.count(); ++i) {
+ const QVideoFrame::PixelFormat surfaceFormat = surfaceFormats.at(i);
+ if (deviceFormats.contains(surfaceFormat)) {
+ pickedFormat = surfaceFormat;
+ break;
}
}
}
@@ -411,13 +412,15 @@ bool AVFCameraViewfinderSettingsControl2::applySettings(const QCameraViewfinderS
CVPixelFormatFromQtFormat(pickedFormat, avfPixelFormat);
}
- if (avfPixelFormat != 0) {
- NSMutableDictionary *videoSettings = [NSMutableDictionary dictionaryWithCapacity:1];
- [videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat]
- forKey:(id)kCVPixelBufferPixelFormatTypeKey];
+ NSMutableDictionary *videoSettings = [NSMutableDictionary dictionaryWithCapacity:1];
+ [videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat]
+ forKey:(id)kCVPixelBufferPixelFormatTypeKey];
- videoOutput.videoSettings = videoSettings;
- }
+ const AVFConfigurationLock lock(captureDevice);
+ if (!lock)
+ qWarning("Failed to set active format (lock failed)");
+
+ videoOutput.videoSettings = videoSettings;
}
qt_set_framerate_limits(captureDevice, videoConnection(), settings.minimumFrameRate(), settings.maximumFrameRate());
diff --git a/src/plugins/avfoundation/camera/avfcamerawindowcontrol.h b/src/plugins/avfoundation/camera/avfcamerawindowcontrol.h
new file mode 100644
index 000000000..d1a950e38
--- /dev/null
+++ b/src/plugins/avfoundation/camera/avfcamerawindowcontrol.h
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** 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 AVFCAMERAWINDOWCONTROL_H
+#define AVFCAMERAWINDOWCONTROL_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 <QVideoWindowControl>
+
+@class AVCaptureVideoPreviewLayer;
+#if defined(Q_OS_MACOS)
+@class NSView;
+typedef NSView NativeView;
+#else
+@class UIView;
+typedef UIView NativeView;
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class AVFCameraWindowControl : public QVideoWindowControl
+{
+ Q_OBJECT
+public:
+ AVFCameraWindowControl(QObject *parent = nullptr);
+ virtual ~AVFCameraWindowControl() override;
+
+ // QVideoWindowControl interface
+public:
+ WId winId() const override;
+ void setWinId(WId id) override;
+
+ QRect displayRect() const override;
+ void setDisplayRect(const QRect &rect) override;
+
+ bool isFullScreen() const override;
+ void setFullScreen(bool fullScreen) override;
+
+ void repaint() override;
+
+ QSize nativeSize() const override;
+
+ Qt::AspectRatioMode aspectRatioMode() const override;
+ void setAspectRatioMode(Qt::AspectRatioMode mode) override;
+
+ int brightness() const override;
+ void setBrightness(int brightness) override;
+
+ int contrast() const override;
+ void setContrast(int contrast) override;
+
+ int hue() const override;
+ void setHue(int hue) override;
+
+ int saturation() const override;
+ void setSaturation(int saturation) override;
+
+ // AVF Camera implementation details
+ void setNativeSize(QSize size);
+ void setLayer(AVCaptureVideoPreviewLayer *capturePreviewLayer);
+
+private:
+ void updateAspectRatio();
+ void updateCaptureLayerBounds();
+
+ void retainNativeLayer();
+ void releaseNativeLayer();
+
+ void attachNativeLayer();
+ void detachNativeLayer();
+
+ WId m_winId{0};
+ QRect m_displayRect;
+ bool m_fullscreen{false};
+ Qt::AspectRatioMode m_aspectRatioMode{Qt::IgnoreAspectRatio};
+ QSize m_nativeSize;
+ AVCaptureVideoPreviewLayer *m_captureLayer{nullptr};
+ NativeView *m_nativeView{nullptr};
+};
+
+QT_END_NAMESPACE
+
+#endif // AVFCAMERAWINDOWCONTROL_H
diff --git a/src/plugins/avfoundation/camera/avfcamerawindowcontrol.mm b/src/plugins/avfoundation/camera/avfcamerawindowcontrol.mm
new file mode 100644
index 000000000..5154d0646
--- /dev/null
+++ b/src/plugins/avfoundation/camera/avfcamerawindowcontrol.mm
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd and/or its subsidiary(-ies).
+** 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 "avfcamerawindowcontrol.h"
+
+#import <AVFoundation/AVFoundation.h>
+#import <QuartzCore/CATransaction.h>
+
+#if QT_HAS_INCLUDE(<AppKit/AppKit.h>)
+#import <AppKit/AppKit.h>
+#endif
+
+#if QT_HAS_INCLUDE(<UIKit/UIKit.h>)
+#import <UIKit/UIKit.h>
+#endif
+
+QT_USE_NAMESPACE
+
+AVFCameraWindowControl::AVFCameraWindowControl(QObject *parent)
+ : QVideoWindowControl(parent)
+{
+ setObjectName(QStringLiteral("AVFCameraWindowControl"));
+}
+
+AVFCameraWindowControl::~AVFCameraWindowControl()
+{
+ releaseNativeLayer();
+}
+
+WId AVFCameraWindowControl::winId() const
+{
+ return m_winId;
+}
+
+void AVFCameraWindowControl::setWinId(WId id)
+{
+ if (m_winId == id)
+ return;
+
+ m_winId = id;
+
+ detachNativeLayer();
+ m_nativeView = (NativeView*)m_winId;
+ attachNativeLayer();
+}
+
+QRect AVFCameraWindowControl::displayRect() const
+{
+ return m_displayRect;
+}
+
+void AVFCameraWindowControl::setDisplayRect(const QRect &rect)
+{
+ if (m_displayRect != rect) {
+ m_displayRect = rect;
+ updateCaptureLayerBounds();
+ }
+}
+
+bool AVFCameraWindowControl::isFullScreen() const
+{
+ return m_fullscreen;
+}
+
+void AVFCameraWindowControl::setFullScreen(bool fullscreen)
+{
+ if (m_fullscreen != fullscreen) {
+ m_fullscreen = fullscreen;
+ Q_EMIT fullScreenChanged(fullscreen);
+ }
+}
+
+void AVFCameraWindowControl::repaint()
+{
+ if (m_captureLayer)
+ [m_captureLayer setNeedsDisplay];
+}
+
+QSize AVFCameraWindowControl::nativeSize() const
+{
+ return m_nativeSize;
+}
+
+void AVFCameraWindowControl::setNativeSize(QSize size)
+{
+ if (m_nativeSize != size) {
+ m_nativeSize = size;
+ Q_EMIT nativeSizeChanged();
+ }
+}
+
+Qt::AspectRatioMode AVFCameraWindowControl::aspectRatioMode() const
+{
+ return m_aspectRatioMode;
+}
+
+void AVFCameraWindowControl::setAspectRatioMode(Qt::AspectRatioMode mode)
+{
+ if (m_aspectRatioMode != mode) {
+ m_aspectRatioMode = mode;
+ updateAspectRatio();
+ }
+}
+
+int AVFCameraWindowControl::brightness() const
+{
+ return 0;
+}
+
+void AVFCameraWindowControl::setBrightness(int brightness)
+{
+ if (0 != brightness)
+ qWarning("AVFCameraWindowControl doesn't support changing Brightness");
+}
+
+int AVFCameraWindowControl::contrast() const
+{
+ return 0;
+}
+
+void AVFCameraWindowControl::setContrast(int contrast)
+{
+ if (0 != contrast)
+ qWarning("AVFCameraWindowControl doesn't support changing Contrast");
+}
+
+int AVFCameraWindowControl::hue() const
+{
+ return 0;
+}
+
+void AVFCameraWindowControl::setHue(int hue)
+{
+ if (0 != hue)
+ qWarning("AVFCameraWindowControl doesn't support changing Hue");
+}
+
+int AVFCameraWindowControl::saturation() const
+{
+ return 0;
+}
+
+void AVFCameraWindowControl::setSaturation(int saturation)
+{
+ if (0 != saturation)
+ qWarning("AVFCameraWindowControl doesn't support changing Saturation");
+}
+
+void AVFCameraWindowControl::setLayer(AVCaptureVideoPreviewLayer *capturePreviewLayer)
+{
+ if (m_captureLayer == capturePreviewLayer)
+ return;
+
+ releaseNativeLayer();
+
+ m_captureLayer = capturePreviewLayer;
+
+ if (m_captureLayer)
+ retainNativeLayer();
+}
+
+void AVFCameraWindowControl::updateAspectRatio()
+{
+ if (m_captureLayer) {
+ switch (m_aspectRatioMode) {
+ case Qt::IgnoreAspectRatio:
+ [m_captureLayer setVideoGravity:AVLayerVideoGravityResize];
+ break;
+ case Qt::KeepAspectRatio:
+ [m_captureLayer setVideoGravity:AVLayerVideoGravityResizeAspect];
+ break;
+ case Qt::KeepAspectRatioByExpanding:
+ [m_captureLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void AVFCameraWindowControl::updateCaptureLayerBounds()
+{
+ if (m_captureLayer && m_nativeView) {
+ [CATransaction begin];
+ [CATransaction setDisableActions: YES]; // disable animation/flicks
+ m_captureLayer.frame = m_displayRect.toCGRect();
+ [CATransaction commit];
+ }
+}
+
+void AVFCameraWindowControl::retainNativeLayer()
+{
+ [m_captureLayer retain];
+
+ updateAspectRatio();
+ attachNativeLayer();
+}
+
+void AVFCameraWindowControl::releaseNativeLayer()
+{
+ if (m_captureLayer) {
+ detachNativeLayer();
+ [m_captureLayer release];
+ m_captureLayer = nullptr;
+ }
+}
+
+void AVFCameraWindowControl::attachNativeLayer()
+{
+ if (m_captureLayer && m_nativeView) {
+#if defined(Q_OS_MACOS)
+ m_nativeView.wantsLayer = YES;
+#endif
+ CALayer *nativeLayer = m_nativeView.layer;
+ [nativeLayer addSublayer:m_captureLayer];
+ updateCaptureLayerBounds();
+ }
+}
+
+void AVFCameraWindowControl::detachNativeLayer()
+{
+ if (m_captureLayer && m_nativeView)
+ [m_captureLayer removeFromSuperlayer];
+}
+
+#include "moc_avfcamerawindowcontrol.cpp"
diff --git a/src/plugins/avfoundation/camera/avfcapturedestinationcontrol.h b/src/plugins/avfoundation/camera/avfcapturedestinationcontrol.h
new file mode 100644
index 000000000..04493437e
--- /dev/null
+++ b/src/plugins/avfoundation/camera/avfcapturedestinationcontrol.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 AVFCAPTUREDESTINATIONCONTROL_H
+#define AVFCAPTUREDESTINATIONCONTROL_H
+
+#include <qcameracapturedestinationcontrol.h>
+
+QT_BEGIN_NAMESPACE
+
+class AVFCaptureDestinationControl : public QCameraCaptureDestinationControl
+{
+public:
+ AVFCaptureDestinationControl() = default;
+ ~AVFCaptureDestinationControl() = default;
+
+ bool isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const override;
+ QCameraImageCapture::CaptureDestinations captureDestination() const override;
+ void setCaptureDestination(QCameraImageCapture::CaptureDestinations destination) override;
+
+private:
+ QCameraImageCapture::CaptureDestinations m_destination = QCameraImageCapture::CaptureToFile;
+};
+
+QT_END_NAMESPACE
+
+#endif // AVFCAPTUREDESTINATIONCONTROL_H
diff --git a/src/plugins/avfoundation/camera/avfcapturedestinationcontrol.mm b/src/plugins/avfoundation/camera/avfcapturedestinationcontrol.mm
new file mode 100644
index 000000000..d0700d69d
--- /dev/null
+++ b/src/plugins/avfoundation/camera/avfcapturedestinationcontrol.mm
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 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 "avfcapturedestinationcontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+bool AVFCaptureDestinationControl::isCaptureDestinationSupported(QCameraImageCapture::CaptureDestinations destination) const
+{
+ return destination & (QCameraImageCapture::CaptureToFile | QCameraImageCapture::CaptureToBuffer);
+}
+
+QCameraImageCapture::CaptureDestinations AVFCaptureDestinationControl::captureDestination() const
+{
+ return m_destination;
+}
+
+void AVFCaptureDestinationControl::setCaptureDestination(QCameraImageCapture::CaptureDestinations destination)
+{
+ if (m_destination != destination) {
+ m_destination = destination;
+ Q_EMIT captureDestinationChanged(m_destination);
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm
index dbaf3ed41..6fca55d29 100644
--- a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm
+++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm
@@ -42,13 +42,14 @@
#include "avfcameraservice.h"
#include "avfcamerautility.h"
#include "avfcameracontrol.h"
+#include "avfcapturedestinationcontrol.h"
+#include <private/qmemoryvideobuffer_p.h>
#include <QtCore/qurl.h>
#include <QtCore/qfile.h>
#include <QtCore/qbuffer.h>
#include <QtConcurrent/qtconcurrentrun.h>
#include <QtGui/qimagereader.h>
-#include <private/qvideoframe_p.h>
QT_USE_NAMESPACE
@@ -112,12 +113,16 @@ int AVFImageCaptureControl::capture(const QString &fileName)
return m_lastCaptureId;
}
- QString actualFileName = m_storageLocation.generateFileName(fileName,
- QCamera::CaptureStillImage,
- QLatin1String("img_"),
- QLatin1String("jpg"));
+ auto destination = m_service->captureDestinationControl()->captureDestination();
+ QString actualFileName;
+ if (destination & QCameraImageCapture::CaptureToFile) {
+ actualFileName = m_storageLocation.generateFileName(fileName,
+ QCamera::CaptureStillImage,
+ QLatin1String("img_"),
+ QLatin1String("jpg"));
- qDebugCamera() << "Capture image to" << actualFileName;
+ qDebugCamera() << "Capture image to" << actualFileName;
+ }
CaptureRequest request = { m_lastCaptureId, QSharedPointer<QSemaphore>::create()};
m_requestsMutex.lock();
@@ -153,11 +158,24 @@ int AVFImageCaptureControl::capture(const QString &fileName)
// so we cannot reliably check the camera's status. Instead, we wait
// with a timeout and treat a failure to acquire a semaphore as an error.
if (!m_service->videoOutput() || request.previewReady->tryAcquire(1, 1000)) {
- qDebugCamera() << "Image capture completed:" << actualFileName;
+ qDebugCamera() << "Image capture completed";
NSData *nsJpgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
QByteArray jpgData = QByteArray::fromRawData((const char *)[nsJpgData bytes], [nsJpgData length]);
+ if (destination & QCameraImageCapture::CaptureToBuffer) {
+ QBuffer data(&jpgData);
+ QImageReader reader(&data, "JPEG");
+ QSize size = reader.size();
+ QVideoFrame frame(new QMemoryVideoBuffer(QByteArray(jpgData.constData(), jpgData.size()), -1), size, QVideoFrame::Format_Jpeg);
+ QMetaObject::invokeMethod(this, "imageAvailable", Qt::QueuedConnection,
+ Q_ARG(int, request.captureId),
+ Q_ARG(QVideoFrame, frame));
+ }
+
+ if (!(destination & QCameraImageCapture::CaptureToFile))
+ return;
+
QFile f(actualFileName);
if (f.open(QFile::WriteOnly)) {
if (f.write(jpgData) != -1) {
@@ -214,7 +232,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/camera/camera.pro b/src/plugins/avfoundation/camera/camera.pro
index 4b960ed5a..76aa8af85 100644
--- a/src/plugins/avfoundation/camera/camera.pro
+++ b/src/plugins/avfoundation/camera/camera.pro
@@ -42,7 +42,9 @@ HEADERS += \
avfcameraflashcontrol.h \
avfvideoencodersettingscontrol.h \
avfmediacontainercontrol.h \
- avfaudioencodersettingscontrol.h
+ avfaudioencodersettingscontrol.h \
+ avfcamerawindowcontrol.h \
+ avfcapturedestinationcontrol.h
OBJECTIVE_SOURCES += \
avfcameraserviceplugin.mm \
@@ -65,7 +67,9 @@ OBJECTIVE_SOURCES += \
avfcameraflashcontrol.mm \
avfvideoencodersettingscontrol.mm \
avfmediacontainercontrol.mm \
- avfaudioencodersettingscontrol.mm
+ avfaudioencodersettingscontrol.mm \
+ avfcamerawindowcontrol.mm \
+ avfcapturedestinationcontrol.mm
osx {
diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h
index 7a268a3d9..db29e88aa 100644
--- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h
+++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h
@@ -67,7 +67,7 @@ public:
QMediaPlayer::MediaStatus mediaStatus() const;
QMediaContent media() const;
- const QIODevice *mediaStream() const;
+ QIODevice *mediaStream() const;
void setMedia(const QMediaContent &content, QIODevice *stream);
qint64 position() const;
@@ -110,6 +110,9 @@ public Q_SLOTS:
void processDurationChange(qint64 duration);
+ void streamReady();
+ void streamDestroyed();
+
Q_SIGNALS:
void positionChanged(qint64 position);
void durationChanged(qint64 duration);
@@ -128,6 +131,7 @@ private:
void setAudioAvailable(bool available);
void setVideoAvailable(bool available);
void setSeekable(bool seekable);
+ void resetStream(QIODevice *stream = nullptr);
AVFMediaPlayerService *m_service;
AVFVideoOutput *m_videoOutput;
diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm
index ba902a53c..a601bb5ac 100644
--- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm
+++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm
@@ -42,6 +42,7 @@
#include "avfvideooutput.h"
#include <qpointer.h>
+#include <QFileInfo>
#import <AVFoundation/AVFoundation.h>
@@ -66,7 +67,7 @@ static void *AVFMediaPlayerSessionObserverBufferLikelyToKeepUpContext = &AVFMedi
static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMediaPlayerSessionObserverCurrentItemObservationContext;
static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext = &AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext;
-@interface AVFMediaPlayerSessionObserver : NSObject
+@interface AVFMediaPlayerSessionObserver : NSObject<AVAssetResourceLoaderDelegate>
@property (readonly, getter=player) AVPlayer* m_player;
@property (readonly, getter=playerItem) AVPlayerItem* m_playerItem;
@@ -74,7 +75,7 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
@property (readonly, getter=session) AVFMediaPlayerSession* m_session;
- (AVFMediaPlayerSessionObserver *) initWithMediaPlayerSession:(AVFMediaPlayerSession *)session;
-- (void) setURL:(NSURL *)url;
+- (void) setURL:(NSURL *)url mimeType:(NSString *)mimeType;
- (void) unloadMedia;
- (void) prepareToPlayAsset:(AVURLAsset *)asset withKeys:(NSArray *)requestedKeys;
- (void) assetFailedToPrepareForPlayback:(NSError *)error;
@@ -84,6 +85,7 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
change:(NSDictionary *)change context:(void *)context;
- (void) detatchSession;
- (void) dealloc;
+- (BOOL) resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest;
@end
@implementation AVFMediaPlayerSessionObserver
@@ -95,6 +97,8 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
AVPlayerLayer *m_playerLayer;
NSURL *m_URL;
BOOL m_bufferIsLikelyToKeepUp;
+ NSData *m_data;
+ NSString *m_mimeType;
}
@synthesize m_player, m_playerItem, m_playerLayer, m_session;
@@ -106,11 +110,20 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
self->m_session = session;
self->m_bufferIsLikelyToKeepUp = FALSE;
+
+ m_playerLayer = [AVPlayerLayer playerLayerWithPlayer:nil];
+ [m_playerLayer retain];
+ m_playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
+ m_playerLayer.anchorPoint = CGPointMake(0.0f, 0.0f);
+
return self;
}
-- (void) setURL:(NSURL *)url
+- (void) setURL:(NSURL *)url mimeType:(NSString *)mimeType
{
+ [m_mimeType release];
+ m_mimeType = [mimeType retain];
+
if (m_URL != url)
{
[m_URL release];
@@ -122,6 +135,8 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
// use __block to avoid maintaining strong references on variables captured by the
// following block callback
__block AVURLAsset *asset = [[AVURLAsset URLAssetWithURL:m_URL options:nil] retain];
+ [asset.resourceLoader setDelegate:self queue:dispatch_get_main_queue()];
+
__block NSArray *requestedKeys = [[NSArray arrayWithObjects:AVF_TRACKS_KEY, AVF_PLAYABLE_KEY, nil] retain];
__block AVFMediaPlayerSessionObserver *blockSelf = self;
@@ -153,6 +168,10 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
[[NSNotificationCenter defaultCenter] removeObserver:self
name:AVPlayerItemTimeJumpedNotification
object:m_playerItem];
+ for (AVPlayerItemOutput *output in m_playerItem.outputs) {
+ if ([output isKindOfClass:[AVPlayerItemVideoOutput class]])
+ [m_playerItem removeOutput:output];
+ }
m_playerItem = 0;
}
if (m_player) {
@@ -163,10 +182,6 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
[m_player release];
m_player = 0;
}
- if (m_playerLayer) {
- [m_playerLayer release];
- m_playerLayer = 0;
- }
}
- (void) prepareToPlayAsset:(AVURLAsset *)asset
@@ -251,14 +266,8 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
[m_player setMuted:m_session->isMuted()];
}
- //Create a new player layer if we don't have one already
- if (!m_playerLayer)
- {
- m_playerLayer = [AVPlayerLayer playerLayerWithPlayer:m_player];
- [m_playerLayer retain];
- m_playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
- m_playerLayer.anchorPoint = CGPointMake(0.0f, 0.0f);
- }
+ //Assign the output layer to the new player
+ m_playerLayer.player = m_player;
//Observe the AVPlayer "currentItem" property to find out when any
//AVPlayer replaceCurrentItemWithPlayerItem: replacement will/did
@@ -403,9 +412,49 @@ static void *AVFMediaPlayerSessionObserverCurrentItemDurationObservationContext
[m_URL release];
}
+ [m_mimeType release];
+ [m_playerLayer release];
[super dealloc];
}
+- (BOOL) resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest
+{
+ Q_UNUSED(resourceLoader);
+
+ if (![loadingRequest.request.URL.scheme isEqualToString:@"iodevice"])
+ return NO;
+
+ QIODevice *device = m_session->mediaStream();
+ if (!device)
+ return NO;
+
+ device->seek(loadingRequest.dataRequest.requestedOffset);
+ if (loadingRequest.contentInformationRequest) {
+ loadingRequest.contentInformationRequest.contentType = m_mimeType;
+ loadingRequest.contentInformationRequest.contentLength = device->size();
+ loadingRequest.contentInformationRequest.byteRangeAccessSupported = YES;
+ }
+
+ if (loadingRequest.dataRequest) {
+ NSInteger requestedLength = loadingRequest.dataRequest.requestedLength;
+ int maxBytes = qMin(32 * 1064, int(requestedLength));
+ char buffer[maxBytes];
+ NSInteger submitted = 0;
+ while (submitted < requestedLength) {
+ qint64 len = device->read(buffer, maxBytes);
+ if (len < 1)
+ break;
+
+ [loadingRequest.dataRequest respondWithData:[NSData dataWithBytes:buffer length:len]];
+ submitted += len;
+ }
+
+ // Finish loading even if not all bytes submitted.
+ [loadingRequest finishLoading];
+ }
+
+ return YES;
+}
@end
AVFMediaPlayerSession::AVFMediaPlayerSession(AVFMediaPlayerService *service, QObject *parent)
@@ -483,11 +532,23 @@ QMediaContent AVFMediaPlayerSession::media() const
return m_resources;
}
-const QIODevice *AVFMediaPlayerSession::mediaStream() const
+QIODevice *AVFMediaPlayerSession::mediaStream() const
{
return m_mediaStream;
}
+static void setURL(void *observer, const QByteArray &url, const QString &mimeType = QString())
+{
+ NSString *urlString = [NSString stringWithUTF8String:url.constData()];
+ NSURL *nsurl = [NSURL URLWithString:urlString];
+ [static_cast<AVFMediaPlayerSessionObserver*>(observer) setURL:nsurl mimeType:[NSString stringWithUTF8String:mimeType.toLatin1().constData()]];
+}
+
+static void setStreamURL(void *observer, const QByteArray &url)
+{
+ setURL(observer, QByteArrayLiteral("iodevice://") + url, QFileInfo(url).suffix());
+}
+
void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *stream)
{
#ifdef QT_DEBUG_AVF
@@ -497,7 +558,7 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st
[static_cast<AVFMediaPlayerSessionObserver*>(m_observer) unloadMedia];
m_resources = content;
- m_mediaStream = stream;
+ resetStream(stream);
setAudioAvailable(false);
setVideoAvailable(false);
@@ -508,7 +569,7 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st
const QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus;
const QMediaPlayer::State oldState = m_state;
- if (content.isNull() || content.request().url().isEmpty()) {
+ if (!m_mediaStream && (content.isNull() || content.request().url().isEmpty())) {
m_mediaStatus = QMediaPlayer::NoMedia;
if (m_mediaStatus != oldMediaStatus)
Q_EMIT mediaStatusChanged(m_mediaStatus);
@@ -524,11 +585,16 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st
if (m_mediaStatus != oldMediaStatus)
Q_EMIT mediaStatusChanged(m_mediaStatus);
- //Load AVURLAsset
- //initialize asset using content's URL
- NSString *urlString = [NSString stringWithUTF8String:content.request().url().toEncoded().constData()];
- NSURL *url = [NSURL URLWithString:urlString];
- [static_cast<AVFMediaPlayerSessionObserver*>(m_observer) setURL:url];
+ if (m_mediaStream) {
+ // If there is a data, try to load it,
+ // otherwise wait for readyRead.
+ if (m_mediaStream->size())
+ setStreamURL(m_observer, m_resources.request().url().toEncoded());
+ } else {
+ //Load AVURLAsset
+ //initialize asset using content's URL
+ setURL(m_observer, m_resources.request().url().toEncoded());
+ }
m_state = QMediaPlayer::StoppedState;
if (m_state != oldState)
@@ -969,3 +1035,28 @@ void AVFMediaPlayerSession::processMediaLoadError()
Q_EMIT error(QMediaPlayer::FormatError, tr("Failed to load media"));
}
+
+void AVFMediaPlayerSession::streamReady()
+{
+ setStreamURL(m_observer, m_resources.request().url().toEncoded());
+}
+
+void AVFMediaPlayerSession::streamDestroyed()
+{
+ resetStream(nullptr);
+}
+
+void AVFMediaPlayerSession::resetStream(QIODevice *stream)
+{
+ if (m_mediaStream) {
+ disconnect(m_mediaStream, &QIODevice::readyRead, this, &AVFMediaPlayerSession::streamReady);
+ disconnect(m_mediaStream, &QIODevice::destroyed, this, &AVFMediaPlayerSession::streamDestroyed);
+ }
+
+ m_mediaStream = stream;
+
+ if (m_mediaStream) {
+ connect(m_mediaStream, &QIODevice::readyRead, this, &AVFMediaPlayerSession::streamReady);
+ connect(m_mediaStream, &QIODevice::destroyed, this, &AVFMediaPlayerSession::streamDestroyed);
+ }
+}
diff --git a/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.h b/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.h
index 99b6bb0b5..ac67090a5 100644
--- a/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.h
+++ b/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.h
@@ -43,18 +43,48 @@
#include <QtCore/QObject>
#include <QtGui/QImage>
#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLTextureBlitter>
#include <QtCore/QSize>
-@class CARenderer;
@class AVPlayerLayer;
+@class AVPlayerItemVideoOutput;
QT_BEGIN_NAMESPACE
-class QOpenGLFramebufferObject;
-class QWindow;
class QOpenGLContext;
+class QOpenGLFramebufferObject;
+class QOpenGLShaderProgram;
+class QOffscreenSurface;
class QAbstractVideoSurface;
+typedef struct __CVBuffer *CVBufferRef;
+typedef CVBufferRef CVImageBufferRef;
+typedef CVImageBufferRef CVPixelBufferRef;
+
+#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
+ typedef struct __CVOpenGLESTextureCache *CVOpenGLESTextureCacheRef;
+ typedef CVImageBufferRef CVOpenGLESTextureRef;
+ // helpers to avoid boring if def
+ typedef CVOpenGLESTextureCacheRef CVOGLTextureCacheRef;
+ typedef CVOpenGLESTextureRef CVOGLTextureRef;
+ #define CVOGLTextureGetTarget CVOpenGLESTextureGetTarget
+ #define CVOGLTextureGetName CVOpenGLESTextureGetName
+ #define CVOGLTextureCacheCreate CVOpenGLESTextureCacheCreate
+ #define CVOGLTextureCacheCreateTextureFromImage CVOpenGLESTextureCacheCreateTextureFromImage
+ #define CVOGLTextureCacheFlush CVOpenGLESTextureCacheFlush
+#else
+ typedef struct __CVOpenGLTextureCache *CVOpenGLTextureCacheRef;
+ typedef CVImageBufferRef CVOpenGLTextureRef;
+ // helpers to avoid boring if def
+ typedef CVOpenGLTextureCacheRef CVOGLTextureCacheRef;
+ typedef CVOpenGLTextureRef CVOGLTextureRef;
+ #define CVOGLTextureGetTarget CVOpenGLTextureGetTarget
+ #define CVOGLTextureGetName CVOpenGLTextureGetName
+ #define CVOGLTextureCacheCreate CVOpenGLTextureCacheCreate
+ #define CVOGLTextureCacheCreateTextureFromImage CVOpenGLTextureCacheCreateTextureFromImage
+ #define CVOGLTextureCacheFlush CVOpenGLTextureCacheFlush
+#endif
+
class AVFVideoFrameRenderer : public QObject
{
public:
@@ -62,22 +92,31 @@ public:
virtual ~AVFVideoFrameRenderer();
- GLuint renderLayerToTexture(AVPlayerLayer *layer);
- QImage renderLayerToImage(AVPlayerLayer *layer);
+ void setPlayerLayer(AVPlayerLayer *layer);
+
+ CVOGLTextureRef renderLayerToTexture(AVPlayerLayer *layer, QSize *size);
+#ifdef Q_OS_MACOS
+ GLuint renderLayerToFBO(AVPlayerLayer *layer, QSize *size);
+#endif
+ QImage renderLayerToImage(AVPlayerLayer *layer, QSize *size);
private:
- QOpenGLFramebufferObject* initRenderer(AVPlayerLayer *layer);
- void renderLayerToFBO(AVPlayerLayer *layer, QOpenGLFramebufferObject *fbo);
+ void initRenderer();
+ CVPixelBufferRef copyPixelBufferFromLayer(AVPlayerLayer *layer, size_t& width, size_t& height);
+ CVOGLTextureRef createCacheTextureFromLayer(AVPlayerLayer *layer, size_t& width, size_t& height);
- CARenderer *m_videoLayerRenderer;
- QAbstractVideoSurface *m_surface;
- QOpenGLFramebufferObject *m_fbo[2];
- QWindow *m_offscreenSurface;
QOpenGLContext *m_glContext;
- QSize m_targetSize;
-
- uint m_currentBuffer;
+ QOffscreenSurface *m_offscreenSurface;
+ QAbstractVideoSurface *m_surface;
+ CVOGLTextureCacheRef m_textureCache;
+ AVPlayerItemVideoOutput* m_videoOutput;
bool m_isContextShared;
+
+#ifdef Q_OS_MACOS
+ QOpenGLFramebufferObject *m_fbo[2];
+ uint m_currentFBO;
+ QOpenGLTextureBlitter m_blitter;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.mm b/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.mm
index 51f961729..a22ee2b82 100644
--- a/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.mm
+++ b/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer.mm
@@ -41,12 +41,20 @@
#include <QtMultimedia/qabstractvideosurface.h>
#include <QtGui/QOpenGLFramebufferObject>
-#include <QtGui/QWindow>
+#include <QtGui/QOpenGLShaderProgram>
+#include <QtGui/QOffscreenSurface>
+
+#include <QtCore/private/qcore_mac_p.h>
#ifdef QT_DEBUG_AVF
#include <QtCore/qdebug.h>
#endif
+#ifdef Q_OS_MACOS
+#import <AppKit/AppKit.h>
+#include <CoreVideo/CVOpenGLTextureCache.h>
+#endif
+
#import <CoreVideo/CVBase.h>
#import <AVFoundation/AVFoundation.h>
@@ -54,15 +62,23 @@ QT_USE_NAMESPACE
AVFVideoFrameRenderer::AVFVideoFrameRenderer(QAbstractVideoSurface *surface, QObject *parent)
: QObject(parent)
- , m_videoLayerRenderer(nullptr)
- , m_surface(surface)
- , m_offscreenSurface(nullptr)
, m_glContext(nullptr)
- , m_currentBuffer(1)
+ , m_offscreenSurface(nullptr)
+ , m_surface(surface)
+ , m_textureCache(nullptr)
+ , m_videoOutput(nullptr)
, m_isContextShared(true)
{
+ m_videoOutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:@{
+ (NSString *)kCVPixelBufferPixelFormatTypeKey: @(kCVPixelFormatType_32BGRA),
+ (NSString *)kCVPixelBufferOpenGLCompatibilityKey: @YES
+ }];
+ [m_videoOutput setDelegate:nil queue:nil];
+
+#ifdef Q_OS_MACOS
m_fbo[0] = nullptr;
m_fbo[1] = nullptr;
+#endif
}
AVFVideoFrameRenderer::~AVFVideoFrameRenderer()
@@ -71,81 +87,200 @@ AVFVideoFrameRenderer::~AVFVideoFrameRenderer()
qDebug() << Q_FUNC_INFO;
#endif
- [m_videoLayerRenderer release];
- delete m_fbo[0];
- delete m_fbo[1];
+ [m_videoOutput release];
+ if (m_textureCache)
+ CFRelease(m_textureCache);
delete m_offscreenSurface;
delete m_glContext;
+
+#ifdef Q_OS_MACOS
+ delete m_fbo[0];
+ delete m_fbo[1];
+#endif
}
-GLuint AVFVideoFrameRenderer::renderLayerToTexture(AVPlayerLayer *layer)
+#ifdef Q_OS_MACOS
+GLuint AVFVideoFrameRenderer::renderLayerToFBO(AVPlayerLayer *layer, QSize *size)
{
- //Is layer valid
- if (!layer)
+ QCFType<CVOGLTextureRef> texture = renderLayerToTexture(layer, size);
+ if (!texture)
return 0;
- //If the glContext isn't shared, it doesn't make sense to return a texture for us
- if (m_offscreenSurface && !m_isContextShared)
- return 0;
+ Q_ASSERT(size);
- QOpenGLFramebufferObject *fbo = initRenderer(layer);
+ // Do we have FBO's already?
+ if ((!m_fbo[0] && !m_fbo[0]) || (m_fbo[0]->size() != *size)) {
+ delete m_fbo[0];
+ delete m_fbo[1];
+ m_fbo[0] = new QOpenGLFramebufferObject(*size);
+ m_fbo[1] = new QOpenGLFramebufferObject(*size);
+ }
+
+ // Switch buffer target
+ m_currentFBO = !m_currentFBO;
+ QOpenGLFramebufferObject *fbo = m_fbo[m_currentFBO];
- if (!fbo)
+ if (!fbo || !fbo->bind())
return 0;
- renderLayerToFBO(layer, fbo);
- if (m_glContext)
- m_glContext->doneCurrent();
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glViewport(0, 0, size->width(), size->height());
+
+ if (!m_blitter.isCreated())
+ m_blitter.create();
+
+ m_blitter.bind(GL_TEXTURE_RECTANGLE);
+ m_blitter.blit(CVOpenGLTextureGetName(texture), QMatrix4x4(), QMatrix3x3());
+ m_blitter.release();
+ glFinish();
+
+ fbo->release();
return fbo->texture();
}
+#endif
+
+CVOGLTextureRef AVFVideoFrameRenderer::renderLayerToTexture(AVPlayerLayer *layer, QSize *size)
+{
+ initRenderer();
+
+ // If the glContext isn't shared, it doesn't make sense to return a texture for us
+ if (!m_isContextShared)
+ return nullptr;
+
+ size_t width = 0, height = 0;
+ auto texture = createCacheTextureFromLayer(layer, width, height);
+ if (size)
+ *size = QSize(width, height);
+ return texture;
+}
-QImage AVFVideoFrameRenderer::renderLayerToImage(AVPlayerLayer *layer)
+CVPixelBufferRef AVFVideoFrameRenderer::copyPixelBufferFromLayer(AVPlayerLayer *layer,
+ size_t& width, size_t& height)
{
//Is layer valid
if (!layer) {
- return QImage();
+#ifdef QT_DEBUG_AVF
+ qWarning("copyPixelBufferFromLayer: invalid layer");
+#endif
+ return nullptr;
}
- QOpenGLFramebufferObject *fbo = initRenderer(layer);
+ AVPlayerItem *item = layer.player.currentItem;
+ if (![item.outputs containsObject:m_videoOutput])
+ [item addOutput:m_videoOutput];
- if (!fbo)
- return QImage();
+ CFTimeInterval currentCAFrameTime = CACurrentMediaTime();
+ CMTime currentCMFrameTime = [m_videoOutput itemTimeForHostTime:currentCAFrameTime];
+
+ // Happens when buffering / loading
+ if (CMTimeCompare(currentCMFrameTime, kCMTimeZero) < 0)
+ return nullptr;
+
+ if (![m_videoOutput hasNewPixelBufferForItemTime:currentCMFrameTime])
+ return nullptr;
+
+ CVPixelBufferRef pixelBuffer = [m_videoOutput copyPixelBufferForItemTime:currentCMFrameTime
+ itemTimeForDisplay:nil];
+ if (!pixelBuffer) {
+#ifdef QT_DEBUG_AVF
+ qWarning("copyPixelBufferForItemTime returned nil");
+ CMTimeShow(currentCMFrameTime);
+#endif
+ return nullptr;
+ }
+
+ width = CVPixelBufferGetWidth(pixelBuffer);
+ height = CVPixelBufferGetHeight(pixelBuffer);
+ return pixelBuffer;
+}
- renderLayerToFBO(layer, fbo);
- QImage fboImage = fbo->toImage();
- if (m_glContext)
- m_glContext->doneCurrent();
+CVOGLTextureRef AVFVideoFrameRenderer::createCacheTextureFromLayer(AVPlayerLayer *layer,
+ size_t& width, size_t& height)
+{
+ CVPixelBufferRef pixelBuffer = copyPixelBufferFromLayer(layer, width, height);
+
+ if (!pixelBuffer)
+ return nullptr;
+
+ CVOGLTextureCacheFlush(m_textureCache, 0);
+
+ CVOGLTextureRef texture = nullptr;
+#ifdef Q_OS_MACOS
+ CVReturn err = CVOpenGLTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
+ m_textureCache,
+ pixelBuffer,
+ nil,
+ &texture);
+#else
+ CVReturn err = CVOGLTextureCacheCreateTextureFromImage(kCFAllocatorDefault, m_textureCache, pixelBuffer, nullptr,
+ GL_TEXTURE_2D, GL_RGBA,
+ (GLsizei) width, (GLsizei) height,
+ GL_BGRA, GL_UNSIGNED_BYTE, 0,
+ &texture);
+#endif
+
+ if (!texture || err) {
+ qWarning() << "CVOGLTextureCacheCreateTextureFromImage failed error:" << err << m_textureCache;
+ }
+
+ CVPixelBufferRelease(pixelBuffer);
- return fboImage;
+ return texture;
}
-QOpenGLFramebufferObject *AVFVideoFrameRenderer::initRenderer(AVPlayerLayer *layer)
+QImage AVFVideoFrameRenderer::renderLayerToImage(AVPlayerLayer *layer, QSize *size)
{
+ size_t width = 0;
+ size_t height = 0;
+ CVPixelBufferRef pixelBuffer = copyPixelBufferFromLayer(layer, width, height);
+ if (size)
+ *size = QSize(width, height);
+
+ if (!pixelBuffer)
+ return QImage();
- //Get size from AVPlayerLayer
- m_targetSize = QSize(layer.bounds.size.width, layer.bounds.size.height);
+ OSType pixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer);
+ if (pixelFormat != kCVPixelFormatType_32BGRA) {
+#ifdef QT_DEBUG_AVF
+ qWarning("CVPixelBuffer format is not BGRA32 (got: %d)", static_cast<quint32>(pixelFormat));
+#endif
+ return QImage();
+ }
- QOpenGLContext *shareContext = !m_glContext && m_surface
- ? qobject_cast<QOpenGLContext*>(m_surface->property("GLContext").value<QObject*>())
- : nullptr;
+ CVPixelBufferLockBaseAddress(pixelBuffer, 0);
+ char *data = (char *)CVPixelBufferGetBaseAddress(pixelBuffer);
+ size_t stride = CVPixelBufferGetBytesPerRow(pixelBuffer);
+
+ // format here is not relevant, only using for storage
+ QImage img = QImage(width, height, QImage::Format_ARGB32);
+ for (size_t j = 0; j < height; j++) {
+ memcpy(img.scanLine(j), data, width * 4);
+ data += stride;
+ }
+
+ CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
+ CVPixelBufferRelease(pixelBuffer);
+ return img;
+}
+
+void AVFVideoFrameRenderer::initRenderer()
+{
+ // even for using a texture directly, we need to be able to make a context current,
+ // so we need an offscreen, and we shouldn't assume we can make the surface context
+ // current on that offscreen, so use our own (sharing with it). Slightly
+ // excessive but no performance penalty and makes the QImage path easier to maintain
//Make sure we have an OpenGL context to make current
- if ((shareContext && shareContext != QOpenGLContext::currentContext())
- || (!QOpenGLContext::currentContext() && !m_glContext)) {
-
- //Create Hidden QWindow surface to create context in this thread
- delete m_offscreenSurface;
- m_offscreenSurface = new QWindow();
- m_offscreenSurface->setSurfaceType(QWindow::OpenGLSurface);
- //Needs geometry to be a valid surface, but size is not important
- m_offscreenSurface->setGeometry(0, 0, 1, 1);
- m_offscreenSurface->create();
+ if (!m_glContext) {
+ //Create OpenGL context and set share context from surface
+ QOpenGLContext *shareContext = nullptr;
+ if (m_surface)
+ shareContext = qobject_cast<QOpenGLContext*>(m_surface->property("GLContext").value<QObject*>());
- delete m_glContext;
m_glContext = new QOpenGLContext();
- m_glContext->setFormat(m_offscreenSurface->requestedFormat());
-
if (shareContext) {
m_glContext->setShareContext(shareContext);
m_isContextShared = true;
@@ -156,83 +291,40 @@ QOpenGLFramebufferObject *AVFVideoFrameRenderer::initRenderer(AVPlayerLayer *lay
m_isContextShared = false;
}
if (!m_glContext->create()) {
+#ifdef QT_DEBUG_AVF
qWarning("failed to create QOpenGLContext");
- return nullptr;
- }
-
- // CARenderer must be re-created with different current context, so release it now.
- // See lines below where m_videoLayerRenderer is constructed.
- if (m_videoLayerRenderer) {
- [m_videoLayerRenderer release];
- m_videoLayerRenderer = nullptr;
+#endif
+ return;
}
}
- //Need current context
- if (m_glContext)
- m_glContext->makeCurrent(m_offscreenSurface);
-
- //Create the CARenderer if needed
- if (!m_videoLayerRenderer) {
- m_videoLayerRenderer = [CARenderer rendererWithCGLContext: CGLGetCurrentContext() options: nil];
- [m_videoLayerRenderer retain];
- }
-
- //Set/Change render source if needed
- if (m_videoLayerRenderer.layer != layer) {
- m_videoLayerRenderer.layer = layer;
- m_videoLayerRenderer.bounds = layer.bounds;
- }
-
- //Do we have FBO's already?
- if ((!m_fbo[0] && !m_fbo[0]) || (m_fbo[0]->size() != m_targetSize)) {
- delete m_fbo[0];
- delete m_fbo[1];
- m_fbo[0] = new QOpenGLFramebufferObject(m_targetSize);
- m_fbo[1] = new QOpenGLFramebufferObject(m_targetSize);
+ if (!m_offscreenSurface) {
+ m_offscreenSurface = new QOffscreenSurface();
+ m_offscreenSurface->setFormat(m_glContext->format());
+ m_offscreenSurface->create();
}
- //Switch buffer target
- m_currentBuffer = !m_currentBuffer;
- return m_fbo[m_currentBuffer];
-}
-
-void AVFVideoFrameRenderer::renderLayerToFBO(AVPlayerLayer *layer, QOpenGLFramebufferObject *fbo)
-{
- //Start Rendering
- //NOTE: This rendering method will NOT work on iOS as there is no CARenderer in iOS
- if (!fbo->bind()) {
- qWarning("AVFVideoRender FBO failed to bind");
- return;
+ // Need current context
+ m_glContext->makeCurrent(m_offscreenSurface);
+
+ if (!m_textureCache) {
+#ifdef Q_OS_MACOS
+ auto *currentContext = NSOpenGLContext.currentContext;
+ // Create an OpenGL CoreVideo texture cache from the pixel buffer.
+ auto err = CVOpenGLTextureCacheCreate(
+ kCFAllocatorDefault,
+ nullptr,
+ currentContext.CGLContextObj,
+ currentContext.pixelFormat.CGLPixelFormatObj,
+ nil,
+ &m_textureCache);
+#else
+ CVReturn err = CVOGLTextureCacheCreate(kCFAllocatorDefault, nullptr,
+ [EAGLContext currentContext],
+ nullptr, &m_textureCache);
+#endif
+ if (err)
+ qWarning("Error at CVOGLTextureCacheCreate %d", err);
}
- glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
- glClear(GL_COLOR_BUFFER_BIT);
-
- glViewport(0, 0, m_targetSize.width(), m_targetSize.height());
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
-
- //Render to FBO with inverted Y
- glOrtho(0.0, m_targetSize.width(), 0.0, m_targetSize.height(), 0.0, 1.0);
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
-
- [m_videoLayerRenderer beginFrameAtTime:CACurrentMediaTime() timeStamp:NULL];
- [m_videoLayerRenderer addUpdateRect:layer.bounds];
- [m_videoLayerRenderer render];
- [m_videoLayerRenderer endFrame];
-
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
-
- glFinish(); //Rendering needs to be done before passing texture to video frame
-
- fbo->release();
}
diff --git a/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer_ios.h b/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer_ios.h
deleted file mode 100644
index d9f6baa7e..000000000
--- a/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer_ios.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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 AVFVIDEOFRAMERENDERER_H
-#define AVFVIDEOFRAMERENDERER_H
-
-#include <QtCore/QObject>
-#include <QtGui/QImage>
-#include <QtGui/QOpenGLContext>
-#include <QtCore/QSize>
-
-@class AVPlayerLayer;
-@class AVPlayerItemVideoOutput;
-
-QT_BEGIN_NAMESPACE
-
-class QOpenGLContext;
-class QOpenGLFramebufferObject;
-class QOpenGLShaderProgram;
-class QOffscreenSurface;
-class QAbstractVideoSurface;
-
-typedef struct __CVBuffer *CVBufferRef;
-typedef CVBufferRef CVImageBufferRef;
-typedef CVImageBufferRef CVPixelBufferRef;
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
-typedef struct __CVOpenGLESTextureCache *CVOpenGLESTextureCacheRef;
-typedef CVImageBufferRef CVOpenGLESTextureRef;
-// helpers to avoid boring if def
-typedef CVOpenGLESTextureCacheRef CVOGLTextureCacheRef;
-typedef CVOpenGLESTextureRef CVOGLTextureRef;
-#define CVOGLTextureGetTarget CVOpenGLESTextureGetTarget
-#define CVOGLTextureGetName CVOpenGLESTextureGetName
-#define CVOGLTextureCacheCreate CVOpenGLESTextureCacheCreate
-#define CVOGLTextureCacheCreateTextureFromImage CVOpenGLESTextureCacheCreateTextureFromImage
-#define CVOGLTextureCacheFlush CVOpenGLESTextureCacheFlush
-#else
-typedef struct __CVOpenGLTextureCache *CVOpenGLTextureCacheRef;
-typedef CVImageBufferRef CVOpenGLTextureRef;
-// helpers to avoid boring if def
-typedef CVOpenGLTextureCacheRef CVOGLTextureCacheRef;
-typedef CVOpenGLTextureRef CVOGLTextureRef;
-#define CVOGLTextureGetTarget CVOpenGLTextureGetTarget
-#define CVOGLTextureGetName CVOpenGLTextureGetName
-#define CVOGLTextureCacheCreate CVOpenGLTextureCacheCreate
-#define CVOGLTextureCacheCreateTextureFromImage CVOpenGLTextureCacheCreateTextureFromImage
-#define CVOGLTextureCacheFlush CVOpenGLTextureCacheFlush
-#endif
-
-class AVFVideoFrameRenderer : public QObject
-{
-public:
- AVFVideoFrameRenderer(QAbstractVideoSurface *surface, QObject *parent = nullptr);
-
- virtual ~AVFVideoFrameRenderer();
-
- void setPlayerLayer(AVPlayerLayer *layer);
-
- CVOGLTextureRef renderLayerToTexture(AVPlayerLayer *layer);
- QImage renderLayerToImage(AVPlayerLayer *layer);
-
-private:
- void initRenderer();
- CVPixelBufferRef copyPixelBufferFromLayer(AVPlayerLayer *layer, size_t& width, size_t& height);
- CVOGLTextureRef createCacheTextureFromLayer(AVPlayerLayer *layer, size_t& width, size_t& height);
-
- QOpenGLContext *m_glContext;
- QOffscreenSurface *m_offscreenSurface;
- QAbstractVideoSurface *m_surface;
- CVOGLTextureCacheRef m_textureCache;
- AVPlayerItemVideoOutput* m_videoOutput;
- bool m_isContextShared;
-};
-
-QT_END_NAMESPACE
-
-#endif // AVFVIDEOFRAMERENDERER_H
diff --git a/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer_ios.mm b/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer_ios.mm
deleted file mode 100644
index 70e402e6c..000000000
--- a/src/plugins/avfoundation/mediaplayer/avfvideoframerenderer_ios.mm
+++ /dev/null
@@ -1,261 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd and/or its subsidiary(-ies).
-** 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 "avfvideoframerenderer_ios.h"
-
-#include <QtMultimedia/qabstractvideosurface.h>
-#include <QtGui/QOpenGLFramebufferObject>
-#include <QtGui/QOpenGLShaderProgram>
-#include <QtGui/QOffscreenSurface>
-
-#ifdef QT_DEBUG_AVF
-#include <QtCore/qdebug.h>
-#endif
-
-#import <CoreVideo/CVBase.h>
-#import <AVFoundation/AVFoundation.h>
-QT_USE_NAMESPACE
-
-AVFVideoFrameRenderer::AVFVideoFrameRenderer(QAbstractVideoSurface *surface, QObject *parent)
- : QObject(parent)
- , m_glContext(nullptr)
- , m_offscreenSurface(nullptr)
- , m_surface(surface)
- , m_textureCache(nullptr)
- , m_videoOutput(nullptr)
- , m_isContextShared(true)
-{
-}
-
-AVFVideoFrameRenderer::~AVFVideoFrameRenderer()
-{
-#ifdef QT_DEBUG_AVF
- qDebug() << Q_FUNC_INFO;
-#endif
-
- [m_videoOutput release]; // sending to nil is fine
- if (m_textureCache)
- CFRelease(m_textureCache);
- delete m_offscreenSurface;
- delete m_glContext;
-}
-
-void AVFVideoFrameRenderer::setPlayerLayer(AVPlayerLayer *layer)
-{
- Q_UNUSED(layer)
- if (m_videoOutput) {
- [m_videoOutput release];
- m_videoOutput = nullptr;
- // will be re-created in first call to copyPixelBufferFromLayer
- }
-}
-
-CVOGLTextureRef AVFVideoFrameRenderer::renderLayerToTexture(AVPlayerLayer *layer)
-{
- initRenderer();
-
- // If the glContext isn't shared, it doesn't make sense to return a texture for us
- if (!m_isContextShared)
- return nullptr;
-
- size_t dummyWidth = 0, dummyHeight = 0;
- return createCacheTextureFromLayer(layer, dummyWidth, dummyHeight);
-}
-
-static NSString* const AVF_PIXEL_FORMAT_KEY = (NSString*)kCVPixelBufferPixelFormatTypeKey;
-static NSNumber* const AVF_PIXEL_FORMAT_VALUE = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
-static NSDictionary* const AVF_OUTPUT_SETTINGS = [NSDictionary dictionaryWithObject:AVF_PIXEL_FORMAT_VALUE forKey:AVF_PIXEL_FORMAT_KEY];
-
-
-CVPixelBufferRef AVFVideoFrameRenderer::copyPixelBufferFromLayer(AVPlayerLayer *layer,
- size_t& width, size_t& height)
-{
- //Is layer valid
- if (!layer) {
-#ifdef QT_DEBUG_AVF
- qWarning("copyPixelBufferFromLayer: invalid layer");
-#endif
- return nullptr;
- }
-
- if (!m_videoOutput) {
- m_videoOutput = [[AVPlayerItemVideoOutput alloc] initWithPixelBufferAttributes:AVF_OUTPUT_SETTINGS];
- [m_videoOutput setDelegate:nil queue:nil];
- AVPlayerItem * item = [[layer player] currentItem];
- [item addOutput:m_videoOutput];
- }
-
- CFTimeInterval currentCAFrameTime = CACurrentMediaTime();
- CMTime currentCMFrameTime = [m_videoOutput itemTimeForHostTime:currentCAFrameTime];
- // happens when buffering / loading
- if (CMTimeCompare(currentCMFrameTime, kCMTimeZero) < 0) {
- return nullptr;
- }
-
- CVPixelBufferRef pixelBuffer = [m_videoOutput copyPixelBufferForItemTime:currentCMFrameTime
- itemTimeForDisplay:nil];
- if (!pixelBuffer) {
-#ifdef QT_DEBUG_AVF
- qWarning("copyPixelBufferForItemTime returned nil");
- CMTimeShow(currentCMFrameTime);
-#endif
- return nullptr;
- }
-
- width = CVPixelBufferGetWidth(pixelBuffer);
- height = CVPixelBufferGetHeight(pixelBuffer);
- return pixelBuffer;
-}
-
-CVOGLTextureRef AVFVideoFrameRenderer::createCacheTextureFromLayer(AVPlayerLayer *layer,
- size_t& width, size_t& height)
-{
- CVPixelBufferRef pixelBuffer = copyPixelBufferFromLayer(layer, width, height);
-
- if (!pixelBuffer)
- return nullptr;
-
- CVOGLTextureCacheFlush(m_textureCache, 0);
-
- CVOGLTextureRef texture = nullptr;
- CVReturn err = CVOGLTextureCacheCreateTextureFromImage(kCFAllocatorDefault, m_textureCache, pixelBuffer, nullptr,
- GL_TEXTURE_2D, GL_RGBA,
- (GLsizei) width, (GLsizei) height,
- GL_BGRA, GL_UNSIGNED_BYTE, 0,
- &texture);
-
- if (!texture || err) {
-#ifdef QT_DEBUG_AVF
- qWarning("CVOGLTextureCacheCreateTextureFromImage failed (error: %d)", err);
-#endif
- }
-
- CVPixelBufferRelease(pixelBuffer);
-
- return texture;
-}
-
-QImage AVFVideoFrameRenderer::renderLayerToImage(AVPlayerLayer *layer)
-{
- size_t width = 0;
- size_t height = 0;
- CVPixelBufferRef pixelBuffer = copyPixelBufferFromLayer(layer, width, height);
-
- if (!pixelBuffer)
- return QImage();
-
- OSType pixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer);
- if (pixelFormat != kCVPixelFormatType_32BGRA) {
-#ifdef QT_DEBUG_AVF
- qWarning("CVPixelBuffer format is not BGRA32 (got: %d)", static_cast<quint32>(pixelFormat));
-#endif
- return QImage();
- }
-
- CVPixelBufferLockBaseAddress(pixelBuffer, 0);
- char *data = (char *)CVPixelBufferGetBaseAddress(pixelBuffer);
- size_t stride = CVPixelBufferGetBytesPerRow(pixelBuffer);
-
- // format here is not relevant, only using for storage
- QImage img = QImage(width, height, QImage::Format_ARGB32);
- for (size_t j = 0; j < height; j++) {
- memcpy(img.scanLine(j), data, width * 4);
- data += stride;
- }
-
- CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
- CVPixelBufferRelease(pixelBuffer);
- return img;
-}
-
-void AVFVideoFrameRenderer::initRenderer()
-{
- // even for using a texture directly, we need to be able to make a context current,
- // so we need an offscreen, and we shouldn't assume we can make the surface context
- // current on that offscreen, so use our own (sharing with it). Slightly
- // excessive but no performance penalty and makes the QImage path easier to maintain
-
- //Make sure we have an OpenGL context to make current
- if (!m_glContext) {
- //Create OpenGL context and set share context from surface
- QOpenGLContext *shareContext = nullptr;
- if (m_surface) {
- shareContext = qobject_cast<QOpenGLContext*>(m_surface->property("GLContext").value<QObject*>());
- }
-
- m_glContext = new QOpenGLContext();
- if (shareContext) {
- m_glContext->setShareContext(shareContext);
- m_isContextShared = true;
- } else {
-#ifdef QT_DEBUG_AVF
- qWarning("failed to get Render Thread context");
-#endif
- m_isContextShared = false;
- }
- if (!m_glContext->create()) {
-#ifdef QT_DEBUG_AVF
- qWarning("failed to create QOpenGLContext");
-#endif
- return;
- }
- }
-
- if (!m_offscreenSurface) {
- m_offscreenSurface = new QOffscreenSurface();
- m_offscreenSurface->setFormat(m_glContext->format());
- m_offscreenSurface->create();
- }
-
- //Need current context
- m_glContext->makeCurrent(m_offscreenSurface);
-
- if (!m_textureCache) {
- // Create a new open gl texture cache
- CVReturn err = CVOGLTextureCacheCreate(kCFAllocatorDefault, nullptr,
- [EAGLContext currentContext],
- nullptr, &m_textureCache);
- if (err) {
- #ifdef QT_DEBUG_AVF
- qWarning("Error at CVOGLTextureCacheCreate %d", err);
- #endif
- }
- }
-
-}
diff --git a/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.h b/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.h
index 85dc19d31..a88573eaa 100644
--- a/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.h
+++ b/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.h
@@ -41,6 +41,8 @@
#define AVFVIDEORENDERERCONTROL_H
#include <QtMultimedia/QVideoRendererControl>
+#include <QtMultimedia/qabstractvideobuffer.h>
+
#include <QtCore/QMutex>
#include <QtCore/QSize>
@@ -82,8 +84,7 @@ private:
AVFVideoFrameRenderer *m_frameRenderer;
AVFDisplayLink *m_displayLink;
- QSize m_nativeSize;
- bool m_enableOpenGL;
+ QAbstractVideoBuffer::HandleType m_surfaceType = QAbstractVideoBuffer::NoHandle;
};
QT_END_NAMESPACE
diff --git a/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm b/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm
index e06ddc4b0..f299d5f86 100644
--- a/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm
+++ b/src/plugins/avfoundation/mediaplayer/avfvideorenderercontrol.mm
@@ -40,11 +40,7 @@
#include "avfvideorenderercontrol.h"
#include "avfdisplaylink.h"
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
-#include "avfvideoframerenderer_ios.h"
-#else
#include "avfvideoframerenderer.h"
-#endif
#include <QtMultimedia/qabstractvideobuffer.h>
#include <QtMultimedia/qabstractvideosurface.h>
@@ -58,69 +54,52 @@
QT_USE_NAMESPACE
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
-class TextureCacheVideoBuffer : public QAbstractVideoBuffer
+class TextureVideoBuffer : public QAbstractVideoBuffer
{
public:
- TextureCacheVideoBuffer(CVOGLTextureRef texture)
- : QAbstractVideoBuffer(GLTextureHandle)
+ TextureVideoBuffer(GLuint texture, QAbstractVideoBuffer::HandleType type)
+ : QAbstractVideoBuffer(type)
, m_texture(texture)
{}
- virtual ~TextureCacheVideoBuffer()
- {
- // absolutely critical that we drop this
- // reference of textures will stay in the cache
- CFRelease(m_texture);
- }
-
MapMode mapMode() const { return NotMapped; }
uchar *map(MapMode, int*, int*) { return nullptr; }
void unmap() {}
QVariant handle() const
{
- GLuint texId = CVOGLTextureGetName(m_texture);
- return QVariant::fromValue<unsigned int>(texId);
+ return QVariant::fromValue<unsigned int>(m_texture);
}
private:
- CVOGLTextureRef m_texture;
+ GLuint m_texture;
};
-#else
-class TextureVideoBuffer : public QAbstractVideoBuffer
+
+class CoreVideoTextureVideoBuffer : public TextureVideoBuffer
{
public:
- TextureVideoBuffer(GLuint tex)
- : QAbstractVideoBuffer(GLTextureHandle)
- , m_texture(tex)
+ CoreVideoTextureVideoBuffer(CVOGLTextureRef texture, QAbstractVideoBuffer::HandleType type)
+ : TextureVideoBuffer(CVOGLTextureGetName(texture), type)
+ , m_coreVideoTexture(texture)
{}
- virtual ~TextureVideoBuffer()
+ virtual ~CoreVideoTextureVideoBuffer()
{
- }
-
- MapMode mapMode() const { return NotMapped; }
- uchar *map(MapMode, int*, int*) { return 0; }
- void unmap() {}
-
- QVariant handle() const
- {
- return QVariant::fromValue<unsigned int>(m_texture);
+ // absolutely critical that we drop this
+ // reference of textures will stay in the cache
+ CFRelease(m_coreVideoTexture);
}
private:
- GLuint m_texture;
+ CVOGLTextureRef m_coreVideoTexture;
};
-#endif
+
AVFVideoRendererControl::AVFVideoRendererControl(QObject *parent)
: QVideoRendererControl(parent)
, m_surface(nullptr)
, m_playerLayer(nullptr)
, m_frameRenderer(nullptr)
- , m_enableOpenGL(false)
-
{
m_displayLink = new AVFDisplayLink(this);
connect(m_displayLink, SIGNAL(tick(CVTimeStamp)), SLOT(updateVideoFrame(CVTimeStamp)));
@@ -170,14 +149,26 @@ void AVFVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
//Surface changed, so we need a new frame renderer
m_frameRenderer = new AVFVideoFrameRenderer(m_surface, this);
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
- if (m_playerLayer) {
- m_frameRenderer->setPlayerLayer(static_cast<AVPlayerLayer*>(m_playerLayer));
- }
-#endif
- //Check for needed formats to render as OpenGL Texture
- m_enableOpenGL = m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).contains(QVideoFrame::Format_BGR32);
+ auto updateSurfaceType = [this] {
+ auto preferredOpenGLSurfaceTypes = {
+#ifdef Q_OS_MACOS
+ QAbstractVideoBuffer::GLTextureRectangleHandle, // GL_TEXTURE_RECTANGLE
+#endif
+ QAbstractVideoBuffer::GLTextureHandle // GL_TEXTURE_2D
+ };
+
+ for (auto surfaceType : preferredOpenGLSurfaceTypes) {
+ auto supportedFormats = m_surface->supportedPixelFormats(surfaceType);
+ if (supportedFormats.contains(QVideoFrame::Format_BGR32)) {
+ m_surfaceType = surfaceType;
+ return;
+ }
+ m_surfaceType = QAbstractVideoBuffer::NoHandle; // QImage
+ }
+ };
+ updateSurfaceType();
+ connect(m_surface, &QAbstractVideoSurface::supportedFormatsChanged, this, updateSurfaceType);
//If we already have a layer, but changed surfaces start rendering again
if (m_playerLayer && !m_displayLink->isActive()) {
@@ -200,12 +191,6 @@ void AVFVideoRendererControl::setLayer(void *playerLayer)
if (m_surface && m_surface->isActive())
m_surface->stop();
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
- if (m_frameRenderer) {
- m_frameRenderer->setPlayerLayer(static_cast<AVPlayerLayer*>(playerLayer));
- }
-#endif
-
//If there is no layer to render, stop scheduling updates
if (m_playerLayer == nullptr) {
m_displayLink->stop();
@@ -234,36 +219,39 @@ void AVFVideoRendererControl::updateVideoFrame(const CVTimeStamp &ts)
if (!playerLayer.readyForDisplay)
return;
- if (m_enableOpenGL) {
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
- CVOGLTextureRef tex = m_frameRenderer->renderLayerToTexture(playerLayer);
-
- //Make sure we got a valid texture
- if (tex == nullptr)
- return;
-
- QAbstractVideoBuffer *buffer = new TextureCacheVideoBuffer(tex);
+ if (m_surfaceType == QAbstractVideoBuffer::GLTextureHandle
+ || m_surfaceType == QAbstractVideoBuffer::GLTextureRectangleHandle) {
+ QSize size;
+ QAbstractVideoBuffer *buffer = nullptr;
+
+#ifdef Q_OS_MACOS
+ if (m_surfaceType == QAbstractVideoBuffer::GLTextureRectangleHandle) {
+ // Render to GL_TEXTURE_RECTANGLE directly
+ if (CVOGLTextureRef tex = m_frameRenderer->renderLayerToTexture(playerLayer, &size))
+ buffer = new CoreVideoTextureVideoBuffer(tex, m_surfaceType);
+ } else {
+ // Render to GL_TEXTURE_2D via FBO
+ if (GLuint tex = m_frameRenderer->renderLayerToFBO(playerLayer, &size))
+ buffer = new TextureVideoBuffer(tex, m_surfaceType);
+ }
#else
- GLuint tex = m_frameRenderer->renderLayerToTexture(playerLayer);
- //Make sure we got a valid texture
- if (tex == 0)
+ Q_ASSERT(m_surfaceType != QAbstractVideoBuffer::GLTextureRectangleHandle);
+ // Render to GL_TEXTURE_2D directly
+ if (CVOGLTextureRef tex = m_frameRenderer->renderLayerToTexture(playerLayer, &size))
+ buffer = new CoreVideoTextureVideoBuffer(tex, m_surfaceType);
+#endif
+ if (!buffer)
return;
- QAbstractVideoBuffer *buffer = new TextureVideoBuffer(tex);
-#endif
- QVideoFrame frame = QVideoFrame(buffer, m_nativeSize, QVideoFrame::Format_BGR32);
+ QVideoFrame frame = QVideoFrame(buffer, size, QVideoFrame::Format_BGR32);
if (m_surface && frame.isValid()) {
if (m_surface->isActive() && m_surface->surfaceFormat().pixelFormat() != frame.pixelFormat())
m_surface->stop();
if (!m_surface->isActive()) {
- QVideoSurfaceFormat format(frame.size(), frame.pixelFormat(), QAbstractVideoBuffer::GLTextureHandle);
-#if defined(Q_OS_IOS) || defined(Q_OS_TVOS)
+ QVideoSurfaceFormat format(frame.size(), frame.pixelFormat(), m_surfaceType);
format.setScanLineDirection(QVideoSurfaceFormat::TopToBottom);
-#else
- format.setScanLineDirection(QVideoSurfaceFormat::BottomToTop);
-#endif
if (!m_surface->start(format)) {
//Surface doesn't support GLTextureHandle
qWarning("Failed to activate video surface");
@@ -275,20 +263,21 @@ void AVFVideoRendererControl::updateVideoFrame(const CVTimeStamp &ts)
}
} else {
//fallback to rendering frames to QImages
- QImage frameData = m_frameRenderer->renderLayerToImage(playerLayer);
+ QSize size;
+ QImage frameData = m_frameRenderer->renderLayerToImage(playerLayer, &size);
if (frameData.isNull()) {
return;
}
QAbstractVideoBuffer *buffer = new QImageVideoBuffer(frameData);
- QVideoFrame frame = QVideoFrame(buffer, m_nativeSize, QVideoFrame::Format_ARGB32);
+ QVideoFrame frame = QVideoFrame(buffer, size, QVideoFrame::Format_ARGB32);
if (m_surface && frame.isValid()) {
if (m_surface->isActive() && m_surface->surfaceFormat().pixelFormat() != frame.pixelFormat())
m_surface->stop();
if (!m_surface->isActive()) {
- QVideoSurfaceFormat format(frame.size(), frame.pixelFormat(), QAbstractVideoBuffer::NoHandle);
+ QVideoSurfaceFormat format(frame.size(), frame.pixelFormat(), m_surfaceType);
if (!m_surface->start(format)) {
qWarning("Failed to activate video surface");
@@ -304,7 +293,4 @@ void AVFVideoRendererControl::updateVideoFrame(const CVTimeStamp &ts)
void AVFVideoRendererControl::setupVideoOutput()
{
- AVPlayerLayer *playerLayer = static_cast<AVPlayerLayer*>(m_playerLayer);
- if (playerLayer)
- m_nativeSize = QSize(playerLayer.bounds.size.width, playerLayer.bounds.size.height);
}
diff --git a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm
index be349710c..0987342b4 100644
--- a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm
+++ b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm
@@ -38,12 +38,9 @@
****************************************************************************/
#include "avfvideowidget.h"
-#include <QtCore/QDebug>
-#include <AVFoundation/AVFoundation.h>
-#include <QtGui/QResizeEvent>
-#include <QtGui/QPaintEvent>
-#include <QtGui/QPainter>
+#import <AVFoundation/AVFoundation.h>
+#import <QuartzCore/CATransaction.h>
#if defined(Q_OS_MACOS)
#import <AppKit/AppKit.h>
@@ -51,6 +48,11 @@
#import <UIKit/UIKit.h>
#endif
+#include <QtCore/QDebug>
+#include <QtGui/QResizeEvent>
+#include <QtGui/QPaintEvent>
+#include <QtGui/QPainter>
+
QT_USE_NAMESPACE
AVFVideoWidget::AVFVideoWidget(QWidget *parent)
@@ -178,5 +180,8 @@ void AVFVideoWidget::updateAspectRatio()
void AVFVideoWidget::updatePlayerLayerBounds(const QSize &size)
{
- m_playerLayer.bounds = CGRectMake(0.0f, 0.0f, (float)size.width(), (float)size.height());
+ [CATransaction begin];
+ [CATransaction setDisableActions: YES]; // disable animation/flicks
+ m_playerLayer.bounds = QRect(QPoint(0, 0), size).toCGRect();
+ [CATransaction commit];
}
diff --git a/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm b/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm
index 7fa41fdc2..d61129ec9 100644
--- a/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm
+++ b/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm
@@ -40,6 +40,7 @@
#include "avfvideowindowcontrol.h"
#include <AVFoundation/AVFoundation.h>
+#import <QuartzCore/CATransaction.h>
#if QT_HAS_INCLUDE(<AppKit/AppKit.h>)
#include <AppKit/AppKit.h>
@@ -244,10 +245,10 @@ void AVFVideoWindowControl::updateAspectRatio()
void AVFVideoWindowControl::updatePlayerLayerBounds()
{
if (m_playerLayer) {
- CGRect newBounds = CGRectMake(0, 0,
- m_displayRect.width(), m_displayRect.height());
- m_playerLayer.bounds = newBounds;
- m_playerLayer.position = CGPointMake(m_displayRect.x(), m_displayRect.y());
+ [CATransaction begin];
+ [CATransaction setDisableActions: YES]; // disable animation/flicks
+ m_playerLayer.frame = m_displayRect.toCGRect();
+ [CATransaction commit];
}
}
diff --git a/src/plugins/avfoundation/mediaplayer/mediaplayer.pro b/src/plugins/avfoundation/mediaplayer/mediaplayer.pro
index b60b276e9..f71e0c3b3 100644
--- a/src/plugins/avfoundation/mediaplayer/mediaplayer.pro
+++ b/src/plugins/avfoundation/mediaplayer/mediaplayer.pro
@@ -39,33 +39,23 @@ OBJECTIVE_SOURCES += \
avfvideowidget.mm
}
-ios|tvos {
- qtConfig(opengl) {
- HEADERS += \
- avfvideoframerenderer_ios.h \
- avfvideorenderercontrol.h \
- avfdisplaylink.h
+qtConfig(opengl) {
+ HEADERS += \
+ avfvideoframerenderer.h \
+ avfvideorenderercontrol.h \
+ avfdisplaylink.h
- OBJECTIVE_SOURCES += \
- avfvideoframerenderer_ios.mm \
- avfvideorenderercontrol.mm \
- avfdisplaylink.mm
- }
+ OBJECTIVE_SOURCES += \
+ avfvideoframerenderer.mm \
+ avfvideorenderercontrol.mm \
+ avfdisplaylink.mm
+}
+
+ios|tvos {
LIBS += -framework Foundation
} else {
- LIBS += -framework AppKit
-
- qtConfig(opengl) {
- HEADERS += \
- avfvideoframerenderer.h \
- avfvideorenderercontrol.h \
- avfdisplaylink.h
-
- OBJECTIVE_SOURCES += \
- avfvideoframerenderer.mm \
- avfvideorenderercontrol.mm \
- avfdisplaylink.mm
- }
+ INCLUDEPATH += $$[QT_INSTALL_HEADERS]
+ LIBS += -framework AppKit -framework Metal
}
OTHER_FILES += \
diff --git a/src/plugins/common/evr/evrcustompresenter.cpp b/src/plugins/common/evr/evrcustompresenter.cpp
index b2dd0426c..3405f6373 100644
--- a/src/plugins/common/evr/evrcustompresenter.cpp
+++ b/src/plugins/common/evr/evrcustompresenter.cpp
@@ -1065,6 +1065,13 @@ void EVRCustomPresenter::setSurface(QAbstractVideoSurface *surface)
supportedFormatsChanged();
}
+void EVRCustomPresenter::setCropRect(QRect cropRect)
+{
+ m_mutex.lock();
+ m_cropRect = cropRect;
+ m_mutex.unlock();
+}
+
HRESULT EVRCustomPresenter::configureMixer(IMFTransform *mixer)
{
// Set the zoom rectangle (ie, the source clipping rectangle).
@@ -1355,13 +1362,30 @@ HRESULT EVRCustomPresenter::createOptimalVideoType(IMFMediaType *proposedType, I
hr = proposedType->GetUINT64(MF_MT_FRAME_SIZE, &size);
width = int(HI32(size));
height = int(LO32(size));
- rcOutput.left = 0;
- rcOutput.top = 0;
- rcOutput.right = width;
- rcOutput.bottom = height;
+
+ if (m_cropRect.isValid()) {
+ rcOutput.left = m_cropRect.x();
+ rcOutput.top = m_cropRect.y();
+ rcOutput.right = m_cropRect.x() + m_cropRect.width();
+ rcOutput.bottom = m_cropRect.y() + m_cropRect.height();
+
+ m_sourceRect.left = float(m_cropRect.x()) / width;
+ m_sourceRect.top = float(m_cropRect.y()) / height;
+ m_sourceRect.right = float(m_cropRect.x() + m_cropRect.width()) / width;
+ m_sourceRect.bottom = float(m_cropRect.y() + m_cropRect.height()) / height;
+
+ if (m_mixer)
+ configureMixer(m_mixer);
+ } else {
+ rcOutput.left = 0;
+ rcOutput.top = 0;
+ rcOutput.right = width;
+ rcOutput.bottom = height;
+ }
// Set the geometric aperture, and disable pan/scan.
- displayArea = qt_evr_makeMFArea(0, 0, rcOutput.right, rcOutput.bottom);
+ displayArea = qt_evr_makeMFArea(0, 0, rcOutput.right - rcOutput.left,
+ rcOutput.bottom - rcOutput.top);
hr = mtOptimal->SetUINT32(MF_MT_PAN_SCAN_ENABLED, FALSE);
if (FAILED(hr))
@@ -1427,7 +1451,7 @@ HRESULT EVRCustomPresenter::setMediaType(IMFMediaType *mediaType)
// Initialize the presenter engine with the new media type.
// The presenter engine allocates the samples.
- hr = m_presentEngine->createVideoSamples(mediaType, sampleQueue);
+ hr = m_presentEngine->createVideoSamples(mediaType, sampleQueue, m_cropRect.size());
if (FAILED(hr))
goto done;
diff --git a/src/plugins/common/evr/evrcustompresenter.h b/src/plugins/common/evr/evrcustompresenter.h
index c1c21580e..403158619 100644
--- a/src/plugins/common/evr/evrcustompresenter.h
+++ b/src/plugins/common/evr/evrcustompresenter.h
@@ -44,6 +44,7 @@
#include <qmutex.h>
#include <qqueue.h>
#include <qevent.h>
+#include <qrect.h>
#include <qvideosurfaceformat.h>
#include "evrdefs.h"
@@ -257,6 +258,7 @@ public:
void supportedFormatsChanged();
void setSurface(QAbstractVideoSurface *surface);
+ void setCropRect(QRect cropRect);
void startSurface();
void stopSurface();
@@ -368,6 +370,7 @@ private:
QAbstractVideoSurface *m_surface;
bool m_canRenderToSurface;
qint64 m_positionOffset; // Seek position in microseconds.
+ QRect m_cropRect; // Video crop rectangle
};
bool qt_evr_setCustomPresenter(IUnknown *evr, EVRCustomPresenter *presenter);
diff --git a/src/plugins/common/evr/evrd3dpresentengine.cpp b/src/plugins/common/evr/evrd3dpresentengine.cpp
index d8e2da6d3..0bf8a0506 100644
--- a/src/plugins/common/evr/evrd3dpresentengine.cpp
+++ b/src/plugins/common/evr/evrd3dpresentengine.cpp
@@ -520,7 +520,7 @@ void D3DPresentEngine::setHint(Hint hint, bool enable)
m_useTextureRendering = enable && supportsTextureRendering();
}
-HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSample*> &videoSampleQueue)
+HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSample*> &videoSampleQueue, QSize frameSize)
{
if (!format)
return MF_E_UNEXPECTED;
@@ -537,6 +537,11 @@ HRESULT D3DPresentEngine::createVideoSamples(IMFMediaType *format, QList<IMFSamp
if (FAILED(hr))
return hr;
+ if (frameSize.isValid() && !frameSize.isEmpty()) {
+ width = frameSize.width();
+ height = frameSize.height();
+ }
+
DWORD d3dFormat = 0;
hr = qt_evr_getFourCC(format, &d3dFormat);
if (FAILED(hr))
diff --git a/src/plugins/common/evr/evrd3dpresentengine.h b/src/plugins/common/evr/evrd3dpresentengine.h
index 8e2a444f3..d7eeacfc0 100644
--- a/src/plugins/common/evr/evrd3dpresentengine.h
+++ b/src/plugins/common/evr/evrd3dpresentengine.h
@@ -41,6 +41,7 @@
#define EVRD3DPRESENTENGINE_H
#include <QMutex>
+#include <QSize>
#include <QVideoSurfaceFormat>
#include <d3d9.h>
@@ -120,7 +121,7 @@ public:
bool supportsTextureRendering() const;
bool isTextureRenderingEnabled() const { return m_useTextureRendering; }
- HRESULT createVideoSamples(IMFMediaType *format, QList<IMFSample*>& videoSampleQueue);
+ HRESULT createVideoSamples(IMFMediaType *format, QList<IMFSample*>& videoSampleQueue, QSize frameSize);
QVideoSurfaceFormat videoSurfaceFormat() const { return m_surfaceFormat; }
QVideoFrame makeVideoFrame(IMFSample* sample);
diff --git a/src/plugins/common/evr/evrvideowindowcontrol.cpp b/src/plugins/common/evr/evrvideowindowcontrol.cpp
index 95f63c2e7..cec263da9 100644
--- a/src/plugins/common/evr/evrvideowindowcontrol.cpp
+++ b/src/plugins/common/evr/evrvideowindowcontrol.cpp
@@ -134,26 +134,29 @@ void EvrVideoWindowControl::setDisplayRect(const QRect &rect)
if (m_displayControl) {
RECT displayRect = { rect.left(), rect.top(), rect.right() + 1, rect.bottom() + 1 };
- QSize sourceSize = nativeSize();
+ QSize fullSize = nativeSize();
- RECT sourceRect = { 0, 0, sourceSize.width(), sourceSize.height() };
+ RECT sourceRect;
+ if (m_cropRect.isValid())
+ sourceRect = { m_cropRect.x(), m_cropRect.y(), m_cropRect.right() + 1, m_cropRect.bottom() + 1 };
+ else
+ sourceRect = { 0, 0, fullSize.width(), fullSize.height() };
if (m_aspectRatioMode == Qt::KeepAspectRatioByExpanding) {
QSize clippedSize = rect.size();
clippedSize.scale(sourceRect.right, sourceRect.bottom, Qt::KeepAspectRatio);
-
sourceRect.left = (sourceRect.right - clippedSize.width()) / 2;
sourceRect.top = (sourceRect.bottom - clippedSize.height()) / 2;
sourceRect.right = sourceRect.left + clippedSize.width();
sourceRect.bottom = sourceRect.top + clippedSize.height();
}
- if (sourceSize.width() > 0 && sourceSize.height() > 0) {
+ if (sourceRect.right - sourceRect.left > 0 && sourceRect.bottom - sourceRect.top > 0) {
MFVideoNormalizedRect sourceNormRect;
- sourceNormRect.left = float(sourceRect.left) / float(sourceRect.right);
- sourceNormRect.top = float(sourceRect.top) / float(sourceRect.bottom);
- sourceNormRect.right = float(sourceRect.right) / float(sourceRect.right);
- sourceNormRect.bottom = float(sourceRect.bottom) / float(sourceRect.bottom);
+ sourceNormRect.left = float(sourceRect.left) / float(fullSize.width());
+ sourceNormRect.top = float(sourceRect.top) / float(fullSize.height());
+ sourceNormRect.right = float(sourceRect.right) / float(fullSize.width());
+ sourceNormRect.bottom = float(sourceRect.bottom) / float(fullSize.height());
m_displayControl->SetVideoPosition(&sourceNormRect, &displayRect);
} else {
m_displayControl->SetVideoPosition(NULL, &displayRect);
@@ -164,6 +167,11 @@ void EvrVideoWindowControl::setDisplayRect(const QRect &rect)
}
}
+void EvrVideoWindowControl::setCropRect(QRect cropRect)
+{
+ m_cropRect = cropRect;
+}
+
bool EvrVideoWindowControl::isFullScreen() const
{
return m_fullScreen;
diff --git a/src/plugins/common/evr/evrvideowindowcontrol.h b/src/plugins/common/evr/evrvideowindowcontrol.h
index ce3b7746f..49d111b99 100644
--- a/src/plugins/common/evr/evrvideowindowcontrol.h
+++ b/src/plugins/common/evr/evrvideowindowcontrol.h
@@ -85,6 +85,8 @@ public:
void applyImageControls();
+ void setCropRect(QRect cropRect);
+
private:
void clear();
DXVA2_Fixed32 scaleProcAmpValue(DWORD prop, int value) const;
@@ -94,6 +96,7 @@ private:
DWORD m_dirtyValues;
Qt::AspectRatioMode m_aspectRatioMode;
QRect m_displayRect;
+ QRect m_cropRect;
int m_brightness;
int m_contrast;
int m_hue;
diff --git a/src/plugins/coreaudio/coreaudiodeviceinfo.mm b/src/plugins/coreaudio/coreaudiodeviceinfo.mm
index 1a79438cb..05d6c613d 100644
--- a/src/plugins/coreaudio/coreaudiodeviceinfo.mm
+++ b/src/plugins/coreaudio/coreaudiodeviceinfo.mm
@@ -60,11 +60,6 @@ CoreAudioDeviceInfo::CoreAudioDeviceInfo(const QByteArray &device, QAudio::Mode
m_deviceId = AudioDeviceID(deviceID);
#else //iOS
m_device = device;
- if (mode == QAudio::AudioInput) {
- if (CoreAudioSessionManager::instance().category() != CoreAudioSessionManager::PlayAndRecord) {
- CoreAudioSessionManager::instance().setCategory(CoreAudioSessionManager::PlayAndRecord);
- }
- }
#endif
}
@@ -336,14 +331,6 @@ QList<QByteArray> CoreAudioDeviceInfo::availableDevices(QAudio::Mode mode)
}
}
#else //iOS
- if (mode == QAudio::AudioInput) {
- if (CoreAudioSessionManager::instance().category() != CoreAudioSessionManager::PlayAndRecord) {
- CoreAudioSessionManager::instance().setCategory(CoreAudioSessionManager::PlayAndRecord);
- }
- }
-
- CoreAudioSessionManager::instance().setActive(true);
-
if (mode == QAudio::AudioOutput)
return CoreAudioSessionManager::instance().outputDevices();
if (mode == QAudio::AudioInput)
diff --git a/src/plugins/coreaudio/coreaudioinput.mm b/src/plugins/coreaudio/coreaudioinput.mm
index f7d511d27..7f305168f 100644
--- a/src/plugins/coreaudio/coreaudioinput.mm
+++ b/src/plugins/coreaudio/coreaudioinput.mm
@@ -483,6 +483,11 @@ CoreAudioInput::~CoreAudioInput()
bool CoreAudioInput::open()
{
+#if defined(Q_OS_IOS)
+ CoreAudioSessionManager::instance().setCategory(CoreAudioSessionManager::PlayAndRecord, CoreAudioSessionManager::MixWithOthers);
+ CoreAudioSessionManager::instance().setActive(true);
+#endif
+
if (m_isOpen)
return true;
diff --git a/src/plugins/coreaudio/coreaudiooutput.mm b/src/plugins/coreaudio/coreaudiooutput.mm
index caa4a1abb..b8addc1cf 100644
--- a/src/plugins/coreaudio/coreaudiooutput.mm
+++ b/src/plugins/coreaudio/coreaudiooutput.mm
@@ -549,6 +549,13 @@ OSStatus CoreAudioOutput::renderCallback(void *inRefCon, AudioUnitRenderActionFl
bool CoreAudioOutput::open()
{
+#if defined(Q_OS_IOS)
+ // Set default category to Ambient (implies MixWithOthers). This makes sure audio stops playing
+ // if the screen is locked or if the Silent switch is toggled.
+ CoreAudioSessionManager::instance().setCategory(CoreAudioSessionManager::Ambient, CoreAudioSessionManager::None);
+ CoreAudioSessionManager::instance().setActive(true);
+#endif
+
if (m_errorCode != QAudio::NoError)
return false;
diff --git a/src/plugins/coreaudio/coreaudiosessionmanager.mm b/src/plugins/coreaudio/coreaudiosessionmanager.mm
index 923a1942f..6c86f0753 100644
--- a/src/plugins/coreaudio/coreaudiosessionmanager.mm
+++ b/src/plugins/coreaudio/coreaudiosessionmanager.mm
@@ -38,7 +38,6 @@
****************************************************************************/
#include "coreaudiosessionmanager.h"
-
#import <AVFoundation/AVAudioSession.h>
#import <Foundation/Foundation.h>
@@ -215,10 +214,6 @@ CoreAudioSessionManager::CoreAudioSessionManager() :
QObject(0)
{
m_sessionObserver = [[CoreAudioSessionObserver alloc] initWithAudioSessionManager:this];
- setActive(true);
- // Set default category to Ambient (implies MixWithOthers). This makes sure audio stops playing
- // if the screen is locked or if the Silent switch is toggled.
- setCategory(CoreAudioSessionManager::Ambient, CoreAudioSessionManager::None);
}
CoreAudioSessionManager::~CoreAudioSessionManager()
diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp
index a0c120816..e47142be1 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"
@@ -429,6 +428,7 @@ bool DSCameraSession::unload()
SAFE_RELEASE(m_nullRendererFilter);
SAFE_RELEASE(m_filterGraph);
SAFE_RELEASE(m_graphBuilder);
+ SAFE_RELEASE(m_outputPin);
setStatus(QCamera::UnloadedStatus);
@@ -637,7 +637,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
@@ -782,6 +782,9 @@ bool DSCameraSession::createFilterGraph()
goto failed;
}
+ if (!DirectShowUtils::getPin(m_sourceFilter, PINDIR_OUTPUT, PIN_CATEGORY_CAPTURE, &m_outputPin, &hr))
+ qWarning() << "Failed to get the pin for the video control:" << hr;
+
// Sample grabber filter
if (!m_previewSampleGrabber) {
m_previewSampleGrabber = new DirectShowSampleGrabber(this);
@@ -1056,24 +1059,18 @@ void DSCameraSession::updateSourceCapabilities()
reinterpret_cast<void**>(&pVideoControl));
if (FAILED(hr)) {
qWarning() << "Failed to get the video control";
- } else {
- IPin *pPin = nullptr;
- if (!DirectShowUtils::getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin, &hr)) {
- qWarning() << "Failed to get the pin for the video control";
- } else {
- long supportedModes;
- hr = pVideoControl->GetCaps(pPin, &supportedModes);
- if (FAILED(hr)) {
- qWarning() << "Failed to get the supported modes of the video control";
- } else if (supportedModes & VideoControlFlag_FlipHorizontal) {
- long mode;
- hr = pVideoControl->GetMode(pPin, &mode);
- if (FAILED(hr))
- qWarning() << "Failed to get the mode of the video control";
- else if (supportedModes & VideoControlFlag_FlipHorizontal)
- m_needsHorizontalMirroring = (mode & VideoControlFlag_FlipHorizontal);
- }
- pPin->Release();
+ } else if (m_outputPin) {
+ long supportedModes;
+ hr = pVideoControl->GetCaps(m_outputPin, &supportedModes);
+ if (FAILED(hr)) {
+ qWarning() << "Failed to get the supported modes of the video control";
+ } else if (supportedModes & VideoControlFlag_FlipHorizontal) {
+ long mode;
+ hr = pVideoControl->GetMode(m_outputPin, &mode);
+ if (FAILED(hr))
+ qWarning() << "Failed to get the mode of the video control";
+ else if (supportedModes & VideoControlFlag_FlipHorizontal)
+ m_needsHorizontalMirroring = (mode & VideoControlFlag_FlipHorizontal);
}
pVideoControl->Release();
}
@@ -1108,28 +1105,22 @@ void DSCameraSession::updateSourceCapabilities()
QList<QCamera::FrameRateRange> frameRateRanges;
- if (pVideoControl) {
- IPin *pPin = nullptr;
- if (!DirectShowUtils::getPin(m_sourceFilter, PINDIR_OUTPUT, &pPin, &hr)) {
- qWarning() << "Failed to get the pin for the video control";
- } else {
- long listSize = 0;
- LONGLONG *frameRates = nullptr;
- SIZE size = { resolution.width(), resolution.height() };
- hr = pVideoControl->GetFrameRateList(pPin, iIndex, size, &listSize, &frameRates);
- if (hr == S_OK && listSize > 0 && frameRates) {
- for (long i = 0; i < listSize; ++i) {
- qreal fr = qreal(10000000) / frameRates[i];
- frameRateRanges.append(QCamera::FrameRateRange(fr, fr));
- }
-
- // Make sure higher frame rates come first
- std::sort(frameRateRanges.begin(), frameRateRanges.end(), qt_frameRateRangeGreaterThan);
+ if (pVideoControl && m_outputPin) {
+ long listSize = 0;
+ LONGLONG *frameRates = nullptr;
+ SIZE size = { resolution.width(), resolution.height() };
+ hr = pVideoControl->GetFrameRateList(m_outputPin, iIndex, size, &listSize, &frameRates);
+ if (hr == S_OK && listSize > 0 && frameRates) {
+ for (long i = 0; i < listSize; ++i) {
+ qreal fr = qreal(10000000) / frameRates[i];
+ frameRateRanges.append(QCamera::FrameRateRange(fr, fr));
}
- CoTaskMemFree(frameRates);
- pPin->Release();
+ // Make sure higher frame rates come first
+ std::sort(frameRateRanges.begin(), frameRateRanges.end(), qt_frameRateRangeGreaterThan);
}
+
+ CoTaskMemFree(frameRates);
}
if (frameRateRanges.isEmpty()) {
@@ -1147,9 +1138,14 @@ void DSCameraSession::updateSourceCapabilities()
m_supportedViewfinderSettings.append(settings);
m_supportedFormats.append(DirectShowMediaType(*pmt));
}
-
-
+ } else {
+ OLECHAR *guidString = nullptr;
+ StringFromCLSID(pmt->subtype, &guidString);
+ if (guidString)
+ qWarning() << "Unsupported media type:" << QString::fromWCharArray(guidString);
+ ::CoTaskMemFree(guidString);
}
+
DirectShowMediaType::deleteType(pmt);
}
}
diff --git a/src/plugins/directshow/camera/dscamerasession.h b/src/plugins/directshow/camera/dscamerasession.h
index 5e7d026c2..9f88163b9 100644
--- a/src/plugins/directshow/camera/dscamerasession.h
+++ b/src/plugins/directshow/camera/dscamerasession.h
@@ -231,6 +231,8 @@ private:
QMap<QCameraImageProcessingControl::ProcessingParameter, QVariant> m_pendingImageProcessingParametrs;
+ IPin *m_outputPin = nullptr;
+
friend class SampleGrabberCallbackPrivate;
};
diff --git a/src/plugins/directshow/common/directshowmediatype.cpp b/src/plugins/directshow/common/directshowmediatype.cpp
index 103f1ddc1..3429f4848 100644
--- a/src/plugins/directshow/common/directshowmediatype.cpp
+++ b/src/plugins/directshow/common/directshowmediatype.cpp
@@ -40,6 +40,11 @@
#include "directshowmediatype.h"
#include "directshowglobal.h"
+#include <initguid.h>
+
+DEFINE_GUID(MEDIASUBTYPE_Y800, 0x30303859, 0x0000, 0x0010, 0x80, 0x00,
+ 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
+
namespace
{
struct TypeLookup
@@ -66,7 +71,8 @@ namespace
{ QVideoFrame::Format_NV12, MEDIASUBTYPE_NV12 },
{ QVideoFrame::Format_YUV420P, MEDIASUBTYPE_IYUV },
{ QVideoFrame::Format_YUV420P, MEDIASUBTYPE_I420 },
- { QVideoFrame::Format_Jpeg, MEDIASUBTYPE_MJPG }
+ { QVideoFrame::Format_Jpeg, MEDIASUBTYPE_MJPG },
+ { QVideoFrame::Format_Y8, MEDIASUBTYPE_Y800 },
};
}
@@ -294,6 +300,7 @@ int DirectShowMediaType::bytesPerLine(const QVideoSurfaceFormat &format)
return format.frameWidth() * 4;
// 24 bpp packed formats.
case QVideoFrame::Format_RGB24:
+ case QVideoFrame::Format_BGR24:
return PAD_TO_DWORD(format.frameWidth() * 3);
// 16 bpp packed formats.
case QVideoFrame::Format_RGB565:
diff --git a/src/plugins/directshow/common/directshowmediatypeenum.cpp b/src/plugins/directshow/common/directshowmediatypeenum.cpp
index 0ff147fea..02281bb98 100644
--- a/src/plugins/directshow/common/directshowmediatypeenum.cpp
+++ b/src/plugins/directshow/common/directshowmediatypeenum.cpp
@@ -42,7 +42,8 @@
#include "directshowpin.h"
DirectShowMediaTypeEnum::DirectShowMediaTypeEnum(DirectShowPin *pin)
- : m_mediaTypes(pin->supportedMediaTypes())
+ : m_pin(pin)
+ , m_mediaTypes(pin->supportedMediaTypes())
{
m_pin->AddRef();
}
diff --git a/src/plugins/directshow/common/directshowutils.cpp b/src/plugins/directshow/common/directshowutils.cpp
index 1457837ce..9222ad779 100644
--- a/src/plugins/directshow/common/directshowutils.cpp
+++ b/src/plugins/directshow/common/directshowutils.cpp
@@ -93,6 +93,25 @@ bool DirectShowUtils::hasPinDirection(IPin *pin, PIN_DIRECTION direction, HRESUL
return (pinDir == direction);
}
+bool pinMatchesCategory(IPin* pPin, REFGUID category)
+{
+ bool found = false;
+ IKsPropertySet *pKs = nullptr;
+ DirectShowUtils::ScopedSafeRelease<IKsPropertySet> ks_property { &pKs };
+ HRESULT hr = pPin->QueryInterface(IID_PPV_ARGS(&pKs));
+
+ if (SUCCEEDED(hr)) {
+ GUID pin_category;
+ DWORD return_value;
+ hr = pKs->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY, NULL, 0,
+ &pin_category, sizeof(pin_category), &return_value);
+ if (SUCCEEDED(hr) && (return_value == sizeof(pin_category)))
+ found = (pin_category == category);
+ }
+
+ return found;
+}
+
/**
* @brief DirectShowUtils::getPin
* @param filter
@@ -101,7 +120,7 @@ bool DirectShowUtils::hasPinDirection(IPin *pin, PIN_DIRECTION direction, HRESUL
* @param hrOut
* @return
*/
-bool DirectShowUtils::getPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, IPin **pin, HRESULT *hrOut)
+bool DirectShowUtils::getPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, REFGUID category, IPin **pin, HRESULT *hrOut)
{
IEnumPins *enumPins = nullptr;
const ScopedSafeRelease<IEnumPins> releaseEnumPins { &enumPins };
@@ -122,9 +141,11 @@ bool DirectShowUtils::getPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, IP
PIN_DIRECTION currentPinDir;
*hrOut = nextPin->QueryDirection(&currentPinDir);
if (currentPinDir == pinDirection) {
- *pin = nextPin;
- (*pin)->AddRef();
- return true;
+ if (category == GUID_NULL || pinMatchesCategory(nextPin, category)) {
+ *pin = nextPin;
+ (*pin)->AddRef();
+ return true;
+ }
}
}
diff --git a/src/plugins/directshow/common/directshowutils.h b/src/plugins/directshow/common/directshowutils.h
index 5f2cfaa23..ec761abe6 100644
--- a/src/plugins/directshow/common/directshowutils.h
+++ b/src/plugins/directshow/common/directshowutils.h
@@ -68,7 +68,7 @@ struct ScopedSafeRelease
}
};
-bool getPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, IPin **pin, HRESULT *hrOut);
+bool getPin(IBaseFilter *filter, PIN_DIRECTION pinDirection, REFGUID category, IPin **pin, HRESULT *hrOut);
bool isPinConnected(IPin *pin, HRESULT *hrOut = nullptr);
bool hasPinDirection(IPin *pin, PIN_DIRECTION direction, HRESULT *hrOut = nullptr);
bool matchPin(IPin *pin, PIN_DIRECTION pinDirection, BOOL shouldBeConnected, HRESULT *hrOut = nullptr);
diff --git a/src/plugins/directshow/player/directshowioreader.cpp b/src/plugins/directshow/player/directshowioreader.cpp
index ced10ea10..3318d57b5 100644
--- a/src/plugins/directshow/player/directshowioreader.cpp
+++ b/src/plugins/directshow/player/directshowioreader.cpp
@@ -155,7 +155,7 @@ HRESULT DirectShowIOReader::Request(IMediaSample *pSample, DWORD_PTR dwUser)
return VFW_E_SAMPLE_TIME_NOT_SET;
}
LONGLONG position = startTime / 10000000;
- LONG length = (endTime - startTime) / 10000000;
+ LONG length = qMin<qint64>((endTime - startTime) / 10000000, m_availableLength);
auto request = new DirectShowSampleRequest(pSample, dwUser, position, length, buffer);
diff --git a/src/plugins/directshow/player/directshowmetadatacontrol.cpp b/src/plugins/directshow/player/directshowmetadatacontrol.cpp
index 46674143e..d9864870a 100644
--- a/src/plugins/directshow/player/directshowmetadatacontrol.cpp
+++ b/src/plugins/directshow/player/directshowmetadatacontrol.cpp
@@ -64,7 +64,7 @@
#endif
#if QT_CONFIG(wshellitem)
-#include <ShlObj.h>
+#include <shlobj.h>
#include <propkeydef.h>
#include <private/qsystemlibrary_p.h>
diff --git a/src/plugins/gstreamer/camerabin/camerabinfocus.cpp b/src/plugins/gstreamer/camerabin/camerabinfocus.cpp
index d4e7fa699..a9cdf8e67 100644
--- a/src/plugins/gstreamer/camerabin/camerabinfocus.cpp
+++ b/src/plugins/gstreamer/camerabin/camerabinfocus.cpp
@@ -192,8 +192,6 @@ void CameraBinFocus::setFocusPointMode(QCameraFocus::FocusPointMode mode)
bool CameraBinFocus::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const
{
- return mode == QCameraFocus::FocusPointAuto || mode == QCameraFocus::FocusPointCustom;
-
switch (mode) {
case QCameraFocus::FocusPointAuto:
case QCameraFocus::FocusPointCustom:
diff --git a/src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp b/src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp
index 52ec75f44..b164bc31a 100644
--- a/src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp
+++ b/src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp
@@ -366,12 +366,9 @@ bool CameraBinImageCapture::processBusMessage(const QGstreamerMessage &message)
#ifdef DEBUG_CAPTURE
qDebug() << Q_FUNC_INFO << "Dropped saving file" << fileName;
#endif
- //camerabin creates an empty file when captured buffer is dropped,
- //let's remove it
QFileInfo info(QString::fromUtf8(fileName));
- if (info.exists() && info.isFile() && info.size() == 0) {
+ if (info.exists() && info.isFile())
QFile(info.absoluteFilePath()).remove();
- }
}
}
}
diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.cpp b/src/plugins/gstreamer/camerabin/camerabinsession.cpp
index 3e505a413..532fb43ec 100644
--- a/src/plugins/gstreamer/camerabin/camerabinsession.cpp
+++ b/src/plugins/gstreamer/camerabin/camerabinsession.cpp
@@ -347,10 +347,12 @@ void CameraBinSession::setupCaptureResolution()
// If capture resolution is specified, use it also for the viewfinder to avoid caps negotiation
// to fail.
if (m_usingWrapperCameraBinSrc) {
- if (m_captureMode == QCamera::CaptureStillImage && !imageResolution.isEmpty())
- viewfinderResolution = imageResolution;
- else if (m_captureMode == QCamera::CaptureVideo && !videoResolution.isEmpty())
- viewfinderResolution = videoResolution;
+ if (viewfinderResolution.isEmpty()) {
+ if (m_captureMode == QCamera::CaptureStillImage && !imageResolution.isEmpty())
+ viewfinderResolution = imageResolution;
+ else if (m_captureMode == QCamera::CaptureVideo && !videoResolution.isEmpty())
+ viewfinderResolution = videoResolution;
+ }
// Make sure we don't use incompatible frame rate and pixel format with the new resolution
if (viewfinderResolution != m_viewfinderSettings.resolution() &&
@@ -477,6 +479,15 @@ GstElement *CameraBinSession::buildCameraSource()
m_inputDeviceHasChanged = false;
m_usingWrapperCameraBinSrc = false;
+ if (m_videoSrc) {
+ gst_object_unref(GST_OBJECT(m_videoSrc));
+ m_videoSrc = 0;
+ }
+ if (m_cameraSrc) {
+ gst_object_unref(GST_OBJECT(m_cameraSrc));
+ m_cameraSrc = 0;
+ }
+
GstElement *camSrc = 0;
g_object_get(G_OBJECT(m_camerabin), CAMERA_SOURCE_PROPERTY, &camSrc, NULL);
@@ -1325,6 +1336,7 @@ QList< QPair<int,int> > CameraBinSession::supportedFrameRates(const QSize &frame
g_value_copy(oldRate, &rate);
gst_structure_remove_all_fields(structure);
gst_structure_set_value(structure, "framerate", &rate);
+ g_value_unset(&rate);
}
#if GST_CHECK_VERSION(1,0,0)
caps = gst_caps_simplify(caps);
@@ -1446,6 +1458,8 @@ QList<QSize> CameraBinSession::supportedResolutions(QPair<int,int> rate,
gst_structure_remove_all_fields(structure);
gst_structure_set_value(structure, "width", &w);
gst_structure_set_value(structure, "height", &h);
+ g_value_unset(&w);
+ g_value_unset(&h);
}
#if GST_CHECK_VERSION(1,0,0)
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..c621a181e 100644
--- a/src/plugins/m3u/qm3uhandler.cpp
+++ b/src/plugins/m3u/qm3uhandler.cpp
@@ -78,14 +78,14 @@ public:
delete m_textStream;
}
- virtual bool atEnd() const
+ bool atEnd() const override
{
//we can't just use m_textStream->atEnd(),
//for files with empty lines/comments at end
return nextResource.isNull();
}
- virtual QMediaContent readItem()
+ QMediaContent readItem() override
{
QMediaContent item;
if (!nextResource.isNull())
@@ -136,7 +136,7 @@ public:
return item;
}
- virtual void close()
+ void close() override
{
}
@@ -161,13 +161,13 @@ public:
delete m_textStream;
}
- virtual bool writeItem(const QMediaContent& item)
+ bool writeItem(const QMediaContent& item) override
{
- *m_textStream << item.request().url().toString() << endl;
+ *m_textStream << item.request().url().toString() << Qt::endl;
return true;
}
- virtual void close()
+ void close() override
{
}
diff --git a/src/plugins/m3u/qm3uhandler.h b/src/plugins/m3u/qm3uhandler.h
index 509ac11d5..1bc0684d3 100644
--- a/src/plugins/m3u/qm3uhandler.h
+++ b/src/plugins/m3u/qm3uhandler.h
@@ -54,15 +54,15 @@ public:
explicit QM3uPlaylistPlugin(QObject *parent = 0);
virtual ~QM3uPlaylistPlugin();
- virtual bool canRead(QIODevice *device, const QByteArray &format = QByteArray() ) const;
- virtual bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const;
+ bool canRead(QIODevice *device, const QByteArray &format = QByteArray()) const override;
+ bool canRead(const QUrl& location, const QByteArray &format = QByteArray()) const override;
- virtual bool canWrite(QIODevice *device, const QByteArray &format) const;
+ bool canWrite(QIODevice *device, const QByteArray &format) const override;
- virtual QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray());
- virtual QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray());
+ QMediaPlaylistReader *createReader(QIODevice *device, const QByteArray &format = QByteArray()) override;
+ QMediaPlaylistReader *createReader(const QUrl& location, const QByteArray &format = QByteArray()) override;
- virtual QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format);
+ QMediaPlaylistWriter *createWriter(QIODevice *device, const QByteArray &format) override;
};
#endif // QM3UHANDLER_H
diff --git a/src/plugins/pulseaudio/qaudiodeviceinfo_pulse.h b/src/plugins/pulseaudio/qaudiodeviceinfo_pulse.h
index 64537229f..1cec772c0 100644
--- a/src/plugins/pulseaudio/qaudiodeviceinfo_pulse.h
+++ b/src/plugins/pulseaudio/qaudiodeviceinfo_pulse.h
@@ -69,15 +69,15 @@ public:
QPulseAudioDeviceInfo(const QByteArray &device, QAudio::Mode mode);
~QPulseAudioDeviceInfo() {}
- QAudioFormat preferredFormat() const;
- bool isFormatSupported(const QAudioFormat &format) const;
- QString deviceName() const;
- QStringList supportedCodecs();
- QList<int> supportedSampleRates();
- QList<int> supportedChannelCounts();
- QList<int> supportedSampleSizes();
- QList<QAudioFormat::Endian> supportedByteOrders();
- QList<QAudioFormat::SampleType> supportedSampleTypes();
+ QAudioFormat preferredFormat() const override;
+ bool isFormatSupported(const QAudioFormat &format) const override;
+ QString deviceName() const override;
+ QStringList supportedCodecs() override;
+ QList<int> supportedSampleRates() override;
+ QList<int> supportedChannelCounts() override;
+ QList<int> supportedSampleSizes() override;
+ QList<QAudioFormat::Endian> supportedByteOrders() override;
+ QList<QAudioFormat::SampleType> supportedSampleTypes() override;
private:
QByteArray m_device;
diff --git a/src/plugins/pulseaudio/qaudioinput_pulse.cpp b/src/plugins/pulseaudio/qaudioinput_pulse.cpp
index 2b5325132..b68b4af1b 100644
--- a/src/plugins/pulseaudio/qaudioinput_pulse.cpp
+++ b/src/plugins/pulseaudio/qaudioinput_pulse.cpp
@@ -402,6 +402,8 @@ int QPulseAudioInput::bytesReady() const
qint64 QPulseAudioInput::read(char *data, qint64 len)
{
+ Q_ASSERT(data != nullptr || len == 0);
+
m_bytesAvailable = checkBytesReady();
setError(QAudio::NoError);
@@ -411,7 +413,8 @@ qint64 QPulseAudioInput::read(char *data, qint64 len)
if (!m_pullMode && !m_tempBuffer.isEmpty()) {
readBytes = qMin(static_cast<int>(len), m_tempBuffer.size());
- memcpy(data, m_tempBuffer.constData(), readBytes);
+ if (readBytes)
+ memcpy(data, m_tempBuffer.constData(), readBytes);
m_totalTimeValue += readBytes;
if (readBytes < m_tempBuffer.size()) {
@@ -502,9 +505,10 @@ qint64 QPulseAudioInput::read(char *data, qint64 len)
void QPulseAudioInput::applyVolume(const void *src, void *dest, int len)
{
+ Q_ASSERT((src && dest) || len == 0);
if (m_volume < 1.f)
QAudioHelperInternal::qMultiplySamples(m_volume, m_format, src, dest, len);
- else
+ else if (len)
memcpy(dest, src, len);
}
diff --git a/src/plugins/pulseaudio/qaudioinput_pulse.h b/src/plugins/pulseaudio/qaudioinput_pulse.h
index 3a6cf03c4..dce212a25 100644
--- a/src/plugins/pulseaudio/qaudioinput_pulse.h
+++ b/src/plugins/pulseaudio/qaudioinput_pulse.h
@@ -78,27 +78,27 @@ public:
qint64 read(char *data, qint64 len);
- void start(QIODevice *device);
- QIODevice *start();
- void stop();
- void reset();
- void suspend();
- void resume();
- int bytesReady() const;
- int periodSize() const;
- void setBufferSize(int value);
- int bufferSize() const;
- void setNotifyInterval(int milliSeconds);
- int notifyInterval() const;
- qint64 processedUSecs() const;
- qint64 elapsedUSecs() const;
- QAudio::Error error() const;
- QAudio::State state() const;
- void setFormat(const QAudioFormat &format);
- QAudioFormat format() const;
-
- void setVolume(qreal volume);
- qreal volume() const;
+ void start(QIODevice *device) override;
+ QIODevice *start() override;
+ void stop() override;
+ void reset() override;
+ void suspend() override;
+ void resume() override;
+ int bytesReady() const override;
+ int periodSize() const override;
+ void setBufferSize(int value) override;
+ int bufferSize() const override;
+ void setNotifyInterval(int milliSeconds) override;
+ int notifyInterval() const override;
+ qint64 processedUSecs() const override;
+ qint64 elapsedUSecs() const override;
+ QAudio::Error error() const override;
+ QAudio::State state() const override;
+ void setFormat(const QAudioFormat &format) override;
+ QAudioFormat format() const override;
+
+ void setVolume(qreal volume) override;
+ qreal volume() const override;
qint64 m_totalTimeValue;
QIODevice *m_audioSource;
@@ -147,8 +147,8 @@ public:
PulseInputPrivate(QPulseAudioInput *audio);
~PulseInputPrivate() {};
- qint64 readData(char *data, qint64 len);
- qint64 writeData(const char *data, qint64 len);
+ qint64 readData(char *data, qint64 len) override;
+ qint64 writeData(const char *data, qint64 len) override;
void trigger();
diff --git a/src/plugins/pulseaudio/qaudiooutput_pulse.cpp b/src/plugins/pulseaudio/qaudiooutput_pulse.cpp
index 19ddac1e5..765efe036 100644
--- a/src/plugins/pulseaudio/qaudiooutput_pulse.cpp
+++ b/src/plugins/pulseaudio/qaudiooutput_pulse.cpp
@@ -506,27 +506,30 @@ qint64 QPulseAudioOutput::write(const char *data, qint64 len)
pulseEngine->lock();
- len = qMin(len, static_cast<qint64>(pa_stream_writable_size(m_stream)));
+ size_t nbytes = len;
+ void *dest = nullptr;
+
+ if (pa_stream_begin_write(m_stream, &dest, &nbytes) < 0) {
+ qWarning("QAudioSink(pulseaudio): pa_stream_begin_write, error = %s",
+ pa_strerror(pa_context_errno(pulseEngine->context())));
+ setError(QAudio::IOError);
+ return 0;
+ }
+
+ len = qMin(len, qint64(nbytes));
if (m_volume < 1.0f) {
// Don't use PulseAudio volume, as it might affect all other streams of the same category
// or even affect the system volume if flat volumes are enabled
- void *dest = NULL;
- size_t nbytes = len;
- if (pa_stream_begin_write(m_stream, &dest, &nbytes) < 0) {
- qWarning("QAudioOutput(pulseaudio): pa_stream_begin_write, error = %s",
- pa_strerror(pa_context_errno(pulseEngine->context())));
- setError(QAudio::IOError);
- return 0;
- }
-
- len = int(nbytes);
QAudioHelperInternal::qMultiplySamples(m_volume, m_format, data, dest, len);
- data = reinterpret_cast<char *>(dest);
+ } else {
+ memcpy(dest, data, len);
}
- if (pa_stream_write(m_stream, data, len, NULL, 0, PA_SEEK_RELATIVE) < 0) {
- qWarning("QAudioOutput(pulseaudio): pa_stream_write, error = %s",
+ data = reinterpret_cast<char *>(dest);
+
+ if ((pa_stream_write(m_stream, data, len, nullptr, 0, PA_SEEK_RELATIVE)) < 0) {
+ qWarning("QAudioSink(pulseaudio): pa_stream_write, error = %s",
pa_strerror(pa_context_errno(pulseEngine->context())));
setError(QAudio::IOError);
return 0;
@@ -683,7 +686,6 @@ qint64 PulseOutputPrivate::readData(char *data, qint64 len)
qint64 PulseOutputPrivate::writeData(const char *data, qint64 len)
{
- int retry = 0;
qint64 written = 0;
if ((m_audioDevice->m_deviceState == QAudio::ActiveState
@@ -691,10 +693,8 @@ qint64 PulseOutputPrivate::writeData(const char *data, qint64 len)
while(written < len) {
int chunk = m_audioDevice->write(data+written, (len-written));
if (chunk <= 0)
- retry++;
- written+=chunk;
- if (retry > 10)
return written;
+ written+=chunk;
}
}
diff --git a/src/plugins/pulseaudio/qaudiooutput_pulse.h b/src/plugins/pulseaudio/qaudiooutput_pulse.h
index 40d052681..e11f2ab2f 100644
--- a/src/plugins/pulseaudio/qaudiooutput_pulse.h
+++ b/src/plugins/pulseaudio/qaudiooutput_pulse.h
@@ -75,30 +75,30 @@ public:
QPulseAudioOutput(const QByteArray &device);
~QPulseAudioOutput();
- void start(QIODevice *device);
- QIODevice *start();
- void stop();
- void reset();
- void suspend();
- void resume();
- int bytesFree() const;
- int periodSize() const;
- void setBufferSize(int value);
- int bufferSize() const;
- void setNotifyInterval(int milliSeconds);
- int notifyInterval() const;
- qint64 processedUSecs() const;
- qint64 elapsedUSecs() const;
- QAudio::Error error() const;
- QAudio::State state() const;
- void setFormat(const QAudioFormat &format);
- QAudioFormat format() const;
-
- void setVolume(qreal volume);
- qreal volume() const;
-
- void setCategory(const QString &category);
- QString category() const;
+ void start(QIODevice *device) override;
+ QIODevice *start() override;
+ void stop() override;
+ void reset() override;
+ void suspend() override;
+ void resume() override;
+ int bytesFree() const override;
+ int periodSize() const override;
+ void setBufferSize(int value) override;
+ int bufferSize() const override;
+ void setNotifyInterval(int milliSeconds) override;
+ int notifyInterval() const override;
+ qint64 processedUSecs() const override;
+ qint64 elapsedUSecs() const override;
+ QAudio::Error error() const override;
+ QAudio::State state() const override;
+ void setFormat(const QAudioFormat &format) override;
+ QAudioFormat format() const override;
+
+ void setVolume(qreal volume) override;
+ qreal volume() const override;
+
+ void setCategory(const QString &category) override;
+ QString category() const override;
public:
void streamUnderflowCallback();
@@ -154,8 +154,8 @@ public:
virtual ~PulseOutputPrivate() {}
protected:
- qint64 readData(char *data, qint64 len);
- qint64 writeData(const char *data, qint64 len);
+ qint64 readData(char *data, qint64 len) override;
+ qint64 writeData(const char *data, qint64 len) override;
private:
QPulseAudioOutput *m_audioDevice;
diff --git a/src/plugins/pulseaudio/qpulseaudioplugin.h b/src/plugins/pulseaudio/qpulseaudioplugin.h
index 120d57df5..7d27cad48 100644
--- a/src/plugins/pulseaudio/qpulseaudioplugin.h
+++ b/src/plugins/pulseaudio/qpulseaudioplugin.h
@@ -58,11 +58,11 @@ public:
QPulseAudioPlugin(QObject *parent = 0);
~QPulseAudioPlugin() {}
- QByteArray defaultDevice(QAudio::Mode mode) const;
- QList<QByteArray> availableDevices(QAudio::Mode mode) const;
- QAbstractAudioInput *createInput(const QByteArray &device);
- QAbstractAudioOutput *createOutput(const QByteArray &device);
- QAbstractAudioDeviceInfo *createDeviceInfo(const QByteArray &device, QAudio::Mode mode);
+ QByteArray defaultDevice(QAudio::Mode mode) const override;
+ QList<QByteArray> availableDevices(QAudio::Mode mode) const override;
+ QAbstractAudioInput *createInput(const QByteArray &device) override;
+ QAbstractAudioOutput *createOutput(const QByteArray &device) override;
+ QAbstractAudioDeviceInfo *createDeviceInfo(const QByteArray &device, QAudio::Mode mode) override;
private:
QPulseAudioEngine *m_pulseEngine;
diff --git a/src/plugins/qnx-audio/audio/audio.pro b/src/plugins/qnx-audio/audio/audio.pro
index bd69dfe1e..d63e58676 100644
--- a/src/plugins/qnx-audio/audio/audio.pro
+++ b/src/plugins/qnx-audio/audio/audio.pro
@@ -19,4 +19,5 @@ SOURCES += qnxaudioplugin.cpp \
OTHER_FILES += qnx_audio.json
PLUGIN_TYPE = audio
+PLUGIN_CLASS_NAME = QnxAudioPlugin
load(qt_plugin)
diff --git a/src/plugins/qnx-audio/audio/qnxaudioinput.cpp b/src/plugins/qnx-audio/audio/qnxaudioinput.cpp
index 70b83390c..9fca8a7e1 100644
--- a/src/plugins/qnx-audio/audio/qnxaudioinput.cpp
+++ b/src/plugins/qnx-audio/audio/qnxaudioinput.cpp
@@ -331,7 +331,7 @@ bool QnxAudioInput::open()
m_pcmNotifier = new QSocketNotifier(snd_pcm_file_descriptor(m_pcmHandle, SND_PCM_CHANNEL_CAPTURE),
QSocketNotifier::Read, this);
- connect(m_pcmNotifier, SIGNAL(activated(int)), SLOT(userFeed()));
+ connect(m_pcmNotifier, SIGNAL(activated(QSocketDescriptor)), SLOT(userFeed()));
return true;
}
diff --git a/src/plugins/qnx/common/windowgrabber.cpp b/src/plugins/qnx/common/windowgrabber.cpp
index 9a65ad3a0..b2470c250 100644
--- a/src/plugins/qnx/common/windowgrabber.cpp
+++ b/src/plugins/qnx/common/windowgrabber.cpp
@@ -393,8 +393,12 @@ GLuint
WindowGrabberImage::getTexture(screen_window_t window, const QSize &size)
{
if (size != m_size) {
- if (!m_glTexture)
- glGenTextures(1, &m_glTexture);
+ // create a brand new texture to be the KHR image sibling, as
+ // previously used textures cannot be reused with new KHR image
+ // sources - note that glDeleteTextures handles nullptr gracefully
+ glDeleteTextures(1, &m_glTexture);
+ glGenTextures(1, &m_glTexture);
+
glBindTexture(GL_TEXTURE_2D, m_glTexture);
if (m_eglImage) {
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, 0);
diff --git a/src/plugins/videonode/imx6/imx6.pro b/src/plugins/videonode/imx6/imx6.pro
index 43e17e725..0e9ed8b73 100644
--- a/src/plugins/videonode/imx6/imx6.pro
+++ b/src/plugins/videonode/imx6/imx6.pro
@@ -1,12 +1,8 @@
TARGET = imx6vivantevideonode
-QT += multimedia-private qtmultimediaquicktools-private
+QT += multimedia-private qtmultimediaquicktools-private multimediagsttools-private
-qtConfig(gstreamer_imxcommon) {
- QT += multimediagsttools-private
- QMAKE_USE += gstreamer_imxcommon
- DEFINES += GST_USE_UNSTABLE_API
-}
+QMAKE_USE += gstreamer
HEADERS += \
qsgvivantevideonode.h \
diff --git a/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp b/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp
index e1468fe34..c44a03896 100644
--- a/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp
+++ b/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp
@@ -50,9 +50,9 @@
#include <unistd.h>
#include <QtMultimedia/private/qtmultimediaglobal_p.h>
-#if QT_CONFIG(gstreamer_imxcommon)
#include "private/qgstvideobuffer_p.h"
-#include <gst/allocators/imx/phys_mem_meta.h>
+#if GST_CHECK_VERSION(1,14,0)
+#include <gst/allocators/gstphysmemory.h>
#endif
//#define QT_VIVANTE_VIDEO_DEBUG
@@ -107,7 +107,7 @@ void QSGVivanteVideoMaterial::updateBlending() {
void QSGVivanteVideoMaterial::setCurrentFrame(const QVideoFrame &frame, QSGVideoNode::FrameFlags flags)
{
QMutexLocker lock(&mFrameMutex);
- mNextFrame = frame;
+ mCurrentFrame = frame;
mMappable = mMapError == GL_NO_ERROR && !flags.testFlag(QSGVideoNode::FrameFiltered);
#ifdef QT_VIVANTE_VIDEO_DEBUG
@@ -124,12 +124,8 @@ void QSGVivanteVideoMaterial::bind()
}
QMutexLocker lock(&mFrameMutex);
- if (mNextFrame.isValid()) {
- mCurrentFrame.unmap();
-
- mCurrentFrame = mNextFrame;
- mCurrentTexture = vivanteMapping(mNextFrame);
- }
+ if (mCurrentFrame.isValid())
+ mCurrentTexture = vivanteMapping(mCurrentFrame);
else
glBindTexture(GL_TEXTURE_2D, mCurrentTexture);
}
@@ -229,11 +225,12 @@ GLuint QSGVivanteVideoMaterial::vivanteMapping(QVideoFrame vF)
#endif
GLuint physical = ~0U;
-#if QT_CONFIG(gstreamer_imxcommon)
+#if GST_CHECK_VERSION(1,14,0)
auto buffer = reinterpret_cast<QGstVideoBuffer *>(vF.buffer());
- GstImxPhysMemMeta *meta = GST_IMX_PHYS_MEM_META_GET(buffer->buffer());
- if (meta && meta->phys_addr)
- physical = meta->phys_addr;
+ auto mem = gst_buffer_peek_memory(buffer->buffer(), 0);
+ auto phys_addr = gst_is_phys_memory(mem) ? gst_phys_memory_get_phys_addr(mem) : 0;
+ if (phys_addr)
+ physical = phys_addr;
#endif
glBindTexture(GL_TEXTURE_2D, tmpTexId);
glTexDirectVIVMap_LOCAL(GL_TEXTURE_2D,
diff --git a/src/plugins/videonode/imx6/qsgvivantevideomaterial.h b/src/plugins/videonode/imx6/qsgvivantevideomaterial.h
index adbd960a4..db59e8fc7 100644
--- a/src/plugins/videonode/imx6/qsgvivantevideomaterial.h
+++ b/src/plugins/videonode/imx6/qsgvivantevideomaterial.h
@@ -78,7 +78,7 @@ private:
QVideoFrame::PixelFormat mFormat;
QMap<const uchar*, GLuint> mBitsToTextureMap;
- QVideoFrame mCurrentFrame, mNextFrame;
+ QVideoFrame mCurrentFrame;
GLuint mCurrentTexture;
bool mMappable;
GLenum mMapError = GL_NO_ERROR;
diff --git a/src/plugins/videonode/videonode.pro b/src/plugins/videonode/videonode.pro
index ab7295406..889862c36 100644
--- a/src/plugins/videonode/videonode.pro
+++ b/src/plugins/videonode/videonode.pro
@@ -1,7 +1,7 @@
TEMPLATE = subdirs
QT_FOR_CONFIG += gui-private multimedia-private
-qtConfig(gpu_vivante) {
+qtConfig(gpu_vivante):qtConfig(gstreamer) {
SUBDIRS += imx6
}
diff --git a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp
index 1182647fc..6ccffc8b2 100644
--- a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp
+++ b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp
@@ -630,7 +630,7 @@ qreal QWindowsAudioOutput::volume() const
void QWindowsAudioOutput::reset()
{
- close();
+ stop();
}
OutputPrivate::OutputPrivate(QWindowsAudioOutput* audio)
diff --git a/src/plugins/winrt/qwinrtcameracontrol.cpp b/src/plugins/winrt/qwinrtcameracontrol.cpp
index ede3f6b04..98dd7c2f7 100644
--- a/src/plugins/winrt/qwinrtcameracontrol.cpp
+++ b/src/plugins/winrt/qwinrtcameracontrol.cpp
@@ -54,7 +54,7 @@
#include <functional>
#include <mfapi.h>
-#include <Mferror.h>
+#include <mferror.h>
#include <mfidl.h>
#include <wrl.h>
#include <windows.devices.enumeration.h>
diff --git a/src/plugins/wmf/player/mfplayersession.cpp b/src/plugins/wmf/player/mfplayersession.cpp
index 24bfda833..daf6f801f 100644
--- a/src/plugins/wmf/player/mfplayersession.cpp
+++ b/src/plugins/wmf/player/mfplayersession.cpp
@@ -47,6 +47,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qfile.h>
#include <QtCore/qbuffer.h>
+#include <QtMultimedia/qmediametadata.h>
#include "mfplayercontrol.h"
#include "mfevrvideowindowcontrol.h"
@@ -56,7 +57,7 @@
#include "mfplayersession.h"
#include "mfplayerservice.h"
#include "mfmetadatacontrol.h"
-#include <Mferror.h>
+#include <mferror.h>
#include <nserror.h>
#include "sourceresolver.h"
#include "samplegrabber.h"
@@ -277,10 +278,13 @@ MFPlayerSession::MediaType MFPlayerSession::getStreamType(IMFStreamDescriptor *s
if (!stream)
return Unknown;
- IMFMediaTypeHandler *typeHandler = NULL;
- if (SUCCEEDED(stream->GetMediaTypeHandler(&typeHandler))) {
+ struct SafeRelease {
+ IMFMediaTypeHandler *ptr = nullptr;
+ ~SafeRelease() { if (ptr) ptr->Release(); }
+ } typeHandler;
+ if (SUCCEEDED(stream->GetMediaTypeHandler(&typeHandler.ptr))) {
GUID guidMajorType;
- if (SUCCEEDED(typeHandler->GetMajorType(&guidMajorType))) {
+ if (SUCCEEDED(typeHandler.ptr->GetMajorType(&guidMajorType))) {
if (guidMajorType == MFMediaType_Audio)
return Audio;
else if (guidMajorType == MFMediaType_Video)
@@ -288,9 +292,6 @@ MFPlayerSession::MediaType MFPlayerSession::getStreamType(IMFStreamDescriptor *s
}
}
- if (typeHandler)
- typeHandler->Release();
-
return Unknown;
}
@@ -428,9 +429,15 @@ IMFTopologyNode* MFPlayerSession::addOutputNode(MediaType mediaType, IMFTopology
if (mediaType == Audio) {
activate = m_playerService->audioEndpointControl()->createActivate();
} else if (mediaType == Video) {
+
+ QSize resolution = m_playerService->metaDataControl()->metaData(QMediaMetaData::Resolution).toSize();
+ QRect cropRect = QRect(QPoint(), resolution);
+
if (m_playerService->videoRendererControl()) {
+ m_playerService->videoRendererControl()->setCropRect(cropRect);
activate = m_playerService->videoRendererControl()->createActivate();
} else if (m_playerService->videoWindowControl()) {
+ m_playerService->videoWindowControl()->setCropRect(cropRect);
activate = m_playerService->videoWindowControl()->createActivate();
} else {
qWarning() << "no videoWindowControl or videoRendererControl, unable to add output node for video data";
diff --git a/src/plugins/wmf/player/mftvideo.cpp b/src/plugins/wmf/player/mftvideo.cpp
index 879911d55..9dce654f2 100644
--- a/src/plugins/wmf/player/mftvideo.cpp
+++ b/src/plugins/wmf/player/mftvideo.cpp
@@ -40,7 +40,7 @@
#include "mftvideo.h"
#include "mfvideoprobecontrol.h"
#include <private/qmemoryvideobuffer_p.h>
-#include <Mferror.h>
+#include <mferror.h>
#include <strmif.h>
#include <uuids.h>
#include <InitGuid.h>
diff --git a/src/plugins/wmf/player/mfvideorenderercontrol.cpp b/src/plugins/wmf/player/mfvideorenderercontrol.cpp
index 94d5f68be..38455090b 100644
--- a/src/plugins/wmf/player/mfvideorenderercontrol.cpp
+++ b/src/plugins/wmf/player/mfvideorenderercontrol.cpp
@@ -2239,10 +2239,12 @@ public:
STDMETHODIMP DetachObject();
void setSurface(QAbstractVideoSurface *surface);
+ void setCropRect(QRect cropRect);
private:
EVRCustomPresenter *m_presenter;
QAbstractVideoSurface *m_surface;
+ QRect m_cropRect;
QMutex m_mutex;
};
@@ -2305,6 +2307,14 @@ void MFVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
static_cast<VideoRendererActivate*>(m_currentActivate)->setSurface(m_surface);
}
+void MFVideoRendererControl::setCropRect(QRect cropRect)
+{
+ m_cropRect = cropRect;
+
+ if (m_presenterActivate)
+ m_presenterActivate->setCropRect(cropRect);
+}
+
void MFVideoRendererControl::customEvent(QEvent *event)
{
if (m_presenterActivate)
@@ -2365,6 +2375,7 @@ IMFActivate* MFVideoRendererControl::createActivate()
if (SUCCEEDED(MFCreateVideoRendererActivate(::GetShellWindow(), &m_currentActivate))) {
m_presenterActivate = new EVRCustomPresenterActivate;
m_currentActivate->SetUnknown(MF_ACTIVATE_CUSTOM_VIDEO_PRESENTER_ACTIVATE, m_presenterActivate);
+ m_presenterActivate->setCropRect(m_cropRect);
} else {
m_currentActivate = new VideoRendererActivate(this);
}
@@ -2388,6 +2399,7 @@ HRESULT EVRCustomPresenterActivate::ActivateObject(REFIID riid, void **ppv)
QMutexLocker locker(&m_mutex);
if (!m_presenter) {
m_presenter = new EVRCustomPresenter;
+ m_presenter->setCropRect(m_cropRect);
if (m_surface)
m_presenter->setSurface(m_surface);
}
@@ -2423,5 +2435,17 @@ void EVRCustomPresenterActivate::setSurface(QAbstractVideoSurface *surface)
m_presenter->setSurface(surface);
}
+void EVRCustomPresenterActivate::setCropRect(QRect cropRect)
+{
+ QMutexLocker locker(&m_mutex);
+ if (m_cropRect == cropRect)
+ return;
+
+ m_cropRect = cropRect;
+
+ if (m_presenter)
+ m_presenter->setCropRect(cropRect);
+}
+
#include "moc_mfvideorenderercontrol.cpp"
#include "mfvideorenderercontrol.moc"
diff --git a/src/plugins/wmf/player/mfvideorenderercontrol.h b/src/plugins/wmf/player/mfvideorenderercontrol.h
index da9e97ba9..8eab19b40 100644
--- a/src/plugins/wmf/player/mfvideorenderercontrol.h
+++ b/src/plugins/wmf/player/mfvideorenderercontrol.h
@@ -43,6 +43,7 @@
#include "qvideorenderercontrol.h"
#include <mfapi.h>
#include <mfidl.h>
+#include <qrect.h>
QT_USE_NAMESPACE
@@ -61,6 +62,8 @@ public:
IMFActivate* createActivate();
void releaseActivate();
+ void setCropRect(QRect cropRect);
+
protected:
void customEvent(QEvent *event);
@@ -74,8 +77,8 @@ private:
QAbstractVideoSurface *m_surface;
IMFActivate *m_currentActivate;
IMFSampleGrabberSinkCallback *m_callback;
-
EVRCustomPresenterActivate *m_presenterActivate;
+ QRect m_cropRect;
};
#endif
diff --git a/src/plugins/wmf/sourceresolver.cpp b/src/plugins/wmf/sourceresolver.cpp
index c6f4e8566..15ef6f0ab 100644
--- a/src/plugins/wmf/sourceresolver.cpp
+++ b/src/plugins/wmf/sourceresolver.cpp
@@ -39,7 +39,7 @@
#include "mfstream.h"
#include "sourceresolver.h"
-#include <Mferror.h>
+#include <mferror.h>
#include <nserror.h>
#include <QtCore/qfile.h>
#include <QtCore/qdebug.h>
diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp
index 32166502d..a948a5218 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,23 @@ 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 source
+*/
+
+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 +224,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 +249,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 +259,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 +302,6 @@ void QDeclarativeVideoOutput::_q_updateMediaObject()
if (m_mediaObject.data() == mediaObject)
return;
- if (m_sourceType != VideoSurfaceSource)
- m_backend.reset();
-
m_mediaObject.clear();
m_service.clear();
@@ -368,6 +374,8 @@ void QDeclarativeVideoOutput::_q_updateNativeSize()
if (!m_backend)
return;
+ m_geometryDirty = true;
+
QSize size = m_backend->nativeSize();
if (!qIsDefaultAspect(m_orientation)) {
size.transpose();
@@ -376,8 +384,6 @@ void QDeclarativeVideoOutput::_q_updateNativeSize()
if (m_nativeSize != size) {
m_nativeSize = size;
- m_geometryDirty = true;
-
setImplicitWidth(size.width());
setImplicitHeight(size.height());
@@ -415,9 +421,8 @@ void QDeclarativeVideoOutput::_q_updateGeometry()
}
if (m_backend) {
- if (!m_backend->videoSurface() || m_backend->videoSurface()->isActive())
- m_backend->updateGeometry();
- else
+ m_backend->updateGeometry();
+ if (m_backend->videoSurface() && !m_backend->videoSurface()->isActive())
m_geometryDirty = true;
}
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/src/qtmultimediaquicktools/qsgvideonode_texture.cpp b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp
index 473a4144f..bac143b43 100644
--- a/src/qtmultimediaquicktools/qsgvideonode_texture.cpp
+++ b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp
@@ -53,6 +53,13 @@ QList<QVideoFrame::PixelFormat> QSGVideoNodeFactory_Texture::supportedPixelForma
{
QList<QVideoFrame::PixelFormat> pixelFormats;
+#ifdef Q_OS_MACOS
+ if (handleType == QAbstractVideoBuffer::GLTextureRectangleHandle) {
+ pixelFormats.append(QVideoFrame::Format_BGR32);
+ pixelFormats.append(QVideoFrame::Format_BGRA32);
+ }
+#endif
+
if (handleType == QAbstractVideoBuffer::GLTextureHandle) {
pixelFormats.append(QVideoFrame::Format_RGB565);
pixelFormats.append(QVideoFrame::Format_RGB32);
@@ -82,8 +89,6 @@ public:
QSGVideoMaterialShader_Texture()
: QSGMaterialShader()
{
- setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qtmultimediaquicktools/shaders/monoplanarvideo.vert"));
- setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qtmultimediaquicktools/shaders/rgbvideo.frag"));
}
void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
@@ -109,10 +114,20 @@ protected:
int m_id_opacity;
};
-class QSGVideoMaterialShader_Texture_swizzle : public QSGVideoMaterialShader_Texture
+class QSGVideoMaterialShader_Texture_2D : public QSGVideoMaterialShader_Texture
{
public:
- QSGVideoMaterialShader_Texture_swizzle(bool hasAlpha)
+ QSGVideoMaterialShader_Texture_2D()
+ {
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qtmultimediaquicktools/shaders/monoplanarvideo.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qtmultimediaquicktools/shaders/rgbvideo.frag"));
+ }
+};
+
+class QSGVideoMaterialShader_Texture_2D_swizzle : public QSGVideoMaterialShader_Texture_2D
+{
+public:
+ QSGVideoMaterialShader_Texture_2D_swizzle(bool hasAlpha)
: m_hasAlpha(hasAlpha)
{
setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qtmultimediaquicktools/shaders/rgbvideo_swizzle.frag"));
@@ -120,14 +135,13 @@ public:
protected:
void initialize() override {
- QSGVideoMaterialShader_Texture::initialize();
+ QSGVideoMaterialShader_Texture_2D::initialize();
program()->setUniformValue(program()->uniformLocation("hasAlpha"), GLboolean(m_hasAlpha));
}
int m_hasAlpha;
};
-
class QSGVideoMaterial_Texture : public QSGMaterial
{
public:
@@ -149,12 +163,6 @@ public:
return needsSwizzling() ? &swizzleType : &normalType;
}
- QSGMaterialShader *createShader() const override {
- const bool hasAlpha = m_format.pixelFormat() == QVideoFrame::Format_ARGB32;
- return needsSwizzling() ? new QSGVideoMaterialShader_Texture_swizzle(hasAlpha)
- : new QSGVideoMaterialShader_Texture;
- }
-
int compare(const QSGMaterial *other) const override {
const QSGVideoMaterial_Texture *m = static_cast<const QSGVideoMaterial_Texture *>(other);
@@ -179,9 +187,42 @@ public:
void setVideoFrame(const QVideoFrame &frame) {
QMutexLocker lock(&m_frameMutex);
m_frame = frame;
+ m_textureSize = frame.size();
+ }
+
+ virtual void bind() = 0;
+
+ QVideoFrame m_frame;
+ QMutex m_frameMutex;
+ QSize m_textureSize;
+ QVideoSurfaceFormat m_format;
+ GLuint m_textureId;
+ qreal m_opacity;
+
+protected:
+ bool needsSwizzling() const {
+ return !QMediaOpenGLHelper::isANGLE()
+ && (m_format.pixelFormat() == QVideoFrame::Format_RGB32
+ || m_format.pixelFormat() == QVideoFrame::Format_ARGB32);
+ }
+};
+
+class QSGVideoMaterial_Texture_2D : public QSGVideoMaterial_Texture
+{
+public:
+ QSGVideoMaterial_Texture_2D(const QVideoSurfaceFormat &format) :
+ QSGVideoMaterial_Texture(format)
+ {
}
- void bind()
+ QSGMaterialShader *createShader() const override
+ {
+ const bool hasAlpha = m_format.pixelFormat() == QVideoFrame::Format_ARGB32;
+ return needsSwizzling() ? new QSGVideoMaterialShader_Texture_2D_swizzle(hasAlpha)
+ : new QSGVideoMaterialShader_Texture_2D;
+ }
+
+ void bind() override
{
QMutexLocker lock(&m_frameMutex);
if (m_frame.isValid()) {
@@ -197,28 +238,84 @@ public:
m_textureId = 0;
}
}
+};
+
+#ifdef Q_OS_MACOS
+class QSGVideoMaterialShader_Texture_Rectangle : public QSGVideoMaterialShader_Texture
+{
+public:
+ QSGVideoMaterialShader_Texture_Rectangle()
+ {
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qtmultimediaquicktools/shaders/rectsampler.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qtmultimediaquicktools/shaders/rectsampler_rgb.frag"));
+ }
- QVideoFrame m_frame;
- QMutex m_frameMutex;
- QSize m_textureSize;
- QVideoSurfaceFormat m_format;
- GLuint m_textureId;
- qreal m_opacity;
+ void updateState(const RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override
+ {
+ QSGVideoMaterial_Texture *mat = static_cast<QSGVideoMaterial_Texture *>(newMaterial);
+ QVector2D size(mat->m_textureSize.width(), mat->m_textureSize.height());
+ program()->setUniformValue(m_id_videoSize, size);
-private:
- bool needsSwizzling() const {
- return !QMediaOpenGLHelper::isANGLE()
- && (m_format.pixelFormat() == QVideoFrame::Format_RGB32
- || m_format.pixelFormat() == QVideoFrame::Format_ARGB32);
+ QSGVideoMaterialShader_Texture::updateState(state, newMaterial, oldMaterial);
}
+
+protected:
+ void initialize() override
+ {
+ QSGVideoMaterialShader_Texture::initialize();
+ m_id_videoSize = program()->uniformLocation("qt_videoSize");
+ }
+
+ int m_id_videoSize;
};
+class QSGVideoMaterial_Texture_Rectangle : public QSGVideoMaterial_Texture
+{
+public:
+ QSGVideoMaterial_Texture_Rectangle(const QVideoSurfaceFormat &format) :
+ QSGVideoMaterial_Texture(format)
+ {
+ }
+
+ QSGMaterialShader *createShader() const override
+ {
+ Q_ASSERT(!needsSwizzling());
+ return new QSGVideoMaterialShader_Texture_Rectangle;
+ }
+
+ void bind() override
+ {
+ QMutexLocker lock(&m_frameMutex);
+ if (m_frame.isValid()) {
+ m_textureId = m_frame.handle().toUInt();
+ QOpenGLFunctions *functions = QOpenGLContext::currentContext()->functions();
+ functions->glActiveTexture(GL_TEXTURE0);
+ functions->glBindTexture(GL_TEXTURE_RECTANGLE, m_textureId);
+
+ functions->glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ functions->glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ functions->glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ functions->glTexParameteri(GL_TEXTURE_RECTANGLE, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ } else {
+ m_textureId = 0;
+ }
+ }
+};
+#endif
QSGVideoNode_Texture::QSGVideoNode_Texture(const QVideoSurfaceFormat &format) :
m_format(format)
{
setFlag(QSGNode::OwnsMaterial);
- m_material = new QSGVideoMaterial_Texture(format);
+
+#ifdef Q_OS_MACOS
+ if (format.handleType() == QAbstractVideoBuffer::GLTextureRectangleHandle)
+ m_material = new QSGVideoMaterial_Texture_Rectangle(format);
+#endif
+
+ if (!m_material)
+ m_material = new QSGVideoMaterial_Texture_2D(format);
+
setMaterial(m_material);
}
diff --git a/src/qtmultimediaquicktools/qsgvideonode_texture_p.h b/src/qtmultimediaquicktools/qsgvideonode_texture_p.h
index 12685dd24..21c905bd5 100644
--- a/src/qtmultimediaquicktools/qsgvideonode_texture_p.h
+++ b/src/qtmultimediaquicktools/qsgvideonode_texture_p.h
@@ -74,7 +74,7 @@ public:
private:
QVideoSurfaceFormat m_format;
- QSGVideoMaterial_Texture *m_material;
+ QSGVideoMaterial_Texture *m_material = nullptr;
QVideoFrame m_frame;
};
diff --git a/src/qtmultimediaquicktools/qtmultimediaquicktools.qrc b/src/qtmultimediaquicktools/qtmultimediaquicktools.qrc
index b8180e31f..86523e771 100644
--- a/src/qtmultimediaquicktools/qtmultimediaquicktools.qrc
+++ b/src/qtmultimediaquicktools/qtmultimediaquicktools.qrc
@@ -11,7 +11,6 @@
<file>shaders/triplanaryuvvideo.vert</file>
<file>shaders/uyvyvideo.frag</file>
<file>shaders/yuyvvideo.frag</file>
-
<file>shaders/monoplanarvideo_core.vert</file>
<file>shaders/rgbvideo_core.frag</file>
<file>shaders/rgbvideo_swizzle_core.frag</file>
@@ -23,5 +22,9 @@
<file>shaders/triplanaryuvvideo_core.vert</file>
<file>shaders/uyvyvideo_core.frag</file>
<file>shaders/yuyvvideo_core.frag</file>
+ <file>shaders/rectsampler.vert</file>
+ <file>shaders/rectsampler_rgb.frag</file>
+ <file>shaders/rectsampler_core.vert</file>
+ <file>shaders/rectsampler_rgb_core.frag</file>
</qresource>
</RCC>
diff --git a/src/qtmultimediaquicktools/shaders/rectsampler.vert b/src/qtmultimediaquicktools/shaders/rectsampler.vert
new file mode 100644
index 000000000..762ec7e7e
--- /dev/null
+++ b/src/qtmultimediaquicktools/shaders/rectsampler.vert
@@ -0,0 +1,10 @@
+uniform highp mat4 qt_Matrix;
+uniform highp vec2 qt_videoSize;
+attribute highp vec4 qt_VertexPosition;
+attribute highp vec2 qt_VertexTexCoord;
+varying highp vec2 qt_TexCoord;
+
+void main() {
+ qt_TexCoord = vec2(qt_VertexTexCoord.x * qt_videoSize.x, qt_VertexTexCoord.y * qt_videoSize.y);
+ gl_Position = qt_Matrix * qt_VertexPosition;
+}
diff --git a/src/qtmultimediaquicktools/shaders/rectsampler_core.vert b/src/qtmultimediaquicktools/shaders/rectsampler_core.vert
new file mode 100644
index 000000000..f0fe02349
--- /dev/null
+++ b/src/qtmultimediaquicktools/shaders/rectsampler_core.vert
@@ -0,0 +1,11 @@
+#version 150 core
+uniform highp mat4 qt_Matrix;
+uniform highp vec2 qt_videoSize;
+in highp vec4 qt_VertexPosition;
+in highp vec2 qt_VertexTexCoord;
+out highp vec2 qt_TexCoord;
+
+void main() {
+ qt_TexCoord = vec2(qt_VertexTexCoord.x * qt_videoSize.x, qt_VertexTexCoord.y * qt_videoSize.y);
+ gl_Position = qt_Matrix * qt_VertexPosition;
+}
diff --git a/src/qtmultimediaquicktools/shaders/rectsampler_rgb.frag b/src/qtmultimediaquicktools/shaders/rectsampler_rgb.frag
new file mode 100644
index 000000000..2a30f7c3d
--- /dev/null
+++ b/src/qtmultimediaquicktools/shaders/rectsampler_rgb.frag
@@ -0,0 +1,8 @@
+uniform sampler2DRect rgbTexture;
+uniform lowp float opacity;
+varying highp vec2 qt_TexCoord;
+
+void main()
+{
+ gl_FragColor = texture2DRect(rgbTexture, qt_TexCoord) * opacity;
+}
diff --git a/src/qtmultimediaquicktools/shaders/rectsampler_rgb_core.frag b/src/qtmultimediaquicktools/shaders/rectsampler_rgb_core.frag
new file mode 100644
index 000000000..17f306456
--- /dev/null
+++ b/src/qtmultimediaquicktools/shaders/rectsampler_rgb_core.frag
@@ -0,0 +1,10 @@
+#version 150 core
+uniform sampler2DRect rgbTexture;
+uniform lowp float opacity;
+in highp vec2 qt_TexCoord;
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = texture(rgbTexture, qt_TexCoord) * opacity;
+}