linux v4l2 camera capture and display 一

https://www.cnblogs.com/emouse/archive/2013/03/04/2943243.htm
http://emb.hqyj.com/Column/Column320.html
http://blog.chinaunix.net/uid-11765716-id-2855735.html
https://my.oschina.net/u/1024767/blog/210801#OSC_h2_14
https://www.cnblogs.com/silence-hust/p/4464291.html

常用的IOCTRL命令

VIDIOC_QUERYCAP     /* 获取设备支持的操作 */
VIDIOC_ENUM_FMT     /*查询支持的格式*/
VIDIOC_G_FMT        /* 获取设置支持的视频格式 */
VIDIOC_S_FMT        /* 设置捕获视频的格式 */
VIDIOC_REQBUFS      /* 向驱动提出申请内存的请求 */
VIDIOC_QUERYBUF     /* 向驱动查询申请到的内存 */
VIDIOC_QBUF         /* 将空闲的内存加入可捕获视频的队列 */
VIDIOC_DQBUF        /* 将已经捕获好视频的内存拉出已捕获视频的队列 */
VIDIOC_STREAMON     /* 打开视频流 */
VIDIOC_STREAMOFF    /* 关闭视频流 */
VIDIOC_QUERYCTRL    /* 查询驱动是否支持该命令 */
VIDIOC_G_CTRL       /* 获取当前命令值 */
VIDIOC_S_CTRL       /* 设置新的命令值 */
VIDIOC_G_TUNER      /* 获取调谐器信息 */
VIDIOC_S_TUNER      /* 设置调谐器信息 */
VIDIOC_G_FREQUENCY  /* 获取调谐器频率 */
VIDIOC_S_FREQUENCY  /* 设置调谐器频率 */

v4l2相关结构体设置

typedef __u64 v4l2_std_id;视频制式的设置;VIDIOC_G_STD,VIDIOC_S_STD
如:PALL制,NTSC

查询当前设备支持的所有格式 VIDIOC_ENUM_FMT

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

 while (!ioctl(fd_output_v4l, VIDIOC_ENUM_FMT, &fmtdesc)) {
        printf("fmt %s: fourcc = 0x%08x\n",
               fmtdesc.description,
               fmtdesc.pixelformat);
        fmtdesc.index++;
    }
/**
  * struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP
  *
  * @driver:	   name of the driver module (e.g. "bttv")
  * @card:	   name of the card (e.g. "Hauppauge WinTV")
  * @bus_info:	   name of the bus (e.g. "PCI:" + pci_name(pci_dev) )
  * @version:	   KERNEL_VERSION
  * @capabilities: capabilities of the physical device as a whole
  * @device_caps:  capabilities accessed via this particular device (node)
  * @reserved:	   reserved fields for future extensions
  */
struct v4l2_capability {
	__u8	driver[16];  //
	__u8	card[32];
	__u8	bus_info[32];
	__u32   version;
	__u32	capabilities;
	__u32	device_caps;
	__u32	reserved[3];
};

查询video设备支持的属性 使用VIDIOC_QUERYCAP命令
#define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls /
#define V4L2_CAP_VIDEO_CAPTURE 0x00000001 /
Is a video capture device /
#define V4L2_CAP_VIDEO_OUTPUT 0x00000002 /
Is a video output device */
对于摄像头是否支持流和capture属性

/*
 *	I N P U T   I M A G E   C R O P P I N G
 */
struct v4l2_cropcap {
	__u32			type;	/* enum v4l2_buf_type */
	struct v4l2_rect        bounds; //camera 极限分辨率大小,取景框的极限大小
	struct v4l2_rect        defrect; //camera 默认采集图像的分辨率,默认取景框的大小
	struct v4l2_fract       pixelaspect;	//定义了图像的帧率采用
};


struct v4l2_crop {
	__u32			type;	/* enum v4l2_buf_type */
	struct v4l2_rect        c;  //设置采集图像的尺寸
};

描述视频流的属性:使用VIDIOC_S_PARM,VIDIOC_G_PARM,设置和获取参数,帧率设置不一定成功,driver会根据硬件限制来设置这些参数,当前的帧率是由当前的视频标准来决定的,可以采用默认设置

struct v4l2_streamparm {
	__u32	 type;			/* enum v4l2_buf_type */
	union {
		struct v4l2_captureparm	capture;
		struct v4l2_outputparm	output;
		__u8	raw_data[200];  /* user-defined */
	} parm;
};

struct v4l2_captureparm {
	__u32		   capability;	  /*  Supported modes */
	__u32		   capturemode;	  /*  Current mode */ 
	struct v4l2_fract  timeperframe;  /*  Time per frame in seconds */
	__u32		   extendedmode;  /*  Driver-specific extensions */
	__u32              readbuffers;   /*  # of buffers for read */
	__u32		   reserved[4];
};

capturemode:是否支持高清图像采集,0:表示一般模式;1:表示高清图像模式
timeperframe://表示视频采集帧率,帧率的值为numerator/denominator
struct v4l2_fract {
	__u32   numerator;   //numerator/denominator
	__u32   denominator;
};

视频流数据格式设置

struct v4l2_format {
	__u32	 type;
	union {
		struct v4l2_pix_format		pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
		struct v4l2_pix_format_mplane	pix_mp;  /* V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE */
		struct v4l2_window		win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
		struct v4l2_vbi_format		vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
		struct v4l2_sliced_vbi_format	sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
		__u8	raw_data[200];                   /* user-defined */
	} fmt;
};

struct v4l2_pix_format {
	__u32         		width;
	__u32			height;
	__u32			pixelformat;
	__u32			field;		/* enum v4l2_field */
	__u32            	bytesperline;	/* for padding, zero if unused */
	__u32          		sizeimage;
	__u32			colorspace;	/* enum v4l2_colorspace */
	__u32			priv;		/* private data, depends on pixelformat */
};
pixelformat:设置像素格式比如:V4L2_PIX_FMT_YUYV
width,height;设置大小,设置发现不成功
field:设置场模式:V4L2_FIELD_INTERLACED
关于场的概念设置可以看:
(https://blog.csdn.net/kickxxx/article/details/6367669)

注册帧缓存buffer,使用VIDIOC_REQBUFS进行设置

struct v4l2_requestbuffers {
	__u32			count;
	__u32			type;		/* enum v4l2_buf_type */
	__u32			memory;		/* enum v4l2_memory */
	__u32			reserved[2];
};
count:帧缓存的个数
memory:V4L2_MEMORY_MMAP采用内存映射的方法读取数据

获取缓冲帧的地址长度

struct v4l2_buffer {
	__u32			index;
	__u32			type;
	__u32			bytesused;
	__u32			flags;
	__u32			field;
	struct timeval		timestamp;
	struct v4l2_timecode	timecode;
	__u32			sequence;

	/* memory location */
	__u32			memory;
	union {
		__u32           offset;
		unsigned long   userptr;
		struct v4l2_plane *planes;
		__s32		fd;
	} m;
	__u32			length;
	__u32			reserved2;
	__u32			reserved;
};
index:缓存buffer的索引
offset:buffer的地址
length:数据长度
mmap (NULL, capture_buffers[i].length,
      PROT_READ | PROT_WRITE, MAP_SHARED,
      fd_capture_v4l, capture_buffers[i].offset);
利用 mmap 将数据映射到用户空间

使用VIDIOC_QBUF将缓冲帧入队,使用VIDIOC_DQBUF将缓冲帧出队

一个video设备对应多个视频源输入选择;VIDIOC_G_INPUT,VIDIOC_S_INPUT设置,只有一个视频输入可以不设置;

struct v4l2_input {
	__u32	     index;		/*  Which input */
	__u8	     name[32];		/*  Label */
	__u32	     type;		/*  Type of input */
	__u32	     audioset;		/*  Associated audios (bitfield) */
	__u32        tuner;             /*  enum v4l2_tuner_type */
	v4l2_std_id  std;
	__u32	     status;
	__u32	     capabilities;
	__u32	     reserved[3];
};

camera采集设置流程

  1. open打开一个video设备:
    if ((fd_capture_v4l = open(CAPTURE_DEVICE, O_RDWR, 0)) < 0)
    {
    printf(“Unable to open %s\n”, CAPTURE_DEVICE);
    return ERROR;
    }

  2. 获取video设备的capacity是否支持capture和stream
    struct v4l2_capability cap;
    ioctl (fd_capture_v4l, VIDIOC_QUERYCAP, &cap)
    cap.capabilities & V4L2_CAP_VIDEO_CAPTURE
    cap.capabilities & V4L2_CAP_STREAMING

  3. 查询和设置camera取景框大小:
    struct v4l2_cropcap cropcap;
    struct v4l2_crop crop;
    if (ioctl (fd_capture_v4l, VIDIOC_CROPCAP, &cropcap) < 0)
    {
    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    crop.c = cropcap.defrect; /* reset to default */
    if (ioctl (fd_capture_v4l, VIDIOC_S_CROP, &crop) < 0)

  4. 设置采集图像的格式:
    struct v4l2_format fmt;
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = 0;
    fmt.fmt.pix.height = 0;
    fmt.fmt.pix.pixelformat = g_fmt;
    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

    if (ioctl (fd_capture_v4l, VIDIOC_S_FMT, &fmt) < 0)

  5. 申请帧缓存:
    struct v4l2_requestbuffers req;
    req.count = g_capture_num_buffers;
    req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    req.memory = V4L2_MEMORY_MMAP;
    if (ioctl (fd_capture_v4l, VIDIOC_REQBUFS, &req) < 0)

  6. 获取帧地址映射到用户空间
    struct v4l2_buffer buf;
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = i;
    if (ioctl(fd_capture_v4l, VIDIOC_QUERYBUF, &buf) < 0)

    capture_buffers[i].length = buf.length;
    capture_buffers[i].offset = (size_t) buf.m.offset;
    capture_buffers[i].start = mmap (NULL, capture_buffers[i].length,
                                     PROT_READ | PROT_WRITE, MAP_SHARED,
                                     fd_capture_v4l, capture_buffers[i].offset);
    
  7. 将申请到的帧缓存入队
    for (i = 0; i < g_capture_num_buffers; i++)
    {
    memset(&buf, 0, sizeof (buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = i;
    buf.m.offset = capture_buffers[i].offset;
    if (ioctl (fd_capture_v4l, VIDIOC_QBUF, &buf) < 0) {
    printf(“VIDIOC_QBUF error\n”);
    return ERROR;
    }
    }

  8. 开始采集视频:
    type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    if (ioctl (fd_capture_v4l, VIDIOC_STREAMON, &type) < 0) {
    printf(“VIDIOC_STREAMON error\n”);
    return ERROR;
    }

  9. 取出采集到的数据帧:
    capture_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    capture_buf.memory = V4L2_MEMORY_MMAP;
    if (ioctl(fd_capture_v4l, VIDIOC_DQBUF, &capture_buf) < 0)

  10. 将取出的数据帧操作完成后重新入队列
    if (ioctl(fd_capture_v4l, VIDIOC_QBUF, &capture_buf) < 0) {
    printf(“VIDIOC_QBUF failed\n”);
    return ERROR;
    }

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值