1

I am working on a Image Processing project where I get frames from camera and send the frame via TCP Connection built with Qt Libraries. I am trying to send 24 frames but when I run the program only 13 frames(roughly) arrive.

I use signals and slots to start connection with button and when connection establishes the timer starts and I send 24 frames in a second.

Edit: I switched to single connection server but it didn't affect performance much also sometimes frames get corrupted(?) (I only see blank frame)

tcpsender.cpp

#include "tcpsender.h"
#include "ui_tcpsender.h"

#include <QtWidgets>
#include <QtNetwork>
#include <QtCore>
#include <QDebug>
#include <QBuffer>
#include <QDataStream>

#define XRES 640
#define YRES 480


TCPSender::TCPSender(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::TCPSender)
{
    ui->setupUi(this);
    statusLabel = new QLabel(tr("Ready to send frames on port 6667"));
    statusLabel->setWordWrap(true);
    startButton = new QPushButton(tr("&Start"));
    auto quitButton = new QPushButton(tr("&Quit"));
    auto buttonBox = new QDialogButtonBox;
    buttonBox->addButton(startButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);

    socket = new QTcpSocket(this);
    connect(startButton, &QPushButton::clicked, this, &TCPSender::startConnection);
    connect(quitButton, &QPushButton::clicked, this, &TCPSender::close);
    connect(socket, SIGNAL(connected()), SLOT(startSending()));
    connect(&timer, &QTimer::timeout, this, &TCPSender::sendFrame);

    auto mainLayout = new QVBoxLayout;
    mainLayout->addWidget(statusLabel);
    mainLayout->addWidget(buttonBox);
    setLayout(mainLayout);

    setWindowTitle(tr("Broadcast Sender"));
    camera = new Camera("/dev/video0", XRES, YRES);

    time = QTime::currentTime();

}

TCPSender::~TCPSender()
{
    delete ui;
}

bool TCPSender::startConnection()
{
    if (socket->state() == QAbstractSocket::UnconnectedState)
    {

        socket->connectToHost(ui->lineEdit->text(), 6667, QIODevice::WriteOnly);
        return socket->waitForConnected();

    }
}

void TCPSender::startSending()
{
    startButton->setEnabled(false);
    timer.start(1000/24);
    qDebug()<<"Timer start";
}

bool TCPSender::sendFrame()
{
    if(socket->state()==QAbstractSocket::ConnectedState){
        auto frame = camera->frame();

        image = new QImage(frame.data,XRES,YRES,QImage::Format_RGB888);
        QImage im = image->convertToFormat(QImage::Format_Grayscale8);
        QByteArray ba;
        QBuffer buffer(&ba);
        im.save(&buffer,"BMP");

        qDebug()<<"writing socket";
        socket->write(ba);

        int speed = time.msecsTo(QTime::currentTime());
        time = QTime::currentTime();
        speed = 1000*300/speed;
        ui->label->setText(QString("%1 kb/s").arg(speed));
        delete image;

   }

}

receiver.cpp

#include "reciever.h"    
#include <QBuffer>
#include <QTcpSocket>
#include <QImage>
#include <QDebug>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <unistd.h>

Reciever::Reciever(QObject* parent): QTcpServer(parent)
{
    connect(this, SIGNAL(newConnection()), this, SLOT(addConnection()));
}

void Reciever::addConnection()
{
    qDebug()<<"Adding Connection";
    QTcpSocket* connection = nextPendingConnection();
    connect(connection, SIGNAL(readyRead()),
            this, SLOT(receiveImage()));

    connections.append(connection);
    QBuffer* buffer = new QBuffer(this);
    buffer->open(QIODevice::ReadWrite);
    buffers.insert(connection, buffer);

}

void Reciever::receiveImage()
{
    qDebug()<<"RECIEVE";
    QTcpSocket* socket = static_cast<QTcpSocket*>(sender());
    QBuffer* buffer = buffers.value(socket);
    qint64 bytes = buffer->write(socket->readAll());   
    emit sendBuffer(buffer,bytes);
}
onur cevik
  • 39
  • 6
  • 2
    A TCP stream has no structure. You can receive the data in any number of `readAll` calls. If you want a sequence of "frames", you need to add that structure yourself. – molbdnilo Jan 16 '19 at 15:44
  • @molbdnilo can you show me some example about the structure you talk about? I mean I am already can send frames the only problem is frame rate is low. – onur cevik Jan 16 '19 at 16:59

1 Answers1

1

You're calling startConnection(); at each timer tick. That has the effect of alternating between closing and reopening the connection.

  • You can either remove the call to startConnection in sendFrame, keeping the TCP connection open.

  • Or double you timer tick rate to timer.start(1000/48);

Tezirg
  • 1,629
  • 1
  • 10
  • 20
  • but I am checking if there is any active connection with `if(socket->state()==QAbstractSocket::ConnectedState)` right ?Then hoow do I call `startConnection()` at each timer tick ? Am I missing something here ? – onur cevik Jan 16 '19 at 17:07
  • 1
    @onurcevik Why do you need to connect and disconnect for each frame? With `TCP` you would usually connect once, leave the connection open while there is data to be exchanged and then disconnect. – G.M. Jan 16 '19 at 17:31
  • Every call to startConnection() actually toggles the connection on and off, which explains why you get half the frames. startButton::clicked is already connected to startConnection(), you shouldn't need to connect/disconnect after sending each Frame. – Tony J Jan 16 '19 at 18:57
  • @G.M. I tried to implement server-client system here : https://stackoverflow.com/questions/20546750/qtcpsocket-reading-and-writing/20558939 I couldn't read socket to buffer fora single connection. But I can with multiple connections with `QBuffer* buffer = buffers.value(socket);` . How can I read from socket to buffer for single connection ? – onur cevik Jan 16 '19 at 18:58
  • @onurcevik It sounds like the basic issue you have is as described by @molbdnilo -- you expect one write from the server to correspond to exactly one read on the client. The question you reference does provide an answer but, if you're not happy using that you might want to look at using the [`QWebSocketServer`](http://doc.qt.io/qt-5/qwebsocketserver.html) framework instead of `QTcpServer`. That way you can simply send each frame via [`QWebSocket::sendBinaryMessage](http://doc.qt.io/qt-5/qwebsocket.html#sendBinaryMessage). – G.M. Jan 16 '19 at 19:19