From ea952e198155283a55779f75d852a7d33de7c7df Mon Sep 17 00:00:00 2001 From: Dustin Thomas Date: Wed, 26 Mar 2025 19:13:13 -0500 Subject: [PATCH] rewrite packets to send in jpeg form --- client.cpp | 27 +++++++--------- meson.build | 2 +- packets/ImagePacket.cpp | 56 -------------------------------- packets/ImagePacket.h | 24 -------------- server.cpp | 22 ++++++------- transfer.h | 71 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 94 insertions(+), 108 deletions(-) delete mode 100644 packets/ImagePacket.cpp delete mode 100644 packets/ImagePacket.h create mode 100644 transfer.h diff --git a/client.cpp b/client.cpp index 5d30c19..d8661d9 100644 --- a/client.cpp +++ b/client.cpp @@ -4,13 +4,15 @@ #include #include #include -#include +#include "transfer.h" using namespace std; int main() { - cv::VideoCapture cap = cv::VideoCapture(0); + // create video capture + //cv::VideoCapture cap = cv::VideoCapture(0); + // create socket int clientSocket = socket(AF_INET, SOCK_STREAM, 0); // specifying address @@ -19,26 +21,19 @@ int main() { serverAddress.sin_port = htons(8080); serverAddress.sin_addr.s_addr = INADDR_ANY; - cv::Mat image = cv::Mat::zeros(cv::Size(640, 480), CV_8UC3); - ImagePacket packet = ImagePacket(&image, 0); + cv::Mat image = cv::Mat(cv::Size(640, 480), CV_8UC3, cv::Scalar(255, 0, 0)); // sending connection request - connect(clientSocket, (struct sockaddr*)&serverAddress, + connect(clientSocket, reinterpret_cast(&serverAddress), sizeof(serverAddress)); - unsigned long pos = 0; - unsigned long len = image.total() * image.elemSize(); - char buffer[IMAGEPACKET_SIZE]; - - cout << "Image length " << len << endl; + // create buffer for serialization + vector imgbuf; while (true) { - cap.read(image); - packet = ImagePacket(&image, pos); - packet.serialize(buffer); - send(clientSocket, buffer, sizeof(buffer), 0); - cout << "Sent packet with index " << pos << endl; - pos = (pos + SLICE_SIZE) % len; + //cap.read(image); + cout << "Sending image" << endl; + sendImage(clientSocket, image, imgbuf); } close(clientSocket); diff --git a/meson.build b/meson.build index a38c26d..c7bdc4b 100644 --- a/meson.build +++ b/meson.build @@ -13,7 +13,7 @@ opencv = dependency('opencv4', version : '>=4.0.0') # SOURCE FILES #======================================================================================================================= # common files between client / server -common = ['packets/ImagePacket.cpp', 'packets/ImagePacket.h'] +common = ['transfer.h'] # client-only files client = common + ['client.cpp'] # server-only files diff --git a/packets/ImagePacket.cpp b/packets/ImagePacket.cpp deleted file mode 100644 index 8fb26f8..0000000 --- a/packets/ImagePacket.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "ImagePacket.h" - -/* - * Construct a packet from a raw array of unsigned chars, and a beginning index. It will take PACKET_SIZE bytes from the - * start and add it to its slice. This will be more useful for embedded scenarios where OpenCV will likely not be used. - */ -ImagePacket::ImagePacket(const uchar *image, const int begin) { - this->begin = begin; - this->slice = new uchar[SLICE_SIZE]; - const uchar *target = &image[begin]; - // TODO: handle out of index cases, pad with zeroes. probably also instantiate our byte array with zeroes - for (int i = 0; i < SLICE_SIZE; i++) { - this->slice[i] = target[begin + i]; - } -} - -/* - * destructor frees memory - */ -ImagePacket::~ImagePacket() = default; - -unsigned long ImagePacket::getBegin() const { - return this->begin; -} - - -/* - * Apply the packet to an OpenCV Mat. - */ -int ImagePacket::apply(const cv::Mat *image) const { - uchar *target = &image->data[this->begin]; - // TODO: handle out of index cases - for (int i = 0; i < SLICE_SIZE; i++) { - target[this->begin + i] = this->slice[i]; - } - // TODO: return the actual written size of the packet - return SLICE_SIZE; -} - -/* - * Serialize the object into a byte array - */ -void ImagePacket::serialize(char* buffer) const { - // TODO: keep the endianness consistent between systems - std::memcpy(buffer, &this->begin, sizeof(this->begin)); - std::memcpy(buffer + sizeof(this->begin), &this->slice, SLICE_SIZE * sizeof(uchar)); -} - -/* - * Deserialize the object from a byte array - */ -void ImagePacket::deserialize(char* buffer) { - // TODO: keep the endianness consistent between systems - std::memcpy(&this->begin, buffer, sizeof(this->begin)); - std::memcpy(this->slice, buffer + sizeof(this->begin), SLICE_SIZE * sizeof(uchar)); -} \ No newline at end of file diff --git a/packets/ImagePacket.h b/packets/ImagePacket.h deleted file mode 100644 index 90b2ad8..0000000 --- a/packets/ImagePacket.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef IMAGEPACKET_H -#define IMAGEPACKET_H -#include - -#define SLICE_SIZE 768 -#define IMAGEPACKET_SIZE sizeof(int) + (SLICE_SIZE * sizeof(uchar)) - -class ImagePacket { - public: - ImagePacket(const cv::Mat *image, int begin) : ImagePacket(image->data, begin) {} - ImagePacket(const uchar *image, int begin); - ~ImagePacket(); - - unsigned long getBegin() const; - int apply(const cv::Mat *image) const; - - void serialize(char* buffer) const; - void deserialize(char* buffer); - private: - unsigned long begin; - uchar *slice; -}; - -#endif //IMAGEPACKET_H diff --git a/server.cpp b/server.cpp index 2255d4a..603137f 100644 --- a/server.cpp +++ b/server.cpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include "transfer.h" using namespace std; @@ -21,7 +21,7 @@ int main() { serverAddress.sin_addr.s_addr = INADDR_ANY; // binding socket. - bind(serverSocket, (struct sockaddr*)&serverAddress, + bind(serverSocket, reinterpret_cast(&serverAddress), sizeof(serverAddress)); // listening to the assigned socket @@ -32,21 +32,21 @@ int main() { = accept(serverSocket, nullptr, nullptr); // TODO: handle multiple images - cv::Mat image = cv::Mat::zeros(480, 640, CV_8UC3); - - // setup packet buffer - char buffer[IMAGEPACKET_SIZE] = { 0 }; - ImagePacket packet = ImagePacket(&image, 0); + cv::Mat image = cv::Mat::zeros(cv::Size(640, 480), CV_8UC3); bool running = true; // TODO: make this asynchronous. probably do that in tandem with setting up networking while (running) { // receive data - recv(clientSocket, buffer, sizeof(buffer), 0); - packet.deserialize(buffer); - cout << "received packet with index " << packet.getBegin() << endl; - packet.apply(&image); + vector buffer; + cout << "Receiving image" << endl; + recvImage(clientSocket, buffer); + + cout << "Applying image" << endl; + applyImage(image, &buffer); + + cout << "Displaying image" << endl; imshow("image", image); running = cv::waitKey(30) != 27; } diff --git a/transfer.h b/transfer.h new file mode 100644 index 0000000..ae96593 --- /dev/null +++ b/transfer.h @@ -0,0 +1,71 @@ +#ifndef TRANSFER_H +#define TRANSFER_H + +#include +#include +#include +#include + +inline void serializeImage(const cv::Mat& image, std::vector& buffer) { + cv::imencode(".jpg", image, buffer); +} + +int sendImage(int socket, const cv::Mat& image, std::vector& buffer) { + serializeImage(image, buffer); + size_t totalSent = 0; + + // first send the size of the serialized image + const size_t size = buffer.size(); + std::cout << "Buffer size: " << size << std::endl; + if (const ssize_t sent = send(socket, &size, sizeof(size), 0); sent == -1) { + perror("Error sending data"); + return -1; + } + + // then start sending the serialized image + while (totalSent < size) { + const ssize_t sent = send(socket, buffer.data() + totalSent, size - totalSent, 0); + if (sent == -1) { + perror("Error sending data"); + return -1; + } + totalSent += sent; + std::cout << "Packet sent (" << sent << " bytes, total " << totalSent << " bytes)" << std::endl; + } + return 0; +} + +int recvImage(int socket, std::vector& buffer) { + size_t dataSize; + + // first receive the size of the image + ssize_t sizeReceived = recv(socket, &dataSize, sizeof(size_t), 0); + if (sizeReceived <= 0) { + return -1; + } + + std::cout << "Buffer size: " << dataSize << std::endl; + + // resize the buffer to fit the whole image + buffer.resize(dataSize); + + // start receiving the image until the whole thing arrives + size_t totalReceived = 0; + while (totalReceived < dataSize) { + ssize_t bytesReceived = recv(socket, buffer.data() + totalReceived, dataSize, 0); + if (bytesReceived <= 0) { + buffer.clear(); + return -1; + } + totalReceived += bytesReceived; + std::cout << "Packet received (" << bytesReceived << " bytes, total " << totalReceived << " bytes)" << std::endl; + } + return 0; +} + +bool applyImage(cv::Mat& image, std::vector *src) { + // decode the image into an OpenCV Mat + cv::imdecode(*src, 0, &image); + return true; +} +#endif //TRANSFER_H