mjpg-streamer_第1页
mjpg-streamer_第2页
mjpg-streamer_第3页
mjpg-streamer_第4页
mjpg-streamer_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、简易的USB摄像头网络传输描述:使用v4l2提供的API获取usb摄像头采集到的jpeg帧,并通过socket传送给客户端;可以使用mjpeg-client里的viewer.exe看arm板传送过来的视频流;如果使用浏览器看的话,只能看到图片,要不断的刷新,才能看到新的图片。最后面的程序主要有两大部分构成,一是v4l2,二是socket网络编程。一、v4l2的介绍V412 主要通过 ioctl(fd, VIDIOC_XXXX, struct_xxx)这种形式来使用 v4l2 的接口的,struct_xxx为下面1中提到的各种结构体,VIDIOC_XXXX 为下面2中提到的各种接口命令,基本上每

2、一步都会用到ioctl()来进行各种设置功能,读取信息,传递参数等等。(以下是摘至网络上的对v4l2的讲解,很详细,我也就不再重复了。)1、常用的结构体在内核目录struct v4l2_requestbuffersstruct v4l2_capabilitystruct v4l2_inputstruct v4l2_standardstruct v4l2_formatstruct v4l2bufferinclude/linux/videodev2.h 中定义/申请帧缓冲,对应命令 VIDIOC_REQBUFS/视频设备的功能,对应命令VIDIOC_QUERYCAP视频输入信息,对应命令VIDIO

3、C_ENUMINPUT视频的制式,比如PAL, NTSC ,对应命令 VIDIOC_ENUMSTD帧的格式,对应命令VIDIOC_G_FMT、VIDIOC_S_FMT 等struct v4l2_crop v4l2stdid/驱动中的一帧图像缓存,对应命令VIDIOC_QUERYBUF视频信号矩形边框视频制式2、常用的IOCTL接口命令也在include/linux/videodev2.h 中定义VIDIOC_REQBUFS / 分配内存VIDIOC_QUERYBUFVIDIOC_QUERYCAPVIDIOC_ENUM_FMTVIDIOC_S_FMTVIDIOC_G_FMT/把VIDIOC_RE

4、QBUFS中分配的数据缓存转换成物理地址查询驱动功能获取当前驱动支持的视频格式设置当前驱动的频捕获格式验证当前驱动的显示格式/查询驱动的修剪能力/设置视频信号的矩形边框读取视频信号的矩形边框/把数据从缓存中读取出来/把数据放回缓存队列/读取当前驱动的频捕获格式VIDIOC_TRY_FMTVIDIOC_CROPCAPVIDIOC_S_CROPVIDIOC_G_CROPVIDIOC_QBUFVIDIOC_DQBUFVIDIOC_STREAMONVIDIOC_STREAMOFFVIDIOC_QUERYSTD/开始视频显示函数/结束视频显示函数/检查当前视频设备支持的标准,例如PAL或NTSC。3、操

5、作流程V4L2提供了很多访问接口,你可以根据具体需要选择操作方法。需要注意的是,很少有驱 动完全实现了所有的接口功能。所以在使用时需要参考驱动源码,或仔细阅读驱动提供者的使用说明。下面列举出一种操作的流程,供参考。(1) 打开设备文件int fd = open(Devicename,mode);Devicename: /dev/video0、/dev/video1 Mode : O_RDWR | O_NONBLOCK如果使用非阻塞模式调用视频设备,则当没有可用的视频数据时,不会阻塞,而立刻返回。(2) 取得设备的 capabilitystruct v4l2_capability capabil

6、ity ;int ret = ioctl(fd, VIDIOC_QUERYCAP, &capability);看看设备具有什么功能,比如是否具有视频输入特性。(3) 选择视频输入struct v4l2_input input ;初始化inputint ret = ioctl(fd, VIDIOC_QUERYCAP, &input);一个视频设备可以有多个视频输入。如果只有一路输入,这个功能可以没有。(4) 检测视频支持的制式v4l2_std_id std;do ret = ioctl(fd, VIDIOC_QUERYSTD, &std); while (ret = -1

7、 && errno = EAGAIN);switch (std) case V4L2_STD_NTSC:/ case V4L2_STD_PAL:/ (5) 设置视频捕获格式struct v4l2_format fmt; fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;fmt.fmt.pix.height = height;fmt.fmt.pix.width = width;fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;ret

8、= ioctl(fd, VIDIOC_S_FMT, &fmt);if(ret) perror("VIDIOC_S_FMTn");close(fd);return -1;(6) 向驱动申请帧缓存struct v4l2_requestbuffers req;if (ioctl(fd, VIDIOC_REQBUFS, &req) = -1) return -1;v4l2_requestbuffers结构中定义了缓存的数量,驱动会据此申请对应数量的视频缓存。多个 缓存可以用于建立FIFO,来提高视频采集的效率。(7) 获取每个缓存的信息,并 mmap到用户空间typ

9、edef struct VideoBuffer void *start;size_t length; VideoBuffer;VideoBuffer* buffers = calloc( req.count, sizeof(*buffers);struct v4l2_buffer buf;for (numBufs = 0; numBufs < req.count; numBufs+) / 映射所有的缓存memset( &buf, 0, sizeof(buf);buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory = V4L2_MEMO

10、RY_MMAP;buf.index = numBufs;if (ioctl(fd, VIDIOC_QUERYBUF, &buf) =-1) / 获取到对应index的缓存信息,此处主要利用length信息及offset信息来完成后面的mmap操作。return -1;buffersnumBufs.length = buf.length;/转换成相对地址buffersnumBufs.start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);if (buffersnumBufs.

11、start = MAP_FAILED) return -1;(8) 开始采集视频int buf_type= V4L2_BUF_TYPE_VIDEO_CAPTURE ; int ret = ioctl(fd, VIDIOC_STREAMON, &buf_type);(9) 取出FIFO缓存中已经采样的帧缓存struct v4l2_buffer buf;memset(&buf,0,sizeof(buf);buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory=V4L2_MEMORY_MMAP; buf.index=0;/此值由下面的ioctl

12、返回 if (ioctl(fd, VIDIOC_DQBUF, &buf) = -1) return -1; 根据返回的buf.index找到对应的mmap映射好的缓存,取出视频数据。(10) 将刚刚处理完的缓冲重新入队列尾,这样可以循环采集if (ioctl(fd, VIDIOC_QBUF, &buf) = -1) return -1;(11) 停止视频的采集int ret = ioctl(fd, VIDIOC_STREAMOFF, &buf_type);(12) 关闭视频设备close(fd);二、socket 介绍网上很多关于这方面的资料,但我没找到令我满意的资料,

13、暂时空着吧,找到了在贴上来,(可能再也没有我没满意的了,呵呵,我很懒的),你就到网上找一些相关资料,然后对照这程序,看吧,程序注释挺详细的,应该能看得懂。三、程序源码以下是Makefile程序文件/*+Makefile+*/CROSS=arm-linux-all: streamstream:stream.c$(CROSS)gcc -o stream stream.c -ljpeg -lpthread# $(CROSS)strip usb_cameraclean:rm -vf stream *.o */*+the end of Makefile+*/以下是stream.c程序文件/*+strea

14、m.c+*/*NAME:stream.cCOPYRIGHT:huangqw*/#include <errno.h>#include <string.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <stdint.h>#include <asm/types.h>#include <linux/videodev2.h>#include <sys/ioctl.h>#include <fcntl.h>

15、; /open(,O_RDWR,)#include <sys/mman.h>/mmap#include <malloc.h>#include <linux/fb.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#define BACKLOG 5#define PORT8080 /* port of daytime server*/ int height = 640;int width = 480;/帧缓存结构体typedef str

16、uct VideoBuffer unsigned char *start;/帧的首地址size_t length;帧长度 VideoBuffer;int main(int argc, char* argv)int numBufs = 0;/缓存区帧的数量int listenfd, connectfd = 0; / 套接字structsockaddr_inserver;structsockaddr_inclient;int sin_size;printf("The programe is video program!n");/ (1)打开设备文件int fd = open(&

17、quot;/dev/video0", O_RDWR);if (fd<0)printf("open errorn");return -1;/ (2)取得设备的 capabilitystruct v4l2_capability capability;int ret = ioctl(fd, VIDIOC_QUERYCAP, &capability);printf("ret = %d driver = %s card = %s bus_info = %s n”,ret,capability.driver,capability.card,capabi

18、lity.bus_info);/ (3)设置视频捕获格式struct v4l2_format fmt;/设置获取视频的格式memset( &fmt, 0, sizeof(fmt);fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;视频数据流类型,永远都是 V4L2_BUF_TYPE_VIDEO_CAPTUREfmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; / V4L2_PIX_FMT_MJPEG; / 视频 源的格式为JPEG或YUN4:2:2或RGBfmt.fmt.pix.width = 320;fmt.fmt.p

19、ix.height = 240;if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0)(printf("set format failed :YUYVn");return -1;/ (4)向驱动申请帧缓存struct v4l2_requestbuffers req;设置视频宽度设置视频高度使配置生效申请帧缓冲memset(&req, 0, sizeof (req);req.count = 5;缓存数量,即可保存的图片数量req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;数据流类型,永远都是 V4L2_B

20、UF_TYPE_VIDEO_CAPTUREreq.memory = V4L2_MEMORY_MMAP;V4L2_MEMORY_MMAP 或 V4L2_MEMORY_USERPTR if (ioctl(fd, VIDIOC_REQBUFS, &req) = -1)/存储类型使配置生效(perror("request buffer error n");return -1;/printf("sizeof(req) is %dn”,sizeof(req);/ (5)获取每个缓存的信息,并 mmap到用户空间VideoBuffer* buffers = calloc

21、( req.count, sizeof(VideoBuffer);struct v4l2_buffer buf;printf("sizeof(VideoBuffer) is %dn sizeof(buf) is %dn", sizeof(VideoBuffer),sizeof(buf);for (numBufs = 0; numBufs < req.count; numBufs+) / 映射所有的缓存 (memset( &buf, 0, sizeof(buf);buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory

22、= V4L2_MEMORY_MMAP;buf.index = numBufs;if (ioctl(fd, VIDIOC_QUERYBUF, &buf) = -1) (/ 获取到对应 index 的缓存信息,此 处主要利用length信息及offset信息来完成后面的mmap操作。return -1;buffersnumBufs.length = buf.length;/ 转换成相对地址buffersnumBufs.start = mmap(NULL, buf.length,PROT_READ | PROT_WRITE,MAP_SHARED,fd, buf.m.offset);if (b

23、uffersnumBufs.start = MAP_FAILED) ( return -1;if (ioctl(fd, VIDIOC_QBUF, &buf) < 0)/ 放入缓存队列(printf("VIDIOC_QBUF errorn");return -1;/开始视频显示/数据流类型,永远都是/数据流类型,永远都读取视频源格式/ (6)开始采集视频enum v4l2_buf_type type;type = V4L2_BUF_TYPE_VIDEO_CAPTURE;V4L2_BUF_TYPE_VIDEO_CAPTUREif (ioctl(fd, VIDIOC

24、_STREAMON, &type) < 0)(printf("VIDIOC_STREAMON errorn");return -1;/ (7)查看视频格式(非必要模块)fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;是 V4L2_BUF_TYPE_VIDEO_CAPTUREif (ioctl(fd, VIDIOC_G_FMT, &fmt) < 0) (printf("get format failedn");return -1;else(printf("Picture:Width = %

25、d Height = %dn", fmt.fmt.pix.width, fmt.fmt.pix.height); printf("Image size = %dn", fmt.fmt.pix.sizeimage);printf("pixelformat = %dn", fmt.fmt.pix.pixelformat);/*socket*/创建套接字if(listenfd = socket(AF_INET,SOCK_STREAM,0)=-1) perror("createing socket failedn");exit(1)

26、;/设置套接字可以重用int opt = SO_REUSEADDR;setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt);设置服务端各个参数,一般都为这个样子bzero(&server,sizeof(server);server.sin_family = AF_INET;server.sin_port = htons(PORT);server.sin_addr.s_addr = htonl (INADDR_ANY);将服务端与套接字绑定if(bind(listenfd,(struct sockaddr *)&a

27、mp;server,sizeof(struct sockaddr)=-1) perror("bind error");exit(1);监听客户端请求if(listen(listenfd,BACKLOG) = -1) perror("listen() error");exit(1);sin_size = sizeof(struct sockaddr_in);接受客户端请求if(connectfd = accept(listenfd,(struct sockaddr *)&client,&sin_size)=-1)perror("a

28、ccept() error");exit(1);printf("you got a connect from %s n”,inet_ntoa(client.sin_addr);/*发送采集到的帧*/while(1)/ (8)取出FIFO缓存中已经采样的帧缓存for (numBufs = 0; numBufs < req.count; numBufs+) / 映射所有的缓存 memset(&buf,0,sizeof(buf);buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;buf.memory=V4L2_MEMORY_MMAP;buf.index=numBufs;/ 此值由下面的 ioctl 返回 if (ioctl(fd, VIDIOC_DQBUF, &a

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论