linux中的USB摄像头驱动(应用层)(基于V4L2)
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