您的位置:首页 > 其它

V4L2视频采集 X264编码项目总结(上)

2015-05-08 14:32 288 查看
做这个项目看了很多博客,也出现了很多问题,我几乎把视频技术论坛的帖都翻完了,还好最后终于都意想不到的解决了。先总结V4L2,然后在使用开源库x264编码的部分,会总结一下常见出现的系列问题和相应的解决方法。
一、V4L2视频采集
<1>V4L2介绍
<2>视频采集流程
1. 打开设备文件。 int fd=open(”/dev/video0″,O_RDWR);
2. 取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability
3. 选择视频输入,一个视频设备可以有多个视频输入。VIDIOC_S_INPUT,struct v4l2_input
4. 设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。
VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format
5. 向驱动申请帧缓冲,一般不超过5个。struct v4l2_requestbuffers
6. 将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。mmap
7. 将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer
8. 开始视频的采集。VIDIOC_STREAMON
9. 出队列以取得已采集数据的帧缓冲,取得原始采集数据。VIDIOC_DQBUF
10. 将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF
11. 停止视频的采集。VIDIOC_STREAMOFF
12. 关闭视频设备。close(fd);

<3>常用的结构体
struct v4l2_requestbuffers reqbufs;//向驱动申请帧缓冲的请求,里面包含申请的个数
struct v4l2_capability cap;//这个设备的功能,比如是否是视频输入设备
struct v4l2_input input; //视频输入
struct v4l2_standard std;//视频的制式,比如PAL,NTSC
struct v4l2_format fmt;//帧的格式,比如宽度,高度等
struct v4l2_buffer buf;//代表驱动中的一帧
v4l2_std_id stdid;//视频制式,例如:V4L2_STD_PAL_B
struct v4l2_queryctrl query;//查询的控制
struct v4l2_control control;//具体控制的值
<4>采集过程
1) 打开设备操作在Linux操作系统中的任何设备都看做文件,对设备的操作就转换成对设备文件的操作。打开视频设备,调用函数fd = open(dev_name, O_RDWR |O_NONBLOCK, 0),其中在main函数中定义了dev_name = "/dev/video3",/dev/video3就是USB摄像头对应的设备文件,O_RDWR |O_NONBLOCK表明本文采用无阻噻模式打开摄像头设备。  2) 视频设备采集前的初始化设置首先使用xioctl(fd, VIDIOC_QUERYCAP, &cap)获取有关摄像头的基本信息,查看是否支持视频输入等功能。然后设置视频捕获格式,本系统选用的摄像头输出格式为YUV422,图像长、宽设置为176144,具体如下:struct v4l2_format fmt;fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; //YUV422fmt.fmt.pix.height = 144;fmt.fmt.pix.width =176;fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;if(-1== ioctl(fd, VIDIOC_S_FMT, &fmt); 3)向驱动申请帧缓存struct v4l2_requestbuffers req; //一帧图像缓存req.count = 4; //count 缓存数量req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { //向驱动申请帧缓存 4)获取每个缓存的信息,并mmap到用户空间struct buffer * buffers = NULL; buffers = calloc(req.count, sizeof(*buffers)); //申请物理内存for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buffers; //缓存编号if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) //获取缓存的地址errno_exit("VIDIOC_QUERYBUF"); buffers[n_buffers].length = buf.length; buffers[n_buffers].start=mmap(NULL ,buf.length,PROT_READ|PROT_WRITE ,MAP_SHARED , fd, buf.m.offset); } //转换成应用程序中的绝对地址,放入缓存队列 5)打开数据流通道,开始采集视频type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) //打开数据流通道,开始采集 6)取出FIFO缓存中已经采样的帧缓存enum v4l2_buf_type type; for (i = 0; i < n_buffers; ++i) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) //把数据从缓存中读取出来 7)将采集到的视频按帧写入文件process_image(buffers[count].start, cap_image_size);static void process_image(const void * p,int len) {if (len > 0) fwrite(p, 1, len, outf); }  8)将刚刚处理完的缓冲重新入队列尾,这样可以循环采集if (ioctl(fd, VIDIOC_QBUF, &buf) == -1)  9)停止视频的采集,释放之前申请的物理内存enum v4l2_buf_type type; type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) //关闭数据流通道errno_exit("VIDIOC_STREAMOFF"); free(buffers); 10)关闭视频设备if (-1 == close(fd))

视频采集就总结到着,下篇总结有关264方面的。


[/code]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: