Задача заключалась в следующем:
1. Написать программу сервер, которая загружает видео из файла, сжимает в JPEG и передает по протоколу TCP программе клиенту.
2. Написать программу клиент, которая принимает видео по TCP, декодирует и отображает.
Описанные выше задачи являются элементарными и служат для того, чтобы «отработать» технологию. Кажется, что эта тема уже описана давно, но после некоторого времени в поиске готового ответа (куска кода) я понял, что не все очевидно. Поэтому здесь я привожу свой опыт в этом вопросе. Возможно кому-то мой опыт окажется полезным.
Программу разрабатывал в среде Visual Studio 2015 с использование библиотеки OpenCV версии 3.1. Опущу этапы создания проекта, подключения библиотек и написание кода, отвечающего за сетевое взаимодействие. В конце статьи дам ссылку на исходные коды проекта с полными коментариями в коде для быстрого понимания. Сосредоточимся на главной проблеме: как получить видео из файла, сжать его в JPEG с нужной степенью компрессии и передать по сети с дальнейшим декодированием и отображением на приемной стороне. Ниже небольшой кусок кода, показывающий как сжать кадр видео и передать его по сети (с учетом того, что соединение с приемной стороной установлено).
// Объявляем переменные Mat srcMat; // Данные исходного изображения vector<uchar> imgBuf; // Буфер для сжатого изображения vector<int> quality_params = vector<int>(2); // Вектор параметров качества сжатия quality_params[0] = CV_IMWRITE_JPEG_QUALITY; // Кодек JPEG quality_params[1] = 20; // По умолчанию качество сжатия (95) 0-100 // Захватываем кадр видео cd.frame = cvQueryFrame(cd.videocap); // Получаем изображение в вектор srcMat = cv::cvarrToMat(cd.frame); // Кодируем изображение кодеком JPEG imencode(".jpg", srcMat, imgBuf, quality_params); // Отправляем данные send(clientSocket, (const char*)&imgBuf[0], static_cast<int>(imgBuf.size()), 0);
Теперь опишем как распаковать изображение на приемной стороне. Ниже фрагмент кода программы клиента.
// Объявляем переменные int iResult; // Переменная на результат операций const int MAX_BUF_SIZE = 2073600; // Произвольно максимальный размер приемного буфера unsigned char *buf = new unsigned char[MAX_BUF_SIZE]; // Буфер для прима сообщений vector<uchar> videoBuffer; // Буфер данных изображения Mat jpegimage; // Вектор данных изображения IplImage img; // Изображение для вывода // Ожидаем прихода данных iResult = recv(connectSocket, (char *)&buf[0], MAX_BUF_SIZE, 0); if (iResult > 0) { // Если пришли данные изображения, копируем их videoBuffer.resize(iResult); memcpy((char*)(&videoBuffer[0]), buf, iResult); // Декодируем данные jpegimage = imdecode(Mat(videoBuffer), CV_LOAD_IMAGE_COLOR); img = jpegimage; // Выводим изображение cvShowImage("Recieved Video", &img); // Ожидаем отклика управления (произвольно 5 ms) cvWaitKey(5); }//if (iResult > 0)...
Описанные операции производятся для каждого кадра видео. Надеюсь этот небольшой пример поможет решить возникающие трудности сжатия и передачи потокового видео через TCP используя библиотеку OpenCV. Ниже по ссылке скриншот работы клиента и сервера.
www.dropbox.com/s/ikisl8rjxxd5d0f/%D0%91%D0%B5%D0%B7%D1%8B%D0%BC%D1%8F%D0%BD%D0%BD%D1%8B%D0%B9.png
Ввиду того, что коэффициент сжатия стоит 20 (высокое сжатие) на приемной стороне можно заметить значительные искажения картинки.
Исходные коды программ сервера и клиента с подробными комментариями вы можете посмотреть по ссылкам:
www.dropbox.com/s/3ucjsdes7khcr24/Server.cpp?dl=0
www.dropbox.com/s/14mat8bhlonz392/Client.cpp?dl=0
Удачи во всех начинаниях!

