0

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!

  • I've just tried the signal&slot method with readyRead reuse and QDatastream data managment without any waitforxxx functions inside. It work with one instance. but if i make two instances of client connection, it fail , same way than before, "error". If i make two separate object with same code inside, 'ie client1.cpp &client2.cpp", it work. so maybe it is related to object creation of tcp client or parent/child relation, or i don't know, something i'm way way far to understand.... Thank you all for any guess! – bertrand HAHN Jul 08 '22 at 22:47
  • I've just tried with a move to thread method, but it crashes, maybe for other reason since it tells that TCP is creted from another thread.but guess what: if i make two different classes (client1 & client2) it still work. really really a matter of things i doesn't even sense... – bertrand HAHN Jul 08 '22 at 23:25
  • Hello all, finally i foud my mistake, it is in declaring the imageSize in static....with one instance, it is fine..but not with more than one! – bertrand HAHN Jul 10 '22 at 00:23

1 Answers1

0

in Instantiation of my streamerSlot classe, i uses a static variable. since you just have one ovbject instantiated, it seems to works. BUT if you instantiate more than one object, the static declaration, is declared just one time...one time for every instantiations, this is why my instantiations was bad. Hope this will help . Regards

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 11 '22 at 13:26