summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/imports/multimedia/qmldir1
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp5
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h1
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamervideooutput.cpp32
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h5
-rw-r--r--src/multimedia/platform/qplatformmediaplayer_p.h1
-rw-r--r--src/multimedia/playback/qmediaplayer.cpp17
-rw-r--r--src/multimedia/playback/qmediaplayer.h3
-rw-r--r--src/multimedia/video/qvideosink.cpp62
-rw-r--r--src/multimedia/video/qvideosink.h8
-rw-r--r--src/multimediawidgets/qvideowidget.cpp20
-rw-r--r--src/multimediawidgets/qvideowidget.h6
-rw-r--r--src/multimediawidgets/qvideowidget_p.h4
13 files changed, 154 insertions, 11 deletions
diff --git a/src/imports/multimedia/qmldir b/src/imports/multimedia/qmldir
index e7dcc3dd6..48cdb0c8c 100644
--- a/src/imports/multimedia/qmldir
+++ b/src/imports/multimedia/qmldir
@@ -2,6 +2,7 @@ module QtMultimedia
plugin declarative_multimedia
classname QMultimediaDeclarativeModule
typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtMultimedia/
typeinfo plugins.qmltypes
Video 5.0 Video.qml
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp
index f7043c7f9..930dec8d1 100644
--- a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp
+++ b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp
@@ -605,6 +605,11 @@ QMediaMetaData QGstreamerMediaPlayer::metaData() const
return m_metaData;
}
+void QGstreamerMediaPlayer::setVideoSink(QVideoSink *sink)
+{
+ gstVideoOutput->setVideoSink(sink);
+}
+
void QGstreamerMediaPlayer::setSeekable(bool seekable)
{
qCDebug(qLcMediaPlayer) << Q_FUNC_INFO << seekable;
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h
index 319059ca1..fcaf3f6aa 100644
--- a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h
+++ b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer_p.h
@@ -108,6 +108,7 @@ public:
QMediaMetaData metaData() const override;
+ void setVideoSink(QVideoSink *sink) override;
void setVideoSurface(QAbstractVideoSurface *surface) override;
int trackCount(TrackType) override;
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideooutput.cpp b/src/multimedia/platform/gstreamer/common/qgstreamervideooutput.cpp
index 939e88599..103a15557 100644
--- a/src/multimedia/platform/gstreamer/common/qgstreamervideooutput.cpp
+++ b/src/multimedia/platform/gstreamer/common/qgstreamervideooutput.cpp
@@ -39,6 +39,8 @@
#include <private/qgstreamervideooutput_p.h>
#include <private/qgstreamervideorenderer_p.h>
+#include <private/qgstreamervideowindow_p.h>
+#include <qvideosink.h>
#include <QtCore/qloggingcategory.h>
#include <qthread.h>
@@ -109,6 +111,36 @@ void QGstreamerVideoOutput::setVideoSurface(QAbstractVideoSurface *surface)
pad.addProbe<&QGstreamerVideoOutput::prepareVideoOutputChange>(this, GST_PAD_PROBE_TYPE_IDLE);
}
+void QGstreamerVideoOutput::setVideoSink(QVideoSink *sink)
+{
+ if (!m_videoWindow) {
+ m_videoWindow = new QGstreamerVideoWindow;
+ gstPipeline.installMessageFilter(static_cast<QGstreamerSyncMessageFilter *>(m_videoWindow));
+ gstPipeline.installMessageFilter(static_cast<QGstreamerBusMessageFilter *>(m_videoWindow));
+ m_videoWindow->setWinId(sink->nativeWindowId());
+ }
+
+ newVideoSink = m_videoWindow->videoSink();
+ if (newVideoSink == videoSink) {
+ newVideoSink = {};
+ return;
+ }
+ gstVideoOutput.add(newVideoSink);
+
+ qCDebug(qLcMediaVideoOutput) << "setVideoSurface: Reconfiguring video output" << QThread::currentThreadId();
+
+ auto state = gstPipeline.state();
+
+ if (state != GST_STATE_PLAYING) {
+ changeVideoOutput();
+ return;
+ }
+
+ // This doesn't quite work, as we're be getting the callback in another thread where state changes aren't allowed.
+ auto pad = videoScale.staticPad("src");
+ pad.addProbe<&QGstreamerVideoOutput::prepareVideoOutputChange>(this, GST_PAD_PROBE_TYPE_IDLE);
+}
+
void QGstreamerVideoOutput::setIsPreview()
{
// configures the queue to be fast and lightweight for camera preview
diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h b/src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h
index d2612e76f..fa6ec3fad 100644
--- a/src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h
+++ b/src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h
@@ -59,6 +59,8 @@ QT_BEGIN_NAMESPACE
class QGstreamerVideoRenderer;
class QAbstractVideoSurface;
+class QVideoSink;
+class QGstreamerVideoWindow;
class Q_MULTIMEDIA_EXPORT QGstreamerVideoOutput : public QObject
{
@@ -69,6 +71,7 @@ public:
~QGstreamerVideoOutput();
void setVideoSurface(QAbstractVideoSurface *surface);
+ void setVideoSink(QVideoSink *sink);
void setPipeline(const QGstPipeline &pipeline) { gstPipeline = pipeline; }
@@ -81,7 +84,9 @@ private:
void changeVideoOutput();
QAbstractVideoSurface *m_videoSurface = nullptr;
+ QVideoSink *m_videoSink = nullptr;
QGstreamerVideoRenderer *m_videoOutput = nullptr;
+ QGstreamerVideoWindow *m_videoWindow = nullptr;
// Gst elements
QGstPipeline gstPipeline;
diff --git a/src/multimedia/platform/qplatformmediaplayer_p.h b/src/multimedia/platform/qplatformmediaplayer_p.h
index e34a8b22b..832caf859 100644
--- a/src/multimedia/platform/qplatformmediaplayer_p.h
+++ b/src/multimedia/platform/qplatformmediaplayer_p.h
@@ -115,6 +115,7 @@ public:
virtual QMediaMetaData metaData() const { return {}; }
virtual void setVideoSurface(QAbstractVideoSurface *surface) = 0;
+ virtual void setVideoSink(QVideoSink */*sink*/) {}
// media streams
enum TrackType { VideoStream, AudioStream, SubtitleStream, NTrackTypes };
diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp
index 2c196a04d..5917b083e 100644
--- a/src/multimedia/playback/qmediaplayer.cpp
+++ b/src/multimedia/playback/qmediaplayer.cpp
@@ -714,6 +714,11 @@ void QMediaPlayer::setActiveSubtitleTrack(int index)
void QMediaPlayer::setVideoOutput(QObject *output)
{
auto *mo = output->metaObject();
+ QVideoSink *sink = nullptr;
+ if (!output || mo->invokeMethod(output, "videoSink", Q_RETURN_ARG(QVideoSink *, sink))) {
+ setVideoOutput(sink);
+ return;
+ }
QAbstractVideoSurface *surface = nullptr;
if (output && !mo->invokeMethod(output, "videoSurface", Q_RETURN_ARG(QAbstractVideoSurface *, surface))) {
qWarning() << "QMediaPlayer::setVideoOutput: Object" << output->metaObject()->className() << "does not have a videoSurface()";
@@ -728,7 +733,6 @@ void QMediaPlayer::setVideoOutput(QObject *output)
If a video output has already been set on the media player the new surface
will replace it.
*/
-
void QMediaPlayer::setVideoOutput(QAbstractVideoSurface *surface)
{
Q_D(QMediaPlayer);
@@ -739,6 +743,16 @@ void QMediaPlayer::setVideoOutput(QAbstractVideoSurface *surface)
d->control->setVideoSurface(surface);
}
+void QMediaPlayer::setVideoOutput(QVideoSink *sink)
+{
+ Q_D(QMediaPlayer);
+
+ if (!d->control)
+ return;
+
+ d->control->setVideoSink(sink);
+}
+
/*!
\since 5.15
Sets multiple video surfaces as the video output of a media player.
@@ -751,7 +765,6 @@ void QMediaPlayer::setVideoOutput(QAbstractVideoSurface *surface)
\sa QAbstractVideoSurface::supportedPixelFormats
*/
-
void QMediaPlayer::setVideoOutput(const QList<QAbstractVideoSurface *> &surfaces)
{
setVideoOutput(!surfaces.empty() ? new QVideoSurfaces(surfaces, this) : nullptr);
diff --git a/src/multimedia/playback/qmediaplayer.h b/src/multimedia/playback/qmediaplayer.h
index 38429ecb7..c52bea22f 100644
--- a/src/multimedia/playback/qmediaplayer.h
+++ b/src/multimedia/playback/qmediaplayer.h
@@ -47,7 +47,7 @@
QT_BEGIN_NAMESPACE
-
+class QVideoSink;
class QAbstractVideoSurface;
class QAudioDeviceInfo;
class QMediaMetaData;
@@ -138,6 +138,7 @@ public:
void setVideoOutput(QObject *);
void setVideoOutput(QAbstractVideoSurface *surface);
void setVideoOutput(const QList<QAbstractVideoSurface *> &surfaces);
+ void setVideoOutput(QVideoSink *sink);
QUrl media() const;
const QIODevice *mediaStream() const;
diff --git a/src/multimedia/video/qvideosink.cpp b/src/multimedia/video/qvideosink.cpp
index de619eab8..77ee54593 100644
--- a/src/multimedia/video/qvideosink.cpp
+++ b/src/multimedia/video/qvideosink.cpp
@@ -88,6 +88,12 @@ void QVideoSink::setGraphicsType(QVideoSink::GraphicsType type)
d->type = type;
}
+bool QVideoSink::isGraphicsTypeSupported(QVideoSink::GraphicsType type)
+{
+ // ####
+ return type == NativeWindow;
+}
+
WId QVideoSink::nativeWindowId() const
{
return d->window;
@@ -184,11 +190,57 @@ void QVideoSink::render(const QVideoFrame &frame)
}
-void QVideoSink::paint(QPainter *painter, const QVideoFrame &frame)
-{
- Q_UNUSED(painter);
- Q_UNUSED(frame);
-
+void QVideoSink::paint(QPainter *painter, const QVideoFrame &f)
+{
+ QVideoFrame frame(f);
+ if (!frame.isValid()) {
+ painter->fillRect(d->targetRect, Qt::black);
+ return;
+ }
+
+ auto imageFormat = QVideoFrame::imageFormatFromPixelFormat(frame.pixelFormat());
+ // Do not render into ARGB32 images using QPainter.
+ // Using QImage::Format_ARGB32_Premultiplied is significantly faster.
+ if (imageFormat == QImage::Format_ARGB32)
+ imageFormat = QImage::Format_ARGB32_Premultiplied;
+
+ QVideoSurfaceFormat::Direction scanLineDirection = QVideoSurfaceFormat::TopToBottom;//format.scanLineDirection();
+ bool mirrored = false;//format.isMirrored();
+
+ QRectF source = d->targetRect; // ####
+
+ if (frame.handleType() == QVideoFrame::QPixmapHandle) {
+ painter->drawPixmap(d->targetRect, frame.handle().value<QPixmap>(), source);
+ } else if (frame.map(QVideoFrame::ReadOnly)) {
+ QImage image = frame.image();
+
+ auto oldOpacity = painter->opacity();
+ const QTransform oldTransform = painter->transform();
+ QTransform transform = oldTransform;
+ QRectF targetRect = d->targetRect;
+ if (scanLineDirection == QVideoSurfaceFormat::BottomToTop) {
+ transform.scale(1, -1);
+ transform.translate(0, -targetRect.bottom());
+ targetRect = QRectF(targetRect.x(), 0, targetRect.width(), targetRect.height());
+ }
+
+ if (mirrored) {
+ transform.scale(-1, 1);
+ transform.translate(-targetRect.right(), 0);
+ targetRect = QRectF(0, targetRect.y(), targetRect.width(), targetRect.height());
+ }
+ painter->setTransform(transform);
+ painter->setOpacity(d->opacity);
+ painter->drawImage(targetRect, image, source);
+ painter->setTransform(oldTransform);
+ painter->setOpacity(oldOpacity);
+
+ frame.unmap();
+ } else if (frame.isValid()) {
+ // #### error handling
+ } else {
+ painter->fillRect(targetRect(), Qt::black);
+ }
}
QT_END_NAMESPACE
diff --git a/src/multimedia/video/qvideosink.h b/src/multimedia/video/qvideosink.h
index e4ae146c0..2c7da355b 100644
--- a/src/multimedia/video/qvideosink.h
+++ b/src/multimedia/video/qvideosink.h
@@ -40,6 +40,7 @@
#ifndef QABSTRACTVIDEOSINK_H
#define QABSTRACTVIDEOSINK_H
+#include <QtMultimedia/qtmultimediaglobal.h>
#include <QtCore/qobject.h>
#include <QtGui/qwindowdefs.h>
@@ -51,7 +52,7 @@ class QVideoFrame;
class QVideoSinkPrivate;
-class QVideoSink : public QObject
+class Q_MULTIMEDIA_EXPORT QVideoSink : public QObject
{
Q_OBJECT
public:
@@ -59,6 +60,7 @@ public:
{
Memory,
NativeWindow,
+ NativeTexture,
OpenGL,
Metal,
Direct3D11,
@@ -71,6 +73,8 @@ public:
GraphicsType graphicsType() const;
void setGraphicsType(GraphicsType type);
+ static bool isGraphicsTypeSupported(GraphicsType type);
+
// setter sets graphics type to NativeWindow
WId nativeWindowId() const;
void setNativeWindowId(WId id);
@@ -108,7 +112,7 @@ public:
Q_SIGNALS:
// would never get called in windowed mode
- QVideoFrame newVideoFrame() const;
+ QVideoFrame newVideoFrame(const QVideoFrame &frame) const;
private:
QVideoSinkPrivate *d = nullptr;
diff --git a/src/multimediawidgets/qvideowidget.cpp b/src/multimediawidgets/qvideowidget.cpp
index 6dc019378..a739f8e96 100644
--- a/src/multimediawidgets/qvideowidget.cpp
+++ b/src/multimediawidgets/qvideowidget.cpp
@@ -43,6 +43,7 @@
#include <QtCore/qobject.h>
#include <QtMultimedia/qtmultimediaglobal.h>
#include <qvideowindowcontrol.h>
+#include <qvideosink.h>
#include <qobject.h>
#include <qvideosurfaceformat.h>
@@ -287,6 +288,12 @@ void QVideoWidgetPrivate::_q_dimensionsChanged()
q_func()->update();
}
+void QVideoWidgetPrivate::_q_newFrame(const QVideoFrame &frame)
+{
+ lastFrame = frame;
+ q_ptr->update();
+}
+
/*!
\class QVideoWidget
@@ -317,6 +324,9 @@ QVideoWidget::QVideoWidget(QWidget *parent)
, d_ptr(new QVideoWidgetPrivate)
{
d_ptr->q_ptr = this;
+ d_ptr->videoSink = new QVideoSink(this);
+ d_ptr->videoSink->setGraphicsType(QVideoSink::NativeWindow);
+ d_ptr->videoSink->setNativeWindowId(winId());
}
/*!
@@ -362,6 +372,11 @@ QAbstractVideoSurface *QVideoWidget::videoSurface() const
return d->backend->videoSurface();
}
+QVideoSink *QVideoWidget::videoSink() const
+{
+ return d_ptr->videoSink;
+}
+
/*!
\property QVideoWidget::aspectRatioMode
\brief how video is scaled with respect to its aspect ratio.
@@ -652,6 +667,11 @@ void QVideoWidget::paintEvent(QPaintEvent *event)
{
Q_D(QVideoWidget);
+ if (d->videoSink && d->lastFrame.isValid()) {
+ QPainter painter(this);
+ d->videoSink->paint(&painter, d->lastFrame);
+ return;
+ }
if (d->backend) {
d->backend->paintEvent(event);
} else if (testAttribute(Qt::WA_OpaquePaintEvent)) {
diff --git a/src/multimediawidgets/qvideowidget.h b/src/multimediawidgets/qvideowidget.h
index 866e5fef4..68e865ddd 100644
--- a/src/multimediawidgets/qvideowidget.h
+++ b/src/multimediawidgets/qvideowidget.h
@@ -46,8 +46,10 @@
QT_BEGIN_NAMESPACE
-class QVideoWidgetPrivate;
class QAbstractVideoSurface;
+class QVideoSink;
+
+class QVideoWidgetPrivate;
class Q_MULTIMEDIAWIDGETS_EXPORT QVideoWidget : public QWidget
{
Q_OBJECT
@@ -64,6 +66,7 @@ public:
~QVideoWidget();
Q_INVOKABLE QAbstractVideoSurface *videoSurface() const;
+ Q_INVOKABLE QVideoSink *videoSink() const;
#ifdef Q_QDOC
bool isFullScreen() const;
@@ -115,6 +118,7 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_saturationChanged(int))
Q_PRIVATE_SLOT(d_func(), void _q_fullScreenChanged(bool))
Q_PRIVATE_SLOT(d_func(), void _q_dimensionsChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_newFrame(const QVideoFrame &))
};
QT_END_NAMESPACE
diff --git a/src/multimediawidgets/qvideowidget_p.h b/src/multimediawidgets/qvideowidget_p.h
index 52a93e99c..9ced54c8f 100644
--- a/src/multimediawidgets/qvideowidget_p.h
+++ b/src/multimediawidgets/qvideowidget_p.h
@@ -136,6 +136,9 @@ public:
Qt::WindowFlags nonFullScreenFlags;
bool wasFullScreen = false;
+ QVideoFrame lastFrame;
+ QVideoSink *videoSink = nullptr;
+
bool createBackend();
void _q_brightnessChanged(int brightness);
@@ -144,6 +147,7 @@ public:
void _q_saturationChanged(int saturation);
void _q_fullScreenChanged(bool fullScreen);
void _q_dimensionsChanged();
+ void _q_newFrame(const QVideoFrame &frame);
};
QT_END_NAMESPACE