v4l2 摄像头信息采集

格式

首先我们必须要弄清楚自己使用的USB摄像头的输出格式

网上说利用ffmpeg的命令,可以打印信息:但是我没有事成功,只好插拔摄像机查看信息

1 [root/]# [  157.840000] usb 1-2.2: USB disconnect, device number 3
2 [  159.840000] usb 1-2.2: new high-speed USB device number 6 using s5p-ehci
3 [  159.990000] usb 1-2.2: New USB device found, idVendor=1908, idProduct=2311
4 [  159.990000] usb 1-2.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
5 [  159.990000] usb 1-2.2: Product: USB2.0 PC CAMERA
6 [  159.990000] usb 1-2.2: Manufacturer: Generic
7 [  159.995000] uvcvideo: Found UVC 1.00 device USB2.0 PC CAMERA (1908:2311)
8 [  160.000000] input: USB2.0 PC CAMERA as /devices/platform/s5p-ehci/usb1/1-2/1-2.2/1-2.2:1.0/input/input4

可以看出,摄像头输出的是yuyv 但是是支持yuyv422

标识符和结构体


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。

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

  

 1 1.打开文件设备 int fd=open(”/dev/video?″,O_RDWR);  
 2 2. 取得设备的capability,看看设备具有什么功能,比如是否具有视频输入,或者音频输入输出等。VIDIOC_QUERYCAP,struct v4l2_capability  
 3 3. 选择视频输入,一个视频设备可以有多个视频输入。VIDIOC_S_INPUT,struct v4l2_input  
 4 4. 设置视频的制式和帧格式,制式包括PAL,NTSC,帧的格式个包括宽度和高度等。  
 5 VIDIOC_S_STD,VIDIOC_S_FMT,struct v4l2_std_id,struct v4l2_format  
 6 5. 向驱动申请帧缓冲,一般不超过5个。struct v4l2_requestbuffers  
 7 6. 将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。mmap  
 8 7. 将申请到的帧缓冲全部入队列,以便存放采集到的数据.VIDIOC_QBUF,struct v4l2_buffer  
 9 8. 开始视频的采集。VIDIOC_STREAMON  
10 9. 出队列以取得已采集数据的帧缓冲,取得原始采集数据。VIDIOC_DQBUF  
11 10. 将缓冲重新入队列尾,这样可以循环采集。VIDIOC_QBUF  
12 11. 停止视频的采集。VIDIOC_STREAMOFF  
13 12. 关闭视频设备。close(fd); 

void *calloc(unsigned n,unsigned size) 

功 能: 在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。跟malloc的区别:calloc在动态分配完内存后,自动初始化该内存空间为零,而malloc不初始化,里边数据是随机的垃圾数据 。

void *memcpy(void *dest, const void *src, size_t n);
从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
所需头文件include <string.h>

#include <sys/mman.h>
void *mmap(void *start, size_t length, int prot, int flags,int fd, off_t offset);
int munmap(void *start, size_t length);

mmap将一个文件或者其它对象映射进内存。文件被映射到多个页上,如果文件的大小不是所有页的大小之和,最后一个页不被使用的空间将会清零

 

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

  1. length:映射区的长度  
  2. prot:期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过or运算合理地组合在一起    PROT_EXEC //页内容可以被执行  
  3.     PROT_READ //页内容可以被读取  
  4.     PROT_WRITE //页可以被写入  
  5.     PROT_NONE //页不可访问  
  6. flags:指定映射对象的类型,映射选项和映射页是否可以共享  
  7.     MAP_SHARED //与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。直到msync()或者munmap()被调用,文件实际上不会被更新  
  8. fd:有效的文件描述词。一般是由open()函数返回,其值也可以设置为-1,此时需要指定flags参数中的MAP_ANON,表明进行的是匿名映射  
  9. offset:被映射对象内容的起点  
  10. 成功执行时,mmap()返回被映射区的指针,munmap()返回0。失败时,mmap()返回MAP_FAILED[其值为(void *)-1],munmap返回-1  

在程序中,我们使用摄像头,当然就要先打开摄像头

int fd = open("/dev/video?",O_RDWR,0);

然后就可以获取摄像头的信息,比如支持那些格式等

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

获取到的信息都保存在cap结构体中,这个结构体就是

struct v4l2_capability {  
        __u8    driver[16];     //i.e. "bttv"            //驱动名称,  
        __u8    card[32];       // i.e. "Hauppauge WinTV"         //  
        __u8    bus_info[32];   // "PCI:" + pci_name(pci_dev)     //PCI总线信息  
        __u32   version;        // should use KERNEL_VERSION()   
        __u32   capabilities;   // Device capabilities         //设备能力  
        __u32   reserved[4];  
}; 

其中,最重要的就是:视频捕获功能V4L2_CAP_VIDEO_CAPTURE或V4L2_CAP_STREAMING。

 

接下来就需要知道视频设备支持的视频格式,视频格式保存在一个结构体v4l2_fmtdesc 中,可以保存多中格式,

int ret;  
fmtdesc.index=0;  
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
 ret=ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc);  
 while (ret != 0)  
  {  
     fmtdesc.index++;  
      ret=ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc);  
  }  
  printf("--------VIDIOC_ENUM_FMT---------\n");  
  printf("get the format what the device support\n{ pixelformat = ''%c%c%c%c'', description = ''%s'' }\n",fmtdesc.pixelformat & 0xFF, (fmtdesc.pixelformat >> 8) & 0xFF, (fmtdesc.pixelformat >> 16) & 0xFF,(fmtdesc.pixelformat >> 24) & 0xFF, fmtdesc.description);  

其中这个结构体的定义为:

struct v4l2_fmtdesc {  
        __u32               index;             // Format number        
        enum v4l2_buf_type  type;              // buffer type          
        __u32               flags;  
        __u8                description[32];   // Description string   
        __u32               pixelformat;       // Format fourcc        
        __u32               reserved[4];  
};

其中最重要的就是视频的格式,例如YUV4:2:2

 

这里,可以先编写一个简单的例子 

 
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <string.h>  
  4. #include <assert.h>  
  5. #include <getopt.h>  
  6. #include <fcntl.h>  
  7. #include <unistd.h>  
  8. #include <errno.h>  
  9. #include <malloc.h>  
  10. #include <sys/stat.h>  
  11. #include <sys/types.h>  
  12. #include <sys/time.h>  
  13. #include <sys/mman.h>  
  14. #include <sys/ioctl.h>  
  15. #include <asm/types.h>  
  16. #include <linux/videodev2.h>  
  17.    
  18. #define CAMERA_DEVICE "/dev/video0"  
  19.    
  20. #define CAPTURE_FILE "frame_yuyv_new.jpg"  
  21. #define CAPTURE_RGB_FILE "frame_rgb_new.bmp"  
  22. #define CAPTURE_show_FILE "a.bmp"  
  23.   
  24. #define VIDEO_WIDTH 640  
  25. #define VIDEO_HEIGHT 480  
  26. #define VIDEO_FORMAT V4L2_PIX_FMT_YUYV  
  27. #define BUFFER_COUNT 4  
  28.   
  29. int fd;  
  30. struct v4l2_capability cap;  
  31. struct v4l2_fmtdesc fmtdesc;  
  32. struct v4l2_format fmt;  
  33. struct v4l2_requestbuffers reqbuf;  
  34. struct v4l2_buffer buf;  
  35. int main()  
  36. {  
  37.     int i,ret;  
  38.     fd = open(CAMERA_DEVICE, O_RDWR, 0);  
  39.     if (fd 0) {  
  40.         printf("Open %s failed\n",CAMERA_DEVICE);  
  41.     }  
  42.     ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);  
  43.     if (ret 0) {  
  44.         printf("VIDIOC_QUERYCAP failed (%d)\n", ret);  
  45.     }  
  46.   
  47.     printf("------------VIDIOC_QUERYCAP-----------\n");  
  48.     printf("Capability Informations:\n");  
  49.     printf(" driver: %s\n", cap.driver);  
  50.     printf(" card: %s\n", cap.card);  
  51.     printf(" bus_info: %s\n", cap.bus_info);  
  52.     printf(" version: %08X\n", cap.version);  
  53.     printf(" capabilities: %08X\n\n", cap.capabilities);  
  54.   
  55.     memset(&fmtdesc,0,sizeof(fmtdesc));  
  56.     fmtdesc.index=0;  
  57.     fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  58.     ret=ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc);  
  59.     while (ret != 0)  
  60.     {  
  61.         fmtdesc.index++;  
  62.         ret=ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc);  
  63.     }  
  64.     printf("--------VIDIOC_ENUM_FMT---------\n");  
  65.     printf("get the format what the device support\n");  
  66.     printf("pixelformat = %c%c%c%c, description = %s \n",fmtdesc.pixelformat & 0xFF, (fmtdesc.pixelformat >> 8) & 0xFF, (fmtdesc.pixelformat >> 16) & 0xFF,(fmtdesc.pixelformat >> 24) & 0xFF, fmtdesc.description);  
  67.   
  68.   
  69. }  

接下来就是设定视频的格式,设置的时候并不一定会成功,因此需要重新读取视频格式

VIDIOC_S_FMT 设置

VIDIOC_G_FMT 读取

VIDIOC_TRY_FMT 验证

先定义一个格式结构体

 
    1. struct v4l2_format {  
    2.         enum v4l2_buf_type type;    //数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE  
    3.         union {  
    4.                 struct v4l2_pix_format          pix;     // V4L2_BUF_TYPE_VIDEO_CAPTURE   
    5.                 struct v4l2_window              win;     // V4L2_BUF_TYPE_VIDEO_OVERLAY   
    6.                 struct v4l2_vbi_format          vbi;     // V4L2_BUF_TYPE_VBI_CAPTURE   
    7.                 struct v4l2_sliced_vbi_format   sliced;  // V4L2_BUF_TYPE_SLICED_VBI_CAPTURE   
    8.                 __u8    raw_data[200];                   // user-defined   
    9.         } fmt;  
    10. };  
    11. struct v4l2_pix_format {  
    12.         __u32                   width;         // 宽,必须是16的倍数  
    13.         __u32                   height;        // 高,必须是16的倍数  
    14.         __u32                   pixelformat;   // 视频数据存储类型,例如是YUV4:2:2还是RGB  
    15.         enum v4l2_field       field;  
    16.         __u32                   bytesperline;  
    17.         __u32                   sizeimage;  
    18.         enum v4l2_colorspace colorspace;  
    19.         __u32                   priv;
    20. };
posted @ 2017-06-29 17:25  root-linux  阅读(306)  评论(1编辑  收藏  举报