1、资料快车

1)https://blog.csdn.net/thisway_diy/article/details/121809610

2)https://cloud.tencent.com/developer/article/2359076

在了解摄像头内核驱动框架之前,先来看看简单的摄像头应用程序,毕竟内核设计的功能理应服务与应用程序,了解“客户的需求”很有必要,也是首要任务!

2、摄像头操作逻辑框图

在这里插入图片描述

1)重点在于Buffer的管理,APP作为消费者,摄像头则是生产者;

3、数据结构

1.ioctl
/android/vendor/amlogic/common/kernel/common_5.4/include/uapi/linux/videodev2.h
#define VIDIOC_QUERYCAP		 _IOR('V',  0, struct v4l2_capability)
#define VIDIOC_ENUM_FMT         _IOWR('V',  2, struct v4l2_fmtdesc)
#define VIDIOC_G_FMT		_IOWR('V',  4, struct v4l2_format)
#define VIDIOC_S_FMT		_IOWR('V',  5, struct v4l2_format)

1)ioctl操作分为两类:
1、VideoStreaming接口:VIDIOC_ENUM_FMT、VIDIOC_G_FMT、VIDIOC_S_FMT、VIDIOC_STREAMON、VIDIOC_STREAMOFF
2、VideoControl接口(大多数):VIDIOC_S_CTRL、VIDIOC_G_CTRL

2)注意不同的摄像头有不同的IOCTL能力,根据当前平台实现支持的IOCTL;


2.v4l2_buffer - 用于指定buffer的属性,并没有实际内存
/android/vendor/amlogic/common/kernel/common_5.4/include/uapi/linux/videodev2.h
struct v4l2_buffer {
	__u32			index;
	__u32			type;
	struct timeval		timestamp;
	struct v4l2_timecode	timecode;
	__u32			sequence;
	__u32			memory;
}

3.v4l2_format
/android/vendor/amlogic/common/kernel/common_5.4/include/uapi/linux/videodev2.h
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 */
		struct v4l2_sdr_format		sdr;     /* V4L2_BUF_TYPE_SDR_CAPTURE */
		struct v4l2_meta_format		meta;    /* V4L2_BUF_TYPE_META_CAPTURE */
		__u8	raw_data[200];                   /* user-defined */
	} fmt;
};

4、v4l2_fmtdesc
/android/vendor/amlogic/common/kernel/common_5.4/include/uapi/linux/videodev2.h
struct v4l2_fmtdesc {
    __u32 index;
    __u32 type;
    __u32 flags;
    __u8 description[32];
    __u32 pixelformat;
    __u32 reserved[4];
};

5.v4l2_capability
/android/vendor/amlogic/common/kernel/common_5.4/include/uapi/linux/videodev2.h
struct v4l2_capability {
	__u8	driver[16];
	__u8	card[32];
	__u8	bus_info[32];
	__u32   version;
	__u32	capabilities;
	__u32	device_caps;
	__u32	reserved[3];
};

6.v4l2_control - uvc摄像头
/android/vendor/amlogic/common/kernel/common_5.4/include/uapi/linux/videodev2.h
struct v4l2_control {
	__u32		     id;
	__s32		     value;
};

4、经典V4L2应用程序

#include <linux/videodev2.h>

int main(void)
{
    int fd;
    struct v4l2_fmtdesc fmtdesc;
    struct v4l2_frmsizeenum fsenum;
    int frame_index = 0;
    
    fd = open("/dev/video1", O_RDWR);
    
    1.列出帧细节
    fmtdesc.index = 0;
    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc); //获取帧格式
    fsenum.index = 0;
    fsenum.pixel_format = fmtdesc.pixelformat;
    ioctl(fd, VIDIOC_ENUM_FRAMESIZES, &fsenum); //获取帧大小
    
    2.查询摄像头设备能力
    struct v4l2_capability cap;
    ioctl(fd, VIDIOC_QUERYCAP, &cap);
    
    3.设置格式
    struct v4l2_format fmt;
    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = 1920;
    fmt.fmt.pix.height = 1080;
    fmt.fmt.pix.pixleformat = V4L2_PIX_FMT_MJPEG;
    ioctl(fd, VIDIOC_S_FMT, &fmt)
    
    4.申请buffer
    1)申请buffer
    struct v4l2_requestbuffers rb;
    rb.count = 1;
    rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    rb.memory = V4L2_MEMORY_MMAP;
    ioctl(fd, VIDIOC_REQBUFS, &rb);
    2)mmap buffer才可以使用
    struct v4l2_buffer buf;
    buf.index = 0;
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    ioctl(fd, VIDIOC_QUERYBUF, &buf);
    mmap(0, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset);
    
    5.启动摄像头
    ioctl(fd, VIDIOC_STREAMON, &type);
    struct v4l2_buffer buf;
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    ioctl(fd, VIDIOC_DQBUF, &buf);
    
    6.保存buf为jpg文件
    int fd_file = open("capture.jpg", O_RDWR | O_CREAT, 0666);
    write(fd_file, bufs[buf.index], buf.bytesused);
    close(fd_file,)
    
    7.将buf重新放回队列使用
    ioctl(fd, VIDIOC_QBUF, &buf)
    
    8.关闭摄像头
    ioctl(fd, VIDIOC_STREAMOFF, &type)
    
    9.设置亮度
    1)查询亮度信息 - 最大值、最小值、当前值等信息
    struct v4l2_queryctrl   qctrl;
    qctrl.id = V4L2_CID_BRIGHTNESS; // V4L2_CID_BASE+0;
    ioctl(fd, VIDIOC_QUERYCTRL, &qctrl)
    2)设置亮度为80
    struct v4l2_control ctl;
    ctl.id = V4L2_CID_BRIGHTNESS; // V4L2_CID_BASE+0;
    ctl.value = 80;
    ioctl(fd, VIDIOC_S_CTRL, &ctl);
    
}

5、UVC应用程序

1)UVC(USB Video class)相对V4L2的操作,稍微有些不同,有少量UVC的特定操作,但大体都使用V4L2 IOCTL来工作;

2)基于USB摄像头的轻量级开源视频流服务器项目(支持命令行),里面有很多UVC摄像头的示例:

https://github.com/jacksonliam/mjpg-streamer

3)源码分析

1.数据结构
1) IOCTL
#define UVCIOC_CTRL_MAP		_IOWR('u', 0x20, struct uvc_xu_control_mapping)
#define UVCIOC_CTRL_QUERY	_IOWR('u', 0x21, struct uvc_xu_control_query)

2) uvc_xu_control_query
/android/vendor/amlogic/common/kernel/common_5.4/include/uapi/linux/uvcvideo.h
XU:Extension Unit(扩展单元),厂家可以在XU上提供自定义的操作
struct uvc_xu_control_query {
	__u8 unit;
	__u8 selector;
	__u8 query;		/* Video Class-Specific Request Code, */
				/* defined in linux/usb/video.h A.8.  */
	__u16 size;
	__u8 __user *data;
};

2.UVC摄像头扩展功能Mapping
mjpg-streamer\mjpg-streamer-experimental\plugins\input_uvc\dynctrl.c

struct uvc_xu_control_mapping xu_mappings[] = {
    {
        .id        = V4L2_CID_LED1_MODE_LOGITECH,
        .name      = "LED1 Mode",
        .entity    = UVC_GUID_LOGITECH_USER_HW_CONTROL,
        .selector  = XU_HW_CONTROL_LED1,
        .size      = 8,
        .offset    = 0,
        .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
        .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED
    },
}
xioctl(fd, UVCIOC_CTRL_MAP, &xu_mappings[i])

3.其它功能与经典V4L2类似,操作都是使用V4L2 ioctl来进行;
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐