Linux下V4L2摄像头设计

一、摄像头设计思路

摄像头在linux系统下的设备名:

/dev/video0

1.学习V4L2编程框架

摄像头采集基本流程

1.参照v4l2手册采集yuyv图片 (v4l2)

2.将yuyv转码rgb (转换成bmp) (rgb图片数据用于lcd屏幕显示)

3.压缩 (压缩成jpg)

二、V4L2框架

1、简介

Video for Linuxtwo(Video4Linux2)简称V4L2,是V4L的改进版。V4L2是linux操作系统下用于采集图片、视频和音频数据的API接口,配合适当的视频采集设备和相应的驱动程序,可以实现图片、视频、音频等的采集。在远程会议、可视电话、视频监控系统和嵌入式多媒体终端中都有广泛的应用。

在Linux下,所有外设都被看成一种特殊的文件,成为“设备文件”,可以象访问普通文件一样对其进行读写。一般来说,采用V4L2驱动的摄像头设备文件是/dev/video0。V4L2支持两种方式来采集图像:内存映射方式(mmap)和直接读取方式(read)。V4L2在include/linux/videodev.h文件中定义了一些重要的数据结构,在采集图像的过程中,就是通过对这些数据的操作来获得最终的图像数据。Linux系统V4L2的能力可在Linux内核编译阶段配置,默认情况下都有此开发接口。

而摄像头所用的主要是capature了,视频的捕捉,具体linux的调用可以参考下图。

2、操作流程

  1. 打开视频设备文件,进行视频采集的参数初始化,通过V4L2接口设置视频图像的采集窗口、采集的点阵大小和格式;
  2. 申请若干视频采集的帧缓冲区,并将这些帧缓冲区从内核空间映射到用户空间,便于应用程序读取/处理视频数据;
  3. 将申请到的帧缓冲区在视频采集输入队列排队,并启动视频采集;
  4. 驱动开始视频数据的采集,应用程序从视频采集输出队列取出帧缓冲区,处理完后,将帧缓冲区重新放入视频采集输入队列,循环往复采集连续的视频数据;
  5. 停止视频采集。

通过ioctl这个接口去设置一些参数。最主要的就是buf管理。他有一个或者多个输入队列和输出队列。

启动视频采集后,驱动程序开始采集一帧数据,把采集的数据放入视频采集输入队列的第一个帧缓冲区,一帧数据采集完成,也就是第一个帧缓冲区存满一帧数据后,驱动程序将该帧缓冲区移至视频采集输出队列,等待应用程序从输出队列取出。驱动程序接下来采集下一帧数据,放入第二个帧缓冲区,同样帧缓冲区存满下一帧数据后,被放入视频采集输出队列。

应用程序从视频采集输出队列中取出含有视频数据的帧缓冲区,处理帧缓冲区中的视频数据,如存储或压缩。

最后,应用程序将处理完数据的帧缓冲区重新放入视频采集输入队列,这样可以循环采集,如图所示。

每一个帧缓冲区都有一个对应的状态标志变量,其中每一个比特代表一个状态

V4L2_BUF_FLAG_UNMAPPED 0B0000

V4L2_BUF_FLAG_MAPPED 0B0001

V4L2_BUF_FLAG_ENQUEUED 0B0010

V4L2_BUF_FLAG_DONE 0B0100

缓冲区的状态转化如图所示。

3、V4L2框架使用

(1)打开摄像头设备

打开视频设备非常简单,在V4L2中,视频设备被看做一个文件。使用open函数打开这个设备:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int open(const char *pathname, int flags);
#include <unistd.h>
int close(int fd);

1. 用非阻塞模式打开摄像头设备
int cameraFd;
cameraFd = open("/dev/video0", O_RDWR | O_NONBLOCK);
2. 如果用阻塞模式打开摄像头设备,上述代码变为:
cameraFd = open("/dev/video0", O_RDWR);

应用程序能够使用阻塞模式或非阻塞模式打开视频设备,如果使用非阻塞模式调用视频设备,即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序。

(2)摄像头操作

设置视频设备属性通过ioctl来进行设置

ioctl有三个参数,分别是fd, cmd,和parameter

fd: 表示设备描述符

cmd:控制命令

parameter:控制命令参数

#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
功能:控制驱动设备工作状态
参数:
    fd      : 文件描述符
    request : 命令码
    ......  : 传递的数据-->必须传递数据的地址
 (可以理解为在用户空间和内核空间的传递只能用地址传递了,不能值传递了)
        写成省略号是因为:可以不传递数据
返回值:
    成功 返回0
    失败 返回 -1 并置位错误码

V4L2 的相关定义包含在头文件<linux/videodev2.h>中
#include <linux/videodev2.h>

相关IOCTL接口命令

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。

(3)摄像头属性查询

#include <linux/videodev2.h>

structv4l2_capability  
{  
    __u8 driver[16];     // 驱动名字  
    __u8 card[32];       // 设备名字  
    __u8bus_info[32];    // 设备在系统中的位置  
    __u32 version;       // 驱动版本号  
    __u32capabilities;   // 设备支持的操作  
    __u32reserved[4];    // 保留字段  
};
capabilities 常用值:  
    V4L2_CAP_VIDEO_CAPTURE    // 是否支持图像获取 
V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING 
表示是一个视频捕捉设备并且具有数据流控制模式

capabilities域是一个位掩码用来描述驱动能做的不同的事情:

#define V4L2_CAP_VIDEO_CAPTURE  0x00000001 /*是视频捕获设备*/
#define V4L2_CAP_VIDEO_OUTPUT  0x00000002 /*是视频输出设备*/
#define V4L2_CAP_VIDEO_OVERLAY  0x00000004 /*可以进行视频覆盖*/
#define V4L2_CAP_VBI_CAPTURE  0x00000010  /*是原始VBI捕获设备*/
#define V4L2_CAP_VBI_OUTPUT  0x00000020  /*是原始VBI输出设备*/
#define V4L2_CAP_SLICED_VBI_CAPTURE 0x00000040 /*是切片VBI捕获设备*/
#define V4L2_CAP_SLICED_VBI_OUTPUT 0x00000080 /*是切片VBI输出设备*/
#define V4L2_CAP_RDS_CAPTURE  0x00000100  /*RDS数据捕获*/
#define V4L2_CAP_VIDEO_OUTPUT_OVERLAY 0x00000200 /*可以进行视频输出叠加*/
#define V4L2_CAP_HW_FREQ_SEEK  0x00000400  /*可以进行硬件频率搜索*/
#define V4L2_CAP_TUNER   0x00010000  /*具有调谐器*/
#define V4L2_CAP_AUDIO   0x00020000  /*支持音频*/
#define V4L2_CAP_RADIO   0x00040000  /*是无线电设备*/
#define V4L2_CAP_READWRITE  0x01000000  /*读/写系统调用*/
#define V4L2_CAP_ASYNCIO    0x02000000  /*异步I/O*/
#define V4L2_CAP_STREAMING  0x04000000  /*流式I/O ioctls*/

使用方法

struct v4l2_capability cap;
    //VIDIOC_QUERYCAP 是查询驱动功能
    int ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
    if (ret < 0) {
        printf("VIDIOC_QUERYCAP error\n");
        return -1;
    }

    printf("驱动名 : %s\n",cap.driver);
    printf("设备名字 : %s\n",cap.card);
    printf("总线信息 : %s\n",cap.bus_info);
    printf("驱动版本号 : %d\n",cap.version);
    
    //常用值:V4L2_CAP_VIDEO_CAPTURE 代表是否支持图片获取  
    if(!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)){
        perror("V4L2_CAP_VIDEO_CAPTURE failed\n");
        close(fd);
        exit(EXIT_FAILURE);  
    }
    //是否支持视频流 
    if(!(cap.capabilities & V4L2_CAP_STREAMING)){
        perror("V4L2_CAP_STREAMING failed\n");
        close(fd);
        exit(EXIT_FAILURE);  
    }
//或者写到一起
    //判断是否为视频捕获设备*/
    if(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE){ 
        printf("视频捕获设备:");
        //判断是否支持视频流捕获
        if(cap.capabilities & V4L2_CAP_STREAMING){
            printf("支持视频流捕获\n");
        }else{
            printf("不支持视频流捕获\n");
        }
    }else {
        printf("非视频流捕获设备\n");
        return -1;
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值