How properly use Gstreamer in QtWidget? - qt

I want to play a local file inside the QVideowidget by using the gstreamer. I tested gstreamer in the terminal without any problem with:
gst-launch-1.0 videotestsrc ! videoconvert ! autovideosink,and it showed this
But when I came to Qt,
#include <QApplication>
#include <QMediaPlayer>
#include <QWidget>
#include <QVideoWidget>
#include <gst/gst.h>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QVideoWidget *videoWidget = new QVideoWidget;
QMediaPlayer *player = new QMediaPlayer;
videoWidget->show();
player->setVideoOutput(videoWidget);
player->setMedia(QUrl("gst-launch-1.0 videotestsrc ! videoconvert ! autovideosink"));
// player->setMedia(QUrl("gst-launch-1.0 videotestsrc ! xvimagesink name=\"qtvideosink\""));
// player->setMedia(QUrl("gst-pipeline udpsrc port=5801 ! application/x-rtp,payload= (int)96,encoding-name=(string)H264,clock-rate=(int)90000 ! rtpjitterbuffer latency=50 ! rtph264depay ! h264parse ! omxh264dec ! videoconvert ! ximagesink"));
player->play();
return a.exec();
}
and in my .pro file I put these:
CONFIG += link_pkgconfig
PKGCONFIG += gstreamer-1.0
PKGCONFIG += gstreamer-video-1.0
I faced the following error:
DirectShowPlayerService::doSetUrlSource: Unresolved error code 0x80040216 (IDispatch error #22)
the output is:
I searched a lot, but I couldn't solve the issue. Could anyone please help me?

I could play a video test inside the Qwidget with the below method. Be aware that picking a compatible sink is essential. for more information about sink (and other elements), use gst-inspect-1.0 | findstr sink in the terminal.
#include <gst/gst.h>;
#include <gst/video/videooverlay.h>;
#include <QApplication>;
#include <QTimer>;
#include <QWidget>;
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit ()));
if (!g_thread_supported ())
g_thread_init (NULL);
gst_init (&argc, &argv);
// prepare the pipeline
GstElement *pipeline = gst_pipeline_new ("xvoverlay");
GstElement *src = gst_element_factory_make ("videotestsrc", NULL);
GstElement *sink = gst_element_factory_make ("glimagesink", NULL);
gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
gst_element_link (src, sink);
// getting more information
gst_debug_set_active(true);
gst_debug_set_default_threshold(GST_LEVEL_WARNING);
QWidget window;
window.resize(320, 240);
window.show();
WId xwinid = window.winId();
gst_video_overlay_set_window_handle (GST_VIDEO_OVERLAY (sink), xwinid);
// run the pipeline
GstStateChangeReturn sret = gst_element_set_state (pipeline,
GST_STATE_PLAYING);
if (sret == GST_STATE_CHANGE_FAILURE) {
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
// Exit application
QTimer::singleShot(0, QApplication::activeWindow(), SLOT(quit()));
}
int ret = app.exec();
window.hide();
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
return ret;
}
the output inside widget:

Related

How to display stream video frames in Qt app using Gstreamer receive from UDP socket

I would like to use Qt Multimedia to display a video stream.
I have run
#server: $gst-launch-1.0 -v videotestsrc pattern=ball ! video/x-raw,width=1280,height=720 ! jpegenc ! rtpjpegpay ! udpsink name=sink host=localhost port=34400 sync=false async=false
#client: $gst-launch-1.0 udpsrc port=34400 caps="application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)JPEG, payload=(int)26" ! rtpjpegdepay ! jpegdec ! filesink location=a.mp4
Its working fine.
now I want to server command on one terminal and Qt app should play the part of client so it will play video.
I have tried one app but its not working.
main.cpp:
#include <QApplication>
#include <QMediaPlayer>
#include <QWidget>
#include <QVideoWidget>
#include <QBoxLayout>
#include <QProcess>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget *window = new QWidget;
QVideoWidget *videoWidget = new QVideoWidget;
QBoxLayout *layout = new QVBoxLayout;
QMediaPlayer *player = new QMediaPlayer;
QProcess *process = new QProcess;
layout->addWidget(videoWidget);
window->setLayout(layout);
window->show();
player->setVideoOutput(videoWidget);
QString program = "gst-launch-1.0";
QStringList arguments;
arguments << "udpsrc" << "port=34400" << "caps=application/x-rtp, media=(string)video,
clock-rate=(int)90000, encoding-name=(string)JPEG, payload=(int)26" << "!" << "rtpjpegdepay"
<< "!" << "jpegdec" << "!" << "filesink location=a.mp4" ;
process->setReadChannel(QProcess::StandardError);
process->start(program, arguments);
while (!process->waitForReadyRead()) {}
player->setMedia(QMediaContent(), process);
player->play();
return a.exec();
project.pro:
QT += core gui multimedia multimediawidgets
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = video_play_file
TEMPLATE = app
SOURCES += main.cpp\
dialog.cpp
HEADERS += dialog.h
FORMS += dialog.ui
Since Qt 5.12.2, you can pass GStreamer pipelines to QMediaPlayer::setMedia() if the GStreamer backend is used. In your case the code for setMedia() should look something like this (untested):
...
player->setMedia(QUrl("gst-pipeline: udpsrc port=34400 caps=\"application/x-rtp, media=(string)video, clock-rate=(int)90000, encoding-name=(string)JPEG, payload=(int)26\" ! rtpjpegdepay ! jpegdec ! videoconvert ! xvimagesink name=\"qtvideosink\""));
...
Take a look at the documentation for more information.

Qt Console Application with optional GUI

I have written a console application for my server. It works very well, I can start it over the terminal and all is okay.
For desktop environments it would be very nice, to set a flag in the settings.ini file of the program to open a MainWindow to show some information of the running console application. The console in the background can be left open. All I need is a window and some SINGAL/SLOTS between the main application running in console and the MainWindow.
How to realize this? I figured out, I have to handle with QApplication and QCoreApplication right?
Simply put this line to your pro file:
CONFIG += console
In Qt5.x from Win7 to Win10 you could do something like this:
//includes
#include <QApplication>
#include <QMainWindow>
#include <QString>
#include <QObject>
#include <QDir>
#include <QSettings>
#include <windows.h>
#include <stdio.h>
#include <iostream>
//
// Add to project file:
// CONFIG += console
//
The server:
//Here we have the Server class able to send signals
//Server will be used in main.cpp for console
//and/or in MainWindow to handle the signals
class Server : public QObject
{
Q_OBJECT
public:
Server( QObject *parent = 0 ) : QObject( parent )
{
//do server stuff
//this->setName( "Test" );
//std::cout << this->getName( ) << std::endl;
//std::cout << "Enter URL: << std::endl;
//std::string url;
//std::cin >> url;
//_url = QString::fromStdString( url );
//emit finished();
}
signals:
void finished( );
private:
QString _url;
};
The MainWindow:
//Here is the MainWindow using Server
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow( QWidget *parent = 0 ) : QMainWindow()
{
server = new Server( this ); //use server in hybrid mode (console and gui)
connect( server, SIGNAL(finished()), this, SLOT(close()) ); //establish connection
}
private:
Server *server;
};
The main:
int main( int argc, char *argv[] )
{
QString iniPath = QFileInfo( QDir::fromNativeSeparators(argv[0]) ).absolutePath(); //get the current dir
QSettings settings( iniPath+"/settings.ini", QSettings::IniFormat ); //open ini
bool gui = settings.value( "gui", false ).toBool(); //read ini
if( gui ) //decide
{
#if defined( Q_OS_WIN )
// hide console window, but not in your case
// ::ShowWindow( ::GetConsoleWindow(), SW_HIDE );
#endif
//std::cout will print to the console in the bg like you wished
QApplication a( argc, argv );
MainWindow *w = new MainWindow;
w->show();
int e = a.exec();
delete w; //needed to execute deconstructor
exit( e ); //needed to exit the hidden console
return e;
}
else
{
QCoreApplication a( argc, argv );
Server *instance = new Server; //use server in console only
exit( 0 );
return a.exec();
}
}
I tried it also without the "CONFIG += console", but then you need to redirect the streams and create the console on your own:
#ifdef _WIN32
if (AttachConsole(ATTACH_PARENT_PROCESS) || AllocConsole()){
freopen("CONOUT$", "w", stdout);
freopen("CONOUT$", "w", stderr);
freopen("CONIN$", "r", stdin);
}
#endif
BUT this only works if you start it through a debugger, otherwise all inputs are directed towards the system too. Means, if you type a name via std::cin the system tries to execute the name as a command. (very strange)
Two other warnings to this attempt would be, that you can't use ::FreeConsole() it won't close it and if you start it through a console the app won't close.
Last there is a Qt help section in QApplication to this topic. I tried the example there with an application and it doesn't work for the GUI, it stucked somewhere in an endless loop and the GUI won't be rendered or it simply crashes:
QCoreApplication* createApplication(int &argc, char *argv[])
{
for (int i = 1; i < argc; ++i)
if (!qstrcmp(argv[i], "-no-gui"))
return new QCoreApplication(argc, argv);
return new QApplication(argc, argv);
}
int main(int argc, char* argv[])
{
QScopedPointer<QCoreApplication> app(createApplication(argc, argv));
if (qobject_cast<QApplication *>(app.data())) {
// start GUI version...
} else {
// start non-GUI version...
}
return app->exec();
}
So if you are using Windows and Qt simply use the console option, hide the console if you need the GUI and close it via exit.

Is it possible to implement SystemTrayIcon functionality in Qt Quick application

I am writing a QtQuick desktop application. I use both c++ (for functionality) and QML (for UI) in it.
I use QQuickView to show the interface written in QML.
I want this application to reside in System Tray when minimised.
I mean a functionality similar to this example. http://qt-project.org/doc/qt-4.8/desktop-systray.html .
I am trying to implement this feature but could not find a way to do this in my Qt Quick application.
Here is my main.cpp code:
#include <QGuiApplication>
#include <QQmlEngine>
#include <QQmlContext>
#include <QQmlFileSelector>
#include <QQuickView>
#include "myapp.h"
int main(int argc, char* argv[])
{
QGuiApplication app(argc,argv);
app.setApplicationName(QFileInfo(app.applicationFilePath()).baseName());
QDir::setCurrent(qApp->applicationDirPath());
MyApp myappObject;
QQuickView view;
view.connect(view.engine(), SIGNAL(quit()), &app, SLOT(quit()));
view.rootContext()->setContextProperty("myappObject", &myappObject);
new QQmlFileSelector(view.engine(), &view);
view.setSource(QUrl("qrc:///myapp.qml"));
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.show();
return app.exec();
}
Please help by providing any hint/pointers to do this.
Thanks.
I was facing the same challenge today and ended up using the following solution within main(). Works great for me when using Qt 5.3. You should of course implement a better way to check whether the first root object is your application window object or not.
#include <QApplication>
#include <QQmlApplicationEngine>
#include <QMessageBox>
#include <QAction>
#include <QMenu>
#include <QSystemTrayIcon>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
if (!QSystemTrayIcon::isSystemTrayAvailable()) {
QMessageBox::critical(0, QObject::tr("Systray"),
QObject::tr("I couldn't detect any system tray "
"on this system."));
return 1;
}
QApplication::setQuitOnLastWindowClosed(false);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
QObject *root = 0;
if (engine.rootObjects().size() > 0)
{
root = engine.rootObjects().at(0);
QAction *minimizeAction = new QAction(QObject::tr("Mi&nimize"), root);
root->connect(minimizeAction, SIGNAL(triggered()), root, SLOT(hide()));
QAction *maximizeAction = new QAction(QObject::tr("Ma&ximize"), root);
root->connect(maximizeAction, SIGNAL(triggered()), root, SLOT(showMaximized()));
QAction *restoreAction = new QAction(QObject::tr("&Restore"), root);
root->connect(restoreAction, SIGNAL(triggered()), root, SLOT(showNormal()));
QAction *quitAction = new QAction(QObject::tr("&Quit"), root);
root->connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
QMenu *trayIconMenu = new QMenu();
trayIconMenu->addAction(minimizeAction);
trayIconMenu->addAction(maximizeAction);
trayIconMenu->addAction(restoreAction);
trayIconMenu->addSeparator();
trayIconMenu->addAction(quitAction);
QSystemTrayIcon *trayIcon = new QSystemTrayIcon(root);
trayIcon->setContextMenu(trayIconMenu);
trayIcon->setIcon(QIcon(":/resources/DatagnanLogoColor.png"));
trayIcon->show();
}
return app.exec();
}
Copy the Windos class (window.cpp/window.h) from systray example to your project, port it to Qt5 if necessary and open both from your main file:
int main(int argc, char* argv[])
{
// ...
QQuickView view;
// ...
view.show();
Window window;
window.show();
return app.exec();
}

Deleting QQuickView on exit cause Qt application to freeze

I founded a deadlock in Qt 5.3. How to fix in correctly? Without ugly fix (not to delete qquickview *)
I have a singleton with a pointer to QQuickView. When I need to close my application I do a call of QGuiApplication::quit() and try to release QQuickView * in destructor of singlenot. Result - application freezes.
Sample:
test.qml
import QtQuick 2.1
Rectangle
{
id: root;
color: "black";
signal quit();
Component.onDestruction: quit();
}
main.cpp
#include <QGuiApplication>
#include <QQuickView>
#include <QQuickItem>
#include <QPointer>
struct Singleton
{
QPointer< QQuickView > w;
static Singleton inst;
int run( int argc, char *argv[] )
{
QGuiApplication a( argc, argv );
w = new QQuickView();
QObject::connect( w, &QQuickView::statusChanged, [=]()
{
QObject::connect( w->rootObject(), SIGNAL( quit() ), qApp, SLOT( quit() ) );
} );
w->setSource( QUrl( "qrc:/test.qml" ) );
w->setResizeMode( QQuickView::SizeRootObjectToView );
w->show();
a.exec();
return 0;
}
~Singleton()
{
delete w; // Comment this to fix bug
}
};
Singleton Singleton::inst;
int main(int argc, char *argv[] )
{
Singleton::inst.run( argc, argv );
return 0;
}
P.S. C++0x is used for simplifying code. Same result on C++03 compilers.
It was a bug in Qt. Fixed since 5.4 version.

QProcess disable stdout redirection

I want to start a process from a QT app and catch its termination event. Its done with the method QProcess::start(). But unlike in startDetached(), the standard output of the process is redirected to a buffer. I don't want that.
I can't find how to disable it. An ugly workaround is to call setStandardOutputFile("/dev/stdout")
test.h
#ifndef MY_TEST_H
#define MY_TEST_H
#include <QCoreApplication>
class MyApp : public QCoreApplication {
Q_OBJECT
private Q_SLOTS:
void subprocessStarted();
void subprocessFinished(int);
public:
MyApp( int & argc, char ** argv );
};
#endif
test.cpp
#include "test.h"
#include <QProcess>
#include <QCoreApplication>
#include <stdio.h>
#define ENTRY printf("%s\n", __PRETTY_FUNCTION__)
MyApp::MyApp( int & argc, char ** argv ) : QCoreApplication(argc, argv) {
ENTRY;
QProcess *process = new QProcess();
//process->setStandardOutputFile("/dev/stdout");
process->start("/bin/echo aaa");
bool b;
b = connect(process, SIGNAL(started()), SLOT(subprocessStarted()));
printf("connect started %d\n", b);
b = connect(process, SIGNAL(finished(int)), SLOT(subprocessFinished(int)));
printf("connect finished %d\n", b);
}
void MyApp::subprocessStarted() {
ENTRY;
}
void MyApp::subprocessFinished(int ret) {
ENTRY;
printf("%d\n", ret);
}
int main(int argc, char *argv[]) {
ENTRY;
MyApp a(argc, argv);
return a.exec();
}
Does QProcess::closeReadChannel(ProcessChannel channel) work for you?
Closes the read channel channel. After calling this function, QProcess
will no longer receive data on the channel. Any data that has already
been received is still available for reading. Call this function to
save memory, if you are not interested in the output of the process.
Like this-
QProcess *process = new QProcess();
process->start("/bin/echo aaa");
process->closeReadChannel(QProcess::StandardOutput);
process->closeReadChannel(QProcess::StandardError);

Resources