i'm quite starting OOP so i can make incredible stupid things. Anyway. I've got 2 cameras (or 4) witch own their tcp server for providing MJPEG video stream. on one base computer i need to handle 2 (or 4) tcp client connections to these units. if i just have one instance, or one camera to handle, it works. but with multiple, it fail in bad tcp connections, I my mind, the issue should be with the instanciation of 2 QTcpsocket objects. I tried with thread, with slots, still the same, when i instanciate more than one object of my client class, the connection read nothing or auto close. I have different TCP port for different units before you tell that. have a look on my main code sirs:
MAIN.CPP
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDebug>
#include <QImage>
#include "streamerclient.h"
#include "camimageprovider.h"
#include "streamerthread.h"
#include "streamerthread2.h"
#include<unistd.h>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
StreamerThread clientSat1(1238,"SAT1-SNTL");clientSat1.start();
CamImageProvider *camImageProviderSat1(new CamImageProvider());
CamImageProvider *camImageProviderSat2(new CamImageProvider());
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("camImageProviderSat1",camImageProviderSat1);
engine.addImageProvider("camSat1", camImageProviderSat1);
engine.rootContext()->setContextProperty("camImageProviderSat2",camImageProviderSat2);
engine.addImageProvider("camSat2", camImageProviderSat2);
const QUrl url(u"qrc:/baseApp001/main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);//const QImage &)) ,Qt::DirectConnection
QObject::connect(&clientSat1, SIGNAL(newImage(QImage)),camImageProviderSat1, SLOT(updateImage(QImage)));
QObject::connect(&clientSat1, SIGNAL(newImage(QImage)),camImageProviderSat2, SLOT(updateImage(QImage)));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
CLIENT OBJECT DECLARATION
#ifndef STREAMERTHREAD_H
#define STREAMERTHREAD_H
#include <QThread>
#include <QTcpSocket>
#include<QDebug>
#include <QObject>
#include <QTimer>
#include <QVector>
#include <QVariant>
#include <QImage>
#include <QFuture>
class StreamerThread : public QThread
{
Q_OBJECT
Q_PROPERTY(NOTIFY newImage)
public:
StreamerThread(int port,char *satName,QObject *parent=0);
qint64 newTcpDataRead();
void run();
QImage img(){return m_Image;}
private:
QTcpSocket *socket;
int socketDescriptor;
QImage m_Image;
QByteArray m_baImage; // Variable contenant l'image reçue.
bool m_quit; // Variable permettant de savoir que l'application est en cours de fermeture.
char m_satName[16];
private slots:
void slotQuit(); // Slot appelé lors de la fermeture de l'application.
signals:
void newImage(const QImage &);
};
#endif // STREAMERTHREAD_H
CLIENT OBJECT DESCRIPTION
#include "streamerthread.h"
#include<iostream>
#include<QImage>
#include<QDebug>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
char datout=0;
int m_port=0;
StreamerThread::StreamerThread(int port,char *satName,QObject *parent)
{
m_quit = 0;
m_port=port;
strcpy(m_satName,satName);
this->socketDescriptor=port;
//m_Image = QImage(640,480, QImage::Format_RGB888);//RGB32);
m_Image = QImage(1280,720, QImage::Format_RGB888);//RGB32);
}
void StreamerThread::run()
{
qInfo()<<this<<" construit pour "<<m_satName <<"d: "<<this->socketDescriptor;
//socket = new QTcpSocket();
socket = new QTcpSocket();
socket->setSocketDescriptor(this->socketDescriptor);
// socket->connectToHost("127.0.0.1", 1234);
socket->connectToHost(m_satName, m_port);
if(!socket->waitForConnected(4000))
{
qDebug()<<"error "<<socket->errorString();
}
// socket->write(new char[4]{1,2,3,4});
// QByteArray buffer;
socket->flush();
std::cout<<"HostOk"<<std::endl;
m_quit=0;
while(m_quit == 0)
{
/* if(socket->state()==QTcpSocket::UnconnectedState)
{
qDebug()<<"deconnecte";
socket->close();
//delete socket;
socket->deleteLater();
sleep(2);
delete socket;
qDebug()<<"essai de reconnecter";
socket = new QTcpSocket();
socket->connectToHost(m_satName, m_port);
// socket->connectToHost("192.168.0.20", 1234);
if(!socket->waitForConnected(3000))
{
qDebug()<<"error "<<socket->errorString();
}
// socket->write(new char[4]{1,2,3,4});
//QByteArray buffer;
socket->flush();
std::cout<<"Host-Ok"<<std::endl;
}
*/
this->newTcpDataRead();
}
}
QImage Mat2QImage(cv::Mat const& src)
{
cv::Mat temp; //make the same cv::Mat
cvtColor(src, temp,cv::COLOR_BGR2RGB); //cvtColor Makes a copt, that what i need
QImage dest((const uchar *) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);
dest.bits(); //enforce deep copy, see documentation
return dest;
}
cv::Mat QImage2Mat(QImage const& src)
{
cv::Mat tmp(src.height(),src.width(),CV_8UC3,(uchar*)src.bits(),src.bytesPerLine());
cv::Mat result; //deep copy just in case (my lack of knowledge with open cv)
cvtColor(tmp, result,cv::COLOR_BGR2RGB);
return result;
}
qint64 StreamerThread::newTcpDataRead()
{
QDataStream in(socket);
in.setVersion(QDataStream::Qt_5_11);
// initialize data
QImage image;
QByteArray data;
static qint64 imageSize = 0;
QString currentSatName="";
QByteArray currentSatData;
socket->waitForReadyRead();
usleep(1000);
//le client envoie un QByteArrayavec la taille du jpeg en premier puis les datas
if ( 0 == imageSize ) {
if ( socket->bytesAvailable() < (int)sizeof(qint64) )
{
std::cout<<"error "<<std::endl;
return-1;
}
in >> imageSize;
in>>currentSatName;
in>>currentSatData;
// qInfo() << imageSize;
//std::cout<<currentSatName.toStdString()<<std::endl;
}
//le client envoie un QByteArrayavec les datas, une chaine jpeg a recoder avec cv::decode
if (socket->bytesAvailable() < imageSize ) {;}//return -2;
else
{
in>>data;
//Vers cv::Mat:
std::vector<uchar> vData(data.begin(), data.end());
cv::Mat matImg;
if(imageSize!=-1&&imageSize!=0&&data.size()>0)
{
matImg = cv::imdecode(cv::Mat(1,
imageSize,//vData.size(),
CV_8UC1,
&vData[0]), cv:: IMREAD_COLOR);
QImage image= Mat2QImage(matImg);
emit newImage(image);
}
else
{
qDebug()<<"matrice a -1";
qInfo()<<this<< " :erreur decodage tcp";
QImage image = QImage(640,480, QImage::Format_RGB888);
image.fill(QColor("red"));
socket->flush();
}
imageSize = 0;
//DATA OUT
QByteArray block;
QByteArray satData;
if(datout>=10)
{
QString satName="RATS";
satData.reserve(8);
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_11);
// initialize data
// serialize
out << qint64(0) <<satName<<satData;
out.device()->seek(0);
out << (qint64)(block.size() - sizeof(qint64)); // the size of the block to be sent
// send over TCP
qint64 written = socket->write(block);
socket->waitForBytesWritten();
datout=0;
}
datout++;
return image.sizeInBytes();
}
}
void StreamerThread::slotQuit()
{
m_quit = 1;
}
I really don't understand why it fail when i instanciate more than one client object when it fail, it's loop here:
if ( 0 == imageSize ) {
if ( socket->bytesAvailable() < (int)sizeof(qint64) )
{
std::cout<<"error "<<std::endl;
return-1;
}
And it is the last instancied object that is running, the first created is keeping saying "error". I really suppose it is related to socket, maybe instanciation is not done correctly. i see that both are created with good TCP port.but, to validate my guess, i copied the
streamerthread.cpp
streamerthread.h
to a new file, a different object so:
streamerthread2.cpp
streamerthread2.h
so for the test i declare like this:
StreamerThread clientSat1(1238,"SAT1-SNTL");clientSat1.start();
StreamerThread2 clientSat2(1234,"SAT2-SNTL");clientSat2.start();
so i've one instance of 2 differents object....and it work here! stupid way of doing but it work.... I really don't want to do like this, i really want to us objects and their power. please say me im stupid and my error is ->there<- . many thanks all!