diff options
25 files changed, 205 insertions, 149 deletions
diff --git a/src/multimedia/platform/gstreamer/common/qgst_p.h b/src/multimedia/platform/gstreamer/common/qgst_p.h index d4ee13cd9..e8245ee66 100644 --- a/src/multimedia/platform/gstreamer/common/qgst_p.h +++ b/src/multimedia/platform/gstreamer/common/qgst_p.h @@ -233,6 +233,12 @@ public: gst_caps_unref(caps); } + void create() { + caps = gst_caps_new_empty(); + } + + void addPixelFormats(const QList<QVideoSurfaceFormat::PixelFormat> &formats, const char *modifier = nullptr); + bool isNull() const { return !caps; } int size() const { return gst_caps_get_size(caps); } diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h b/src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h index 8f4946e1f..03dcbcb98 100644 --- a/src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h +++ b/src/multimedia/platform/gstreamer/common/qgstreamervideooutput_p.h @@ -59,7 +59,6 @@ QT_BEGIN_NAMESPACE -class QGstreamerVideoRenderer; class QVideoSink; class QGstreamerVideoSink; diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideooverlay.cpp b/src/multimedia/platform/gstreamer/common/qgstreamervideooverlay.cpp index 54d38cc06..33b1d91f8 100644 --- a/src/multimedia/platform/gstreamer/common/qgstreamervideooverlay.cpp +++ b/src/multimedia/platform/gstreamer/common/qgstreamervideooverlay.cpp @@ -59,9 +59,6 @@ struct ElementMap // Ordered by descending priority static constexpr ElementMap elementMap[] = { -#if QT_CONFIG(gstreamer_gl) - { "xcb", "glimagesink" }, -#endif { "xcb", "vaapisink" }, { "xcb", "xvimagesink" }, { "xcb", "ximagesink" }, @@ -334,10 +331,6 @@ static QGstElement findBestVideoSink() // First, try some known video sinks, depending on the Qt platform plugin in use. for (auto i : elementMap) { -#if QT_CONFIG(gstreamer_gl) - if (!QGstUtils::useOpenGL() && qstrcmp(i.gstreamerElement, "glimagesink") == 0) - continue; -#endif if (platform != QLatin1String(i.qtPlatform)) continue; QGstElement choice(i.gstreamerElement, i.gstreamerElement); diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideorenderer.cpp b/src/multimedia/platform/gstreamer/common/qgstreamervideorenderer.cpp index 9a9884079..5de7ee032 100644 --- a/src/multimedia/platform/gstreamer/common/qgstreamervideorenderer.cpp +++ b/src/multimedia/platform/gstreamer/common/qgstreamervideorenderer.cpp @@ -46,8 +46,7 @@ #include <gst/gst.h> QGstreamerVideoRenderer::QGstreamerVideoRenderer(QVideoSink *parent) - : QObject(parent), - m_sink(parent) + : m_sink(parent) { } diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideorenderer_p.h b/src/multimedia/platform/gstreamer/common/qgstreamervideorenderer_p.h index da8eff6cd..2f7bcc72f 100644 --- a/src/multimedia/platform/gstreamer/common/qgstreamervideorenderer_p.h +++ b/src/multimedia/platform/gstreamer/common/qgstreamervideorenderer_p.h @@ -58,20 +58,14 @@ QT_BEGIN_NAMESPACE -class Q_MULTIMEDIA_EXPORT QGstreamerVideoRenderer : public QObject +class Q_MULTIMEDIA_EXPORT QGstreamerVideoRenderer { - Q_OBJECT public: QGstreamerVideoRenderer(QVideoSink *parent = nullptr); virtual ~QGstreamerVideoRenderer(); QGstElement gstVideoSink(); - bool isReady() const { return m_sink != 0; } - -signals: - void readyChanged(bool); - private: QGstElement gstSink; QPointer<QVideoSink> m_sink; diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideosink.cpp b/src/multimedia/platform/gstreamer/common/qgstreamervideosink.cpp index d8a65a771..75a548225 100644 --- a/src/multimedia/platform/gstreamer/common/qgstreamervideosink.cpp +++ b/src/multimedia/platform/gstreamer/common/qgstreamervideosink.cpp @@ -40,6 +40,7 @@ #include "qgstreamervideosink_p.h" #include "qgstreamervideorenderer_p.h" #include <private/qgstutils_p.h> +#include <QtGui/private/qrhi_p.h> #include <QtCore/qdebug.h> @@ -57,6 +58,7 @@ QGstreamerVideoSink::QGstreamerVideoSink(QVideoSink *parent) QGstreamerVideoSink::~QGstreamerVideoSink() { delete m_videoOverlay; + delete m_videoRenderer; } QVideoSink::GraphicsType QGstreamerVideoSink::graphicsType() const @@ -98,6 +100,16 @@ void QGstreamerVideoSink::setWinId(WId id) m_videoOverlay->setWindowHandle(m_windowId); } +void QGstreamerVideoSink::setRhi(QRhi *rhi) +{ + if (rhi && rhi->backend() != QRhi::OpenGLES2) + rhi = nullptr; + if (m_rhi == rhi) + return; + + m_rhi = rhi; +} + bool QGstreamerVideoSink::processSyncMessage(const QGstreamerMessage &message) { return m_videoOverlay->processSyncMessage(message); @@ -205,7 +217,4 @@ void QGstreamerVideoSink::createOverlay() void QGstreamerVideoSink::createRenderer() { m_videoRenderer = new QGstreamerVideoRenderer(sink); - - qCDebug(qLcMediaVideoSink) << Q_FUNC_INFO; - connect(m_videoRenderer, SIGNAL(sinkChanged()), this, SLOT(sinkChanged())); } diff --git a/src/multimedia/platform/gstreamer/common/qgstreamervideosink_p.h b/src/multimedia/platform/gstreamer/common/qgstreamervideosink_p.h index 2b6843694..3142d8de6 100644 --- a/src/multimedia/platform/gstreamer/common/qgstreamervideosink_p.h +++ b/src/multimedia/platform/gstreamer/common/qgstreamervideosink_p.h @@ -78,6 +78,9 @@ public: WId winId() const override; void setWinId(WId id) override; + QRhi *rhi() const { return m_rhi; } + void setRhi(QRhi *rhi) override; + QRect displayRect() const override; void setDisplayRect(const QRect &rect) override; @@ -119,6 +122,7 @@ private: QGstreamerVideoRenderer *m_videoRenderer = nullptr; QVideoSink::GraphicsType m_graphicsType = QVideoSink::Memory; WId m_windowId = 0; + QRhi *m_rhi = nullptr; QRect m_displayRect; bool m_fullScreen = false; mutable QColor m_colorKey = QColor::Invalid; diff --git a/src/multimedia/platform/gstreamer/common/qgstutils.cpp b/src/multimedia/platform/gstreamer/common/qgstutils.cpp index be121bdcd..24bb4a3a1 100644 --- a/src/multimedia/platform/gstreamer/common/qgstutils.cpp +++ b/src/multimedia/platform/gstreamer/common/qgstutils.cpp @@ -250,29 +250,34 @@ QVideoSurfaceFormat QGstUtils::formatForCaps( return QVideoSurfaceFormat(); } -QGstMutableCaps QGstUtils::capsForFormats(const QList<QVideoSurfaceFormat::PixelFormat> &formats) +void QGstMutableCaps::addPixelFormats(const QList<QVideoSurfaceFormat::PixelFormat> &formats, const char *modifier) { - GstCaps *caps = gst_caps_new_empty(); + GValue list = {}; + g_value_init(&list, GST_TYPE_LIST); for (QVideoSurfaceFormat::PixelFormat format : formats) { int index = indexOfVideoFormat(format); - - if (index != -1) { - gst_caps_append_structure(caps, gst_structure_new( - "video/x-raw", - "format" , G_TYPE_STRING, gst_video_format_to_string(qt_videoFormatLookup[index].gstFormat), - nullptr)); - } + if (index == -1) + continue; + GValue item = {}; + + g_value_init(&item, G_TYPE_STRING); + g_value_set_string(&item, gst_video_format_to_string(qt_videoFormatLookup[index].gstFormat)); + gst_value_list_append_value(&list, &item); + g_value_unset(&item); } - - gst_caps_set_simple( - caps, - "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, - nullptr); - - return caps; + QGValue v(&list); + auto *structure = gst_structure_new("video/x-raw", + "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, + nullptr); + gst_structure_set_value(structure, "format", &list); + gst_caps_append_structure(caps, structure); + g_value_unset(&list); + + if (modifier) + gst_caps_set_features(caps, size() - 1, gst_caps_features_from_string(modifier)); } void QGstUtils::setFrameTimeStamps(QVideoFrame *frame, GstBuffer *buffer) @@ -375,12 +380,6 @@ QGRange<float> QGstStructure::frameRateRange() const return {minRate, maxRate}; } -bool QGstUtils::useOpenGL() -{ - static bool result = qEnvironmentVariableIntValue("QT_GSTREAMER_USE_OPENGL_PLUGIN"); - return result; -} - GList *qt_gst_video_sinks() { GList *list = nullptr; diff --git a/src/multimedia/platform/gstreamer/common/qgstutils_p.h b/src/multimedia/platform/gstreamer/common/qgstutils_p.h index 39063b45a..b71f016a4 100644 --- a/src/multimedia/platform/gstreamer/common/qgstutils_p.h +++ b/src/multimedia/platform/gstreamer/common/qgstutils_p.h @@ -78,10 +78,7 @@ namespace QGstUtils { GstCaps *caps, GstVideoInfo *info = 0); - Q_MULTIMEDIA_EXPORT QGstMutableCaps capsForFormats(const QList<QVideoSurfaceFormat::PixelFormat> &formats); void setFrameTimeStamps(QVideoFrame *frame, GstBuffer *buffer); - - Q_MULTIMEDIA_EXPORT bool useOpenGL(); } Q_MULTIMEDIA_EXPORT GList *qt_gst_video_sinks(); diff --git a/src/multimedia/platform/gstreamer/common/qgstvideobuffer.cpp b/src/multimedia/platform/gstreamer/common/qgstvideobuffer.cpp index 711472f29..a345fc8c2 100644 --- a/src/multimedia/platform/gstreamer/common/qgstvideobuffer.cpp +++ b/src/multimedia/platform/gstreamer/common/qgstvideobuffer.cpp @@ -39,23 +39,27 @@ #include "qgstvideobuffer_p.h" -QT_BEGIN_NAMESPACE +#include <gst/video/video.h> +#include <gst/video/gstvideometa.h> + +#include "qgstutils_p.h" + +#if QT_CONFIG(gstreamer_gl) +#include <QtGui/private/qrhi_p.h> +#include <QtGui/private/qrhigles2_p.h> + +#include <gst/gl/gstglconfig.h> +#include <gst/gl/gstglmemory.h> +#endif -QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info) - : QAbstractVideoBuffer(QVideoFrame::NoHandle) - , m_videoInfo(info) - , m_buffer(buffer) -{ - gst_buffer_ref(m_buffer); -} -QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info, - QVideoFrame::HandleType handleType, - const QVariant &handle) - : QAbstractVideoBuffer(handleType) +QT_BEGIN_NAMESPACE + +QGstVideoBuffer::QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info, QRhi *rhi, BufferFormat format) + : QAbstractVideoBuffer(QVideoFrame::NoHandle, rhi) + , bufferFormat(format) , m_videoInfo(info) , m_buffer(buffer) - , m_handle(handle) { gst_buffer_ref(m_buffer); } @@ -116,4 +120,34 @@ void QGstVideoBuffer::unmap() m_mode = QVideoFrame::NotMapped; } +quint64 QGstVideoBuffer::textureHandle(int plane) const +{ + if (plane != 0) + return 0; +#if QT_CONFIG(gstreamer_gl) + if (bufferFormat == GLTexture) { + auto *memory = gst_buffer_peek_memory(m_buffer, 0); + if (gst_is_gl_memory(memory)) { + GstGLMemory *glmem = GST_GL_MEMORY_CAST(memory); + // ### Handle multiple planes + return gst_gl_memory_get_texture_id(glmem); + } + } else if (bufferFormat == VideoGLTextureUploadMeta) { + Q_ASSERT(rhi && rhi->backend() == QRhi::OpenGLES2); + + auto *upload = gst_buffer_get_video_gl_texture_upload_meta(m_buffer); + if (upload) { + rhi->makeThreadLocalNativeContextCurrent(); + // ### Handle multiple planes + guint textures[4]; + gst_video_gl_texture_upload_meta_upload(upload, textures); + return textures[0]; + } else { + qWarning() << "Could not use GstVideoGLTextureUploadMeta"; + } + } +#endif + return 0; +} + QT_END_NAMESPACE diff --git a/src/multimedia/platform/gstreamer/common/qgstvideobuffer_p.h b/src/multimedia/platform/gstreamer/common/qgstvideobuffer_p.h index bcda66cf0..5f5899da3 100644 --- a/src/multimedia/platform/gstreamer/common/qgstvideobuffer_p.h +++ b/src/multimedia/platform/gstreamer/common/qgstvideobuffer_p.h @@ -63,10 +63,17 @@ QT_BEGIN_NAMESPACE class Q_MULTIMEDIA_EXPORT QGstVideoBuffer : public QAbstractVideoBuffer { public: - QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info); - QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info, - QVideoFrame::HandleType handleType, const QVariant &handle); + enum BufferFormat { + Memory, + GLTexture, + VideoGLTextureUploadMeta, + DMABuf + }; + QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info, QRhi *rhi, BufferFormat format); + QGstVideoBuffer(GstBuffer *buffer, const GstVideoInfo &info) + : QGstVideoBuffer(buffer, info, nullptr, Memory) + {} ~QGstVideoBuffer(); GstBuffer *buffer() const { return m_buffer; } @@ -75,8 +82,9 @@ public: MapData map(QVideoFrame::MapMode mode) override; void unmap() override; - QVariant handle() const override { return m_handle; } + quint64 textureHandle(int plane) const override; private: + BufferFormat bufferFormat = Memory; GstVideoInfo m_videoInfo; GstVideoFrame m_frame; GstBuffer *m_buffer = nullptr; diff --git a/src/multimedia/platform/gstreamer/common/qgstvideorenderersink.cpp b/src/multimedia/platform/gstreamer/common/qgstvideorenderersink.cpp index b6b9704dc..8825097f1 100644 --- a/src/multimedia/platform/gstreamer/common/qgstvideorenderersink.cpp +++ b/src/multimedia/platform/gstreamer/common/qgstvideorenderersink.cpp @@ -51,12 +51,15 @@ #include "qgstvideorenderersink_p.h" #include <gst/video/video.h> +#include <gst/video/gstvideometa.h> #include "qgstutils_p.h" #if QT_CONFIG(gstreamer_gl) -#include <QOpenGLContext> +#include <QtGui/private/qrhi_p.h> +#include <QtGui/private/qrhigles2_p.h> #include <QGuiApplication> +#include <QtGui/qopenglcontext.h> #include <QWindow> #include <qpa/qplatformnativeinterface.h> @@ -77,24 +80,30 @@ QT_BEGIN_NAMESPACE -QGstVideoRenderer::QGstVideoRenderer() = default; +QGstVideoRenderer::QGstVideoRenderer(QVideoSink *sink) + : m_sink(sink) +{ +} QGstVideoRenderer::~QGstVideoRenderer() = default; QGstMutableCaps QGstVideoRenderer::getCaps() { + QGstMutableCaps caps; + caps.create(); + // All the formats that both we and gstreamer support #if QT_CONFIG(gstreamer_gl) - if (QGstUtils::useOpenGL()) { - m_handleType = QVideoFrame::RhiTextureHandle; + QRhi *rhi = m_sink->rhi(); + if (rhi->backend() == QRhi::OpenGLES2) { auto formats = QList<QVideoSurfaceFormat::PixelFormat>() - << QVideoSurfaceFormat::Format_YUV420P - << QVideoSurfaceFormat::Format_YUV422P - << QVideoSurfaceFormat::Format_YV12 +// << QVideoSurfaceFormat::Format_YUV420P +// << QVideoSurfaceFormat::Format_YUV422P +// << QVideoSurfaceFormat::Format_YV12 << QVideoSurfaceFormat::Format_UYVY << QVideoSurfaceFormat::Format_YUYV - << QVideoSurfaceFormat::Format_NV12 - << QVideoSurfaceFormat::Format_NV21 +// << QVideoSurfaceFormat::Format_NV12 +// << QVideoSurfaceFormat::Format_NV21 << QVideoSurfaceFormat::Format_AYUV444 << QVideoSurfaceFormat::Format_YUV444 // << QVideoSurfaceFormat::Format_P010LE @@ -105,8 +114,8 @@ QGstMutableCaps QGstVideoRenderer::getCaps() << QVideoSurfaceFormat::Format_ARGB32 << QVideoSurfaceFormat::Format_ABGR32 << QVideoSurfaceFormat::Format_BGRA32 - << QVideoSurfaceFormat::Format_RGB555 - << QVideoSurfaceFormat::Format_BGR555 +// << QVideoSurfaceFormat::Format_RGB555 +// << QVideoSurfaceFormat::Format_BGR555 // << QVideoSurfaceFormat::Format_Y16 // << QVideoSurfaceFormat::Format_RGB24 // << QVideoSurfaceFormat::Format_BGR24 @@ -116,14 +125,10 @@ QGstMutableCaps QGstVideoRenderer::getCaps() // glupload will be added to the pipeline and GLMemory will be requested. // This will lead to upload data to gl textures // and download it when the buffer will be used within rendering. - if (!formats.isEmpty()) { - QGstMutableCaps caps = QGstUtils::capsForFormats(formats); - for (int i = 0; i < caps.size(); ++i) - gst_caps_set_features(caps.get(), i, gst_caps_features_from_string(GST_CAPS_FEATURE_MEMORY_GL_MEMORY)); - - return caps; - } - m_handleType = QVideoFrame::NoHandle; + caps.addPixelFormats(formats, GST_CAPS_FEATURE_MEMORY_GL_MEMORY); + // ### needs more work, somehow casting the GstBuffer to texture upload meta + // fails. In addition, the texture upload seems to be broken for VAAPI decoders +// caps.addPixelFormats(formats, GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META); } #endif auto formats = QList<QVideoSurfaceFormat::PixelFormat>() @@ -150,13 +155,25 @@ QGstMutableCaps QGstVideoRenderer::getCaps() << QVideoSurfaceFormat::Format_RGB24 << QVideoSurfaceFormat::Format_BGR24 << QVideoSurfaceFormat::Format_RGB565; - return QGstUtils::capsForFormats(formats); + caps.addPixelFormats(formats); + qDebug() << "CAPS:" << caps.toString(); + return caps; } bool QGstVideoRenderer::start(GstCaps *caps) { m_flushed = true; m_format = QGstUtils::formatForCaps(caps, &m_videoInfo); +// qDebug() << "START:" << QGstCaps(caps).toString(); +// qDebug() << m_format; + + auto *features = gst_caps_get_features(caps, 0); + if (gst_caps_features_contains(features, GST_CAPS_FEATURE_MEMORY_GL_MEMORY)) + bufferFormat = QGstVideoBuffer::GLTexture; + else if (gst_caps_features_contains(features, GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META)) + bufferFormat = QGstVideoBuffer::VideoGLTextureUploadMeta; + else if (gst_caps_features_contains(features, "memory:DMABuf")) + bufferFormat = QGstVideoBuffer::DMABuf; return m_format.isValid(); } @@ -170,17 +187,7 @@ bool QGstVideoRenderer::present(QVideoSink *sink, GstBuffer *buffer) { m_flushed = false; - QGstVideoBuffer *videoBuffer = nullptr; -#if QT_CONFIG(gstreamer_gl) - if (m_handleType == QVideoFrame::RhiTextureHandle) { - GstGLMemory *glmem = GST_GL_MEMORY_CAST(gst_buffer_peek_memory(buffer, 0)); - guint textureId = gst_gl_memory_get_texture_id(glmem); - videoBuffer = new QGstVideoBuffer(buffer, m_videoInfo, m_handleType, textureId); - } -#endif - - if (!videoBuffer) - videoBuffer = new QGstVideoBuffer(buffer, m_videoInfo); + QGstVideoBuffer *videoBuffer = new QGstVideoBuffer(buffer, m_videoInfo, m_sink->rhi(), bufferFormat); auto meta = gst_buffer_get_video_crop_meta (buffer); if (meta) { @@ -216,7 +223,7 @@ bool QGstVideoRenderer::proposeAllocation(GstQuery *) QVideoSurfaceGstDelegate::QVideoSurfaceGstDelegate(QVideoSink *sink) : m_sink(sink) { - m_renderer = new QGstVideoRenderer; + m_renderer = new QGstVideoRenderer(sink); updateSupportedFormats(); connect(m_sink, SIGNAL(supportedFormatsChanged()), this, SLOT(updateSupportedFormats())); } @@ -240,6 +247,7 @@ QGstMutableCaps QVideoSurfaceGstDelegate::caps() bool QVideoSurfaceGstDelegate::start(GstCaps *caps) { +// qDebug() << "QVideoSurfaceGstDelegate::start" << QGstCaps(caps).toString(); QMutexLocker locker(&m_mutex); if (m_activeRenderer) { @@ -332,8 +340,12 @@ GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer) #if QT_CONFIG(gstreamer_gl) static GstGLContext *gstGLDisplayContext(QVideoSink *sink) { - auto glContext = qobject_cast<QOpenGLContext*>(sink->property("GLContext").value<QObject*>()); - // Context is not ready yet. + QRhi *rhi = sink->rhi(); + if (!rhi || rhi->backend() != QRhi::OpenGLES2) + return nullptr; + + auto *nativeHandles = static_cast<const QRhiGles2NativeHandles *>(rhi->nativeHandles()); + auto glContext = nativeHandles->context; if (!glContext) return nullptr; @@ -427,7 +439,7 @@ bool QVideoSurfaceGstDelegate::query(GstQuery *query) gst_query_set_context(query, context); gst_context_unref(context); - return m_gstGLDisplayContext; + return true; } #else Q_UNUSED(query); @@ -563,7 +575,7 @@ QGstVideoRendererSink *QGstVideoRendererSink::createSink(QVideoSink *sink) QGstVideoRendererSink *gstSink = reinterpret_cast<QGstVideoRendererSink *>( g_object_new(QGstVideoRendererSink::get_type(), nullptr)); - g_signal_connect(G_OBJECT(sink), "notify::show-preroll-frame", G_CALLBACK(handleShowPrerollChange), sink); + g_signal_connect(G_OBJECT(gstSink), "notify::show-preroll-frame", G_CALLBACK(handleShowPrerollChange), gstSink); return gstSink; } diff --git a/src/multimedia/platform/gstreamer/common/qgstvideorenderersink_p.h b/src/multimedia/platform/gstreamer/common/qgstvideorenderersink_p.h index aadf1fb78..6833b468d 100644 --- a/src/multimedia/platform/gstreamer/common/qgstvideorenderersink_p.h +++ b/src/multimedia/platform/gstreamer/common/qgstvideorenderersink_p.h @@ -62,7 +62,7 @@ #include <QtCore/qwaitcondition.h> #include <qvideosurfaceformat.h> #include <qvideoframe.h> - +#include <private/qgstvideobuffer_p.h> #include <private/qgst_p.h> #if QT_CONFIG(gstreamer_gl) @@ -78,7 +78,7 @@ class QVideoSink; class QGstVideoRenderer { public: - QGstVideoRenderer(); + QGstVideoRenderer(QVideoSink *sink); ~QGstVideoRenderer(); QGstMutableCaps getCaps(); @@ -91,10 +91,11 @@ public: void flush(QVideoSink *surface); private: + QVideoSink *m_sink = nullptr; QVideoSurfaceFormat m_format; GstVideoInfo m_videoInfo; bool m_flushed = true; - QVideoFrame::HandleType m_handleType = QVideoFrame::NoHandle; + QGstVideoBuffer::BufferFormat bufferFormat = QGstVideoBuffer::Memory; }; class QVideoSurfaceGstDelegate : public QObject diff --git a/src/multimedia/platform/qplatformvideosink_p.h b/src/multimedia/platform/qplatformvideosink_p.h index faa0f6d77..d519f17f0 100644 --- a/src/multimedia/platform/qplatformvideosink_p.h +++ b/src/multimedia/platform/qplatformvideosink_p.h @@ -64,6 +64,8 @@ public: virtual WId winId() const = 0; virtual void setWinId(WId id) = 0; + virtual void setRhi(QRhi */*rhi*/) {} + virtual QRect displayRect() const = 0; virtual void setDisplayRect(const QRect &rect) = 0; diff --git a/src/multimedia/video/qabstractvideobuffer.cpp b/src/multimedia/video/qabstractvideobuffer.cpp index bfb97a8fd..db43beb81 100644 --- a/src/multimedia/video/qabstractvideobuffer.cpp +++ b/src/multimedia/video/qabstractvideobuffer.cpp @@ -104,8 +104,9 @@ QT_BEGIN_NAMESPACE /*! Constructs an abstract video buffer of the given \a type. */ -QAbstractVideoBuffer::QAbstractVideoBuffer(QVideoFrame::HandleType type) - : m_type(type) +QAbstractVideoBuffer::QAbstractVideoBuffer(QVideoFrame::HandleType type, QRhi *rhi) + : m_type(type), + rhi(rhi) { } @@ -173,17 +174,12 @@ QVideoFrame::HandleType QAbstractVideoBuffer::handleType() const \sa map() */ -/*! - Returns a type specific handle to the data buffer. +/*! \fn quint64 QAbstractVideoBuffer::textureHandle(QRhi *rhi, int plane) const - The type of the handle is given by handleType() function. + Returns a texture handle to the data buffer. \sa handleType() */ -QVariant QAbstractVideoBuffer::handle() const -{ - return QVariant(); -} /*! \fn int QAbstractPlanarVideoBuffer::map(MapMode mode, int *numBytes, int bytesPerLine[4], uchar *data[4]) diff --git a/src/multimedia/video/qabstractvideobuffer_p.h b/src/multimedia/video/qabstractvideobuffer_p.h index e3a0fb86c..a82f13723 100644 --- a/src/multimedia/video/qabstractvideobuffer_p.h +++ b/src/multimedia/video/qabstractvideobuffer_p.h @@ -60,11 +60,12 @@ QT_BEGIN_NAMESPACE class QVariant; +class QRhi; class Q_MULTIMEDIA_EXPORT QAbstractVideoBuffer { public: - QAbstractVideoBuffer(QVideoFrame::HandleType type); + QAbstractVideoBuffer(QVideoFrame::HandleType type, QRhi *rhi = nullptr); virtual ~QAbstractVideoBuffer(); QVideoFrame::HandleType handleType() const; @@ -81,11 +82,11 @@ public: virtual MapData map(QVideoFrame::MapMode mode) = 0; virtual void unmap() = 0; - virtual QVariant handle() const; virtual quint64 textureHandle(int /*plane*/) const { return 0; } protected: QVideoFrame::HandleType m_type; + QRhi *rhi = nullptr; private: Q_DISABLE_COPY(QAbstractVideoBuffer) diff --git a/src/multimedia/video/qvideoframe.cpp b/src/multimedia/video/qvideoframe.cpp index 375f19930..2fa5f9f88 100644 --- a/src/multimedia/video/qvideoframe.cpp +++ b/src/multimedia/video/qvideoframe.cpp @@ -808,21 +808,13 @@ int QVideoFrame::planeCount() const return d->format.nPlanes(); } -quint64 QVideoFrame::textureHandle(int plane) -{ - return d->buffer->textureHandle(plane); -} - /*! - Returns a type specific handle to a video frame's buffer. - - For an OpenGL texture this would be the texture ID. - - \sa QAbstractVideoBuffer::handle() + \internal + Returns a texture id to the video frame's buffers. */ -QVariant QVideoFrame::handle() const +quint64 QVideoFrame::textureHandle(int plane) { - return d->buffer != nullptr ? d->buffer->handle() : QVariant(); + return d->buffer->textureHandle(plane); } /*! diff --git a/src/multimedia/video/qvideoframe.h b/src/multimedia/video/qvideoframe.h index 5e90b6ca1..ea01ccb92 100644 --- a/src/multimedia/video/qvideoframe.h +++ b/src/multimedia/video/qvideoframe.h @@ -115,8 +115,6 @@ public: quint64 textureHandle(int plane); - QVariant handle() const; - qint64 startTime() const; void setStartTime(qint64 time); diff --git a/src/multimedia/video/qvideosink.cpp b/src/multimedia/video/qvideosink.cpp index f5112b173..b996392b4 100644 --- a/src/multimedia/video/qvideosink.cpp +++ b/src/multimedia/video/qvideosink.cpp @@ -126,7 +126,10 @@ QRhi *QVideoSink::rhi() const void QVideoSink::setRhi(QRhi *rhi) { + if (d->rhi == rhi) + return; d->rhi = rhi; + d->videoSink->setRhi(rhi); } void QVideoSink::setFullScreen(bool fullscreen) diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp index fad92bc5f..a45350fdc 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_render.cpp @@ -62,12 +62,6 @@ QDeclarativeVideoBackend::QDeclarativeVideoBackend(QDeclarativeVideoOutput *pare : q(parent), m_frameChanged(false) { - m_sink = new QVideoSink(q); - m_sink->setRhi(QQuickWindowPrivate::get(q->window())->rhi); - qRegisterMetaType<QVideoSurfaceFormat>(); - QObject::connect(m_sink, SIGNAL(newVideoFrame(const QVideoFrame &)), - q, SLOT(_q_newFrame(const QVideoFrame &)), Qt::QueuedConnection); - // Prioritize the plugin requested by the environment QString requestedVideoNode = QString::fromLatin1(qgetenv("QT_VIDEONODE")); @@ -324,6 +318,13 @@ QSGNode *QDeclarativeVideoBackend::updatePaintNode(QSGNode *oldNode, QVideoSink *QDeclarativeVideoBackend::videoSink() const { + if (!m_sink) { + m_sink = new QVideoSink(q); + m_sink->setRhi(QQuickWindowPrivate::get(q->window())->rhi); + qRegisterMetaType<QVideoSurfaceFormat>(); + QObject::connect(m_sink, SIGNAL(newVideoFrame(const QVideoFrame &)), + q, SLOT(_q_newFrame(const QVideoFrame &)), Qt::QueuedConnection); + } return m_sink; } diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h b/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h index 68c73f0c6..95b3f1ebd 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput_render_p.h @@ -95,7 +95,7 @@ private: QDeclarativeVideoOutput *q; QList<QSGVideoNodeFactoryInterface*> m_videoNodeFactories; - QVideoSink *m_sink; + mutable QVideoSink *m_sink = nullptr; QVideoSurfaceFormat m_surfaceFormat; QVideoFrame m_frame; diff --git a/src/qtmultimediaquicktools/qsgvideonode_texture.cpp b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp index cc345d61a..70abf5b90 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_texture.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_texture.cpp @@ -185,7 +185,7 @@ void QSGVideoMaterialRhiShader_Texture::updateSampledImage(RenderState &state, i m->m_frameMutex.lock(); auto size = m->m_frame.size(); if (m->m_frame.isValid()) - m->m_textureId = m->m_frame.handle().toULongLong(); + m->m_textureId = m->m_frame.textureHandle(0); m->m_frameMutex.unlock(); m->m_texture->setNativeObject(m->m_textureId, size); diff --git a/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp b/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp index efefaf0f1..182e98610 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp @@ -354,12 +354,12 @@ void QSGVideoMaterialRhiShader_NV12::mapFrame(QSGVideoMaterial_YUV *m) if (m->m_frame.handleType() == QVideoFrame::RhiTextureHandle) { m->m_planeWidth[0] = m->m_planeWidth[1] = 1; - auto textures = m->m_frame.handle().toList(); - if (!textures.isEmpty()) { + quint64 textures[2] = { m->m_frame.textureHandle(0), m->m_frame.textureHandle(1) }; + if (textures[0] && textures[1]) { auto w = m->m_frame.size().width(); auto h = m->m_frame.size().height(); - m->m_textures[0]->setNativeObject(textures[0].toULongLong(), {w, h}, QRhiTexture::R8); - m->m_textures[1]->setNativeObject(textures[1].toULongLong(), {w / 2, h / 2}, QRhiTexture::RG8); + m->m_textures[0]->setNativeObject(textures[0], {w, h}, QRhiTexture::R8); + m->m_textures[1]->setNativeObject(textures[1], {w / 2, h / 2}, QRhiTexture::RG8); } else { qWarning() << "NV12/NV21 requires 2 textures"; } @@ -367,8 +367,12 @@ void QSGVideoMaterialRhiShader_NV12::mapFrame(QSGVideoMaterial_YUV *m) return; } - if (!m->m_frame.map(QVideoFrame::ReadOnly)) + if (!m->m_frame.map(QVideoFrame::ReadOnly)) { + qWarning()<< "NV12: Couldn't map frame"; + m->m_textures[0]->setData(QRhiTexture::RG8, QSize(1, 1), (const uchar *)"\0\0", 2); + m->m_textures[1]->setData(QRhiTexture::BGRA8, QSize(1, 1), (const uchar *)"\0\0\0\0", 4); return; + } int y = 0; int uv = 1; @@ -392,12 +396,12 @@ void QSGVideoMaterialRhiShader_P010::mapFrame(QSGVideoMaterial_YUV *m) if (m->m_frame.handleType() == QVideoFrame::RhiTextureHandle) { m->m_planeWidth[0] = m->m_planeWidth[1] = 1; - auto textures = m->m_frame.handle().toList(); - if (!textures.isEmpty()) { + quint64 textures[2] = { m->m_frame.textureHandle(0), m->m_frame.textureHandle(1) }; + if (textures[0] && textures[1]) { auto w = m->m_frame.size().width(); auto h = m->m_frame.size().height(); - m->m_textures[0]->setNativeObject(textures[0].toULongLong(), {w, h}, QRhiTexture::RG8); - m->m_textures[1]->setNativeObject(textures[1].toULongLong(), {w / 2, h / 2}, QRhiTexture::BGRA8); + m->m_textures[0]->setNativeObject(textures[0], {w, h}, QRhiTexture::RG8); + m->m_textures[1]->setNativeObject(textures[1], {w / 2, h / 2}, QRhiTexture::BGRA8); } else { qWarning() << "P010/P016 requires 2 textures"; } @@ -405,8 +409,12 @@ void QSGVideoMaterialRhiShader_P010::mapFrame(QSGVideoMaterial_YUV *m) return; } - if (!m->m_frame.map(QVideoFrame::ReadOnly)) + if (!m->m_frame.map(QVideoFrame::ReadOnly)) { + qWarning()<< "NV12: Couldn't map frame"; + m->m_textures[0]->setData(QRhiTexture::RG8, QSize(1, 1), (const uchar *)"\0\0", 2); + m->m_textures[1]->setData(QRhiTexture::BGRA8, QSize(1, 1), (const uchar *)"\0\0\0\0", 4); return; + } int y = 0; int uv = 1; diff --git a/tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp b/tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp index cd6e756ab..94594ba99 100644 --- a/tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp +++ b/tests/auto/unit/multimedia/qabstractvideobuffer/tst_qabstractvideobuffer.cpp @@ -121,7 +121,7 @@ void tst_QAbstractVideoBuffer::handle() { QtTestVideoBuffer buffer(QVideoFrame::NoHandle); - QVERIFY(buffer.handle().isNull()); + QVERIFY(buffer.textureHandle(0) == 0); } void tst_QAbstractVideoBuffer::mapMode() diff --git a/tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp b/tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp index 6db33c7f6..588162085 100644 --- a/tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp +++ b/tests/auto/unit/multimedia/qvideoframe/tst_qvideoframe.cpp @@ -195,7 +195,7 @@ void tst_QVideoFrame::create() QVERIFY(frame.isValid()); QCOMPARE(frame.handleType(), QVideoFrame::NoHandle); - QCOMPARE(frame.handle(), QVariant()); + QCOMPARE(frame.textureHandle(0), 0); QCOMPARE(frame.pixelFormat(), pixelFormat); QCOMPARE(frame.size(), size); QCOMPARE(frame.width(), size.width()); @@ -234,7 +234,7 @@ void tst_QVideoFrame::createInvalid() QVERIFY(!frame.isValid()); QCOMPARE(frame.handleType(), QVideoFrame::NoHandle); - QCOMPARE(frame.handle(), QVariant()); + QCOMPARE(frame.textureHandle(0), 0); QCOMPARE(frame.pixelFormat(), pixelFormat); QCOMPARE(frame.size(), size); QCOMPARE(frame.width(), size.width()); |