关于Linux的视频编程(v4l2编程)

最近在看TQ2440从摄像头采集图像,然后直接在LCD显示的程序,看到文章有用转过来吧。其实V4L2标准说的很清楚,只是太多了,只好找别人的经验直接拿过来看看,重要的参考文件就是V4L2页面的参考程序capture.c
地址http://v4l2spec.bytesex.org/
我的摄像头在Linux下面用lsusb显示信息如下 
root@ubuntu:/opt/myproject/capture# lsusb
Bus 002 Device 003: ID 0e0f:0002 VMware, Inc. Virtual USB Hub
Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 023: ID 1871:2000 Aveo Technology Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
第三个是摄像头的公司,和ID号
root@ubuntu:/opt/myproject/capture# lsusb -s 001:023 -v
这个命令显示摄像头具体的详细信息,这个相当有参考价值,比较多就不列出了。我的摄像头是UVC标准的,可能在高版本的内核直接插上就可以用V4L2标准,其驱动已经是标准内核的一部分了,支持YUYV一种输出格式,在TQ2440上面用摄像头采集图像,然后直接用frame buffer显示。刚开始一直疑惑,显示的帧率只有一帧左右,但是同样的程序在PC上面就没有问题。

#include <sys/time.h>
struct timeval tpstart,tpend,temp;
float timeuse;
gettimeofday(&tpstart,0);
####   test code ####
gettimeofday(&tpend,0);
timeuse = 1000000*(tpend.tv_sec-tpstart.tv_sec) + (tpend.tv_usec-tpstart.tv_usec);
timeuse /= 1000000;
printf("select used time:%f\n",timeuse);

用上面这种方式,把整个程序都翻了一遍,才发现整个程序的时间大部分都浪费在等待时间上。当摄像头采集完图像,将图像发往2440的板子,才开始下一帧图像的采集,可能是S3C2440带的是USB1.1的原因,数据传输速度不给力,造成图像帧率低,在capcure.c中有这样一段代码
 fd_set fds;
                        struct timeval tv;
                        int r;

                 FD_ZERO (&fds);
                        FD_SET (fd, &fds);


                        /* Timeout. */
                       tv.tv_sec = 2;
                        tv.tv_usec = 0;

                       r = select (fd + 1, &fds, NULL, NULL, &tv);

                        if (-1 == r) {
                                if (EINTR == errno)
                                        continue;


                                errno_exit ("select");
                        }


                        if (0 == r) {
                                fprintf (stderr, "select timeout\n");
                                exit (EXIT_FAILURE);
这一段涉及到异步IO,个人理解就是摄像头在图像采集发送是否准备好,发送下一帧或者采集下一帧的准备。这部分还没有完全理解,但是可以确定的就是2440帧率低就是卡在这部分。
同样这一段代码,同一个摄像头,
select used time:1.030893
select used time:0.930856
select used time:0.450871
select used time:0.482971
select used time:0.482919
select used time:0.451559
select used time:0.483664
select used time:0.483384
这个是在TQ2440上面执行的时间,从上面的时间可以看出基本上采集速度不会超过两帧。
同样的这段代码,在UBUNTU上面执行,
select used time:0.287534
.select used time:0.059609
.select used time:0.059887
.select used time:0.060287
.select used time:0.059686
.select used time:0.059965
.select used time:0.059967
这部分代码在所有采集程序中占的最多时间,可以想像为什么很多人抱怨用2440用USB采集图像显示帧率那么低了。很大部分原因是出在USB接口上,2440用的是USB1.1的协议。
上面是今天的收获,就是用2440 USB1.1口不是很给力,这个因为是芯片的原因,估计很难提高。也难怪在网上也很难找到有人说拿2440去播放视频之类的,播放MP3貌似可以。

今天拿了一个中芯微的摄像头,传统的Z301发现前面讲到的摄像头帧率低也不完全是USB1.1的问题。因为拿中芯微的摄像头,帧率貌似也不是很低
select used time:0.167488
.select used time:0.062586
.select used time:0.095201
.select used time:0.063380
.select used time:0.095356
.select used time:0.063119
.select used time:0.095463
从这里可以看出这个摄像头的帧率到少在十帧以上,明显比原来的那个摄像头流畅
这个摄像头采集图像是JPEG格式,速率差不多可以跟原来那个摄像头在PC上面的速度相比了。
另外他采集的图片比原来YUYV格式的数据要小很多。
YUYV   一个像素占两个字节,一帧图像640*480*2 = 614400字节
JPEG   一帧图像 640*480        压缩后                          118784字节

614400/118784= 5.1724
这就看出差别了,光数据量至少压缩了五倍,这样看来USB1.1传输也不是不可能,关键是要选对摄像头。
另一方面原因可能跟驱动也有一定关系。今天拿到Z301插到电脑上,XP没有识别出来,虚拟机居然提示有摄像头。这点是我没想到的,这个摄像头居然在Linux下支持这么好。Z301的驱动有很多人弄,所以驱动做的好一些。至于UVC的摄像头可能在Linux支持还不是那么好。限于能用吧,效率应该还有待提高 

下面转载是看别人讲V4L2的,讲的不错,转过来参考

前言:目前正在忙于ARM平台的Linux应用程序的开发(其实是刚刚起步学习啦)。底层的东西不用考虑了,开发板子提供了NAND Bootloader,和Linux 2.6的源码,而且都编译好了。自己编译的bootloader可以用,但是Linux编译后,文件很大,暂且就用人家编译的系统,先专心写应用程序 吧。。

正文:要做的任务是,把一块板子上的摄像头采集的图像和声卡采集的声音(貌似很啰嗦哈)通过TCP/IP协议传输到另一块板子上。第一步,先把视频获取并且在本地LCD上显示。看了板子提供的文档,视频传输需要用V4L2的API。

一.什么是video4linux
Video4linux2(简称V4L2),是linux中关于视频设备的内核驱动。在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video0下。

二、一般操作流程(视频设备):
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);
三、常用的结构体(参见/usr/include/linux/videodev2.h):

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;//具体控制的值


 http://blog.chinaunix.net/uid-26696487-id-3076027.html
这是一个哥们写的V4L学习心得,注解都加的很清楚,相当不错的参考

附录:标准的V4l2的API

http://v4l.videotechnology.com/dwg/v4l2.pdf

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值