您的位置:首页 > 理论基础 > 计算机网络

基于socket(TCP)和opencv的实时视频传输

2017-09-22 15:55 561 查看
基于socket的实时视频传输大概需要以下基本函数:

**在服务端:建立socket-bind-listen-accept

在客户端:建立socket-connect

通俗看来说就是在创建socket后服务端的作用是连接服务端的IP,端口然后聆听等待客户端的连接之后接受服务端的数据,而客户端创建socket后就是连接服务端,传送数据。话不多说先上代码

SERVER:

#include "stdafx.h"
#include <stdio.h>
#include <winsock2.h>
#include <cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#pragma comment(lib,"ws2_32.lib")

int main(void)
{
//初始化WSA
WORD sockVersion = MAKEWORD(2, 2);//使用的是WINSOCK 2版本
WSADATA wsaData;
if (WSAStartup(sockVersion, &wsaData) != 0)
{
return 0;
}
SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (slisten == INVALID_SOCKET)
{
printf("socket error !");
return 0;
}
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(8888);//连接端口
sin.sin_addr.S_un.S_addr = INADDR_ANY;//可接受所有IP
if (bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)
{
printf("bind error !");
}

if (listen(slisten, 5) == SOCKET_ERROR)// 监听5代表着最大等待长度
{
printf("listen error !");
return 0;
}

SOCKET sClient;
sockaddr_in remoteAddr;
int nAddrlen = sizeof(remoteAddr);

printf("等待连接...\n");
do
{
sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);
} while (sClient == INVALID_SOCKET);
printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));
// 以上都是创建socket通信的通常步骤也就是我开头所说的流程所需要的,如有不懂可以查看这几个函数得具体功能。
char recvData[1000000] = "";//接受客户端发送数据的缓存
IplImage *image_src = cvCreateImage(cvSize(640, 480), 8, 1);//接受到的图片是640*480
int i, j;
int ret;
cvNamedWindow("server", 1);
while (true)
{
//接收客户端的数据
ret = recv(sClient, recvData, 1000000, 0);
if (ret > 0)
{
for (i = 0; i < image_src->height; i++)
{
for (j = 0; j < image_src->width; j++)
{
((char *)(image_src->imageData + i * image_src->widthStep))[j] = recvData[image_src->width * i + j];
}
}//以上就是传送一张图片的过程
ret = 0;
}
cvShowImage("server", image_src);//显示图片
cvWaitKey(1);
}
cvDestroyWindow("server");
closesocket(slisten);
WSACleanup();
return 0;
}


Client:

#include "stdafx.h"
#include <WINSOCK2.H>
#include <iostream>
#include <stdio.h>
#include <cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;

#pragma  comment(lib,"ws2_32.lib")

int main(int argc, char* argv[])
{
WORD sockVersion = MAKEWORD(2, 2);
WSADATA data;
if (WSAStartup(sockVersion, &data) != 0)
{
return 0;
}

SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sclient == INVALID_SOCKET)
{
printf("invalid socket !\n");
return 0;
}

sockaddr_in serAddr;
serAddr.sin_family = AF_INET;
serAddr.sin_port = htons(8888);
serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1"); //这里可以改成服务端的IP,若是都在一台电脑就不用改变
if (connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
{
printf("connect error !\n");
closesocket(sclient);
return 0;
}

VideoCapture capture(0);//打开摄像头,cvQueryFrame这个函数并不能打开我的摄像头,好像是因为函数版本太低,我的是VS2017+opencv3.3.0,若是可以使用cvQueryFrame那么就不用进行下面的图片拷贝以及转换
if (!capture.isOpened())
{
printf("摄像头打开失败,请检查设备!\n");
}
int i, j;
char sendData[1000000] = "";// 存放要输出去的数据
cvNamedWindow("client", 1);
Mat frame;  //定义一个Mat类的frame
while (1)
{
capture >> frame;// 将摄像头拍摄的每一帧图片都放进frame
IplImage* img = &IplImage(frame);
IplImage *image_src = cvCloneImage(img);//这是一个深拷贝讲Mat类变成IplImage类,若是上面打开摄像头的cvQueryFrame函数可以用那么就不用转换
for (i = 0; i < image_src->height; i++)
{
for (j = 0; j < image_src->width; j++)
{
sendData[image_src->width * i + j] = ((char *)(image_src->imageData + i * image_src->widthStep))[j];
}
}
cvShowImage("client",image_src);
cvWaitKey(3);
send(sclient, sendData, 1000000, 0);
}
cvReleaseImage(&image_dsrc);
cvDestroyWindow("client");
closesocket(sclient);
WSACleanup();
return 0;
}


以上就是我可以把自己电脑摄像头拍摄的视频实时传输给服务端的代码,亲测有用,也希望能够帮助大家。本人也是刚开始学习这个,希望能与大家一起交流
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: