setup more proper logging and get stuff working maybe
This commit is contained in:
parent
ea952e1981
commit
ed8c594a30
10
client.cpp
10
client.cpp
@ -10,7 +10,7 @@ using namespace std;
|
|||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
// create video capture
|
// create video capture
|
||||||
//cv::VideoCapture cap = cv::VideoCapture(0);
|
cv::VideoCapture cap = cv::VideoCapture(0);
|
||||||
|
|
||||||
// create socket
|
// create socket
|
||||||
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
|
int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
@ -21,18 +21,20 @@ int main() {
|
|||||||
serverAddress.sin_port = htons(8080);
|
serverAddress.sin_port = htons(8080);
|
||||||
serverAddress.sin_addr.s_addr = INADDR_ANY;
|
serverAddress.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
cv::Mat image = cv::Mat(cv::Size(640, 480), CV_8UC3, cv::Scalar(255, 0, 0));
|
cv::Mat image = cv::Mat::zeros(cv::Size(640, 480), CV_8UC3);
|
||||||
|
|
||||||
|
info("Ready to connect.");
|
||||||
// sending connection request
|
// sending connection request
|
||||||
connect(clientSocket, reinterpret_cast<sockaddr *>(&serverAddress),
|
connect(clientSocket, reinterpret_cast<sockaddr *>(&serverAddress),
|
||||||
sizeof(serverAddress));
|
sizeof(serverAddress));
|
||||||
|
|
||||||
|
info("Connected.");
|
||||||
// create buffer for serialization
|
// create buffer for serialization
|
||||||
vector<uchar> imgbuf;
|
vector<uchar> imgbuf;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
//cap.read(image);
|
cap.read(image);
|
||||||
cout << "Sending image" << endl;
|
trace("Sending image");
|
||||||
sendImage(clientSocket, image, imgbuf);
|
sendImage(clientSocket, image, imgbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
178
logging.h
Normal file
178
logging.h
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
#ifndef LOGGING_H
|
||||||
|
#define LOGGING_H
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <chrono>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
// Logging levels
|
||||||
|
#define LOG_ERROR 0
|
||||||
|
#define LOG_WARN 1
|
||||||
|
#define LOG_INFO 2
|
||||||
|
#define LOG_DEBUG 3
|
||||||
|
#define LOG_TRACE 4
|
||||||
|
|
||||||
|
// Set logging arguments
|
||||||
|
// TODO: set these by compiler arguments or env vars or something
|
||||||
|
#define LOGGING LOG_DEBUG // logging level
|
||||||
|
#define LOGGING_COLOR true // enable color
|
||||||
|
#define LOGGING_TIMESTAMP true // enable timestamp
|
||||||
|
#define LOGGING_TIMESTAMP_FMT "%Y-%m-%dT%H:%M:%S%z" // timestamp format (local time)
|
||||||
|
#define LOGGING_POSITION true // display position (only works on C++20 or newer)
|
||||||
|
|
||||||
|
// Color codes
|
||||||
|
#define ANSI_RESET "\033[0m"
|
||||||
|
#define ANSI_BLACK "\033[30m" /* Black */
|
||||||
|
#define ANSI_RED "\033[31m" /* Red */
|
||||||
|
#define ANSI_GREEN "\033[32m" /* Green */
|
||||||
|
#define ANSI_YELLOW "\033[33m" /* Yellow */
|
||||||
|
#define ANSI_BLUE "\033[34m" /* Blue */
|
||||||
|
#define ANSI_MAGENTA "\033[35m" /* Magenta */
|
||||||
|
#define ANSI_CYAN "\033[36m" /* Cyan */
|
||||||
|
#define ANSI_WHITE "\033[37m" /* White */
|
||||||
|
#define ANSI_BOLD "\033[1m" /* Bold */
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void print(T t) {
|
||||||
|
std::cout << t << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename... Args>
|
||||||
|
void print(T t, Args... args) {
|
||||||
|
std::cout << t;
|
||||||
|
print(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void printTimestamp() {
|
||||||
|
#if LOGGING_TIMESTAMP
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
auto time_c = std::chrono::system_clock::to_time_t(now);
|
||||||
|
std::tm time_tm;
|
||||||
|
localtime_r(&time_c, &time_tm);
|
||||||
|
std::cout << std::put_time(&time_tm, LOGGING_TIMESTAMP_FMT) << ": ";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're on C++20 or later, then use the source_location header and add source location to logs
|
||||||
|
#if __cplusplus >= 202002L
|
||||||
|
#include <source_location>
|
||||||
|
|
||||||
|
inline void printPosition(std::source_location& location) {
|
||||||
|
#if LOGGING_POSITION
|
||||||
|
std::cout << location.file_name() << ":" << location.function_name << ":" << ANSI_CYAN << location.line() << ANSI_RESET << ": ";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void printHeader(std::string name, std::string color, std::source_location& location) {
|
||||||
|
#if LOGGING_COLOR
|
||||||
|
std::cout << ANSI_BOLD << color << "[" << name << "] " << ANSI_RESET;
|
||||||
|
printTimestamp();
|
||||||
|
printPosition(location);
|
||||||
|
#else
|
||||||
|
printHeader(name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void printHeader(std::string name, std::source_location& location) {
|
||||||
|
std::cout << "[" << name << "] ";
|
||||||
|
printTimestamp();
|
||||||
|
printPosition(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args, typename Sl = std::source_location>
|
||||||
|
void trace(Args... args, Sl location = std::source_location::current()) {
|
||||||
|
#if LOGGING >= LOG_TRACE
|
||||||
|
printHeader("TRACE", ANSI_CYAN, location);
|
||||||
|
print(args...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args, typename Sl = std::source_location>
|
||||||
|
void debug(Args... args, Sl location = std::source_location::current()) {
|
||||||
|
#if LOGGING >= LOG_DEBUG
|
||||||
|
printHeader("DEBUG", ANSI_MAGENTA, location);
|
||||||
|
print(args...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args, typename Sl = std::source_location>
|
||||||
|
void info(Args... args, Sl location = std::source_location::current()) {
|
||||||
|
#if LOGGING >= LOG_INFO
|
||||||
|
printHeader("INFO", ANSI_GREEN, location);
|
||||||
|
print(args...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args, typename Sl = std::source_location>
|
||||||
|
void warn(Args... args, Sl location = std::source_location::current()) {
|
||||||
|
#if LOGGING >= LOG_WARN
|
||||||
|
printHeader("WARN", ANSI_YELLOW, location);
|
||||||
|
print(args...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args, typename Sl = std::source_location>
|
||||||
|
void error(Args... args, Sl location = std::source_location::current()) {
|
||||||
|
#if LOGGING >= LOG_ERROR
|
||||||
|
printHeader("ERROR", ANSI_RED, location);
|
||||||
|
print(args...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
inline void printHeader(std::string name, std::string color) {
|
||||||
|
#if LOGGING_COLOR
|
||||||
|
std::cout << ANSI_BOLD << color << "[" << name << "] " << ANSI_RESET;
|
||||||
|
printTimestamp();
|
||||||
|
#else
|
||||||
|
printHeader(name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void printHeader(std::string name) {
|
||||||
|
std::cout << "[" << name << "] ";
|
||||||
|
printTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void trace(Args... args) {
|
||||||
|
#if LOGGING >= LOG_TRACE
|
||||||
|
printHeader("TRACE", ANSI_CYAN);
|
||||||
|
print(args...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void debug(Args... args) {
|
||||||
|
#if LOGGING >= LOG_DEBUG
|
||||||
|
printHeader("DEBUG", ANSI_MAGENTA);
|
||||||
|
print(args...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void info(Args... args) {
|
||||||
|
#if LOGGING >= LOG_INFO
|
||||||
|
printHeader("INFO", ANSI_GREEN);
|
||||||
|
print(args...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void warn(Args... args) {
|
||||||
|
#if LOGGING >= LOG_WARN
|
||||||
|
printHeader("WARN", ANSI_YELLOW);
|
||||||
|
print(args...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
void error(Args... args) {
|
||||||
|
#if LOGGING >= LOG_ERROR
|
||||||
|
printHeader("ERROR", ANSI_RED);
|
||||||
|
print(args...);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //LOGGING_H
|
@ -1,7 +1,8 @@
|
|||||||
#=======================================================================================================================
|
#=======================================================================================================================
|
||||||
# PROJECT SETTINGS
|
# PROJECT SETTINGS
|
||||||
#=======================================================================================================================
|
#=======================================================================================================================
|
||||||
project('video-streaming-poc', 'cpp')
|
project('video-streaming-poc', 'cpp', version : '0.0.1-SNAPSHOT',
|
||||||
|
default_options : ['c_std=c17', 'cpp_std=c++20'])
|
||||||
|
|
||||||
#=======================================================================================================================
|
#=======================================================================================================================
|
||||||
# DEPENDENCIES
|
# DEPENDENCIES
|
||||||
@ -13,7 +14,7 @@ opencv = dependency('opencv4', version : '>=4.0.0')
|
|||||||
# SOURCE FILES
|
# SOURCE FILES
|
||||||
#=======================================================================================================================
|
#=======================================================================================================================
|
||||||
# common files between client / server
|
# common files between client / server
|
||||||
common = ['transfer.h']
|
common = ['transfer.h', 'logging.h']
|
||||||
# client-only files
|
# client-only files
|
||||||
client = common + ['client.cpp']
|
client = common + ['client.cpp']
|
||||||
# server-only files
|
# server-only files
|
||||||
|
12
server.cpp
12
server.cpp
@ -24,12 +24,13 @@ int main() {
|
|||||||
bind(serverSocket, reinterpret_cast<sockaddr *>(&serverAddress),
|
bind(serverSocket, reinterpret_cast<sockaddr *>(&serverAddress),
|
||||||
sizeof(serverAddress));
|
sizeof(serverAddress));
|
||||||
|
|
||||||
|
info("Ready to accept connections.");
|
||||||
// listening to the assigned socket
|
// listening to the assigned socket
|
||||||
listen(serverSocket, 5);
|
listen(serverSocket, 5);
|
||||||
|
|
||||||
// accepting connection request
|
// accepting connection request
|
||||||
int clientSocket
|
int clientSocket = accept(serverSocket, nullptr, nullptr);
|
||||||
= accept(serverSocket, nullptr, nullptr);
|
info("Client connected.");
|
||||||
|
|
||||||
// TODO: handle multiple images
|
// TODO: handle multiple images
|
||||||
cv::Mat image = cv::Mat::zeros(cv::Size(640, 480), CV_8UC3);
|
cv::Mat image = cv::Mat::zeros(cv::Size(640, 480), CV_8UC3);
|
||||||
@ -39,14 +40,13 @@ int main() {
|
|||||||
while (running) {
|
while (running) {
|
||||||
// receive data
|
// receive data
|
||||||
vector<uchar> buffer;
|
vector<uchar> buffer;
|
||||||
|
trace("Receiving image");
|
||||||
cout << "Receiving image" << endl;
|
|
||||||
recvImage(clientSocket, buffer);
|
recvImage(clientSocket, buffer);
|
||||||
|
|
||||||
cout << "Applying image" << endl;
|
trace("Applying new data to image");
|
||||||
applyImage(image, &buffer);
|
applyImage(image, &buffer);
|
||||||
|
|
||||||
cout << "Displaying image" << endl;
|
trace("Displaying image");
|
||||||
imshow("image", image);
|
imshow("image", image);
|
||||||
running = cv::waitKey(30) != 27;
|
running = cv::waitKey(30) != 27;
|
||||||
}
|
}
|
||||||
|
54
transfer.h
54
transfer.h
@ -4,7 +4,24 @@
|
|||||||
#include <opencv2/core/mat.hpp>
|
#include <opencv2/core/mat.hpp>
|
||||||
#include <opencv2/imgcodecs.hpp>
|
#include <opencv2/imgcodecs.hpp>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <iostream>
|
#include <logging.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
struct imageHeader {
|
||||||
|
size_t size;
|
||||||
|
chrono::milliseconds timestamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
chrono::milliseconds getMillis() {
|
||||||
|
// Get current time
|
||||||
|
const auto now = chrono::system_clock::now();
|
||||||
|
|
||||||
|
// Get time since epoch in milliseconds
|
||||||
|
const chrono::duration ms = chrono::duration_cast<chrono::milliseconds>(now.time_since_epoch());
|
||||||
|
|
||||||
|
return chrono::milliseconds(ms.count());
|
||||||
|
}
|
||||||
|
|
||||||
inline void serializeImage(const cv::Mat& image, std::vector<uchar>& buffer) {
|
inline void serializeImage(const cv::Mat& image, std::vector<uchar>& buffer) {
|
||||||
cv::imencode(".jpg", image, buffer);
|
cv::imencode(".jpg", image, buffer);
|
||||||
@ -16,9 +33,13 @@ int sendImage(int socket, const cv::Mat& image, std::vector<uchar>& buffer) {
|
|||||||
|
|
||||||
// first send the size of the serialized image
|
// first send the size of the serialized image
|
||||||
const size_t size = buffer.size();
|
const size_t size = buffer.size();
|
||||||
std::cout << "Buffer size: " << size << std::endl;
|
const chrono::milliseconds timestamp = getMillis();
|
||||||
if (const ssize_t sent = send(socket, &size, sizeof(size), 0); sent == -1) {
|
imageHeader header;
|
||||||
perror("Error sending data");
|
header.size = size;
|
||||||
|
header.timestamp = timestamp;
|
||||||
|
trace("Buffer size: ", size);
|
||||||
|
if (const ssize_t sent = send(socket, &header, sizeof(header), 0); sent == -1) {
|
||||||
|
error("Error sending data header");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,25 +47,27 @@ int sendImage(int socket, const cv::Mat& image, std::vector<uchar>& buffer) {
|
|||||||
while (totalSent < size) {
|
while (totalSent < size) {
|
||||||
const ssize_t sent = send(socket, buffer.data() + totalSent, size - totalSent, 0);
|
const ssize_t sent = send(socket, buffer.data() + totalSent, size - totalSent, 0);
|
||||||
if (sent == -1) {
|
if (sent == -1) {
|
||||||
perror("Error sending data");
|
error("Error sending data");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
totalSent += sent;
|
totalSent += sent;
|
||||||
std::cout << "Packet sent (" << sent << " bytes, total " << totalSent << " bytes)" << std::endl;
|
debug("Packet sent (", sent, " bytes, total ", totalSent, " bytes)");
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int recvImage(int socket, std::vector<uchar>& buffer) {
|
int recvImage(int socket, std::vector<uchar>& buffer) {
|
||||||
size_t dataSize;
|
|
||||||
|
|
||||||
// first receive the size of the image
|
// first receive the size of the image
|
||||||
ssize_t sizeReceived = recv(socket, &dataSize, sizeof(size_t), 0);
|
imageHeader header;
|
||||||
if (sizeReceived <= 0) {
|
if (ssize_t recvd = recv(socket, &header, sizeof(imageHeader), 0); recvd <= 0) {
|
||||||
|
error("Error receiving data header");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Buffer size: " << dataSize << std::endl;
|
size_t dataSize = header.size;
|
||||||
|
chrono::milliseconds sentTime = header.timestamp;
|
||||||
|
|
||||||
|
trace("Buffer size: ", dataSize);
|
||||||
|
|
||||||
// resize the buffer to fit the whole image
|
// resize the buffer to fit the whole image
|
||||||
buffer.resize(dataSize);
|
buffer.resize(dataSize);
|
||||||
@ -54,18 +77,23 @@ int recvImage(int socket, std::vector<uchar>& buffer) {
|
|||||||
while (totalReceived < dataSize) {
|
while (totalReceived < dataSize) {
|
||||||
ssize_t bytesReceived = recv(socket, buffer.data() + totalReceived, dataSize, 0);
|
ssize_t bytesReceived = recv(socket, buffer.data() + totalReceived, dataSize, 0);
|
||||||
if (bytesReceived <= 0) {
|
if (bytesReceived <= 0) {
|
||||||
|
error("Error receiving data");
|
||||||
buffer.clear();
|
buffer.clear();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
totalReceived += bytesReceived;
|
totalReceived += bytesReceived;
|
||||||
std::cout << "Packet received (" << bytesReceived << " bytes, total " << totalReceived << " bytes)" << std::endl;
|
debug("Packet received (", bytesReceived, " bytes, total ", totalReceived, " bytes)");
|
||||||
}
|
}
|
||||||
|
chrono::milliseconds currentTime = getMillis();
|
||||||
|
|
||||||
|
chrono::milliseconds diff = currentTime - sentTime;
|
||||||
|
debug("Packet latency: ", diff.count(), "ms");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool applyImage(cv::Mat& image, std::vector<uchar> *src) {
|
bool applyImage(cv::Mat& image, std::vector<uchar> *src) {
|
||||||
// decode the image into an OpenCV Mat
|
// decode the image into an OpenCV Mat
|
||||||
cv::imdecode(*src, 0, &image);
|
cv::imdecode(*src, cv::IMREAD_UNCHANGED, &image);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif //TRANSFER_H
|
#endif //TRANSFER_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user