我使用UDP套接字將圖像從客戶端傳輸到服務器。對於編碼和解碼,我使用OpenCV。有時我會得到錯誤的解碼圖像,因爲丟失了一個或一些數據包(只發送了頭文件,請查看我的終端屏幕瞭解一些信息)。我必須將jpeg的質量降低到30,以減少錯誤的解碼圖像比例。如何使用條件代碼忽略丟失某些數據包的幀(不進行解碼工作),或者在imshow函數中不顯示錯誤的解碼圖像。如何修復或忽略通過套接字流式傳輸的錯誤解碼圖像
這裏的錯誤解碼圖像:
終端跟蹤屏幕:
我的客戶代碼:
#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:[email protected].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代碼
#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;
}
我想了解你的問題。當你檢測到一個意想不到的大小數據包時,你想跳過整個幀;基本上,當你檢查解碼失敗並繼續時,你會想檢查幀是否有意想不到的大小數據包並繼續? – Basya