I use UDP socket to stream image from client to server. For encoding and decoding I use OpenCV. Sometimes I get a wrong decoded image, because one or some packet is lossed (only the header is sent, please see my terminal screen for some info). I have to reduce the quality of jpeg to only 30 to decrease wrong decode image ratio. How can I use condition code to ignore that frame (not do decode work) in which some packet is lossed , or not show the wrong decoded image in imshow function.
Here's the wrong decoded image:
Terminal trace screen:
My Client code:
#include "PracticalSocket.h"
#include <iostream>
#include <cstdlib>
#include "cv.hpp"
#include "config.h"
#include "logger.h" // For trace
using namespace ModernCppCI;
using namespace cv;
using namespace std;
int main(int argc, char * argv[]) {
Logger log{__func__};
if ((argc < 4) || (argc > 4)) { // Test for correct number of arguments
log.error("Usage: {} <Server> <Server Port>\n <RTSP link>", argv[0]);
exit(1);
}
string servAddress = argv[1]; // First arg: server address
unsigned short servPort = Socket::resolveService(argv[2], "udp");
try {
UDPSocket sock;
int jpegqual = ENCODE_QUALITY; // It's 30
Mat frame, send;
vector < uchar > encoded;
//VideoCapture cap("rtsp://admin:centic.vn@10.49.34.234/Streaming/Channels/1?tcp"); // Grab the camera
VideoCapture cap(argv[3]);
if (!cap.isOpened()) {
log.error("OpenCV failed to open camera");
exit(1);
}
clock_t last_cycle = clock();
unsigned char pressed_key;
while (1) {
vector < int > compression_params;
cap >> send;
if(send.empty())continue;
// JPEG encoding
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
compression_params.push_back(jpegqual);
imencode(".jpg", send, encoded, compression_params);
imshow("send", send);
int total_pack = 1 + (encoded.size() - 1) / PACK_SIZE; // PACK_SIZE is 4096
int ibuf[1];
ibuf[0] = total_pack;
sock.sendTo(ibuf, sizeof(int), servAddress, servPort);
for (int i = 0; i < total_pack; i++)
sock.sendTo( & encoded[i * PACK_SIZE], PACK_SIZE, servAddress, servPort);
pressed_key = waitKey(1);
if(pressed_key == ' ')
pressed_key = waitKey(0);
if(pressed_key == 'q')
break;
clock_t next_cycle = clock();
double duration = (next_cycle - last_cycle) / (double) CLOCKS_PER_SEC;
log.info(" FPS: {}, kbps: {}, Processing time: {}ms" , (1 / duration), (PACK_SIZE * total_pack / duration / 1024 * 8), 1000*duration);
last_cycle = next_cycle;
}
// Destructor closes the socket
} catch (SocketException & e) {
log.error(e.what());
exit(1);
}
return 0;
}
Server code
#include "PracticalSocket.h"
#include <iostream>
#include <cstdlib>
#include "cv.hpp"
#include "config.h"
#include "logger.h" // For trace
using namespace ModernCppCI;
using namespace cv;
int main(int argc, char * argv[]) {
Logger log{__func__};
if (argc != 2) { // Test for correct number of parameters
log.error("Usage: {} <Server Port>", argv[0]);
exit(1);
}
unsigned short servPort = atoi(argv[1]); // First arg: Server port
try {
UDPSocket sock(servPort);
char buffer[BUF_LEN]; // Buffer for echo string
int recvMsgSize; // Size of received message
string sourceAddress; // Address of datagram source
unsigned short sourcePort; // Port of datagram source
clock_t last_cycle = clock();
unsigned char pressed_key;
while (1) {
// Block until receive message from a client
do {
recvMsgSize = sock.recvFrom(buffer, BUF_LEN, sourceAddress, sourcePort); // BUF_LEN is 65540
} while (recvMsgSize > sizeof(int));
int total_pack = ((int * ) buffer)[0];
log.info("expecting length of packs: {}", total_pack);
char * longbuf = new char[PACK_SIZE * total_pack];
for (int i = 0; i < total_pack; i++) {
recvMsgSize = sock.recvFrom(buffer, BUF_LEN, sourceAddress, sourcePort);
if (recvMsgSize != PACK_SIZE) {
log.error("Received unexpected size pack: {}", recvMsgSize);
continue;
}
memcpy( & longbuf[i * PACK_SIZE], buffer, PACK_SIZE); // Copy PACK_SIZE bytes from buffer to longbuf
}
log.info("Received packet from {}:{}", sourceAddress, sourcePort);
Logger::level(LogLevel::trace);
log.trace("longbuf size: {}", ((int * ) &longbuf)[0]);
Mat rawData = Mat(1, PACK_SIZE * total_pack, CV_8UC1, longbuf);
Mat frame = imdecode(rawData, CV_LOAD_IMAGE_COLOR);
if (frame.empty()) {
log.error("Decode failure!");
continue;
}
imshow("recv", frame);
pressed_key = waitKey(1);
if(pressed_key == ' ')
pressed_key = waitKey(0);
if(pressed_key == 'q')
break;
free(longbuf);
clock_t next_cycle = clock();
double duration = (next_cycle - last_cycle) / (double) CLOCKS_PER_SEC;
log.info(" FPS: {} , kbps: {} , Processing time: {}", (1 / duration), (PACK_SIZE * total_pack / duration / 1024 * 8), (next_cycle - last_cycle));
last_cycle = next_cycle;
}
} catch (SocketException & e) {
log.error(e.what());
exit(1);
}
return 0;
}