Передача видео с камеры клиенту OPENCV с++ tcp ip

K

Пользователь

от konstitycii , в категории: C/C++ , год назад

Доброе время суток. Я новичок в 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;
}


Facebook Vk Ok Twitter LinkedIn Telegram Whatsapp

1 ответ

Пользователь

от jaren , год назад

@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".