使用TCP协议完成在客户端和服务端之间的视频图像传输并保存,将网络编程,图像技术,c++等多方面结合起来
服务器端代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<opencv2/opencv.hpp>
#include<winsock.h>
#include <sstream>
#include <fstream>
#pragma comment(lib,"WS2_32.lib")
using namespace std;
using namespace cv;
void InitSocket()
{
WSAData wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData))
{
cout << "初始化套接字失败" << endl;
exit(0);
}
}
SOCKET Listen(int port = 37915)
{
SOCKET server = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == server)
{
cout << "创建套接字失败" << endl;
exit(0);
}
SOCKADDR_IN addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
if (::bind(server, (SOCKADDR*)&addr, sizeof(addr)) != 0)
{
cout << "连接失败" << WSAGetLastError() << endl;
return INVALID_SOCKET;
}
return server;
}
void ShowVideo()
{
//SOCKET server = Listen();
/*SOCKADDR_IN addr;
int addrSize = sizeof(addr);
char buffer[1024] = " ";
int index = 0;
Mat mat;
while (true)
{
SOCKET client = accept(server, (SOCKADDR*)&addr, &addrSize);
string preFix = "./Res/img";
preFix += to_string(index++) + ".jpg";
int size = 0;
//接受客户端发送数据
//接受大小
if (recv(client, (char*)&size, sizeof(int), 0) == SOCKET_ERROR)
{
cout << "接受失败" << endl;
exit(0);
}*/
//接受图片
//接完的图像不能直接显示,先保存存到本地
//SOCKET sockConn = accept(server, NULL, NULL);
//std::vector buffer(1024 * 1024); // 接收缓存,此处设为1MB大小
SOCKET server = socket(AF_INET, SOCK_STREAM, 0);
char buffer[2048] = " ";
SOCKET sockConn = accept(server, NULL, NULL);
Mat videoData;
while (true) {
int bytes = recv(sockConn, buffer, 2048, 0);
if (bytes <= 0) break;
// 将接收到的视频数据拼接在一起
videoData.push_back(Mat(1, bytes, CV_8UC1, buffer).clone());
}
closesocket(sockConn);
size_t fileSize = 0;
while (true) {
int bytes = recv(sockConn, buffer, 2048, 0);
if (bytes <= 0) break;
fileSize += bytes;
// 将接收到的视频数据写入到.avi文件中
std::ofstream videoFile("server_video.avi", std::ios::binary | std::ios::app);
videoFile.write(buffer, bytes);
videoFile.close();
}
VideoWriter writer("server_video.avi", cv::VideoWriter::fourcc('M', 'J', 'P', 'G'), 25.0, Size(640, 480));
if (writer.isOpened()) {
writer.write(videoData);
}
closesocket(sockConn);
closesocket(server);
WSACleanup();
/*int byte;
FILE* fp = fopen(preFix.c_str(), "ab+");
int curSize = 0;
while (curSize < size)
{
byte = recv(client, buffer, 1024, 0);
fwrite(buffer, 1, byte, fp);
curSize += byte;
}
cout << "接受图像大小" << curSize << endl;
fclose(fp);
mat = imread(preFix.c_str());
imshow("客户端摄像头", mat);
waitKey(20);
closesocket(client);
}*/
}
int main()
{
InitSocket();
ShowVideo();
return 0;
}
客户端代码
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include <sstream>
#include<string>
#include <fstream>
#include <vector>
#include<winsock.h>
#pragma comment(lib,"WS2_32.lib")
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/opencv.hpp>
#include <thread>
using namespace std;
using namespace cv;
template<class Type>
class className
{
private:
typename vector<Type>::iterator iter;
};
//文件读操作
int readFile(const char* fileName, char* buffer, int size)
{
FILE* fp = fopen(fileName, "rb");
if (fp == NULL)
{
return 0;
}
fread(buffer, 1, size, fp);
fclose(fp);
return 1;
}
int GetFileSize(const char* fileName)
{
//操作文件指针函数
//打开文件,把文件指针移动到文件末尾
FILE* fp = fopen(fileName, "rb");
if (fp == NULL)
{
return 0;
}
fseek(fp, 0L, SEEK_END);
int length = ftell(fp);
fclose(fp);
return length;
}
void InitSocket()
{
WSAData wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData))
{
cout << "初始化套接字失败"<<endl;
exit(0);
}
}
SOCKET ConectServer(const char* ip, int port = 37915)
{
//创建套接字
SOCKET server = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == server)
{
cout << "创建失败" << endl;
}
//IP地址处理
SOCKADDR_IN addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.S_un.S_addr = inet_addr(ip);
//发出请求
if (::connect(server, (SOCKADDR*)&addr, sizeof(addr)) != 0)
{
cout << "连接失败" << WSAGetLastError() << endl;
return INVALID_SOCKET;
}
return server;
}
void ShowVideo()
{
//VideoCapture cap = VideoCapture(0);//VideoCapture是OpenCV中的一个类,创建一个对象
cv::VideoCapture cap(0);
if (!cap.isOpened())
{
cout << "打开失败" << endl;
return;
}
// 定义保存视频的格式和编码器
int fourCC = cv::VideoWriter::fourcc('M', 'J', 'P', 'G');
double fps = 30.0;
cv::Size frameSize(cap.get(cv::CAP_PROP_FRAME_WIDTH),
cap.get(cv::CAP_PROP_FRAME_HEIGHT));
// 创建VideoWriter对象,将获取的视频保存为.avi格式
cv::VideoWriter writer("client_video.avi", fourCC, fps, frameSize);
if (!writer.isOpened()) {
cout << "打开失败" << endl;
return;
}
// 循环采集图像并保存到.avi文件中
cv::Mat frame;
while (cap.read(frame)) {
writer.write(frame);
cv::imshow("Client Video", frame);
if (cv::waitKey(1) == 'q') break;
}
std::ifstream videoFile("client_video.avi", std::ios::binary);
if (!videoFile.is_open())
{
cout << "打开失败" << endl;
return;
}
videoFile.seekg(0, std::ios::end);
size_t fileSize = videoFile.tellg();
videoFile.seekg(0, std::ios::beg);
//std::vector buffer(fileSize);
//char buffer[1024] = " ";
char* buffer= new char[fileSize];
videoFile.read((char*)&fileSize, fileSize);
//videoFile.close();
//发送视频
SOCKET sock = ConectServer("127.0.0.1");
send(sock, (char*)&fileSize, fileSize, 0);
closesocket(sock);
/*if (!cap.isOpened())
{
cout << "打开失败" << endl;
return;
}
Mat img;
int index = 0;
while (true)
{
SOCKET server = ConectServer("127.0.0.1");//本地测试
string preFix = "./Res/img";
preFix += to_string(index++) + ".jpg";
cap >> img;
imshow("摄像头", img);
imwrite(preFix.c_str(), img);
//输出当前文件的大小
//cout << preFix << ":" << GetFileSize(preFix.c_str()) << endl;
//写文件
int imgSize = GetFileSize(preFix.c_str());
char* buffer = new char[imgSize];
readFile(preFix.c_str(), buffer, imgSize);
//网络实现数据发送
if (send(server, (char*)&imgSize, sizeof(imgSize), 0) == SOCKET_ERROR)
{
cout << "发送失败" << WSAGetLastError() << endl;
}
if (send(server, buffer, imgSize, 0) == SOCKET_ERROR)
{
cout << "发送失败" << WSAGetLastError() << endl;
}
waitKey(20);
closesocket(server);
}
cap.release();*/
}
int main()
{
InitSocket();
ShowVideo();
return 0;
}