Доброе время суток. Я новичок в OpenCV. У меня стоит задача, написать программу клиент-сервер, которая будет записывать видео в буфер, до тех пор, пока не подключится клиент к камере, и дальше передать этот буфер с видео ему через TCP IP.
Код все равно не работает так, как нужно. Он записывает видео в файл на клиенте размером 5.7 kB,продолжительностью 0 секунд, т.е. либо клиент не так принимает данные, либо сервер неверно их формирует и отправляет. Ещё раз напомню, что задача моя, состоит в том, чтобы разработать сервер, который будет записывать видео до тех пор, пока не подключится клиент к нему, дальше запись прекращается и передаются данные на клиент, где уже сохраняются в виде файла. Буду рад любой помощи!
Сервер (ВИДЕОКАМЕРА)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
#include <unistd.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <string> #include <vector> #include <opencv2/opencv.hpp> #include <fcntl.h> #include <opencv2/highgui/highgui.hpp> #include <opencv2/core/core.hpp> using namespace std; using namespace cv; int c,new_socket; std::vector<uchar> buffer; std::vector<uchar> arrak; int i=0,k=0; int bbytee; Mat image; int main() { int sock,listener; std::vector<uchar> buf; std::vector<int> params(2); params[0] = cv::IMWRITE_PNG_COMPRESSION; params[1] = 10; struct sockaddr_in addr,client; sock = socket(AF_INET, SOCK_STREAM, 0); // создание сокета if(sock < 0) { perror("socket"); exit(1); } fcntl(sock, F_SETFL, O_NONBLOCK); // установка н****кирующего режима memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(3425); addr.sin_addr.s_addr = htonl(INADDR_ANY); // подключение к любому IP-адресу VideoCapture cap(2); // захват видеокамеры if(!cap.isOpened()) { // проверка условий подключения cout<< "Could not open the camera" << endl; close(sock); return -1; } if(bind(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) { // связывание сокетов perror("[server] binding failed!"); exit(2); } Mat frame = Mat::zeros(1080, 1920, CV_8UC3); // создание матрицы изображения int imgSize = frame.cols*frame.rows*3; // узнаем размер изображения на три канала listen(sock, 1); // прослушивание подключений c = sizeof(struct sockaddr_in); // размер структуры while (true) { puts("Waiting for incoming connections..."); new_socket = accept(sock, (struct sockaddr *)&client, (socklen_t*)&c);// прием сокета cout << "New_socket: " << new_socket << endl; cap >> frame;//чтение с cap в frame imencode(".jpg", frame, buffer,params); //перекодирование в буфер buffer if(frame.empty()) { cerr<<"[client] VideoCapture(0) error!"<<endl; } cout<< ++i << ":"<< frame.isContinuous()<<"," <<frame.size()<<endl; if(new_socket == -1) {//если подключения клиента нет, то... puts("Connection not accepted"); cout << "new_socket = " << new_socket << "\n"; } else {//если подключился клиент, то .. int size = buffer.size()*sizeof buffer[0];//определяем размер буфера send(new_socket, &size, sizeof(size), 0);// передаем размер буфера клиенту cout << "Razmer" << size << endl; cout << "Transmission started" << endl; sleep(5); if(buffer.size()) { cout <<"PEREDASHA POSHLA"<<endl; send(new_socket,buffer.data(), buffer.size()*sizeof buffer[0], 0);//передача данных(буфера) клиенту } cout << "Transmission ended"<<endl; break; } } cout << "END" << endl; close(sock); // закрытие сокета return 0; } |
Клиент ( ПК )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
#include <unistd.h> #include <arpa/inet.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <sys/socket.h> #include <string> #include <vector> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; int recv_size; Mat frame; std::vector<uchar> buffer; uint32_t size = 0; int main() { int sock; struct sockaddr_in addr; sock = socket(AF_INET, SOCK_STREAM, 0);// создание нового сокета if (sock < 0) { perror("socket"); exit(1); } memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(3425); addr.sin_addr.s_addr = htonl(INADDR_ANY); addr.sin_addr.s_addr = inet_addr("192.168.3.11");// IP камеры if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) { // подключение к серверу perror("connect"); exit(2); } if ((recv_size = recv(sock, (char*)&size, sizeof(uint32_t), 0)) != sizeof(uint32_t)) { //прием размера буфера perror("recv"); exit(3); } cout << "SIZE FRAME: " << recv_size << endl; int num_of_recv_bytes; VideoWriter outputVideo; Size S = Size((int)1920, (int)1080);//размер изображения outputVideo.open("receive.avi", VideoWriter::fourcc('H', '2', '6', '4'), 25, S, true);//открытие файла receive.avi для записи int imgSize = 1920 * 1080 * 3; buffer.resize(recv_size);//изменение буфера клиента под размер буфера сервера recv(sock, buffer.data(), recv_size, 0);//прием буфера с камеры cout << "IDET DO IMDECODE " << recv_size << endl; frame = imdecode(buffer, IMREAD_COLOR);//конвертирование данных в формат Mat outputVideo << frame;//запись буфера в файл receive.avi с указанными параметрами close(sock); outputVideo.release();//освобождение outputVideo return 0; } |
@konstitycii Ваш код имеет несколько проблем, которые могут приводить к неверному поведению программы. Ниже я приведу список наиболее значимых проблем и предложу возможные решения.
После принятия нового клиентского соединения Вы записываете в буфер изображение и отправляете его клиенту. Однако, при этом Вы не продолжаете работу с камерой и не ждете новых клиентов. Вместо этого, программа завершает свою работу. Если клиент подключится позже, ему не удастся получить изображение.
Чтобы исправить эту ошибку, Вам следует перенести цикл чтения изображения и отправки его клиенту внутрь цикла while, который будет работать до тех пор, пока не будет получен новый клиентский запрос. В таком случае Вы сможете принимать запросы на подключение несколько раз и отправлять каждому клиенту свое изображение.
При передаче размера буфера клиенту Вы используете следующий код:
1 2 |
int size = buffer.size()*sizeof buffer[0]; send(new_socket, &size, sizeof(size), 0); |
Однако, размер буфера не равен размеру в байтах, поэтому данная логика некорректна. Вместо этого Вам следует передавать размер буфера в байтах, используя функцию sizeof, следующим образом:
1 2 |
int size = buffer.size(); send(new_socket, &size, sizeof(size), 0); |
В Вашем коде отсутствует обработка ошибок при передаче данных. В частности, Вы не проверяете возвращаемое значение функции send, которая может вернуть отрицательное значение в случае ошибки. В таком случае, Вам следует обрабатывать ошибку и попробовать отправить данные еще раз.
В качестве формата изображения Вы используете ".jpg". Однако, при этом Вы записываете изображение в матрицу frame с форматом CV_8UC3, что указывает на наличие трех каналов (красный, зеленый, синий). В результате при передаче данных Вам следует использовать формат, который соответствует данному типу изображения, например, "MJPG".