Я создаю удаленный просмотрщик для приложения обработки изображений, и мне нужно отправить результаты по сети, чтобы их можно было записать.В настоящее время я пытаюсь передавать изображения через сокет UDP на основе QUpdSocket.UDP хорош, потому что мне не нужно каждое изображение, чтобы я мог справиться с потенциальной потерей пакета.При тестировании реализации ниже на localhost я могу получить> 20 кадров в секунду, что намного больше, чем мне нужно в реальном приложении.Но как только я перехожу на 2 компьютера в сети, я почти не получаю никаких изображений.Я знаю, что пакеты пропускаются, потому что я вижу сетевую активность, но у меня пропадает загрузка эфира, или происходит что-то еще странное с декодированием / рендерингом.
Реализация довольно проста, поэтому любые указатели приветствуются.,Или я не должен делать это сам, потому что есть хорошие библиотеки для такого рода вещей?
Отправитель: сидит в ожидании, когда получатель отправит пакет и идентифицирует себя, после того, как один найден, привязывает изображение, разбивает его на размер дейтаграммы (здесь 508) и затем отправляет х количество дейтаграмм.
while (!foundReceiver) {
while (!socket.waitForReadyRead(500));
QByteArray buffer;
buffer.resize(socket.pendingDatagramSize());
socket.readDatagram(buffer.data(), buffer.size(), &sender, nullptr);
if (strcmp("RECEIVER", buffer) == 0) {
foundReceiver = true;
printf_s("Found receiver on : %s", sender.toString().toStdString().c_str());
}
}
printf_s("ctrl-c to quit\n");
while (!socket.hasPendingDatagrams()) {
cv::Mat img = ih->getLatestImage();
if (!img.empty()) {
std::vector<uint8_t> buf;
std::vector<int> params;
params.push_back(IMWRITE_JPEG_QUALITY);
params.push_back(80);
cv::imencode(".jpg", img, buf, params);
char imgDetails[28];
int numPackets = std::ceil((float)buf.size() / (float)datagramSize);
sprintf_s(imgDetails, "START %04d %04d %04d %06d", img.rows, img.cols, numPackets, datagramSize);
bool result = socket.writeDatagram(imgDetails, sizeof(imgDetails), sender, 9000);
for (int i = 0; i < numPackets; i++) {
int start = i * datagramSize;
int end = ((i + 1) * datagramSize);
if (end > buf.size())
end = buf.size();
std::vector<uint8_t> shortBuff((end - start) + 4);
char np[5];
sprintf_s(np, "%04d", i);
for (int j = 0; j < 4; j++)
shortBuff[j] = np[j];
std::copy(buf.begin() + start, buf.begin() + end, shortBuff.begin() + 4);
bool result = socket.writeDatagram((char*)shortBuff.data(), shortBuff.size(), sender, 9000);
}
}
camera.ExecuteSoftwareTrigger();
}
QByteArray buffer;
buffer.resize(socket.pendingDatagramSize());
socket.readDatagram(buffer.data(), buffer.size(), &sender, nullptr);
if (strcmp("RECEIVER DISCONNECT", buffer) == 0) {
foundReceiver = false;
printf_s("Receiver %s disconnected", sender.toString().toStdString().c_str());
}
}
Получатель: QUdpSocket вызывает datagramPending, который считывает дейтаграмму, отправляет ее в precessDatagram, которая решает, является ли заголовок или пакет изображения.Если это пакет изображений, то содержимое перемещается в буфер в месте, указанном 4-значным числом в начале пакета.Когда все пакеты изображений будут получены, преобразуйте буфер в изображение.
void UDPSocket::datagramPending() {
while (socket->hasPendingDatagrams()) {
QByteArray buffer;
buffer.resize(socket->pendingDatagramSize());
QHostAddress sender;
socket->readDatagram(buffer.data(), buffer.size(), &sender, nullptr);
emit receivedDatagram(buffer, sender);
}
}
void Receiver::processDatagram(QByteArray buff, QHostAddress address) {
if (buff.size() > 0) {
ImageHeader ih = isStartPacket(buff);
if (ih.startPacket) {
streamStarted = true;
senderAddress = address;
currentImageRows = ih.rows;
currentImageCols = ih.cols;
currentImageNumPackets = ih.numPackets;
currentImagePacketSize = ih.packetSize;
rawBuffer = std::vector<uint8_t>(currentImagePacketSize * currentImageNumPackets);
numReceivedPackets = 0;
}
else {
if (rawBuffer.size() > 0) {
std::vector<uint8_t> packetNumChar(5);
std::move(buff.begin(), buff.begin() + 4, packetNumChar.begin());
int packetNumber;
packetNumChar[4] = '\0';
sscanf_s((const char*)packetNumChar.data(), "%04d", &packetNumber);
int start = packetNumber * currentImagePacketSize;
if ((start + buff.size()) < rawBuffer.size())
std::move(buff.begin() + 4, buff.end(), rawBuffer.begin() + start);
numReceivedPackets++;
if (numReceivedPackets == currentImageNumPackets)
emit receivedImage(rawBuffer);
}
}
}
}
ImageHeader Receiver::isStartPacket(QByteArray buff) {
int rows = 0, cols = 0, numPackets = 0, packetSize = 0;
bool startPacket = false;
if (strncmp(buff.data(), startHeader, 5) == 0)
startPacket = true;
if (startPacket)
sscanf_s(buff.data(), "START %04d %04d %04d %06d", &rows, &cols, &numPackets, &packetSize);
ImageHeader ih = { startPacket, rows, cols, numPackets, packetSize };
return ih;
}
void Receiver::receivedImage(std::vector<uint8_t> buff) {
rawImageData = cv::Mat(1, buff.size(), CV_8UC1, buff.data());
currentImage = cv::imdecode(rawImageData, IMREAD_COLOR);
}