V4L2学习笔记

简介:

Video4linux2(简称V4L2),是linux中关于视频设备的内核驱动。

在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写。

摄像头文件一般放在在/dev/video0下。

 

流程:

1、打开视频设备。  

  int g_videofd = open(“/dev/video0”, O_RDWR, 0); //选项可为 O_RDWR| O_NONBLOCK,非阻塞,即无数据依然返回。


2、取得设备的capability。(重要)//l inux-2.6.30/include/linux/videodev2.h定义

 1 int VIPP_VIDEO_Queryinfo() 
 2 {
 3     int ret;
 4     struct v4l2_capability cap;
 5 
 6     ret = ioctl(g_videofd, VIDIOC_QUERYCAP, &cap);
 7     if (ret < 0) {
 8         printf("VIDIOC_QUERYCAP failed (%d)\n",ret);
 9         return ret;
10     }
11 
12     printf(“ Capability Informations:\n”);        //  
13     printf(" driver: %s\n", cap.driver);           // 
14     printf(“ card: %s\n”,     cap.card);        // 
15     printf(“ bus_info: %s\n”, cap.bus_info);    //
16     printf(“ version: %08X\n”, cap.version);    // 
17     printf(“ version: %u.%u.%u\n”, (cap.version>>16)&0xff, (cap.version>>8)&0xff,             cap.version&0xff);        // 
18     printf(" capabilities: %08X\n", cap.capabilities);
19     printf(" reserved: %08X.%08X.%08X.%08X\n",cap.reserved[0],cap.reserved[1],
20         cap.reserved[2],cap.reserved[3]);    // 
21 
22     return 0;
23 }
View Code

3、设置视频的制式和帧格式。

  注意:如果该视频设备驱动不支持你所设定的图像格式,视频驱动会重新修改struct v4l2_format结构体变量的值为该视频设备所支持的                      图像格式,所以在程序设计中,设定完所有的视频格式后,要获取实际的视频格式,要重新读取struct v4l2_format结构体变量。

 1 int VIPP_VIDEO_Setparam(int width, int height, int format)
 2 {
 3     int ret;
 4     memset(&gst_videofmt, 0, sizeof(gst_videofmt));
 5     gst_videofmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //数据流类型,必须永远是                    //V4L2_BUF_TYPE_VIDEO_CAPTURE
 6     gst_videofmt.fmt.pix.width = width;
 7     gst_videofmt.fmt.pix.height = height;
 8     gst_videofmt.fmt.pix.pixelformat = format;
 9     gst_videofmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
10     ret = ioctl(g_videofd, VIDIOC_S_FMT, &gst_videofmt);//设置当前驱动的频捕获格式 
11     if (ret < 0) {    
12         printf("VIDIOC_S_FMT failed (%d)\n", ret);    
13         return ret;    
14     }
15 
16     gst_videofmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
17     if (ioctl(g_videofd, VIDIOC_TRY_FMT, &gst_videofmt) == -1)//验证当前驱动的显示格式 
18     {
19         if ( errno == EINVAL ){
20             printf("not support format RGB32\n");
21             return (-1);        
22         }
23     }
24     return 0;
25 }
View Code

4、向系统申请帧缓冲(一般不超过5个)。

struct v4l2_requestbuffers reqbuf;
 
reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;     
       // 数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE 
reqbuf.memory = V4L2_MEMORY_MMAP; 
        // V4L2_MEMORY_MMAP或 V4L2_MEMORY_USERPTR(内存片段由应用程序自己分配)
reqbuf.count = count;  //缓存数量,也就是说在缓存队列里保持多少张照片,一般不超过5个
 
ret = ioctl(g_videofd , VIDIOC_REQBUFS, &reqbuf);
if(ret < 0) {
   printf("VIDIOC_REQBUFS failed (%d)\n", ret);  
   return ret;
}

5、将申请到的帧缓冲映射到用户空间。

6、将申请到的帧缓冲全部入队列。

for(i = 0; i< count; i++) {    
    gst_videobuf.index = i;     // 要获取内核视频缓冲区的信息编号
    gst_videobuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; // 数据流类型
    gst_videobuf.memory = V4L2_MEMORY_MMAP;
              
    //把内核空间缓冲区映射到用户空间缓冲区
    ret = ioctl(g_videofd , VIDIOC_QUERYBUF, &gst_videobuf);
    if(ret < 0) {
        printf("VIDIOC_QUERYBUF (%d) failed (%d)\n", i, ret);        
        return ret;        
    }
    frame[i].length = gst_videobuf.length;        // 图像的大小
    frame[i].start = (char *) mmap(0, gst_videobuf.length, PROT_READ|PROT_WRITE,                 MAP_SHARED, g_videofd, gst_videobuf.m.offset);
    if (frame[i].start == MAP_FAILED) {
        printf("mmap (%d) failed: %s\n", i, strerror(errno));
        return -1; 
    }
    ret = ioctl(g_videofd , VIDIOC_QBUF, &gst_videobuf);    
    if (ret < 0){
        printf ("VIDIOC_QBUF (%d) failed (%d)\n", i, ret);
        return -1; 
    }
}
View Code

7、开始视频的采集。

  启动视频采集命令,应用程序调用VIDIOC_STREAMON启动视频采集命令后,视频设备驱动程序开始采集视频数据,并把采集到的视频       数据保存到视频驱动的视频缓冲区中

int VIPP_VIDEO_Streamon()
{
    int ret;
    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ret = ioctl(g_videofd, VIDIOC_STREAMON, &type);
    if (ret < 0) {
        printf("VIDIOC_STREAMON failed (%d)\n", ret);
        return ret;
    }

    return 0;
}
View Code

8、出队列以取得已采集数据的帧缓冲,取得原始采集数据。

int VIPP_VIDEO_ReleaseStream()
{
    int ret;
    
    ret = ioctl(g_videofd, VIDIOC_QBUF, &gst_videobuf);    
    if (ret < 0) {        
        LOG("VIDIOC_QBUF failed (%d)\n", ret);        
        return ret;        
    }

    return 0;
}
View Code

9、把原始数据保存入文件中。

  char filename[100] = {0};
  FILE *fp = NULL;
  sprintf(filename, "Image%d.%d_jpeg", i, j);
  fp = fopen(filename, "w");
  fwrite(frame[i].start, 1, frame[i].length, fp);
  fclose(fp);
10、将缓冲重新入队列尾,这样可以循环采集。

int VIPP_VIDEO_ReleaseStream()
{
    int ret;    
    ret = ioctl(g_videofd, VIDIOC_QBUF, &gst_videobuf);    
    if (ret < 0) {        
        printf("VIDIOC_QBUF failed (%d)\n", ret);        
        return ret;        
    }

    return 0;
}
View Code

11、停止视频的采集。

int VIPP_VIDEO_Streamoff()
{
    int ret;
    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    ret = ioctl(g_videofd, VIDIOC_STREAMOFF, &type);
    if (ret < 0) {
        printf("VIDIOC_STREAMON failed (%d)\n", ret);
        return ret;

    }
    return 0;    
}
View Code

12、关闭视频设备文件。

int VIPP_VIDEO_End()
{
    int i;

    for (i=0; i < COUNT; i++) {
        munmap(frame[i].start, frame[i].length);
    }
    close(g_videofd);
    
    return 0;
}
View Code

 

相关结构体:

struct v4l2_requestbuffers  //申请帧缓冲,对应命令VIDIOC_REQBUFS
struct v4l2_capability      //视频设备的功能,对应命令VIDIOC_QUERYCAP
struct v4l2_input           //视频输入信息,对应命令VIDIOC_ENUMINPUT
struct v4l2_standard        //视频的制式,比如PAL,NTSC,对应命令VIDIOC_ENUMSTD
struct v4l2_format          //帧的格式,对应命令VIDIOC_G_FMT、VIDIOC_S_FMT等
struct v4l2_buffer          //驱动中的一帧图像缓存,对应命令VIDIOC_QUERYBUF
struct v4l2_crop            //视频信号矩形边框
v4l2_std_id                 //视频制式

 

常用命令:

VIDIOC_REQBUFS:分配内存
VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址 
VIDIOC_QUERYCAP:查询驱动功能
VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式
VIDIOC_S_FMT:设置当前驱动的频捕获格式
VIDIOC_G_FMT:读取当前驱动的频捕获格式
VIDIOC_TRY_FMT:验证当前驱动的显示格式
VIDIOC_CROPCAP:查询驱动的修剪能力
VIDIOC_S_CROP:设置视频信号的边框
VIDIOC_G_CROP:读取视频信号的边框
VIDIOC_QBUF:把数据从缓存中读取出来
VIDIOC_DQBUF:把数据放回缓存队列
VIDIOC_STREAMON:开始视频显示函数
VIDIOC_STREAMOFF:结束视频显示函数
VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。

 

 

posted @ 2014-01-17 16:46  Trace...  Views(380)  Comments(0Edit  收藏  举报