Linux Camera应用编程

本文介绍在Linux 下怎么操作camera,camera在linux的设备文件一般都是/dev/videoX,如果只有一个摄像头一般都是/dev/video0。
需要包含v4l2的内核头文件:#include <linux/videodev2.h>
1.打开设备文件:

/*open video node*/
video2lcd->videofd = open(“/dev/video0”, O_RDWR);
if(video2lcd->videofd < 0){
	printf("open %s fail!\r\n", VIDEODEV);
	return -1;
}

2.查询v4l2设备的能力:
通过VIDIOC_QUERYCAP 获取V4L2设备的能力保存到 tV4l2Cap中,V4L2_CAP_VIDEO_CAPTURE 代表是视频设备,V4L2_CAP_STREAMING代表是通过流的方式获取帧输出,这个比使用read来读取数据相对更快,比较适合获取视频数据。

//struct v4l2_capability   tV4l2Cap;
//quer video capabilities: VIDIOC_QUERYCAP
memset(&video2lcd->tV4l2Cap, 0, sizeof(struct v4l2_capability));
ret = ioctl(video2lcd->videofd, VIDIOC_QUERYCAP, &video2lcd->tV4l2Cap);
if (ret) {
	printf("Error: unable to query device.\n");
	close(video2lcd->videofd);
}

if (!(video2lcd->tV4l2Cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
{
	printf("%s is not a video capture device\n", VIDEODEV);
	close(video2lcd->videofd);
	return -1;
}
if (video2lcd->tV4l2Cap.capabilities & V4L2_CAP_STREAMING) 
	printf("%s supports streaming i/o\n", VIDEODEV);

3.VIDIOC_ENUM_FMT获取该设备支持的格式
常见格式如下:
V4L2_PIX_FMT_UYVY,
V4L2_PIX_FMT_JPEG,
V4L2_PIX_FMT_RGB565,

/*get video fmt: VIDIOC_ENUM_FMT*/
memset(&video2lcd->tFmtDesc, 0, sizeof(video2lcd->tFmtDesc));
video2lcd->tFmtDesc.index = 0;
video2lcd->tFmtDesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
while ((ret = ioctl(video2lcd->videofd, VIDIOC_ENUM_FMT, &video2lcd->tFmtDesc)) == 0) {
        if (isSupportThisFormat(video2lcd->tFmtDesc.pixelformat))
        {
            video2lcd->iPixelFormat = video2lcd->tFmtDesc.pixelformat;
            break;
        }
	printf("tFmtDesc.index:%d iPixelFormat:%x\n", video2lcd->tFmtDesc.index, video2lcd->tFmtDesc.pixelformat);
	video2lcd->tFmtDesc.index++;
}

4.VIDIOC_S_FMT 设置上一步中支持的一种格式,同时设置采样的窗口大小(x y)。

/*set video fmt: VIDIOC_S_FMT*/
memset(&video2lcd->tV4l2Fmt, 0, sizeof(struct v4l2_format));
video2lcd->tV4l2Fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
video2lcd->tV4l2Fmt.fmt.pix.pixelformat = video2lcd->iPixelFormat;
video2lcd->tV4l2Fmt.fmt.pix.width       = x;
video2lcd->tV4l2Fmt.fmt.pix.height      = y;
video2lcd->tV4l2Fmt.fmt.pix.field       = V4L2_FIELD_ANY;
ret = ioctl(video2lcd->videofd , VIDIOC_S_FMT, &video2lcd->tV4l2Fmt); 
if (ret)
	printf("Unable to set format\n");   
printf("set format success\n");

5.设置了视频格式以后需要申请内存,这里通过VIDIOC_REQBUFS申请了4个帧缓冲内存,然后VIDIOC_QUERYBUF将内核的帧缓冲内存拿到应用层并且保存mmap以后的地址。在通过VIDIOC_QBUF把这四个buff放到内核的队列中,等待使用。

/* request buffers */
memset(&video2lcd->tV4l2ReqBuffs, 0, sizeof(struct v4l2_requestbuffers));
video2lcd->tV4l2ReqBuffs.count = 4;
video2lcd->tV4l2ReqBuffs.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
video2lcd->tV4l2ReqBuffs.memory = V4L2_MEMORY_MMAP;
ret = ioctl(video2lcd->videofd, VIDIOC_REQBUFS, &video2lcd->tV4l2ReqBuffs);
if (ret) 
	printf("Unable to allocate buffers.\n");
printf("request buffers success\n");

if (video2lcd->tV4l2Cap.capabilities & V4L2_CAP_STREAMING)
{
    /* map the buffers */
    for (i = 0; i < video2lcd->tV4l2ReqBuffs.count; i++) 
    {
    	memset(&video2lcd->tV4l2Buf, 0, sizeof(struct v4l2_buffer));
    	video2lcd->tV4l2Buf.index = i;
    	video2lcd->tV4l2Buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    	video2lcd->tV4l2Buf.memory = V4L2_MEMORY_MMAP;
    	ret = ioctl(video2lcd->videofd, VIDIOC_QUERYBUF, &video2lcd->tV4l2Buf);
    	if (ret) 
    	    printf("Unable to query buffer.\n");

        video2lcd->iVideoBufMaxLen = video2lcd->tV4l2Buf.length;
    	video2lcd->pucVideBuf[i] = mmap(0 /* start anywhere */ ,
    			  video2lcd->tV4l2Buf.length, PROT_READ, MAP_SHARED, video2lcd->videofd,
    			  video2lcd->tV4l2Buf.m.offset);
    	if (video2lcd->pucVideBuf[i] == MAP_FAILED) 
    	    printf("Unable to map buffer\n");

	printf(" buffer[%d] length:%d, addr:%x \n", i, video2lcd->iVideoBufMaxLen, video2lcd->pucVideBuf[i]);
    }       

    /* Queue the buffers. */
    for (i = 0; i < video2lcd->tV4l2ReqBuffs.count; i++) 
    {
    	memset(&video2lcd->tV4l2Buf, 0, sizeof(struct v4l2_buffer));
    	video2lcd->tV4l2Buf.index = i;
    	video2lcd->tV4l2Buf.type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    	video2lcd->tV4l2Buf.memory = V4L2_MEMORY_MMAP;
    	ret = ioctl(video2lcd->videofd, VIDIOC_QBUF, &video2lcd->tV4l2Buf);
    	if (ret)
    	    printf("Unable to queue buffer.\n");
    }
}

6.一切准备就绪,下面只需要打开stream

while(1){ 
	tFds[0].fd  = video2lcd.videofd;
	tFds[0].events = POLLIN;

	ret = poll(tFds, 1, -1);
	if (ret <= 0){
	    printf("poll error!\n");
	    return -1;
	}
   
	/* VIDIOC_DQBUF */
	memset(&tV4l2Buf, 0, sizeof(struct v4l2_buffer));
	tV4l2Buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	tV4l2Buf.memory = V4L2_MEMORY_MMAP;
	ret = ioctl(video2lcd.videofd, VIDIOC_DQBUF, &tV4l2Buf);
	if (ret < 0) {
		printf("Unable to dequeue buffer.\n");
		return -1;
	}
	video2lcd.iVideoBufCurIndex = tV4l2Buf.index;
	printf("VIDIOC_DQBUF VideoBuf:%d\n",video2lcd.iVideoBufCurIndex);

	/* VIDIOC_QBUF */
	memset(&tV4l2Buf, 0, sizeof(struct v4l2_buffer));
	tV4l2Buf.index  = video2lcd.iVideoBufCurIndex;
	tV4l2Buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	tV4l2Buf.memory = V4L2_MEMORY_MMAP;
	ret = ioctl(video2lcd.videofd, VIDIOC_QBUF, &tV4l2Buf);
	if (ret) {
	    printf("Unable to queue buffer.\n");
	    return -1;
	}
	printf("VIDIOC_QBUF Ok\n");
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值