How do i play a stream with QMediaPlayer - c++

I have set up a server and video streaming so that I can connect to the stream with ffplay using the following command line:
ffplay rtmp://<IP>/path
Is it possible to use QMediaPlayer QMediaContent or something to connect to this stream?
Or maybe any other kind of stream I can create with ffserver.
using the same path as with ffplay results in "Unsupported url scheme!"
With further experiments i have tried ffserver http server streaming, but that ended with Qt crashing in MFStreamer::doRead()
Apparently it should have called BeginRead for MFStreamer but it didn't.
How do i play video streams with QMediaPlayer?
Edit: here's my code
videotest.cpp
#include "videotest.h"
#include <QVBoxLayout>
#include <QVideoWidget>
#include <qmediaplayer.h>
#include <QMediaContent>
#include <QNetworkAccessManager>
#include <QNetworkReply>
struct VideoTest::Private
{
QMediaPlayer * mediaPlayer;
QNetworkAccessManager * networkAccessManager;
QNetworkReply * reply;
};
VideoTest::VideoTest(QWidget *parent)
: QMainWindow(parent)
{
d = new Private;
d->mediaPlayer = new QMediaPlayer(this, QMediaPlayer::StreamPlayback);
d->networkAccessManager = new QNetworkAccessManager(this);
ui.setupUi(this);
QVideoWidget * videoWidget = new QVideoWidget(ui.centralWidget);
videoWidget->show();
QPalette palette = videoWidget->palette();
palette.setColor(QPalette::Background, QColor(0, 0, 0));
videoWidget->setPalette(palette);
ui.videoLayout->addWidget(videoWidget);
d->mediaPlayer->setVideoOutput(videoWidget);
connect(ui.playButton, SIGNAL(clicked()), d->mediaPlayer, SLOT(play()));
connect(ui.pauseButton, SIGNAL(clicked()), d->mediaPlayer, SLOT(pause()));
connect(ui.videoUrlEdit, SIGNAL(editingFinished()), this, SLOT(sourceChanged()));
connect(d->mediaPlayer, SIGNAL(error()), this, SLOT(stateChanged()));
connect(d->mediaPlayer, SIGNAL(stateChanged), this, SLOT(stateChanged()));
}
VideoTest::~VideoTest()
{
delete d;
}
void VideoTest::sourceChanged()
{
d->reply = d->networkAccessManager->get(QNetworkRequest(ui.videoUrlEdit->text()));
if(d->reply)
{
connect(d->reply, SIGNAL(readyRead()), this, SLOT(networkRequestReady()));
}
}
void VideoTest::stateChanged()
{
QString text = ui.textEdit->toPlainText();
text.append("\n").append(d->mediaPlayer->errorString()).append(" : ").append(d->mediaPlayer->mediaStatus());
ui.textEdit->setText(text);
}
void VideoTest::networkRequestReady()
{
d->mediaPlayer->setMedia(QMediaContent(), d->reply);
}
videotest.h
#ifndef VIDEOTEST_H
#define VIDEOTEST_H
#include <QtWidgets/QMainWindow>
#include "ui_videotest.h"
class VideoTest : public QMainWindow
{
Q_OBJECT
public:
VideoTest(QWidget *parent = 0);
~VideoTest();
public slots:
void sourceChanged();
void stateChanged();
void networkRequestReady();
private:
Ui::VideoTestClass ui;
struct Private;
Private * d;
};
#endif // VIDEOTEST_H

I found a way to make it work.
I gave up on Qt. The guys at Qt were insistent that it should work, but were unable to produce any configuration that works. They said that it should work if you stream from VLC, but I didn't get it to work. I also tried ffmpeg, ffserver and nginx rtmp streaming. I got these things working with mplayer, ffplay, VLC and some even with Windows Media Player, but never QMediaPlayer.
I tried to just give the URL to setMedia.
I tried to make a custom QIODevice to read the stream data and give that data to QMediaPlayer which was initialized with StreamPlayback, but it just would not succeed in reading the data.
In the end, all I needed was something to play a stream, is a QWidget and isn't GPL licensed.
I used libVLC and vlc-qt both of which work wonderfully.
Following these instructions was easy, but you need to remember to copy the header files from vlc-qt/windows/vlc_headers/2.2/ to vlc/sdk/include/vlc/plugins (sic). This is important, if you don't do this you might get errors during compilation. Note that these paths might be different if you have different versions of your platform doesn't match mine. Also, it might not be necessary when you read this.
VideoTest.h
#ifndef VIDEOTEST_H_
#define VIDEOTEST_H_
#include <QtWidgets/QMainWindow>
#include "ui_videotest.h"
class VideoTest: public QMainWindow
{
Q_OBJECT
public:
VideoTest(QWidget * p_parent = 0);
~VideoTest();
public slots:
void sourceChanged();
private:
struct Private;
Private * d;
Ui::VideoTestClass ui;
};
#endif
videotest.cpp
#include "videotest.h"
#include <vlc-qt/Common.h>
#include <vlc-qt/Instance.h>
#include <vlc-qt/Media.h>
#include <vlc-qt/MediaPlayer.h>
#include <vlc-qt/WidgetVideo.h>
struct VideoTest::Private
{
VlcInstance * vlcInstance;
VlcMediaPlayer * vlcMediaPlayer;
VlcMedia * vlcMedia;
VlcWidgetVideo * vlcVideoWidget;
};
VideoTest::VideoTest(QWidget * p_parent)
{
d = new Private();
ui.setupUi(this);
d->vlcMedia = 0;
d->vlcInstance = new VlcInstance(VlcCommon::args(), this);
d->vlcMediaPlayer = new VlcMediaPlayer(d->vlcInstance);
d->vlcVideoWidget = new VlcWidgetVideo(this);
d->vlcMediaPlayer->setVideoWidget(d->vlcVideoWidget);
d->vlcVideoWidget->setMediaPlayer(d->vlcMediaPlayer);
ui.videoLayout->addWidget(d->vlcVideoWidget);
connect(ui.playButton, SIGNAL(clicked()), d->vlcMediaPlayer, SLOT(play()));
connect(ui.pauseButton, SIGNAL(clicked()), d->vlcMediaPlayer, SLOT(pause()));
connect(ui.videoUrlEdit, SIGNAL(editingFinished()), this, SLOT(sourceChanged()));
}
VideoTest::~VideoTest()
{
delete d->vlcInstance;
delete d->vlcMediaPlayer;
delete d->vlcMedia;
delete d;
}
VideoTest::sourceChanged()
{
QUrl url(ui.videoUrlEdit->test());
if(url.isValid() == false)
{
return;
}
d->vlcMediaPlayer->stop();
delete d->vlcMedia;
d->vlcMedia = new VlcMedia(url.toString(), d->vlcInstance);
d->vlcMediaPlayer->open(d->vlcMedia);
}
VideoTest.ui
Make your own, I don't work for you :D
Just make sure that it has pauseButton, playButton, videoUrlEdit(QLineEdit) and videoLayout where the video widget will be inserted.

I've just managed to play stream in QML VideoOutput with C++ QMediaPlayer using the setMedia(QUrl("http://127.0.0.1:8080"));
The stream was created by VLC media player using the HTTP to the 8080 port. I've also succeeded in playing the stream created by VLC media player to local file by passing it to QMediaPlayer via setMedia(QMediaContent(), &localFile);.

Related

No reply data with QNetworkAccessManager when running on another machine

I have a simple program that should retrieve the HTML from a website URL.
main.cpp
#include "Downloader.h"
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
auto dl = new Downloader(&a);
QString url = "https://www.dognow.at/ergebnisse/?page=1";
dl->fetch(url);
return a.exec();
}
Downloader.h
#ifndef DOWNLOADER_H
#define DOWNLOADER_H
#include <QNetworkReply>
#include <QObject>
class Downloader : public QObject
{
Q_OBJECT
public:
explicit Downloader(QObject* parent = nullptr);
void fetch(QString &url);
private:
QNetworkAccessManager* m_manager;
private slots:
void replyFinished(QNetworkReply* rep);
};
#endif // DOWNLOADER_H
Downloader.cpp
#include "Downloader.h"
#include <QDebug>
Downloader::Downloader(QObject* parent): QObject(parent),
m_manager(new QNetworkAccessManager(parent))
{}
void Downloader::fetch(QString& url)
{
qDebug() << "fetch " << url;
connect(m_manager, &QNetworkAccessManager::finished, this, &Downloader::replyFinished);
m_manager->get(QNetworkRequest(QUrl(url)));
}
void Downloader::replyFinished(QNetworkReply* rep)
{
QByteArray data=rep->readAll();
QString str(data);
qDebug() << "data len: " << str.length();
rep->close();
}
When I run the program on my local PC it works fine. When I run it on another machine the reply data is empty. On both systems I use Linux (x86_64) and Qt 5.15.0.
I hope someone can give me a hint where I should have a look at.
UPDATE: 2022-04-04 - 16:22:
when I run a simple curl command on the failing machine it works fine.
Ok, I found the problem.
On the failing machin I have an older ubuntu (16.04 LTS) running with an incompatible openssl version.
I found it out because I copied my own Qt libs build (debug) to the other machine and I got SSL error (incompatbile version).
I installed a newer openssl version and know it works.

Passing/giving commands to CMD through Qt GUI

What I'm trying to achieve (And struggling with) is basically passing commands to CMD through my QT Mainwindow application.
I would like to have my code, first run CMD (preferably hidden). I used here QProcess like this:
(in my Mainwindow.cpp file)
QString exePath = "C:/Windows/System32/cmd.exe";
QProcess pro;
pro.startDetached(exePath);
pro.waitForStarted();
this question helped me a lot
However, what this answer/question lacks is actual help on "appending" commands to CMD (not sure if this is a correct term, please correct me if I'm wrong!)
I have tried the following with this piece of code
(also in my Mainwindow.cpp file)
string exepathstring = "C:/Windows/System32/cmd.exe"; //because fstream doesnt accept argument of type QString
QProcess pro;
pro.startDetached(exePath); //do I have to use "detached" here?
pro.waitForFinished(); //not sure if i should use "for
//finished" or "for started" or something else
string connecttoserver = ui->lineEdit_command->text().toStdString(); //this is where people input a cmd command
//need to convert it to to be able to append it
fstream myoutfile(exepathstring, ios::in | ios::out | ios::app);
myoutfile <<""<< connecttoserver << endl;
Hoping that I can use a normal "append to file" code but it does nothing, I don't even get an error :(
could someone tell me where i'm going wrong?
and how can I go about achieving what I want?
which is
starting cmd (preferably in hidden) upon launch of my "mainwindow app"
take user input and let my app pass it to cmd upon my button click.
Here's my entire mainwindow.cpp source file
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QProcess>
#include <QString>
#include <fstream>
#include <iostream>
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{ui->setupUi(this);}
MainWindow::~MainWindow()
{delete ui;}
void MainWindow::on_pushButton_clicked()
{
QString exePath = "C:/Windows/System32/cmd.exe";
string exepathstring = "C:/Windows/System32/cmd.exe"; //because fstream doesnt accept argument of type QString
QProcess pro;
pro.startDetached(exePath);
pro.waitForFinished(); //not sure if i should use "for finished" or "for started" or something else
string connecttoserver = ui->lineEdit_command->text().toStdString(); /*this is where people input a cmd command
need to convert it to to be able to append it*/
fstream myoutfile(exepathstring, ios::in | ios::out | ios::app);
myoutfile <<""<< connecttoserver << endl;
}
Any input would really help me a lot ^.^ also I'm really sorry if I had used wrong terminology
If you looked at this post, one apparent problem is that you are using the static method startDetached() with the blocking function waitForFinished() ... QProcess::waitForStarted()/waitForFinished() won't catch signals from detached QProcess;
Thus you could use:
QProcess pro;
pro.start(exePath);
pro.waitForStarted(); // the correct is `waitForStarted()`
What your trying to do with fstream is not clear - to me - while in your description, you want user to send a command to your process:
then this could, for instance, be :
QByteArray user_cmd = QVariant(ui->lineEdit_command->text()).toByteArray();
pro.write(user_cmd);
pro.write("\n\r"); // press Enter to execute the command
Thus your code could be:
.h
#include <QProcess>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void readResult();
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QProcess* pro;
};
.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QString>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::on_pushButton_clicked);
QString exePath = "C:/Windows/System32";
pro = new QProcess(parent);
pro->setWorkingDirectory(exePath);
pro->setReadChannel(QProcess::StandardOutput);
connect(pro,&QProcess::readyReadStandardOutput, this, &MainWindow::readResult);
pro->start("cmd.exe");
if (!pro->waitForStarted())
{
qDebug() << "The process didnt start" << pro->error();
}
}
void MainWindow::on_pushButton_clicked()
{
if (ui->lineEdit_command->text().isEmpty())
return;
QByteArray cmd = QVariant(ui->lineEdit_command->text()).toByteArray();
pro->write(cmd);
pro->write("\n\r");
ui->lineEdit_command->clear();
}
void MainWindow::readResult()
{
while(pro->bytesAvailable()){
QString dirout = pro->readLine();
qDebug() << dirout;
}
}
MainWindow::~MainWindow()
{
delete ui;
}

How can i make a two message events for json Data by pushButton click in Qt?

How can I make a message?
I want make 2 message events. First, if is nothing include in my lineEdits and push the button. Must come error message "You have not includet the data". And second, if i include my lineEdits and push the button. Must come message "You have includet the data." But it's not work for me. If i push the button, then program saved empty json. If i push write data in lineEdits and push the button, then program saved as normal json. But no matter how I write, the programs always overwrite old json file. And I always get the logging that I have stored data.
Here is my code:
My .Cpp file:
#include "address_dialog.h"
#include "ui_address_dialog.h"
Address_Dialog::Address_Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Address_Dialog)
{
ui->setupUi(this);
connect(ui->pb_Cancel,SIGNAL(clicked(bool)),this,SLOT(close()));
//Save data in json on click
connect(ui->pb_save,SIGNAL(clicked(bool)),
this,SLOT(on_pb_save_clicked()));
}
Address_Dialog::~Address_Dialog()
{
delete ui;
}
void Address_Dialog::SaveDat()
{
m_address.mVorname= ui->le_Vorname->text();
m_address.mNachname= ui->le_Nachname->text();
m_address.mLand= ui->le_Land->text();
m_address.mName= ui->le_Name->text();
m_address.mPassword= ui->le_Password->text();
QJsonObject json_obj;
json_obj["FirstName"]= m_address.mVorname;
json_obj["MiddleName"]= m_address.mNachname;
json_obj["Country"]= m_address.mLand;
json_obj["NickName"]= m_address.mName;
json_obj["Password"]= m_address.mPassword;
//Open the file for Recording using the path specified
QString file_path = "C:/Users/frs/Documents/test_obj.json";
QFile save_file(file_path);
save_file.open(QIODevice::WriteOnly);
//if(!save_file.open(QIODevice::WriteOnly))
//QMessageBox::warning(0,"Error","Cannot open the file");
QJsonDocument json_doc(json_obj);
QString json_string = json_doc.toJson();
if(save_file.write(json_string.toLocal8Bit()))
QMessageBox::information(0,"Saving....",
"The item has been successfully added");
else
QMessageBox::critical(0,"Error","The item cannot be added");
save_file.close();
}
void Address_Dialog::on_pb_save_clicked()
{
SaveDat();
}
That is my .H file
#ifndef ADDRESS_DIALOG_H
#define ADDRESS_DIALOG_H
#include <QDialog>
#include <QMessageBox>
#include "address.h"
#include <QFile>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QString>
#include <QDir>
namespace Ui
{
class Address_Dialog;
}
class Address_Dialog : public QDialog
{
Q_OBJECT
public:
explicit Address_Dialog(QWidget *parent = 0);
~Address_Dialog();
Address m_address;//Creation of the Class object <=> /*QString mVorname,
// mNachname, mLand, mName, mPassword;*/
private slots:
void on_pb_save_clicked();
void SaveDat();
private:
Ui::Address_Dialog *ui;
};
#endif // ADDRESS_DIALOG_H
I found a solution. That was easy. I thanks all for response.
Here is my code:
if(ui->le_Vorname->text().isEmpty() || ui->le_Nachname->text().isEmpty() ||
ui->le_Land->text().isEmpty() || ui->le_Name->text().isEmpty() ||
ui->le_Password->text().isEmpty())
{
ui->pb_save->setEnabled(false);
QMessageBox::critical(0,"Error","The item cannot be added");
}else
{
ui->pb_save->setEnabled(true);
save_file.write(json_string.toLocal8Bit());
QMessageBox::information(0,"Saving....", "The item has been successfully added");
}
save_file.close();

How to read data using QSerialPort to write to a file using QFile?

New to C++ and Qt, I'm trying to use a microcontroller to send a large set of data (made up of integers and commas) over serial to be put in a .csv file for use in Excel. My mainwindow.cpp code so far (where I've put all the action for testing purposes):
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <string>
#include <QtSerialPort/QSerialPort>
#include <QString>
#include <QTextEdit>
#include <QFile>
#include <QTextStream>
QSerialPort *serial;
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
serial = new QSerialPort(this);
serial->setPortName("/dev/cu.usbmodemfa131");
serial->setBaudRate(QSerialPort::Baud9600);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
serial->open(QIODevice::ReadWrite);
connect(serial, SIGNAL(readyRead()), this, SLOT(serialReceived()));
}
MainWindow::~MainWindow()
{
delete ui;
serial->close();
}
void MainWindow::serialReceived()
{
QString filename = "/Users/me/Documents/myFile/datacollecting.csv";
QFile file(filename);
QTextStream out(&file);
file.open(QIODevice::ReadWrite);
QByteArray ba;
ba = serial->readAll();
out << ba;
file.close();
}
The code however is giving me some issues. It does not work reliably at all and in the resultant file it only stores the last 10 or so (out of several thousand) characters. I have searched around but have not found a way to properly store large chunks of data over serial. Is there a better way to achieve what I'm trying to do above? New to this so any help would be greatly appreciated!
As already written in comments you should open your output file in append mode by adding QIODevice::Append flag so that all data is written to the end of the file.
You can also connect to error signal where you can inspect possible errors. See serial port enums here.
connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this, SLOT(handleError(QSerialPort::SerialPortError)));
void MainWindow::handleError(QSerialPort::SerialPortError error)
{
...
}

Qt 5.3 Can't make QCompass (QSensor) work on Windows 8.1

I can't make sensors works on my Asus Transformer T100.
Magnetometer and Compass don't start, and I have fake value from the accelerometer (always x=0, y=9.8, z=0).
I always get the same result, even with my laptop :
first textEdit:
Initialisation...
QAccelerometer is connected to backend...
QAccelerometer isActive...
Attente des données capteur...
Second textEdit:
ven. juin 6 14:56:41 2014
Acceleration: x = 0
y = 9.8
z = 0
Compass: UNAVAILABLE
QMagnetometer: UNAVAILABLE
And this code :
QList<QByteArray> sensorList = QSensor::sensorTypes();
ui->init->append("Sensor list length: " + QString::number(sensorList.size()).toUtf8());
foreach( QByteArray sensorName, sensorList ) {
ui->init->append("Sensor: " + sensorName);
}
Give me :
Sensor: QAmbientLightSensor
Sensor: QAccelerometer
Sensor: QTiltSensor
Sensor: QOrientationSensor
Sensor: QRotationSensor
Where is QCompass ? QMagnetometer ? Why QAccelerometer is faked ? :'(
Here is my simplified test-code, only with QCompass :
header:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QCompass>
#include <QCompassReading>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void update();
void error(int);
private:
Ui::MainWindow *ui;
QCompass *compass;
QCompassReading *compass_reading;
};
#endif // MAINWINDOW_H
code :
#include <QDateTime>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->init->setText("Initialisation...");
compass = new QCompass(this);
connect(compass, SIGNAL(readingChanged()), this, SLOT(update()));
connect(compass, SIGNAL(sensorError(int)), this, SLOT(error(int)));
compass->setDataRate(1);
compass->start();
if (compass->isBusy()) {
ui->init->append("QCompass is busy...");
}
if(compass->isConnectedToBackend()) {
ui->init->append("QCompass is connected to backend...");
}
if(compass->isActive()) {
ui->init->append("QCompass isActive...");
}
ui->init->append("Waiting for sensors...");
}
MainWindow::~MainWindow()
{
delete compass;
delete ui;
}
void MainWindow::update()
{
QString text_compass;
ui->textEdit->clear();
accel_reading = accel->reading();
compass_reading = compass->reading();
if(compass_reading != 0) {
text_compass = QDateTime::currentDateTime().toString() +
+ "\nCompass: azimuth = " + QString::number(compass_reading->azimuth());
+ "\ncalibration level = " + QString::number(compass_reading->calibrationLevel());
ui->textEdit->append(text_compass);
}
else {
text_compass = "\nCompass: UNAVAILABLE";
ui->textEdit->append(text_compass);
}
}
void MainWindow::error(int erreur) {
QMessageBox::critical(this, "Erreur", "Erreur num : " + QString::number(erreur).toUtf8());
}
The solution for now is to hack the winrt sensors plugin and rebuild it.
(the sensors backend for winrt works for windows 7/8 desktop application).
First git clone the plugin, or get Qt's source code.
then open src/plugins/sensors/sensors.pro and add these lines :
win32-msvc2012|win32-msvc2013 {
isEmpty(SENSORS_PLUGINS): SENSORS_PLUGINS = winrt generic dummy
}
winrt|win32-msvc2012|win32-msvc2013 {
isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, winrt):SUBDIRS += winrt
}
REMOVE this line :
isEmpty(SENSORS_PLUGINS)|contains(SENSORS_PLUGINS, winrt):winrt:SUBDIRS += winrt
Then open src/plugins/sensors/winrt/winrt.pro and add this lines :
win32-msvc2012|win32-msvc2013: LIBS += -lruntimeobject
And finally run qmake, make/nmake, make/nmake install
(Ask google for more informations about how to build)
IMPORTANT : the run process should start from the directory where the qtsensors.pro file is (e. g. C:\Qt\5.4\Src\qtsensors).
To get more informations, and follow :
Link to the bug : https://bugreports.qt-project.org/browse/QTBUG-39590
Link to the patch : https://codereview.qt-project.org/#/c/87370/