From 702e0498ae941a7ac6937af823b0195a770c6ccf Mon Sep 17 00:00:00 2001 From: Mehran Dehghanian Date: Wed, 3 Aug 2022 17:34:10 +0430 Subject: [PATCH] Added sample player for project --- QtApp/README.md | 2 + QtApp/VideoItem.h | 28 +++++++++++++ QtApp/main.cpp | 58 ++++++++++++++++++++++++++ QtApp/main.qml | 47 +++++++++++++++++++++ QtApp/qml.qrc | 5 +++ QtApp/test.pro | 42 +++++++++++++++++++ QtApp/videoitem.cpp | 78 +++++++++++++++++++++++++++++++++++ QtApp/videosurface.cpp | 26 ++++++++++++ QtApp/videosurface.h | 25 +++++++++++ QtApp/videosurfaceprivate.cpp | 0 QtApp/videosurfaceprivate.h | 17 ++++++++ 11 files changed, 328 insertions(+) create mode 100755 QtApp/README.md create mode 100755 QtApp/VideoItem.h create mode 100755 QtApp/main.cpp create mode 100755 QtApp/main.qml create mode 100755 QtApp/qml.qrc create mode 100755 QtApp/test.pro create mode 100755 QtApp/videoitem.cpp create mode 100755 QtApp/videosurface.cpp create mode 100755 QtApp/videosurface.h create mode 100755 QtApp/videosurfaceprivate.cpp create mode 100755 QtApp/videosurfaceprivate.h diff --git a/QtApp/README.md b/QtApp/README.md new file mode 100755 index 0000000..94a15e7 --- /dev/null +++ b/QtApp/README.md @@ -0,0 +1,2 @@ +# qt-gstreamer +Video rendering using gstreamer over Qt5 surface (QML) using qtquick2videosink diff --git a/QtApp/VideoItem.h b/QtApp/VideoItem.h new file mode 100755 index 0000000..dc2776e --- /dev/null +++ b/QtApp/VideoItem.h @@ -0,0 +1,28 @@ +#ifndef VIDEOITEM_H +#define VIDEOITEM_H +#include +#include +#include +#include +#include +#include +#include +#include "VideoItem.h" +#include "videosurface.h" + +class VideoSurface; +class VideoItem: public QQuickItem{ + Q_OBJECT + Q_PROPERTY(VideoSurface* surface READ surface WRITE setSurface) +public: + explicit VideoItem(QQuickItem *parent = 0); + virtual ~VideoItem(); + + VideoSurface *surface(); + void setSurface(VideoSurface *surface); + virtual QSGNode* updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *UpdatePaintNodeData); + struct Private; + Private* const d; +}; + +#endif // VIDEOITEM_H diff --git a/QtApp/main.cpp b/QtApp/main.cpp new file mode 100755 index 0000000..47b3d7a --- /dev/null +++ b/QtApp/main.cpp @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +int main(int argc, char *argv[]) +{ + gst_init(NULL, NULL); + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + + QGuiApplication app(argc, argv); + qmlRegisterType("VideoItem", 1, 0,"VideoItem"); + + GstElement *pipeline = gst_pipeline_new(NULL); + GstElement *testsrc = gst_element_factory_make("videotestsrc", NULL); + GstElement *videoconvert = gst_element_factory_make("videoconvert", NULL); + GstElement *videosink = gst_element_factory_make("qt5videosink", NULL); + GstElement *testsrc1 = gst_element_factory_make("videotestsrc", NULL); + GstElement *videoconvert1 = gst_element_factory_make("videoconvert", NULL); + GstElement *videosink1 = gst_element_factory_make("qt5videosink", NULL); + QQmlApplicationEngine engine; + +// QGLContext *gl; +// QGLContext::create(gl); +// gl->currentContext(); + //engine.rootContext()->setContextProperty((QString)QGLContext::currentContext(),NULL); + +// g_object_set(G_OBJECT(videosink),"glcontext",(GValue *)QGLContext::currentContext(), NULL); +// gl->doneCurrent(); + VideoSurface *surface = new VideoSurface; + videosink = surface->videoSink(); + engine.rootContext()->setContextProperty(QLatin1String("videoSurface1"), surface); + VideoSurface *surface1 = new VideoSurface; + videosink1 = surface1->videoSink(); + engine.rootContext()->setContextProperty(QLatin1String("videoSurface2"), surface1); + + gst_bin_add_many(GST_BIN(pipeline), testsrc, videoconvert, videosink, testsrc1, videoconvert1, videosink1, NULL); + gst_element_link_many(testsrc, videoconvert, videosink, NULL); + gst_element_link_many(testsrc1, videoconvert1, videosink1, NULL); + + + engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); + if (engine.rootObjects().isEmpty()) + return -1; + gst_element_set_state(pipeline, GST_STATE_PLAYING); + return app.exec(); +} diff --git a/QtApp/main.qml b/QtApp/main.qml new file mode 100755 index 0000000..db799cf --- /dev/null +++ b/QtApp/main.qml @@ -0,0 +1,47 @@ +import QtQuick 2.9 +import QtQuick.Controls 2.12 +import QtQuick.Window 2.2 +import VideoItem 1.0 +import QtMultimedia 5.12 + +Window { + visible: true + width: 640 + height: 480 + title: qsTr("Hello World") + + VideoItem{ + id: video + + width: 300 + height: 300 + surface: videoSurface1 + z: 3 + } + + VideoItem{ + id: video1 + x: 300 + y: 300 + width: 300 + height: 300 + surface: videoSurface2 + z: 3 + } + +// MediaPlayer{ +// id: mediaplayer +// source: "gst-pipeline: videotestsrc ! xvimagesink name=\"qtvideosink\"" +// autoPlay: true +// } + +// VideoOutput{ +// source: mediaplayer +// width: 800 +// height: 800 + +// Label{ +// text: "2323232" +// } +// } +} diff --git a/QtApp/qml.qrc b/QtApp/qml.qrc new file mode 100755 index 0000000..5f6483a --- /dev/null +++ b/QtApp/qml.qrc @@ -0,0 +1,5 @@ + + + main.qml + + diff --git a/QtApp/test.pro b/QtApp/test.pro new file mode 100755 index 0000000..3699fac --- /dev/null +++ b/QtApp/test.pro @@ -0,0 +1,42 @@ +QT += quick +CONFIG += c++11 +QT += opengl +QT += core +# The following define makes your compiler emit warnings if you use +# any feature of Qt which as been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +# You can also make your code fail to compile if you use deprecated APIs. +# In order to do so, uncomment the following line. +# You can also select to disable deprecated APIs only up to a certain version of Qt. +#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 + +SOURCES += main.cpp \ + videoitem.cpp \ + videosurface.cpp \ + videosurfaceprivate.cpp + +RESOURCES += qml.qrc + +CONFIG += link_pkgconfig + + +PKGCONFIG += gstreamer-1.0 + +# Additional import path used to resolve QML modules in Qt Creator's code model +QML_IMPORT_PATH = + +# Additional import path used to resolve QML modules just for Qt Quick Designer +QML_DESIGNER_IMPORT_PATH = + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target + +HEADERS += \ + videosurface.h \ + videosurfaceprivate.h \ + VideoItem.h diff --git a/QtApp/videoitem.cpp b/QtApp/videoitem.cpp new file mode 100755 index 0000000..7dc14c2 --- /dev/null +++ b/QtApp/videoitem.cpp @@ -0,0 +1,78 @@ +#include "VideoItem.h" + +struct VideoItem::Private{ + QPointer surface; + bool surfaceDirty; + QRectF targetArea; +}; + +VideoItem::VideoItem(QQuickItem *parent): QQuickItem(parent), d(new Private){ + d->surfaceDirty = true; + setFlag(QQuickItem::ItemHasContents, true); +} + +VideoItem::~VideoItem(){ + setSurface(0); + delete d; +} + +VideoSurface *VideoItem::surface(){ + return d->surface.data(); +} + +void VideoItem::setSurface(VideoSurface *surface) +{ + if(d->surface){ + d->surface.data()->d->items.remove(this); + } + d->surface = surface; + d->surfaceDirty = true; + + if(d->surface){ + d->surface.data()->d->items.insert(this); + } +} + +QSGNode* VideoItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *UpdatePaintNodeData){ + + Q_UNUSED(UpdatePaintNodeData); + QRectF r = boundingRect(); + QSGNode* newNode = 0; + + if(d->surfaceDirty){ + delete oldNode; + oldNode = 0; + d->surfaceDirty = false; + } + + if(!d->surface || d->surface.data()->d->videosink == NULL ){ + if(!oldNode){ + QSGFlatColorMaterial *material = new QSGFlatColorMaterial; + material->setColor(Qt::black); + QSGGeometryNode *node = new QSGGeometryNode; + node->setMaterial(material); + node->setFlag(QSGNode::OwnsMaterial); + node->setFlag(QSGNode::OwnsGeometry); + newNode = node; + d->targetArea = QRectF(); + }else{ + newNode = oldNode; + } + if( r != d->targetArea ){ + QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 4); + geometry->vertexDataAsPoint2D()[0].set(r.x(),r.y()); + geometry->vertexDataAsPoint2D()[1].set(r.x(), r.height()); + geometry->vertexDataAsPoint2D()[2].set(r.width(), r.y()); + geometry->vertexDataAsPoint2D()[3].set(r.width(), r.height()); + QSGGeometryNode *node = static_cast(newNode); + node->setGeometry(geometry); + d->targetArea = r; + } + } else { + g_signal_emit_by_name(d->surface.data()->d->videosink,"update-node", (void *)oldNode, r.x(), r.y(), r.width(), r.height(), (void**)&newNode); + } + + return newNode; +} + + diff --git a/QtApp/videosurface.cpp b/QtApp/videosurface.cpp new file mode 100755 index 0000000..60c4aef --- /dev/null +++ b/QtApp/videosurface.cpp @@ -0,0 +1,26 @@ +#include "videosurface.h" + +VideoSurface::VideoSurface(QObject *parent): QObject(parent), d(new VideoSurfacePrivate){ + +} + +VideoSurface:: ~VideoSurface(){ + delete d; +} +void VideoSurface::onUpdate(){ + Q_FOREACH(QQuickItem *item, d->items){ + item->update(); + } +} +void VideoSurface::onUpdateThunk(GstElement *sink, gpointer data){ + Q_UNUSED(sink); + VideoSurface *pThis = (VideoSurface *)data; + pThis->onUpdate(); +} +GstElement *VideoSurface::videoSink(){ + d->videosink = gst_element_factory_make("qtquick2videosink", NULL); + g_signal_connect(d->videosink,"update",G_CALLBACK(onUpdateThunk),(void *)this); + return d->videosink; +} + + diff --git a/QtApp/videosurface.h b/QtApp/videosurface.h new file mode 100755 index 0000000..42b8cb9 --- /dev/null +++ b/QtApp/videosurface.h @@ -0,0 +1,25 @@ +#ifndef VIDEOSURFACE_H +#define VIDEOSURFACE_H +#include +#include +#include +#include +#include +#include +#include +#include "videosurfaceprivate.h" + + +class VideoSurface: public QObject{ + Q_OBJECT + Q_DISABLE_COPY(VideoSurface) +public: + explicit VideoSurface(QObject *parent = 0); + virtual ~VideoSurface(); + GstElement *videoSink(); + void onUpdate(); + static void onUpdateThunk(GstElement* sink, gpointer data); + VideoSurfacePrivate *const d; +}; + +#endif // VIDEOSURFACE_H diff --git a/QtApp/videosurfaceprivate.cpp b/QtApp/videosurfaceprivate.cpp new file mode 100755 index 0000000..e69de29 diff --git a/QtApp/videosurfaceprivate.h b/QtApp/videosurfaceprivate.h new file mode 100755 index 0000000..32ff7f6 --- /dev/null +++ b/QtApp/videosurfaceprivate.h @@ -0,0 +1,17 @@ +#ifndef VIDEOSURFACEPRIVATE_H +#define VIDEOSURFACEPRIVATE_H +#include +#include +#include "videosurface.h" +#include "VideoItem.h" +class VideoItem; +class VideoSurfacePrivate { +public: + VideoSurfacePrivate(): videosink(NULL){} + QSet items; + GstElement* videosink; +}; + + + +#endif // VIDEOSURFACEPRIVATE_H