linux中的USB摄像头驱动(应用层)(基于V4L2)

10 篇文章 0 订阅

V4L2 是 Video4Linux2 的缩写,是 Linux 内核中的一个视频设备驱动接口。 

 USB-V4L2 初始化流程

1.打开设备节点 open

2.配置参数:分辨率,fps,格式 ioctl

3.请求分配帧缓存->地址映射

4.加入队列中

/**
  ******************************************************************************
  * @file    usbcamera.c
  * @author  CJ
  * @version V1.0
  * @date    2020/8
  * @brief
  ******************************************************************************
  * @attention
  ******************************************************************************
  */

#include "usbcamera.h"
#include <sys/types.h>
#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <linux/fb.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <dirent.h>
#include <stdlib.h>
#include <fcntl.h>
#include <poll.h>
#include <sys/time.h>
#include <assert.h>
#include <sys/select.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

static UsbCameraSyspara g_cameraSyspara;

bool usbCamera_init()
{
    /* 1、打开设备节点 */
    g_cameraSyspara.fd = open("/dev/video0", O_RDWR);
    if(g_cameraSyspara.fd < 0)
    {
        printf("Camera device failed to open !\n");
        return false;
    }

    /* 2、定义v4l2_format结构体变量并完成赋值 */
    memset(&g_cameraSyspara.tV4l2Fmt, 0, sizeof(struct v4l2_format));
    g_cameraSyspara.tV4l2Fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;	//视频捕获
    g_cameraSyspara.tV4l2Fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;

    //设置输出图像尺寸
    g_cameraSyspara.tV4l2Fmt.fmt.pix.width  = 1280;
    g_cameraSyspara.tV4l2Fmt.fmt.pix.height = 720;
    g_cameraSyspara.tV4l2Fmt.fmt.pix.field  = V4L2_FIELD_ANY;	//驱动自行选择合适的格式(逐行、隔行)接收images

    /* 3、调用IOCTL完成以上参数配置 */
    if(ioctl(g_cameraSyspara.fd, VIDIOC_S_FMT, &g_cameraSyspara.tV4l2Fmt) != 0)
    {
        printf("tV4l2Fmt failed !\n");
        return false;
    }
    printf("w = %d, h = %d\n", g_cameraSyspara.tV4l2Fmt.fmt.pix.width, g_cameraSyspara.tV4l2Fmt.fmt.pix.height);
    printf("size = %d\n", g_cameraSyspara.tV4l2Fmt.fmt.pix.sizeimage);
    printf("format = %x, nv12 = %x\n", g_cameraSyspara.tV4l2Fmt.fmt.pix.pixelformat, V4L2_PIX_FMT_YUYV);

    g_cameraSyspara.RGBData=(unsigned char*)malloc(g_cameraSyspara.tV4l2Fmt.fmt.pix.sizeimage);

    /* 4、定义v4l2_request结构体变量并完成赋值 */
    memset(&g_cameraSyspara.tV4l2ReqBuffs, 0, sizeof(struct v4l2_requestbuffers));

    g_cameraSyspara.tV4l2ReqBuffs.count   = 10;								//帧缓存个数
    g_cameraSyspara.tV4l2ReqBuffs.memory  = V4L2_MEMORY_MMAP;				//该缓存支持映射
    g_cameraSyspara.tV4l2ReqBuffs.type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;	//视频捕获支持

    /* 5、调用IOCTL请求分配帧缓存 */
    ioctl(g_cameraSyspara.fd, VIDIOC_REQBUFS, &g_cameraSyspara.tV4l2ReqBuffs);

    /* 6、将帧缓存映射至进程空间 */
    unsigned int i;

    for(i = 0;i < g_cameraSyspara.tV4l2ReqBuffs.count;i++)
    {
        memset(&g_cameraSyspara.tV4l2Buf, 0, sizeof(struct v4l2_buffer));

        g_cameraSyspara.tV4l2Buf.index = i;								//帧缓存编号
        g_cameraSyspara.tV4l2Buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;	//视频捕获支持
        g_cameraSyspara.tV4l2Buf.memory = V4L2_MEMORY_MMAP;				//内存映射支持

        //调用IOCTL获取每个帧缓存的相关信息,其中长度、偏移量将作为mmap的参数
        ioctl(g_cameraSyspara.fd, VIDIOC_QUERYBUF, &g_cameraSyspara.tV4l2Buf);

        //映射空间地址
        g_cameraSyspara.MyVideBuf[i] = (unsigned char *)mmap(0, g_cameraSyspara.tV4l2Buf.length, PROT_READ,MAP_SHARED, g_cameraSyspara.fd, g_cameraSyspara.tV4l2Buf.m.offset);

    }

    /* 7、将帧缓存加入队列循环采集 */
    for (i = 0; i <g_cameraSyspara.tV4l2ReqBuffs.count; i++)
    {
        memset(&g_cameraSyspara.tV4l2Buf, 0, sizeof(struct v4l2_buffer));
        g_cameraSyspara.tV4l2Buf.index = i;
        g_cameraSyspara.tV4l2Buf.type  = V4L2_BUF_TYPE_VIDEO_CAPTURE;
        g_cameraSyspara.tV4l2Buf.memory = V4L2_MEMORY_MMAP;
        ioctl(g_cameraSyspara.fd, VIDIOC_QBUF, &g_cameraSyspara.tV4l2Buf);
    }

    struct v4l2_streamparm Stream_Parm;

    Stream_Parm.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;

    int ret = ioctl(g_cameraSyspara.fd, VIDIOC_G_PARM, &Stream_Parm);
    printf("ret = %d >>!!!!!!!!!!!!!!!!!!: Frame rate: %u/%u\n",ret, Stream_Parm.parm.capture.timeperframe.numerator,
                                     Stream_Parm.parm.capture.timeperframe.denominator);
    Stream_Parm.parm.capture.timeperframe.numerator = 1;
    Stream_Parm.parm.capture.timeperframe.denominator = 15;
    printf("ret = %d >>!!!!!!!!!!!!!!!!!!: Frame rate: %u/%u\n",ret, Stream_Parm.parm.capture.timeperframe.numerator,
                                     Stream_Parm.parm.capture.timeperframe.denominator);
    ret = ioctl(g_cameraSyspara.fd, VIDIOC_S_PARM, &Stream_Parm);

    printf("ret = %d >>!!!!!!!!!!!!!!!!!!: Frame rate: %u/%u\n",ret, Stream_Parm.parm.capture.timeperframe.numerator,
                                     Stream_Parm.parm.capture.timeperframe.denominator);
    return true;
}

bool openUsbCamera()
{
    int iType = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    /* 启动摄像头开始采集 */
    if(ioctl(g_cameraSyspara.fd, VIDIOC_STREAMON, &iType) == 0)
    {
        return true;
    }

    return false;
}

bool clsoeUsbCamera()
{
    int iType = V4L2_BUF_TYPE_VIDEO_CAPTURE;

    if(ioctl(g_cameraSyspara.fd, VIDIOC_STREAMOFF, &iType) == 0)
    {
        return true;
    }

    return false;
}

unsigned char *getUsbCameraImage(unsigned int *size)
{
    fd_set readfds;
    unsigned int ListNum;

    FD_ZERO(&readfds);
    FD_SET(g_cameraSyspara.fd,&readfds);

    struct timeval tv;
    unsigned int time1, time2;
    gettimeofday(&tv, NULL);
    time1 = tv.tv_sec*1000000+tv.tv_usec;

    select(g_cameraSyspara.fd+1, &readfds, NULL, NULL, NULL);

    gettimeofday(&tv, NULL);
    time2 = tv.tv_sec*1000000+tv.tv_usec;
    printf("time = %dms\n", (time2-time1)/1000);



    memset(&g_cameraSyspara.tV4l2Buf, 0, sizeof(struct v4l2_buffer));
    g_cameraSyspara.tV4l2Buf.type    = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    g_cameraSyspara.tV4l2Buf.memory  = V4L2_MEMORY_MMAP;

    /* read data */
    ioctl(g_cameraSyspara.fd, VIDIOC_DQBUF, &g_cameraSyspara.tV4l2Buf);
    ListNum = g_cameraSyspara.tV4l2Buf.index;	//数据地址 MyVideBuf[ListNum]

    memset(&g_cameraSyspara.tV4l2Buf, 0, sizeof(struct v4l2_buffer));
    g_cameraSyspara.tV4l2Buf.index  = ListNum;
    g_cameraSyspara.tV4l2Buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    g_cameraSyspara.tV4l2Buf.memory = V4L2_MEMORY_MMAP;
    ioctl(g_cameraSyspara.fd, VIDIOC_QBUF, &g_cameraSyspara.tV4l2Buf);  //将缓冲区再次放入队列

    *size = g_cameraSyspara.tV4l2Fmt.fmt.pix.sizeimage;
    printf("format cnt = %d\n", ListNum);

    return g_cameraSyspara.MyVideBuf[ListNum];
}
/**
  ******************************************************************************
  * @file    usbcamera.h
  * @author  CJ
  * @version V1.0
  * @date    2020/8
  * @brief
  ******************************************************************************
  * @attention

  ******************************************************************************
  */
#ifndef USB_CAMERA_H
#define USB_CAMERA_H

#include "stdbool.h"
#include <linux/videodev2.h>

typedef struct _UsbCameraSyspara
{
    int fd;
    unsigned char *RGBData;              //解码
    struct v4l2_format  tV4l2Fmt;
    struct v4l2_buffer tV4l2Buf;			//缓存区的相关信息
    unsigned char* MyVideBuf[10];			//映射的空间地址
    struct v4l2_requestbuffers tV4l2ReqBuffs;
}UsbCameraSyspara;

bool usbCamera_init();
bool openUsbCamera();
bool clsoeUsbCamera();
unsigned char *getUsbCameraImage(unsigned int *size);
#endif

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值