QtcpSocket instantiation not morking properly
-
Hello Sirs,
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:The main entry:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QDebug> #include <QImage> #include <QThread> #include "streamerslot.h" #include "streamerslot2.h" #include "camimageprovider.h" //#include "streamerclient.h" //#include "streamerthread.h" //#include "streamerthread2.h" #include<unistd.h> int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); streamerSlot clientSat1(1238,"SAT1-SNTL"); streamerSlot clientSat2(1234,"SAT2-SNTL"); clientSat2.test(); clientSat1.test(); 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(&clientSat2, SIGNAL(newImage(QImage)),camImageProviderSat2, SLOT(updateImage(QImage))); //QObject::connect(&clientSat1, SIGNAL(bridgenewImage(QImage)),camImageProviderSat1, SLOT(updateImage(QImage))); //QObject::connect(&clientSat2, SIGNAL(bridgenewImage(QImage)),camImageProviderSat2, SLOT(updateImage(QImage))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
The connectToServer classe:
#ifndef STREAMERSLOT_H #define STREAMERSLOT_H #include <QObject> #include <QDebug> #include<QTcpsocket> #include<QAbstractsocket> #include<QImage> #include <opencv2/core.hpp> class streamerSlot : public QObject { Q_OBJECT public: explicit streamerSlot(int port,char *satName,QObject *parent = nullptr); void test(); signals: void newImage(const QImage &); public slots: void connected(); void disconnected(); void bytesWritten (qint64 bytes); void readyRead(); private: QTcpSocket *socket; QImage m_Image; char m_satName[16]; int m_satPort=0; QImage Mat2QImage(cv::Mat const& src); cv::Mat QImage2Mat(QImage const& src); QDataStream in; char _datout=0; int n=0; }; #endif // STREAMERSLOT_H
And its declaration:
#include "streamerslot.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> #include <unistd.h> //QDataStream in(socket); QImage streamerSlot::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 streamerSlot::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; } streamerSlot::streamerSlot(int port,char *satName,QObject *parent) : QObject{parent} { m_satPort=port; strcpy(m_satName,satName); //m_Image = QImage(640,480, QImage::Format_RGB888);//RGB32); m_Image = QImage(1280,720, QImage::Format_RGB888);//RGB32); } void streamerSlot::test() { socket=new QTcpSocket(this); connect(socket,SIGNAL(connected()),this,SLOT(connected())); connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected())); connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead()),Qt::QueuedConnection); connect(socket,SIGNAL(bytesWritten(qint64 )),this,SLOT(bytesWritten(qint64 ))); qDebug()<<"connecting.."; socket->connectToHost(m_satName,m_satPort);// "SAT1-SNTL",1238); n=m_satPort; if(!socket->waitForConnected(3000)) { qDebug()<<"error"<<socket->errorString(); } in.setDevice(socket); in.setVersion(QDataStream::Qt_5_11); in.startTransaction(); } void streamerSlot::connected() { qDebug()<<"connected.."; } void streamerSlot::disconnected() { qDebug()<<"disconnected.."; } void streamerSlot::bytesWritten(qint64 bytes) { qDebug()<<"wrote.."; } void streamerSlot::readyRead() { // QImage image; QByteArray data; static qint64 imageSize = 0; QString currentSatName=""; QByteArray currentSatData; //depart de trame , on recoit la taille, le nom du sat et les data params(SNTL) if ( 0 == imageSize ) { if ( socket->bytesAvailable() < (int)sizeof(qint64) ) return; in >> imageSize; in>>currentSatName; in>>currentSatData; // qDebug()<<"reading.."<<n<<" " << imageSize<<" "<<currentSatName<<" "<<currentSatData; } //si on a pas encore la taille necessaire on quitte if ( socket->bytesAvailable() < imageSize ) return; //une fois qu'on l'a, on charge in>>data; // et on traite 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,CV_8UC1,&vData[0]), cv:: IMREAD_COLOR); QImage image= Mat2QImage(matImg); emit newImage(image); // socket->flush(); } //Si on a un soucis eventuel, on vide tout else { qDebug()<<"matrice a -1 "<<this<< " :erreur decodage tcp";; QImage image = QImage(640,480, QImage::Format_RGB888); image.fill(QColor("red")); socket->flush(); } imageSize = 0; }
if i create in main 2 streamerSlot object, the communication is crashing by hangling in the
qDebug()<<"matrice a -1 "<<this<< " :erreur decodage tcp";;
on camera server side, the connection opened and it stared to emit and it stopped
BUT, if i copy the streamerslot.cpp& streamerslot.h to a streamerslot2.cpp& streamerslot2.h and i instantiate as this:streamerSlot clientSat1(1238,"SAT1-SNTL"); streamerSlot2 clientSat2(1234,"SAT2-SNTL");
It works....connection is up and running....too stupid.
What do i don't understand in socket instatiation or class creation?
is there someting related to stack/heap creation or someting?
i also tried to instatiate like this:streamerSlot *clientSat1=new streamerSlot(1238,"SAT1-SNTL");
but it is the same, the tcp connection seems to collapse.
Or maybe with the parent/child mecanism? i don't understand theses mecanisms, so hope someone is far more illuminated than me....Regards.
B.HAHN -
Hi and welcome to devnet,
Any chances you have a second call to the test function somewhere else in your code ?
On an unrelated note, since you are using using Qt, you don't need to use raw char array especially since connecToHost uses a QString for the hostname.
And second unrelated note, usually, class names in C++ are UpperCamelCase. This makes it easier to differentiate them from variable names. -
@SGaist Hello, thank you for your remarks. yes totally agree with char arrays...just lasy because i come from C world.
anyway . no, the test function is not call anaywhere again. I really don't understand why instantiation fail,
i tried to make test with my 4 cameras server at runtime. and if i create 4 different classes with same methods but wih one instantation , such as:StreamerSlot clientSat1(1238,"SAT1-SNTL"); StreamerSlot2 clientSat2(1234,"SAT2-SNTL"); StreamerSlot3 clientSat3(1236,"SAT3-SNTL"); StreamerSlot4 clientSat4(1232,"SAT4-SNTL");
i can see my streams.... too silly!!
A notion that i totally don't understand for now is parent too child relationship.is there any clue that instantiation of QTcpSocket fail beacause my relation is not good?
I'm too far from understanding this kind of problems now.Regards.
-
Hello, i'm doubting too myself. and what about the classes variables?
when i use them, don't i need to call such as:this->m_Image = QImage(1280,720, QImage::Format_RGB888);//RGB32);
because for now, i use them such as:
m_Image = QImage(1280,720, QImage::Format_RGB888);//RGB32);
maybe the instantiation doesn't agree with this?
hope this help to help me :)
BH -
Hello all, i'm still on my issue...
after searching,
the program runn well since the second object creation.
when there is only one object running, the readyread() slot is performing well,
here you are the readyread slot:void streamerSlot::readyRead() { QByteArray data; static qint64 imageSize = 0; QString currentSatName=""; QByteArray currentSatData; //depart de trame , on recoit la taille, le nom du sat et les data params(SNTL) if ( 0 == imageSize ) { if ( socket->bytesAvailable() < (int)sizeof(qint64) ) {qDebug()<<"<";return;} in >> imageSize; in>>currentSatName; in>>currentSatData; // qDebug()<<"reading.."<<n<<" " << imageSize<<" "<<currentSatName<<" "<<currentSatData; } //si on a pas encore la taille necessaire on quitte if ( socket->bytesAvailable() < imageSize ) {qDebug()<<"s/i"<<socket->bytesAvailable()<<" "<< imageSize;return;} //une fois qu'on l'a, on charge in>>data; // et on traite Vers cv::Mat: std::vector<uchar> vData(data.begin(), data.end()); cv::Mat matImg; if(imageSize!=-1&&imageSize!=0)//&&data.size()>0) {qDebug()<<"tcp "<<imageSize; /* commentedout for debuging matImg = cv::imdecode(cv::Mat(1,imageSize,CV_8UC1,&vData[0]), cv:: IMREAD_COLOR); QImage image= Mat2QImage(matImg); emit newImage(image); socket->flush();*/ } //Si on a un soucis eventuel, on vide tout else { qDebug()<<"matrice a -1 "<<this<< " :erreur decodage tcp "<<imageSize; QImage image = QImage(640,480, QImage::Format_RGB888); image.fill(QColor("red")); socket->flush(); } imageSize = 0; }
which is giving this print:
data are growing in Qdatastream and when i have correct size of image, i go further:
tcp 48737
s/i 37416 48728
s/i 48712 48728
s/i 48712 48728
tcp 48728
s/i 37416 48602
s/i 48586 48602
s/i 48586 48602
tcp 48602
the QDatastream works ok, data are coming all is fine.
after this the second opbject is created, and now, the readyRead slots are still running but data arriving are not good,
the socket are still opened but data are now
s/i 3751036 64622077935624
s/i 3751036 64622077935624
s/i 3759482 64622077935624
s/i 1670978 64622077935624
s/i 1695458 64622077935624
s/i 1701170 64622077935624So my guess is that my class is not correctly written, maybe my variables are not instantiated corectly?
i tried to add a descriptor id in the prints as this:
qDebug()<<"s/i"<<socket->socketDescriptor()<<" "<<socket->bytesAvailable()<<" "<< imageSize;return;
s/i 1028 1882900 140630114172936
s/i 1196 1254619 140630114172936
s/i 1196 1284736 140630114172936
s/i 1196 1284736 140630114172936
s/i 1028 1895860 140630114172936
s/i 1028 1895860 140630114172936
s/i 1028 1907380 140630114172936
s/i 1028 1930517 140630114172936
s/i 1028 1930517 140630114172936we can see that the two sockets are running, they both exist. but data in datastream are crasy.
So , i don't know where to seek now.
many thanks! -
Hello all, seems that i'm i alone in the dark here, since, exept one tag from Sgaist helping me, nothing happened.
anyway, seems that i finded the error.
in my readyread slot, i create the imageSize variable in static....void streamerSlot2::readyRead() { // QImage image; QByteArray data; static qint64 imageSize = 0; QString currentSatName=""; QByteArray currentSatData; ...
so, with one object it is okay, the imageSize is created, fixed to zero and readyread runs....but with a second object instantiated...
it is not the same, the variable is doing something i'm not understanding. but it lay to bad results.
declared it in .h private section not in static. and my 2 instances are working now!!class streamerSlot : public QTcpSocket//QObject { Q_OBJECT public: explicit streamerSlot(int port,char *satName,QObject *parent = nullptr); void test(); signals: void newImage(const QImage &); public slots: void connected(); void disconnected(); void bytesWritten (qint64 bytes); void readyRead(); private: QTcpSocket *socket; QImage m_Image; char m_satName[16]; int m_satPort=0; QImage Mat2QImage(cv::Mat const& src); cv::Mat QImage2Mat(QImage const& src); QDataStream in; qint64 imageSize = 0; char _datout=0; int n=0; };
need to make some more test tomorrow with my 4 units to be sure, but...smells good!
Regards.
-
@beHa said in QtcpSocket instantiation not morking properly:
declared it in .h private section not in static. and my 2 instances are working now!!
Indeed! When you declare a variable
static
in (say)streamerSlot2::readyRead()
that means there is only one (shared) instance of the variable used no matter how many different instances ofstreamerSlot2
you access it from. This is (usually) a very bad idea. Basically keep clear ofstatic
unless you really know what you are doing.When you move it to a member variable of
streamerSlot2
you have separateimageSise
s for each instance ofstreamerSlot2
. Which is what you want here! -
Damn ! I was looking for a static variable but missed the only one that was there.
When handling video stream image sizes, it's always a bad idea to do that through a static variable. Static variables create hidden shared global states when used like that.
@beHa said in QtcpSocket instantiation not morking properly:
Hello all, seems that i'm i alone in the dark here, since, exept one tag from Sgaist helping me, nothing happened.
No you're not. It's just that you asked your question on the weekend on a voluntary driven forum, hence a bit less active :-)