#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <error.h> #include <string.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 <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <strings.h> struct buffer { void* start; unsigned int length; }*buffers; int main(void) { char id[10]; int ret; int sockfd; //套接字描述符 sockfd = socket(AF_INET ,SOCK_STREAM, 0); //创建通信套接字(TCP) if(sockfd == -1) { printf("socket failed\n"); exit(-1); } //定义addr存入本机地址信息 struct sockaddr_in addr; addr.sin_family = AF_INET; //协议 addr.sin_port = htons(9999); //端口 addr.sin_addr.s_addr= inet_addr("127.0.0.1"); //服务器地址 ret = connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)); //连接tcp客服端 // printf("sdf\n"); if(ret == -1) { printf("connect failed!\n"); return 0; } printf("connect success!\n"); strcpy(id, "video"); send(sockfd, id, sizeof(id),0);//发送身份信息 //打开摄像头 int fd = open("/dev/video0",O_RDWR); if(fd<0) return -1; // 查看设备属性 struct v4l2_capability cap; ioctl(fd,VIDIOC_QUERYCAP,&cap); printf("Driver Name:%s\nCard Name:%s\nBus info:%s\nDriver Version:%u.%u.%u\n",cap.driver,cap.card,cap.bus_info,(cap.version>>16)&0XFF, (cap.version>>8)&0XFF,cap.version&0XFF); //设置摄像头格式 struct v4l2_format fmt; fmt.fmt.pix.width = 1024; fmt.fmt.pix.height = 768; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; ioctl(fd, VIDIOC_S_FMT,&fmt); //申请摄像头采集图片的buf struct v4l2_requestbuffers req; memset(&req,0,sizeof(req)); req.count = 3; //缓冲个数 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; ioctl(fd, VIDIOC_REQBUFS,&req); // //映射 系统空间 ---> 用户空间 buffers = (struct buffer*)calloc(req.count, sizeof (*buffers)); if (!buffers) { fprintf(stderr, "Out of memory/n"); exit(EXIT_FAILURE); } for (unsigned int n_buffers = 0; n_buffers < req.count; ++n_buffers) { struct v4l2_buffer buf; memset(&buf,0,sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buffers; // 查询序号为n_buffers 的缓冲区,得到其起始物理地址和大小 if (-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf)) exit(-1); buffers[n_buffers].length = buf.length; // 映射内存 buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ | PROT_WRITE ,MAP_SHARED,fd, buf.m.offset); if (MAP_FAILED == buffers[n_buffers].start) exit(-1); } // 把四个缓冲帧放入队列,并启动数据流 unsigned int i; enum v4l2_buf_type type; for (i = 0; i < 3; ++i) // 将缓冲帧放入队列 { struct v4l2_buffer buf; buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; ioctl(fd, VIDIOC_QBUF, &buf); } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl(fd, VIDIOC_STREAMON, &type); struct v4l2_buffer buf; // CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; while(1) { ioctl(fd, VIDIOC_DQBUF, &buf); // 从缓冲区取出一个缓冲帧 // printf("图片大小: %d\n", buf.bytesused); send(sockfd, &(buf.bytesused), 4, 0); //发送图片长度信息 send(sockfd, buffers[buf.index].start, buf.bytesused, 0);//发送图片 ioctl(fd, VIDIOC_QBUF, &buf); // 从缓冲区放回一个缓冲帧 // break; usleep(500); } //关闭摄像头 close(sockfd); close(fd); return 0; }