linux 视频采集v4l2

视频采集步骤
1.打开设备

(1)源代码

fd = open(VIDEO_DEVICE,O_RDWR | O_NONBLOCK,0);

if(fd<0)

{

printf("video device open failure!\n");

}



2.获取设备的功能信息

(1)源代码

ret = ioctl(fd,VIDIOC_QUERYCAP,&cap);

if(ret<0)

{

printf("VIDIOC_QUERYCAP error!\n");

}

printf("driver name is %s\n",cap.driver);

printf("device name is %s\n",cap.card);

printf("bus id is %s\n",cap.bus_info);

printf("capabilities is %x\n",cap.capabilities);

(2)VIDIOC_QUERYCAP 查询驱动功能

结构体:struct v4l2_capability * argp

struct v4l2_capability

{

 __u8 driver[16];   //驱动名。

 __u8 card[32];     // Device名

 __u8 bus_info[32];  //在Bus系统中存放位置

 __u32 version;      //driver 版本

 __u32 capabilities;  //能力集

 __u32 reserved[4];

};

所有的能力集如下

V4L2_CAP_VIDEO_CAPTURE 0x00000001 The device supports the Video Capture interface.

V4L2_CAP_VIDEO_OUTPUT 0x00000002 The device supports the Video Output interface.

V4L2_CAP_VIDEO_OVERLAY 0x00000004 The device supports the Video Overlay interface. A video overlay device typically stores captured images directly in the video memory of a graphics card, with hardware clipping and scaling.

V4L2_CAP_VBI_CAPTURE 0x00000010 The device supports the Raw VBI Capture interface, providing Teletext and Closed Caption data.

V4L2_CAP_VBI_OUTPUT 0x00000020 The device supports the Raw VBI Output interface.

V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040 The device supports the Sliced VBI Capture interface.

V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080 The device supports the Sliced VBI Output interface.

V4L2_CAP_RDS_CAPTURE 0x00000100 The device supports the RDS interface.

V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200 The device supports the Video Output Overlay (OSD) interface. Unlike the Video Overlay interface, this is a secondary function of video output devices and overlays an image onto an outgoing video signal. When the driver sets this flag, it must clear the V4L2_CAP_VIDEO_OVERLAY flag and vice versa.[a]

V4L2_CAP_HW_FREQ_SEEK 0x00000400 The device supports the VIDIOC_S_HW_FREQ_SEEK ioctl for hardware frequency seeking.

V4L2_CAP_TUNER 0x00010000 The device has some sort of tuner to receive RF-modulated video signals. For more information about tuner programming see Section 1.6, “Tuners and Modulators”.

V4L2_CAP_AUDIO 0x00020000 The device has audio inputs or outputs. It may or may not support audio recording or playback, in PCM or compressed formats. PCM audio support must be implemented as ALSA or OSS interface. For more information on audio inputs and outputs see Section 1.5, “Audio Inputs and Outputs”.

V4L2_CAP_RADIO 0x00040000 This is a radio receiver.

V4L2_CAP_MODULATOR 0x00080000 The device has some sort of modulator to emit RF-modulated video/audio signals. For more information about modulator programming see Section 1.6, “Tuners and Modulators”.

V4L2_CAP_READWRITE 0x01000000 The device supports the read() and/or write() I/O methods.

V4L2_CAP_ASYNCIO 0x02000000 The device supports the asynchronous I/O methods.

V4L2_CAP_STREAMING 0x04000000 The device supports the streaming I/O method.



3.设置视频的帧格式

(1)源代码

memset ( &fmt, 0, sizeof(fmt) );

fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;

fmt.fmt.pix.width       = 720;

fmt.fmt.pix.height      = 576;

fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;

fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;

ret = ioctl(fd, VIDIOC_S_FMT, &fmt);

if (ret < 0) 

{

printf("VIDIOC_S_FMT error!\n");

}

(2)VIDIOC_S_FMT 设置视频格式

结构体:

struct v4l2_format

{

 enum v4l2_buf_type type;    //必须设置成V4L2_BUF_TYPE_VIDEO_CAPTURE

 union

 {

 struct v4l2_pix_format pix; 

 struct v4l2_window win;

 struct v4l2_vbi_format vbi;

 struct v4l2_sliced_vbi_format sliced;

 __u8 raw_data[200];

 } fmt;

};

struct v4l2_pix_format

{

 __u32 width;     //Image的宽

 __u32 height;    //Image的高

 __u32 pixelformat;   //Image格式,最常见的有:V4L2_PIX_FMT_YYUV

 enum v4l2_field field;  //是否逐行扫描,是否隔行扫描. Sam通常采用V4L2_FIELD_INTERLACED,隔行交替放置数据

 __u32 bytesperline;  //每行的byte数

 __u32 sizeimage;      //总共的byte数,bytesperline * height

 enum v4l2_colorspace colorspace;  //This information supplements the pixelformat and must be set by the driver

 __u32 priv;

};



4.申请帧缓冲

(1)源代码

memset (&reqbuf, 0, sizeof (reqbuf));

reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

reqbuf.memory = V4L2_MEMORY_MMAP;

reqbuf.count = 5;



if (-1 == ioctl (fd, VIDIOC_REQBUFS, &reqbuf))

{

if (errno == EINVAL)

printf ("Video capturing or mmap-streaming is not supported\n");

else

perror ("VIDIOC_REQBUFS");



exit (EXIT_FAILURE);

}

(2)VIDIOC_REQBUFS 申请帧缓冲

结构体:

struct v4l2_requestbuffers

{

__u32 count, //设置缓冲区的大小,这个设置只对V4L2_MEMORY_MMAP.

enum v4l2_buf_type type, //设置缓冲区的类型

enum v4l2_memory, //设置成V4L2_MEMORY_MMAP或者V4L2_MEMORY_USERPTR.

__u32 reserved[2],

}

type可以取如下值

V4L2_BUF_TYPE_VIDEO_CAPTURE 1 Buffer of a video capture stream

V4L2_BUF_TYPE_VIDEO_OUTPUT 2 Buffer of a video output stream

V4L2_BUF_TYPE_VIDEO_OVERLAY 3 Buffer for video overlay

V4L2_BUF_TYPE_VBI_CAPTURE 4 Buffer of a raw VBI capture stream

V4L2_BUF_TYPE_VBI_OUTPUT 5 Buffer of a raw VBI output stream

V4L2_BUF_TYPE_SLICED_VBI_CAPTURE 6 Buffer of a sliced VBI capture stream

V4L2_BUF_TYPE_SLICED_VBI_OUTPUT 7 Buffer of a sliced VBI output stream

V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY 8 Buffer for video output overlay (OSD) Status: Experimental.

V4L2_BUF_TYPE_PRIVATE 0x80 This and higher values are reserved for custom (driver defined) buffer types.





5.将申请到的帧缓冲使用mmap的方式映射到用户空间

(1)源代码

buffers = calloc (reqbuf.count, sizeof (*buffers));

for (i = 0; i < reqbuf.count; i++) 

{

memset (&buf, 0, sizeof (buf));

buf.type = reqbuf.type;

buf.memory = V4L2_MEMORY_MMAP;

buf.index = i;



if (-1 == ioctl (fd, VIDIOC_QUERYBUF, &buf)) 

{

perror ("VIDIOC_QUERYBUF");

exit (EXIT_FAILURE);

}



buffers[i].length = buf.length; 

buffers[i].start = mmap (NULL, buf.length,

PROT_READ | PROT_WRITE, 

MAP_SHARED, 

fd, buf.m.offset);



if (MAP_FAILED == buffers[i].start) {

perror ("mmap");

exit (EXIT_FAILURE);

}

}

(2)结构

struct v4l2_buffer

{

__u32 index,   //帧缓冲的index

enum v4l2_buf_type type, //帧缓冲的类型

enum v4l2_memory memory, //设定为V4L2_MEMORY_MMAP

......

}

(3)calloc函数

函数原型:

void *calloc(size_t n, size_t size);

功 能: 

在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。

一般使用后要使用 free(起始地址的指针) 对内存进行释放

(4)mmap函数

函数原型:

#include <sys/mman.h>

void *mmap(void *start, size_t length, int prot, int flags,

int fd, off_t offset);

功能:

mmap操作提供了一种机制,让用户程序直接访问设备内存,这种机制,相比较在用户空间和内核空间互相拷贝数据,效率更高。在要求高性能的应用中比较常用。mmap映射内存必须是页面大小的整数倍,面向流的设备不能进行mmap,mmap的实现和硬件有关。

参数说明:

start:映射区的开始地址,设置为0时表示由系统决定映射区的起始地址。

length:映射区的长度。长度单位是 以字节为单位,不足一内存页按一内存页处理

prot:期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算合理地组合在一起

PROT_EXEC //页内容可以被执行

PROT_READ //页内容可以被读取

PROT_WRITE //页可以被写入

PROT_NONE //页不可访问

flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体

MAP_FIXED //使用指定的映射起始地址,如果由start和len参数指定的内存区重叠于现存的映射空间,重叠部分将会被丢弃。如果指定的起始地址不可用,操作将会失败。并且起始地址必须落在页的边界上。

MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新。

MAP_PRIVATE //建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以上标志是互斥的,只能使用其中一个。

MAP_DENYWRITE //这个标志被忽略。

MAP_EXECUTABLE //同上

MAP_NORESERVE //不要为这个映射保留交换空间。当交换空间被保留,对映射区修改的可能会得到保证。当交换空间不被保留,同时内存不足,对映射区的修改会引起段违例信号。

MAP_LOCKED //锁定映射区的页面,从而防止页面被交换出内存。

MAP_GROWSDOWN //用于堆栈,告诉内核VM系统,映射区可以向下扩展。

MAP_ANONYMOUS //匿名映射,映射区不与任何文件关联。

MAP_ANON //MAP_ANONYMOUS的别称,不再被使用。

MAP_FILE //兼容标志,被忽略。

MAP_32BIT //将映射区放在进程地址空间的低2GB,MAP_FIXED指定时会被忽略。当前这个标志只在x86-64平台上得到支持。

MAP_POPULATE //为文件映射通过预读的方式准备好页表。随后对映射区的访问不会被页违例阻塞。

MAP_NONBLOCK //仅和MAP_POPULATE一起使用时才有意义。不执行预读,只为已存在于内存中的页面建立页表入口。

fd:有效的文件描述词。一般是由open()函数返回,其值也可以设置为-1,此时需要指定flags参数中的MAP_ANON,表明进行的是匿名映射。

offset:被映射对象内容的起点。



6.帧缓冲全部入列

(1)源代码

for (i = 0; i < reqbuf.count; ++i) 

{

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory = V4L2_MEMORY_MMAP;

buf.index = i;



if (-1 == ioctl(fd, VIDIOC_QBUF, &buf))

printf("VIDIOC_QBUF error\n");

}

(2)结构体

struct v4l2_buffer

{

__u32 index,   //帧缓冲的index

enum v4l2_buf_type type, //帧缓冲的类型

enum v4l2_memory memory, //设定为V4L2_MEMORY_MMAP

......

}



7.开始采集数据

(1)源代码

type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (-1 == ioctl(fd, VIDIOC_STREAMON, &type))

printf("VIDIOC_STREAMON error\n");

(2)结构

enum v4l2_buf_type type; //type设置为V4L2_BUF_TYPE_VIDEO_CAPTURE



8.出列获取采集到的数据

(1)源代码

fd_set fds;

struct timeval tv;

int r,j;



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(r<0)

{

printf("select function error\n");

}

do 

{

ret = ioctl(fd,VIDIOC_DQBUF, &buf);

}while(ret==-1 && errno==EAGAIN);

(2)结构

struct v4l2_buffer

{

__u32 index,   //帧缓冲的index

enum v4l2_buf_type type, //帧缓冲的类型

enum v4l2_memory memory, //设定为V4L2_MEMORY_MMAP

......

}

(3)select函数

头文件

#include <sys/select.h> /* 根据POSIX.1 - 2001 */

/*根据早期的标准*/

#include<sys/types.h>

#include<sys/time.h>

#include<unistd.h>

原型

int select (int maxfd + 1,fd_set *readset,fd_set *writeset,

fd_set *exceptset,const struct timeval * timeout);

参数

参数一:最大的文件描述符加1。

参数二:用于检查可读性,

参数三:用于检查可写性,

参数四:用于检查带外数据,

参数五:一个指向timeval结构的指针,用于决定select等待I/o的最长时间。如果为空将一直等待。

timeval结构的定义:struct timeval{

long tv_sec; // seconds

long tv_usec; // microseconds

}

返回值

>0:就绪描述字的正数目

-1:出错

0 :超时

注意

readset writeset exceptset指定我们要让内核测试读、写和异常条件的描述字。如果对某一个的条件不感兴趣,就可以把它设为NULL。如果三个指针都为NULL,我们就有了一个比sleep()函数更为精确的定时器(sleep()以秒为最小单位,这个以微秒为单位)。

select使用描述字集,典型地是一个整数数组,其中每个整数中的每一位对应一个描述字。假设使用32位整数,那么该数组的第一个元素对应于描述字0~31,第二个元素对应于描述字32~63,依此类推。所有的实现细节都与应用程序无关,它们隐藏在名为fd_set的数据类型和以下四个宏中:

void FD_ZERO (fd_set *fdset); // clear all bits in fdset

void FD_SET (int fd,fd_set *fdset); // turn on the bit for fd in fdset

void FD_CLR (int fd,fd_set *fdset); // turn off the bit for fd in fdset

intFD_ISSET(int fd,fd_set *fdset); // is the bit for fd on in fdset



9.帧缓冲入列,形成循环获取视频数据

(1)源代码

buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

buf.memory = V4L2_MEMORY_MMAP;

do 

{

ret = ioctl(fd,VIDIOC_QBUF, &buf);

}while(ret==-1 && errno==EAGAIN);



10.关闭视频设备等

(1)源代码

type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

if (-1 == ioctl(fd, VIDIOC_STREAMOFF, &type))

printf("VIDIOC_STREAMOFF error \n");



for (i = 0; i < reqbuf.count; ++i)

if (-1 == munmap(buffers[i].start, buffers[i].length))

printf("munmap error\n");

free(buffers);


close(fd);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux 上,使用 V4L2(Video for Linux 2)接口可以实现 USB 相机的视频采集。下面是一个简单的实现过程: 1. 打开相机设备 使用 open() 函数打开相机设备文件,例如 /dev/video0。如果打开成功,则返回文件描述符。如果打开失败,则需要检查设备文件是否存在或是否拥有读写权限。 2. 查询设备信息 使用 ioctl() 函数和 VIDIOC_QUERYCAP 命令查询设备信息,包括设备名称、设备类型、支持的视频格式等。 3. 配置视频格式 使用 ioctl() 函数和 VIDIOC_S_FMT 命令设置视频格式,包括图像大小、像素格式、帧率等。在设置之前,需要先查询设备支持的视频格式,以确保所设置的格式被支持。 4. 分配视频缓冲区 使用 ioctl() 函数和 VIDIOC_REQBUFS 命令请求相机分配视频缓冲区。在请求之前,需要先设置好视频格式。分配的缓冲区可以用于存储相机采集视频数据。 5. 将缓冲区映射到用户空间 使用 mmap() 函数将缓冲区映射到用户空间,以便用户程序可以直接访问缓冲区。 6. 开始视频采集 使用 ioctl() 函数和 VIDIOC_STREAMON 命令启动视频采集。此时,相机会不断采集视频数据,并将数据存储到缓冲区中。 7. 读取视频数据 使用 read() 函数从缓冲区中读取视频数据,然后进行处理或显示。读取数据之前,需要先使用 select() 函数或 poll() 函数等待相机数据就绪。 8. 停止视频采集 使用 ioctl() 函数和 VIDIOC_STREAMOFF 命令停止视频采集。此时,相机不再采集视频数据。 9. 释放缓冲区 使用 munmap() 函数解除缓冲区的映射,并使用 ioctl() 函数和 VIDIOC_REQBUFS 命令释放缓冲区。 10. 关闭相机设备 使用 close() 函数关闭相机设备文件。 以上是一个简单的 USB 相机视频采集的实现过程。实际实现中,可能需要考虑更多的细节问题,例如错误处理、图像处理、多线程操作等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值