Reputation: 926
I'm new to Qt and GStreamer, but I need to create a simple player for a QuickTime/H.264 video file into a Qt 5.15.2 application (running on Linux Ubuntu 20.04 (Focal Fossa)).
I managed to play a standard videotestsrc
(bouncing ball pattern) inside my application, and this is the code (main.cpp
):
#include "mainwindow.h"
#include <QApplication>
#include <QQuickView>
#include <QWidget>
#include <QQuickItem>
#include <gst/gst.h>
int main(int argc, char *argv[])
{
GstElement* mPipeline = nullptr;
GstElement* mSource = nullptr;
GstElement* mGLUpload = nullptr;
GstElement* mSink = nullptr;
QQuickView* mView = nullptr;
QWidget* mWidget = nullptr;
QQuickItem* mItem = nullptr;
gst_init(argc, argv);
QApplication app(argc, argv);
MainWindow* window = new MainWindow;
mPipeline = gst_pipeline_new(NULL);
mSource = gst_element_factory_make("videotestsrc", NULL);
mGLUpload = gst_element_factory_make("glupload", NULL);
mSink = gst_element_factory_make("qmlglsink", NULL);
gst_bin_add_many(GST_BIN (mPipeline), mSource, mGLUpload, mSink, NULL);
gst_element_link_many(mSource, mGLUpload, mSink, NULL);
g_object_set(mSource, "pattern", 18, NULL);
mView = new QQuickView;
mView->scheduleRenderJob(new SetPlaying (mPipeline),
QQuickView::BeforeSynchronizingStage);
mView->setSource(QUrl(QStringLiteral("qrc:/video.qml")));
mWidget = QWidget::createWindowContainer(mView, parent);
mItem = mView->findChild<QQuickItem*>("videoItem");
window->setCentralWidget(mWidget);
window->show();
ret = app.exec();
g_object_set(mSink, "widget", mItem, NULL);
gst_deinit();
}
SetPlaying class...
#include <QRunnable>
#include <gst/gst.h>
class SetPlaying : public QRunnable
{
public:
SetPlaying(GstElement *pipeline) {
this->pipeline_ = pipeline ? static_cast<GstElement *> (gst_object_ref (pipeline)) : NULL;
}
~SetPlaying() {
if (this->pipeline_)
gst_object_unref (this->pipeline_);
}
void run () {
if (this->pipeline_)
gst_element_set_state (this->pipeline_, GST_STATE_PLAYING);
}
private:
GstElement * pipeline_;
};
The MainWindow
code should not be relevant for the issue management (it's a standard empty window).
This is the source code of the only .qml
item that's needed to provide an acceptable widget surface to qmlglsink
:
import QtQuick 2.15
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.3
import QtQuick.Dialogs 1.2
import QtQuick.Window 2.1
import org.freedesktop.gstreamer.GLVideoItem 1.0
Item {
anchors.fill: parent
GstGLVideoItem {
id: video
objectName: "videoItem"
anchors.centerIn: parent
width: parent.width
height: parent.height
}
}
Now since the actual pipeline to plays the file is quite long and complex to manage the @ code I opted to use a gst_parse_launch()
approach.
To proceed step by step, I tried to use such a method to create a videotestsrc
pipeline, i.e.:
mPipeline = gst_parse_launch( "videotestsrc ! glupload ! qmlglsink", NULL);
mSink = gst_bin_get_by_name(GST_BIN(mPipeline), "sink");
mSource = gst_bin_get_by_name(GST_BIN(mPipeline), "source");
If I run the code this is the result:
(videotest:14930): GLib-GObject-CRITICAL **: 16:33:08.868: g_object_set: assertion 'G_IS_OBJECT (object)' failed
(videotest:14930): GLib-GObject-CRITICAL **: 16:33:09.342: g_object_set: assertion 'G_IS_OBJECT (object)' failed
Of course, the application window displays nothing.
Upvotes: 0
Views: 851
Reputation: 7373
You should give the elements a name property. They will default to ones, but they include a numerical value and are incremented whenever you rebuild the pipeline. So it is better to not rely on those.
To make your existing code work, try this:
mPipeline = gst_parse_launch( "videotestsrc name=source ! glupload ! qmlglsink name=sink", NULL);
Upvotes: 2