利用网线在电脑与开发板之间组成一个局域网,能够让电脑与开发板之间的网络互通,(记着要IP地址固定哟!!)
在电脑上挂载摄像头并作为服务端,开发板在显示屏上显示摄像头所拍摄的画面。
服务端
利用V4L2来采集视频
V4L2 是 Video for linux two 的简称,是 Linux 内核中视频类设备的一套驱动框架,为视频类设备驱动开发和应用层提供了一套统一的接口规范。
- 首先是打开摄像头设备;
/* 初始化摄像头 */
static int v4l2_dev_init(char *path)
{
v4l2_fd = open(path, O_RDWR);
if(v4l2_fd < 0) {
perror("open_video error");
exit(1);
}
return 1;
}
- 枚举出摄像头所支持的所有视频像素格式\采集分辨率\帧率
/* 枚举出摄像头所支持的所有视频像素格式\采集分辨率\帧率 */
static void v4l2_print_formats(void)
{
struct v4l2_fmtdesc fmtdesc;
struct v4l2_frmsizeenum frmsize;
struct v4l2_frmivalenum frmival;
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频采集
/*查看支持的像素格式*/
while(ioctl(v4l2_fd, VIDIOC_ENUM_FMT, &fmtdesc)==0)
{
printf("fmt: \" %s \" <0x%d>\n", fmtdesc.description, fmtdesc.pixelformat);
fmtdesc.index++;
frmsize.index = 0;
frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
frmsize.pixel_format = fmtdesc.pixelformat;
/*查看支持的分辨率*/
while(ioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0)
{
printf("frm_size<%d*%d> ", frmsize.discrete.width, frmsize.discrete.height);
frmsize.index++;
frmival.index = 0;
frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
frmival.pixel_format = fmtdesc.pixelformat;
frmival.width = frmsize.discrete.width;
frmival.height = frmsize.discrete.height;
/*查看支持的帧率*/
while(ioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) == 0)
{
printf("<%dfps>\n", (frmival.discrete.denominator / frmival.discrete.numerator));
frmival.index++;
}
}
printf("\r\n");
}
}
- 设置设备的参数,譬如像素格式、 帧大小
/* 设置格式 */
static int v4l2_set_format(unsigned int format, int width, int height)
{
struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频采集
fmt.fmt.pix.width = width;//设置分辨率的宽
fmt.fmt.pix.height = height;//设置分辨率的高
fmt.fmt.pix.pixelformat = format;//设置视频输出格式
if(ioctl(v4l2_fd, VIDIOC_S_FMT, &fmt) < 0){
printf("Error: v4l2_set_format\r\n");
return 0;
}
/*查询当前摄像头的工作模式*/
ioctl(v4l2_fd, VIDIOC_G_FMT, &fmt);
printf("width:%d, height:%d \n", fmt.fmt.pix.width, fmt.fmt.pix.height);
return 1;
}
- 申请帧缓冲、内存映射
/*申请帧缓冲、内存映射*/
static int v4l2_init_buffer(void)
{
struct v4l2_requestbuffers reqbuf;
struct v4l2_buffer buf;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.count = 4; //帧缓冲的数量
reqbuf.memory = V4L2_MEMORY_MMAP;
/*申请帧缓冲*/
if(ioctl(v4l2_fd, VIDIOC_REQBUFS, &reqbuf) < 0){
printf("error: v4l2_init_buffer\r\n");
return 0;
}
buf.index = 0;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
/*内存映射*/
for(buf.index = 0;buf.index < 4;buf.index++)
{
ioctl(v4l2_fd, VIDIOC_QUERYBUF, &buf);
frm_base[buf.index] = mmap(NULL, buf.length, \
PROT_READ | PROT_WRITE, MAP_SHARED, \
v4l2_fd, buf.m.offset);
if (MAP_FAILED == frm_base[buf.index]) {
perror("mmap error");
return -1;
}
printf("查询内存成功 buf[%d]==%d长度\r\n",buf.index,buf.length);
if(ioctl(v4l2_fd,VIDIOC_QBUF,&buf) < 0){//加入缓冲队列
printf("error: VIDIOC_QBUF\r\n");
return 0;
}
}
return 1;
}
- 打开摄像头
static int v4l2_stream_on(void)
{
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* 打开摄像头、摄像头开始采集数据 */
if(ioctl(v4l2_fd, VIDIOC_STREAMON, &type) < 0){
printf("error: v4l2_stream_on\r\n");
return 0;
}
printf("Camera_open : success\r\n");
return 1;
}
- 读取数据
static void v4l2_read_data(void)
{
struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 1;
while(1)
{
for(buf.index = 1; buf.index < 4; buf.index++)
{
if(ioctl(v4l2_fd, VIDIOC_DQBUF, &buf)!=0)//出队
{
printf("提取数据失败\r\n");
break;
}
Send_Video_Data(connfd,frm_base[buf.index],buf.length);
if(ioctl(v4l2_fd, VIDIOC_QBUF, &buf)!=0)//入队
{
printf("放回队列失败\r\n");
exit(0);
}
usleep(33000);
}
}
}
服务端整体代码
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#define SERVER_PORT 55555
static int sockfd, connfd;
static int v4l2_fd = -1; //摄像头设备文件描述符
static unsigned char *frm_base[4] = {NULL}; //帧缓冲起始地址
/* 初始化摄像头 */
static int v4l2_dev_init(char *path)
{
v4l2_fd = open(path, O_RDWR);
if(v4l2_fd < 0) {
perror("open_video error");
exit(1);
}
return 1;
}
/* 枚举出摄像头所支持的所有视频像素格式\采集分辨率\帧率 */
static void v4l2_print_formats(void)
{
struct v4l2_fmtdesc fmtdesc;
struct v4l2_frmsizeenum frmsize;
struct v4l2_frmivalenum frmival;
fmtdesc.index = 0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频采集
/*查看支持的像素格式*/
while(ioctl(v4l2_fd, VIDIOC_ENUM_FMT, &fmtdesc)==0)
{
printf("fmt: \" %s \" <0x%d>\n", fmtdesc.description, fmtdesc.pixelformat);
fmtdesc.index++;
frmsize.index = 0;
frmsize.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
frmsize.pixel_format = fmtdesc.pixelformat;
/*查看支持的分辨率*/
while(ioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0)
{
printf("frm_size<%d*%d> ", frmsize.discrete.width, frmsize.discrete.height);
frmsize.index++;
frmival.index = 0;
frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
frmival.pixel_format = fmtdesc.pixelformat;
frmival.width = frmsize.discrete.width;
frmival.height = frmsize.discrete.height;
/*查看支持的帧率*/
while(ioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) == 0)
{
printf("<%dfps>\n", (frmival.discrete.denominator / frmival.discrete.numerator));
frmival.index++;
}
}
printf("\r\n");
}
}
/* 设置格式 */
static int v4l2_set_format(unsigned int format, int width, int height)
{
struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频采集
fmt.fmt.pix.width = width;//设置分辨率的宽
fmt.fmt.pix.height = height;//设置分辨率的高
fmt.fmt.pix.pixelformat = format;//设置视频输出格式
if(ioctl(v4l2_fd, VIDIOC_S_FMT, &fmt) < 0){
printf("Error: v4l2_set_format\r\n");
return 0;
}
/*查询当前摄像头的工作模式*/
ioctl(v4l2_fd, VIDIOC_G_FMT, &fmt);
printf("width:%d, height:%d \n", fmt.fmt.pix.width, fmt.fmt.pix.height);
return 1;
}
/*申请帧缓冲、内存映射*/
static int v4l2_init_buffer(void)
{
struct v4l2_requestbuffers reqbuf;
struct v4l2_buffer buf;
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
reqbuf.count = 4; //帧缓冲的数量
reqbuf.memory = V4L2_MEMORY_MMAP;
/*申请帧缓冲*/
if(ioctl(v4l2_fd, VIDIOC_REQBUFS, &reqbuf) < 0){
printf("error: v4l2_init_buffer\r\n");
return 0;
}
buf.index = 0;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
/*内存映射*/
for(buf.index = 0;buf.index < 4;buf.index++)
{
ioctl(v4l2_fd, VIDIOC_QUERYBUF, &buf);
frm_base[buf.index] = mmap(NULL, buf.length, \
PROT_READ | PROT_WRITE, MAP_SHARED, \
v4l2_fd, buf.m.offset);
if (MAP_FAILED == frm_base[buf.index]) {
perror("mmap error");
return -1;
}
printf("查询内存成功 buf[%d]==%d长度\r\n",buf.index,buf.length);
if(ioctl(v4l2_fd,VIDIOC_QBUF,&buf) < 0){//加入缓冲队列
printf("error: VIDIOC_QBUF\r\n");
return 0;
}
}
return 1;
}
static int v4l2_stream_on(void)
{
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
/* 打开摄像头、摄像头开始采集数据 */
if(ioctl(v4l2_fd, VIDIOC_STREAMON, &type) < 0){
printf("error: v4l2_stream_on\r\n");
return 0;
}
printf("Camera_open : success\r\n");
return 1;
}
void Send_Video_Data(int fd,uint8_t * data,int data_len)
{
int tmp = 0;
int current = 0;
if(fd > 0)
{
while(1)
{
tmp = write(fd,data,data_len);
if(tmp < 0){
perror("write buf");
close("fd");
exit(1);
}
current = data_len - tmp;//还有多少字节没有写入
data+=tmp;//指针位移
data_len = current;//写入剩下的字节
if(data_len == 0)
{
break;
}
}
}
}
unsigned char rgbdatabuf[640*480*4]={0};
static void v4l2_read_data(void)
{
struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 1;
while(1)
{
for(buf.index = 1; buf.index < 4; buf.index++)
{
if(ioctl(v4l2_fd, VIDIOC_DQBUF, &buf)!=0)//出队
{
printf("提取数据失败\r\n");
break;
}
Send_Video_Data(connfd,frm_base[buf.index],buf.length);
if(ioctl(v4l2_fd, VIDIOC_QBUF, &buf)!=0)//入队
{
printf("放回队列失败\r\n");
exit(0);
}
usleep(33000);
}
}
}
void tcp_server(void)
{
struct sockaddr_in server_addr = {0};
struct sockaddr_in client_addr = {0};
char ip_str[20] = {'\0'};//客户端IP
int addrlen = sizeof(struct sockaddr_in);//结构体 struct sockaddr_in 所占字节
int ret;
/* 打开套接字,得到套接字描述符 */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (0 > sockfd) {
perror("socket error");
exit(1);
}
/*配置监听描述符地址复用属性*/
int opt = 1;//opt 只有(关闭(0)/打开(1))
ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
if(ret < 0) {
perror("setsockopt error");
exit(1);
}
/* 将套接字与指定端口号进行绑定 */
server_addr.sin_family = AF_INET;//协议族为IPV4
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//绑定IP
server_addr.sin_port = htons(SERVER_PORT);//绑定端口
ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (0 > ret) {
perror("bind error");
close(sockfd);
exit(1);
}
/* 使服务器进入监听状态 */
ret = listen(sockfd, 50);
if (0 > ret) {
perror("listen error");
close(sockfd);
exit(1);
}
/* 阻塞等待客户端连接 */
connfd = accept(sockfd, (struct sockaddr *)&client_addr, &addrlen);
if (0 > connfd) {
printf("\n有客户端连接失败\n");
exit(1);
}
printf("有客户端接入...\n");
//将二进制 Ipv4 地址转换成 点分十进制
inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip_str, sizeof(ip_str));
printf("客户端主机的 IP 地址: %s\n", ip_str);
printf("客户端进程的端口号: %d\n", client_addr.sin_port);
}
int main(int argc, char *argv[])
{
v4l2_dev_init(argv[1]);
v4l2_print_formats();
v4l2_set_format(V4L2_PIX_FMT_YUYV, 640, 480);
v4l2_init_buffer();
v4l2_stream_on();
tcp_server();
v4l2_read_data();
}
客户端
初始化 LCD
/* 初始化 LCD */
static int fb_dev_init(void)
{
struct fb_var_screeninfo fb_var = {0};
struct fb_fix_screeninfo fb_fix = {0};
unsigned long screen_size;
/* 打开framebuffer设备 */
fb_fd = open(FB_DEV, O_RDWR);
if (0 > fb_fd) {
perror("open_fb error");
return -1;
}
/* 获取framebuffer设备信息 */
ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var);
ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_fix);
screen_size = fb_fix.line_length * fb_var.yres;
width = fb_var.xres_virtual;
height = fb_var.yres_virtual;
printf("%d*%d\n", width, height);
/* 内存映射 */
screen_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
if (MAP_FAILED == (void *)screen_base) {
perror("mmap error");
close(fb_fd);
return -1;
}
/* LCD背景刷白 */
memset(screen_base, 0xFF, screen_size);
return 0;
}
显示图片
void show_pic(unsigned char * pic_data, int w, int h)
{
int i,j;
unsigned int * p = screen_base;//LCD起始地址
unsigned int tmpdata;
for(i=0;i<h;i++)//对某一行
{
for(j=0;j<w;j++)//一行中的一个像素点
{
//三个十六进制表示一个像素点
//j*3表示当前行的第j+1个十六进制的数据
//i*w*3表示第i+1行
tmpdata = (pic_data[j*3+i*w*3]<<16 | pic_data[j*3+i*w*3+1]<<8 | pic_data[(j*3)+(i*w*3)+2]<<0);
* (p+j) = tmpdata;
}
p+=width;
}
}
YUYV422 转RGB 数据
//YUYV422 转RGB 数据
void yuyv_to_rgb(unsigned char *yuyvdata, unsigned char *rgbdata, int w, int h)
{
//码流Y0 U0 Y1 V1 Y2 U2 Y3 V3 --》YUYV像素[Y0 U0 V1] [Y1 U0 V1] [Y2 U2 V3] [Y3 U2 V3]--》RGB像素
int r1, g1, b1;
int r2, g2, b2;
int i =0 ;
for(i=0; i<w*h/2; i++)
{
char data[4];
memcpy(data, yuyvdata+i*4, 4);
unsigned char Y0=data[0];
unsigned char U0=data[1];
unsigned char Y1=data[2];
unsigned char V1=data[3];
//Y0U0Y1V1 -->[Y0 U0 V1] [Y1 U0 V1]
r1 = Y0+1.4075*(V1-128); if(r1>255)r1=255; if(r1<0)r1=0;
g1 =Y0- 0.3455 * (U0-128) - 0.7169*(V1-128); if(g1>255)g1=255; if(g1<0)g1=0;
b1 = Y0 + 1.779 * (U0-128); if(b1>255)b1=255; if(b1<0)b1=0;
r2 = Y1+1.4075*(V1-128);if(r2>255)r2=255; if(r2<0)r2=0;
g2 = Y1- 0.3455 * (U0-128) - 0.7169*(V1-128); if(g2>255)g2=255; if(g2<0)g2=0;
b2 = Y1 + 1.779 * (U0-128); if(b2>255)b2=255; if(b2<0)b2=0;
rgbdata[i*6+0]=r1;
rgbdata[i*6+1]=g1;
rgbdata[i*6+2]=b1;
rgbdata[i*6+3]=r2;
rgbdata[i*6+4]=g2;
rgbdata[i*6+5]=b2;
}
}
彩色图像水平镜像
/**
* @desc 彩色图像水平镜像
* @param pImg 图像缓存,3个像素一个字节,RGB888格式
* @param w 图像宽度
* @param h 图像高度
**/
void rotateColorImgMirrorH(unsigned char *pImg,unsigned int w,unsigned int h)
{
unsigned char tmp;
unsigned int i=0,j=0,m=0;
unsigned char *t = NULL,*tt = NULL;
unsigned int w3 = w*3;
tt = pImg;
for(i=0;i<h;i++)
{
t = tt + ((w-1)*3);
for(j=0;j<(w>>1);j++)
{
for(m=0;m<3;m++)
{
tmp = *tt;
*tt = *t;
*t = tmp;
tt++;
t++;
}
t -= 6;
}
tt += ((w>>1)*3);
}
}
客户端整体程序
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>
#define SERVER_PORT 55555
#define FB_DEV "/dev/fb0"
int sockfd;
static int width; //LCD宽度
static int height; //LCD高度
static int fb_fd = -1; //LCD设备文件描述符
static int v4l2_fd = -1; //摄像头设备文件描述符
static unsigned int *screen_base = NULL;//LCD显存基地址
static unsigned char *frm_base[4] = {NULL}; //帧缓冲起始地址
unsigned char rgbdatabuf[640*480*4]={0};
char yuyvbuf[614400]={0};
/* 初始化 LCD */
static int fb_dev_init(void)
{
struct fb_var_screeninfo fb_var = {0};
struct fb_fix_screeninfo fb_fix = {0};
unsigned long screen_size;
/* 打开framebuffer设备 */
fb_fd = open(FB_DEV, O_RDWR);
if (0 > fb_fd) {
perror("open_fb error");
return -1;
}
/* 获取framebuffer设备信息 */
ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var);
ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_fix);
screen_size = fb_fix.line_length * fb_var.yres;
width = fb_var.xres_virtual;
height = fb_var.yres_virtual;
printf("%d*%d\n", width, height);
/* 内存映射 */
screen_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
if (MAP_FAILED == (void *)screen_base) {
perror("mmap error");
close(fb_fd);
return -1;
}
/* LCD背景刷白 */
memset(screen_base, 0xFF, screen_size);
return 0;
}
//YUYV422 转RGB 数据
void yuyv_to_rgb(unsigned char *yuyvdata, unsigned char *rgbdata, int w, int h)
{
//码流Y0 U0 Y1 V1 Y2 U2 Y3 V3 --》YUYV像素[Y0 U0 V1] [Y1 U0 V1] [Y2 U2 V3] [Y3 U2 V3]--》RGB像素
int r1, g1, b1;
int r2, g2, b2;
int i =0 ;
for(i=0; i<w*h/2; i++)
{
char data[4];
memcpy(data, yuyvdata+i*4, 4);
unsigned char Y0=data[0];
unsigned char U0=data[1];
unsigned char Y1=data[2];
unsigned char V1=data[3];
//Y0U0Y1V1 -->[Y0 U0 V1] [Y1 U0 V1]
r1 = Y0+1.4075*(V1-128); if(r1>255)r1=255; if(r1<0)r1=0;
g1 =Y0- 0.3455 * (U0-128) - 0.7169*(V1-128); if(g1>255)g1=255; if(g1<0)g1=0;
b1 = Y0 + 1.779 * (U0-128); if(b1>255)b1=255; if(b1<0)b1=0;
r2 = Y1+1.4075*(V1-128);if(r2>255)r2=255; if(r2<0)r2=0;
g2 = Y1- 0.3455 * (U0-128) - 0.7169*(V1-128); if(g2>255)g2=255; if(g2<0)g2=0;
b2 = Y1 + 1.779 * (U0-128); if(b2>255)b2=255; if(b2<0)b2=0;
rgbdata[i*6+0]=r1;
rgbdata[i*6+1]=g1;
rgbdata[i*6+2]=b1;
rgbdata[i*6+3]=r2;
rgbdata[i*6+4]=g2;
rgbdata[i*6+5]=b2;
}
}
/**
* @desc 彩色图像水平镜像
* @param pImg 图像缓存,3个像素一个字节,RGB888格式
* @param w 图像宽度
* @param h 图像高度
**/
void rotateColorImgMirrorH(unsigned char *pImg,unsigned int w,unsigned int h)
{
unsigned char tmp;
unsigned int i=0,j=0,m=0;
unsigned char *t = NULL,*tt = NULL;
unsigned int w3 = w*3;
tt = pImg;
for(i=0;i<h;i++)
{
t = tt + ((w-1)*3);
for(j=0;j<(w>>1);j++)
{
for(m=0;m<3;m++)
{
tmp = *tt;
*tt = *t;
*t = tmp;
tt++;
t++;
}
t -= 6;
}
tt += ((w>>1)*3);
}
}
void show_pic(unsigned char * pic_data, int w, int h)
{
int i,j;
unsigned int * p = screen_base;//LCD起始地址
unsigned int tmpdata;
for(i=0;i<h;i++)//对某一行
{
for(j=0;j<w;j++)//一行中的一个像素点
{
//三个十六进制表示一个像素点
//j*3表示当前行的第j+1个十六进制的数据
//i*w*3表示第i+1行
tmpdata = (pic_data[j*3+i*w*3]<<16 | pic_data[j*3+i*w*3+1]<<8 | pic_data[(j*3)+(i*w*3)+2]<<0);
* (p+j) = tmpdata;
}
p+=width;
}
}
void Recv_Video_Data(int fd,uint8_t * data,int data_len)
{
int tmp = 0;
int current = 0;
if(fd > 0)
{
while(1)
{
tmp = read(fd,data,data_len);
if(tmp < 0){
perror("read buf");
close("fd");
exit(1);
}
current = data_len - tmp;
data+=tmp;
data_len = current;
if(data_len == 0)
{
break;
}
}
}
}
void tcp_client(char * SERVER_IP)
{
struct sockaddr_in server_addr = {0};
int ret;
/* 打开套接字,得到套接字描述符 */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (0 > sockfd) {
perror("socket error");
exit(EXIT_FAILURE);
}
/* 调用 connect 连接远端服务器 */
server_addr.sin_family = AF_INET;//IPV4
server_addr.sin_port = htons(SERVER_PORT); //端口号
server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
// inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);//IP 地址
/* 请求与服务器建立连接 */
ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (0 > ret) {
perror("connect error");
close(sockfd);
exit(EXIT_FAILURE);
}
printf("服务器连接成功...\n\n");
/* 向服务器发送数据 */
while(1)
{
Recv_Video_Data(sockfd,yuyvbuf,sizeof(yuyvbuf));
yuyv_to_rgb(yuyvbuf, rgbdatabuf ,640, 480);
rotateColorImgMirrorH(rgbdatabuf,640,480);
show_pic(rgbdatabuf,640,480);
usleep(66000);
}
close(sockfd);
exit(EXIT_SUCCESS);
}
int main(int argc, char **argv)
{
fb_dev_init();
tcp_client("192.168.88.88");
}