v4l2 编程接口(一) — ioctl
在应用程序获取视频数据的流程中,都是通过 ioctl 命令与驱动程序进行交互,常见的 ioctl 命令有: [cpp] view plaincopyprint? VIDIOC_QUERYCAP /*获取设备支持的操作*/ VIDIOC_G_FMT /*获取设置支持的视频式*/ VIDIOC_S_FMT /*设置捕获视频的式*/ VIDIOC_R
在应用程序获取视频数据的流程中,都是通过 ioctl 命令与驱动程序进行交互,常见的 ioctl 命令有:
[cpp] view plaincopyprint?
- VIDIOC_QUERYCAP /* 获取设备支持的操作 */
- 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 /* 设置调谐器频率 */
VIDIOC_QUERYCAP /* 获取设备支持的操作 */ 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 /* 设置调谐器频率 */
VIDIOC_QUERYCAP 命令通过结构 v4l2_capability 获取设备支持的操作模式:
[cpp] view plaincopyprint?
- struct v4l2_capability {
- __u8 driver[16]; /* i.e. "bttv" */
- __u8 card[32]; /* i.e. "Hauppauge WinTV" */
- __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */
- __u32 version; /* should use KERNEL_VERSION() */
- __u32 capabilities; /* Device capabilities */
- __u32 reserved[4];
- };
struct v4l2_capability { __u8 driver[16]; /* i.e. "bttv" */ __u8 card[32]; /* i.e. "Hauppauge WinTV" */ __u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */ __u32 version; /* should use KERNEL_VERSION() */ __u32 capabilities; /* Device capabilities */ __u32 reserved[4]; };
2、struct v4l2_format 与 VIDIOC_G_FMT、VIDIOC_S_FMT、VIDIOC_TRY_FMT
通常用 VIDIOC_S_FMT 命令通过结构 v4l2_format 初始化捕获视频的格式,如果要改变格式则用 VIDIOC_TRY_FMT 命令:
[cpp] view plaincopyprint?
- struct v4l2_format {
- enum v4l2_buf_type type;
- union {
- struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
- 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;
- };
- 其中
- enum v4l2_buf_type {
- V4L2_BUF_TYPE_VIDEO_CAPTURE = 1,
- V4L2_BUF_TYPE_VIDEO_OUTPUT = 2,
- V4L2_BUF_TYPE_VIDEO_OVERLAY = 3,
- ...
- V4L2_BUF_TYPE_PRIVATE = 0x80,
- };
- struct v4l2_pix_format {
- __u32 width;
- __u32 height;
- __u32 pixelformat;
- enum v4l2_field field;
- __u32 bytesperline; /* for padding, zero if unused */
- __u32 sizeimage;
- enum v4l2_colorspace colorspace;
- __u32 priv; /* private data, depends on pixelformat */
- };
struct v4l2_format { enum v4l2_buf_type type; union { struct v4l2_pix_format pix; /* V4L2_BUF_TYPE_VIDEO_CAPTURE */ 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; }; 其中 enum v4l2_buf_type { V4L2_BUF_TYPE_VIDEO_CAPTURE = 1, V4L2_BUF_TYPE_VIDEO_OUTPUT = 2, V4L2_BUF_TYPE_VIDEO_OVERLAY = 3, ... V4L2_BUF_TYPE_PRIVATE = 0x80, }; struct v4l2_pix_format { __u32 width; __u32 height; __u32 pixelformat; enum v4l2_field field; __u32 bytesperline; /* for padding, zero if unused */ __u32 sizeimage; enum v4l2_colorspace colorspace; __u32 priv; /* private data, depends on pixelformat */ };
3、struct v4l2_requestbuffers 与 VIDIOC_REQBUFS
VIDIOC_REQBUFS 命令通过结构 v4l2_requestbuffers 请求驱动申请一片连续的内存用于缓存视频信息:
[cpp] view plaincopyprint?
- struct v4l2_requestbuffers {
- __u32 count;
- enum v4l2_buf_type type;
- enum v4l2_memory memory;
- __u32 reserved[2];
- };
- 其中
- enum v4l2_memory {
- V4L2_MEMORY_MMAP = 1,
- V4L2_MEMORY_USERPTR = 2,
- V4L2_MEMORY_OVERLAY = 3,
- };
struct v4l2_requestbuffers { __u32 count; enum v4l2_buf_type type; enum v4l2_memory memory; __u32 reserved[2]; }; 其中 enum v4l2_memory { V4L2_MEMORY_MMAP = 1, V4L2_MEMORY_USERPTR = 2, V4L2_MEMORY_OVERLAY = 3, };
4、struct v4l2_buffer与 VIDIOC_QUERYBUF
VIDIOC_QUERYBUF 命令通过结构 v4l2_buffer 查询驱动申请的内存区信息:
[cpp] view plaincopyprint?
- struct v4l2_buffer {
- __u32 index;
- enum v4l2_buf_type type;
- __u32 bytesused;
- __u32 flags;
- enum v4l2_field field;
- struct timeval timestamp;
- struct v4l2_timecode timecode;
- __u32 sequence;
- /* memory location */
- enum v4l2_memory memory;
- union {
- __u32 offset;
- unsigned long userptr;
- } m;
- __u32 length;
- __u32 input;
- __u32 reserved;
- };
struct v4l2_buffer { __u32 index; enum v4l2_buf_type type; __u32 bytesused; __u32 flags; enum v4l2_field field; struct timeval timestamp; struct v4l2_timecode timecode; __u32 sequence; /* memory location */ enum v4l2_memory memory; union { __u32 offset; unsigned long userptr; } m; __u32 length; __u32 input; __u32 reserved; };
另外 VIDIOC_QBUF 和 VIDIOC_DQBUF 命令都采用结构 v4l2_buffer 与驱动通信:VIDIOC_QBUF 命令向驱动传递应用程序已经处理完的缓存,即将缓存加入空闲可捕获视频的队列,传递的主要参数为 index;VIDIOC_DQBUF 命令向驱动获取已经存放有视频数据的缓存,v4l2_buffer 的各个域几乎都会被更新,但主要的参数也是 index,应用程序会根据 index 确定可用数据的起始地址和范围。
5、enum v4l2_buf_type 与 VIDIOC_STREAMON、VIDIOC_STREAMOFF
这两个命令使用的只是一个整形数据,即 v4l2_buf_type,一般只要指定其值为 V4L2_BUF_TYPE_VIDEO_CAPTURE 即可。
6、struct v4l2_queryctrl 与 VIDIOC_QUERYCTRL
VIDIOC_QUERYCTRL 命令通过结构 v4l2_queryctrl 查询驱动是否支持该 id 代表的命令,并返回该命令的各种参数:
[cpp] view plaincopyprint?
- struct v4l2_queryctrl {
- __u32 id; /* 命令编号 */
- enum v4l2_ctrl_type type; /* 命令值的类型 */
- __u8 name[32]; /* 命令名称*/
- __s32 minimum; /* 最小的命令值 */
- __s32 maximum; /* 最大的命令值 */
- __s32 step; /* 命令值变化的步长 */
- __s32 default_value; /* 默认的命令值 */
- __u32 flags; /* 命令的标志 */
- __u32 reserved[2]; /* 命令值的位图表示 */
- };
- 其中
- enum v4l2_ctrl_type {
- V4L2_CTRL_TYPE_INTEGER = 1, /* 整形 */
- V4L2_CTRL_TYPE_BOOLEAN = 2, /* 真值 */
- V4L2_CTRL_TYPE_MENU = 3, /* 菜单 */
- V4L2_CTRL_TYPE_BUTTON = 4, /* 无值 */
- V4L2_CTRL_TYPE_INTEGER64 = 5, /* 后面三种不常用 */
- V4L2_CTRL_TYPE_CTRL_CLASS = 6,
- V4L2_CTRL_TYPE_STRING = 7,
- };
- 命令的标志取值如下:
- /* Control flags */
- #define V4L2_CTRL_FLAG_DISABLED 0x0001
- #define V4L2_CTRL_FLAG_GRABBED 0x0002
- #define V4L2_CTRL_FLAG_READ_ONLY 0x0004
- #define V4L2_CTRL_FLAG_UPDATE 0x0008
- #define V4L2_CTRL_FLAG_INACTIVE 0x0010
- #define V4L2_CTRL_FLAG_SLIDER 0x0020
- #define V4L2_CTRL_FLAG_WRITE_ONLY 0x0040
- /* Query flag, to be ORed with the control ID */
- #define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000
struct v4l2_queryctrl { __u32 id; /* 命令编号 */ enum v4l2_ctrl_type type; /* 命令值的类型 */ __u8 name[32]; /* 命令名称*/ __s32 minimum; /* 最小的命令值 */ __s32 maximum; /* 最大的命令值 */ __s32 step; /* 命令值变化的步长 */ __s32 default_value; /* 默认的命令值 */ __u32 flags; /* 命令的标志 */ __u32 reserved[2]; /* 命令值的位图表示 */ }; 其中 enum v4l2_ctrl_type { V4L2_CTRL_TYPE_INTEGER = 1, /* 整形 */ V4L2_CTRL_TYPE_BOOLEAN = 2, /* 真值 */ V4L2_CTRL_TYPE_MENU = 3, /* 菜单 */ V4L2_CTRL_TYPE_BUTTON = 4, /* 无值 */ V4L2_CTRL_TYPE_INTEGER64 = 5, /* 后面三种不常用 */ V4L2_CTRL_TYPE_CTRL_CLASS = 6, V4L2_CTRL_TYPE_STRING = 7, }; 命令的标志取值如下: /* Control flags */ #define V4L2_CTRL_FLAG_DISABLED 0x0001 #define V4L2_CTRL_FLAG_GRABBED 0x0002 #define V4L2_CTRL_FLAG_READ_ONLY 0x0004 #define V4L2_CTRL_FLAG_UPDATE 0x0008 #define V4L2_CTRL_FLAG_INACTIVE 0x0010 #define V4L2_CTRL_FLAG_SLIDER 0x0020 #define V4L2_CTRL_FLAG_WRITE_ONLY 0x0040 /* Query flag, to be ORed with the control ID */ #define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000
id 是命令的编号,常见的命令有两种:一种以 V4L2_CID_BASE 为起始值,是公用命令;一种以 V4L2_CID_PRIVATE_BASE 为起始值,是私有命令。在一般的应用中命令值可见如下:
[cpp] view plaincopyprint?
- V4L2_CID_CONTRAST (V4L2_CID_BASE+1) /* 对比度调节 */
- V4L2_CID_SATURATION (V4L2_CID_BASE+2) /* 饱和度调节 */
- V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) /* 音量调节 */
- V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) /* 静音设置 */
- V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) /* 白平衡调节 */
- V4L2_CID_GAMMA (V4L2_CID_BASE+16) /* 伽马值调节 */
- V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) /* 曝光度调节 */
- V4L2_CID_PRIVATE_ATXX_FLASH (V4L2_CID_PRIVATE_BASE + 2) /* 闪光灯控制 */
- V4L2_CID_PRIVATE_ATXX_FRAME (V4L2_CID_PRIVATE_BASE + 12) /* 帧率调节 */
V4L2_CID_CONTRAST (V4L2_CID_BASE+1) /* 对比度调节 */ V4L2_CID_SATURATION (V4L2_CID_BASE+2) /* 饱和度调节 */ V4L2_CID_AUDIO_VOLUME (V4L2_CID_BASE+5) /* 音量调节 */ V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9) /* 静音设置 */ V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13) /* 白平衡调节 */ V4L2_CID_GAMMA (V4L2_CID_BASE+16) /* 伽马值调节 */ V4L2_CID_EXPOSURE (V4L2_CID_BASE+17) /* 曝光度调节 */ V4L2_CID_PRIVATE_ATXX_FLASH (V4L2_CID_PRIVATE_BASE + 2) /* 闪光灯控制 */ V4L2_CID_PRIVATE_ATXX_FRAME (V4L2_CID_PRIVATE_BASE + 12) /* 帧率调节 */
type 为命令值的类型(总共有7中类型的值),name 是命令的名称,reserved 则是命令值的位图表示,驱动会将所有的命令值都以 bit 的形式写到 64 位的域中,上层应用查询时可以根据位图判断命令支持的值。
7、struct v4l2_control 与 VIDIOC_G_CTRL、VIDIOC_S_CTRL
VIDIOC_S_CTRL 或 VIDIOC_G_CTRL 命令通过结构 v4l2_control 设置或者获取 id 命令的值:
[cpp] view plaincopyprint?
- struct v4l2_control {
- __u32 id;
- __s32 value;
- };
struct v4l2_control { __u32 id; __s32 value; };
这个结构只有 2 个域,id 是命令编号,value 则是命令的值。
8、struct v4l2_tuner 与 VIDIOC_G_TUNER、VIDIOC_S_TUNER
VIDIOC_S_TUNER 或 VIDIOC_G_TUNER 命令通过结构 v4l2_tuner 设置调谐器的信息:
[cpp] view plaincopyprint?
- struct v4l2_tuner {
- __u32 index; /* 调谐器编号,由应用程序设置 */
- __u8 name[32]; /* 调谐器名称 */
- enum v4l2_tuner_type type; /* 调谐器类型 */
- __u32 capability; /* 调谐器支持的操作 */
- __u32 rangelow; /* 最低频率值,单位为62.5Hz或者62.5KHz */
- __u32 rangehigh; /* 最高频率值 */
- __u32 rxsubchans; /* 接收的音频信号类型 */
- __u32 audmode; /* 当前音频播放形式 */
- __s32 signal; /* 信号强度 */
- __s32 afc; /* 自动频率控制 */
- __u32 reserved[4]; /* 保留备用 */
- };
- 其中
- enum v4l2_tuner_type {
- V4L2_TUNER_RADIO = 1, /* 调频收音机 */
- V4L2_TUNER_ANALOG_TV = 2, /* 模拟电视高频头 */
- V4L2_TUNER_DIGITAL_TV = 3, /* 数字电视高频头 */
- };
struct v4l2_tuner { __u32 index; /* 调谐器编号,由应用程序设置 */ __u8 name[32]; /* 调谐器名称 */ enum v4l2_tuner_type type; /* 调谐器类型 */ __u32 capability; /* 调谐器支持的操作 */ __u32 rangelow; /* 最低频率值,单位为62.5Hz或者62.5KHz */ __u32 rangehigh; /* 最高频率值 */ __u32 rxsubchans; /* 接收的音频信号类型 */ __u32 audmode; /* 当前音频播放形式 */ __s32 signal; /* 信号强度 */ __s32 afc; /* 自动频率控制 */ __u32 reserved[4]; /* 保留备用 */ }; 其中 enum v4l2_tuner_type { V4L2_TUNER_RADIO = 1, /* 调频收音机 */ V4L2_TUNER_ANALOG_TV = 2, /* 模拟电视高频头 */ V4L2_TUNER_DIGITAL_TV = 3, /* 数字电视高频头 */ };
9、struct v4l2_frequency 与 VIDIOC_G_FREQUENCY、VIDIOC_S_FREQUENCY
VIDIOC_S_FREQUENCY 或 VIDIOC_G_FREQUENCY 命令通过结构 v4l2_frequency 设置或获取当前频率值:
[cpp] view plaincopyprint?
- struct v4l2_frequency {
- __u32 tuner; /* 调谐器编号 */
- enum v4l2_tuner_type type; /* 调谐器类型 */
- __u32 frequency; /* 调谐器频率 */
- __u32 reserved[8];
- };
struct v4l2_frequency { __u32 tuner; /* 调谐器编号 */ enum v4l2_tuner_type type; /* 调谐器类型 */ __u32 frequency; /* 调谐器频率 */ __u32 reserved[8]; };
附:_IO、_IOR、_IOW、_IOWR 宏的使用说明
驱动程序中 ioctl 函数传递的变量 cmd 是应用程序向驱动程序请求处理的命令。cmd 除了用于区别不同命令的数值,还可包含有助于处理的几种信息。cmd 的大小为 32 bit,共分 4 个域:
bit29 ~ bit31: 3bit 为 “读写” 区,作用是区分是读命令还是写命令。
bit16 ~ bit28:13bit 为 "数据大小" 区,表示 ioctl 中的 arg 变量传递的数据大小;有时候为 14bit 即将 bit29 覆盖。
bit8 ~ bit15: 8bit 为 “魔数"(也称为"幻数")区,这个值用以与其它设备驱动程序的 ioctl 命令进行区别。
bit0 ~ bit7: 8bit 为 "序号" 区,是区分命令的命令顺序序号。
魔数(magic number)
魔数范围为 0~255 。通常,用英文字符 'A' ~ 'Z' 或者 'a' ~ 'z' 来表示。设备驱动程序从传递进来的命令获取魔数,然后与自身处理的魔数想比较,如果相同则处理,不同则不处理。魔数是拒绝误使用的初步辅助参数。设备驱动程序可以通过宏 _IOC_TYPE (cmd) 来获取魔数。不同的设备驱动程序最好设置不同的魔数,但并不是要求绝对,也是可以使用其他设备驱动程序已用过的魔数。
基数(序号)
基数用于区别各种命令。通常,从 0开始递增,相同设备驱动程序上可以重复使用该值。例如,读和写命令中使用了相同的基数,设备驱动程序也能分辨出来,原因在于设备驱动程序区分命令时使用 switch ,且直接使用命令变量 cmd 值。创建命令的宏生成的值由多个域组合而成,所以即使是相同的基数,也会判断为不同的命令。设备驱动程序想要从命令中获取该基数,就使用宏 _IOC_NR (cmd)。
下面我们看一下上述宏在内核中的原型:
[cpp] view plaincopyprint?
- /*
- * Our DIR and SIZE overlap in order to simulteneously provide
- * a non-zero _IOC_NONE (for binary compatibility) and
- * 14 bits of size as on i386. Here's the layout:
- *
- * 0xE0000000 DIR 3bit
- * 0x80000000 DIR = WRITE bit31
- * 0x40000000 DIR = READ bit30
- * 0x20000000 DIR = NONE bit29
- * 0x3FFF0000 SIZE (overlaps NONE bit) 13bit
- * 0x0000FF00 TYPE 8bit
- * 0x000000FF NR (CMD) 8bit
- */
- /* 各个域的长度 */
- #define _IOC_NRBITS 8
- #define _IOC_TYPEBITS 8
- #define _IOC_SIZEBITS 13 /* Actually 14, see below. */
- #define _IOC_DIRBITS 3
- /* 各个域的掩码 */
- #define _IOC_NRMASK ((1
- #define _IOC_TYPEMASK ((1
- #define _IOC_SIZEMASK ((1
- #define _IOC_XSIZEMASK ((1
- #define _IOC_DIRMASK ((1
- /* 各个域的偏移 */
- #define _IOC_NRSHIFT 0
- #define _IOC_TYPESHIFT (_IOC_NRSHIFT + _IOC_NRBITS) /* 8 */
- #define _IOC_SIZESHIFT (_IOC_TYPESHIFT + _IOC_TYPEBITS) /* 16 */
- #define _IOC_DIRSHIFT (_IOC_SIZESHIFT + _IOC_SIZEBITS) /* 29 */
- /* 读写域的值 */
- #define _IOC_NONE 1U
- #define _IOC_READ 2U
- #define _IOC_WRITE 4U
- #define _IOC(dir,type,nr,size) \
- (((dir) /* 读写方向左移 29bit */
- ((type) /* 幻数左移 8bit */
- ((nr) /* 命令序号 */
- ((size) /* 参数大小左移 16bit */
- /* 宏原型,这里将会根据传递的数据类型取其长度 */
- #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
- #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
- #define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
- #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
- /* 获取各个域的值 */
- #define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
- #define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
- #define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
- #define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
/* * Our DIR and SIZE overlap in order to simulteneously provide * a non-zero _IOC_NONE (for binary compatibility) and * 14 bits of size as on i386. Here's the layout: * * 0xE0000000 DIR 3bit * 0x80000000 DIR = WRITE bit31 * 0x40000000 DIR = READ bit30 * 0x20000000 DIR = NONE bit29 * 0x3FFF0000 SIZE (overlaps NONE bit) 13bit * 0x0000FF00 TYPE 8bit * 0x000000FF NR (CMD) 8bit */ /* 各个域的长度 */ #define _IOC_NRBITS 8 #define _IOC_TYPEBITS 8 #define _IOC_SIZEBITS 13 /* Actually 14, see below. */ #define _IOC_DIRBITS 3 /* 各个域的掩码 */ #define _IOC_NRMASK ((1 > _IOC_DIRSHIFT) & _IOC_DIRMASK) #define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) #define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) #define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
[cpp] view plaincopyprint?
- #define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability)
- #define VIDIOC_RESERVED _IO('V', 1)
- #define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format)
- #define VIDIOC_STREAMON _IOW('V', 18, int)
#define VIDIOC_QUERYCAP _IOR('V', 0, struct v4l2_capability) #define VIDIOC_RESERVED _IO('V', 1) #define VIDIOC_S_FMT _IOWR('V', 5, struct v4l2_format) #define VIDIOC_STREAMON _IOW('V', 18, int)
[cpp] view plaincopyprint?
- static unsigned long cmd_input_size(unsigned int cmd)
- {
- #define CMDINSIZE(cmd, type, field) \
- case VIDIOC_##cmd: \
- return offsetof(struct v4l2_##type, field) + \ /* 域的偏移 */
- sizeof(((struct v4l2_##type *)0)->field); /* 域的长度 */
- switch (cmd) {
- CMDINSIZE(ENUM_FMT, fmtdesc, type);
- CMDINSIZE(G_FMT, format, type);
- ...
- CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format);
- CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height);
- default:
- return _IOC_SIZE(cmd); /* 剩下的是需要全部拷贝的命令 */
- }
- }
- long video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg)
- {
- char sbuf[128]; /* 在栈中分配128个字节空间用来储存命令的参数 */
- void *mbuf = NULL;
- void *parg = NULL; /* 参数存放的首地址 */
- long err = -EINVAL;
- int is_ext_ctrl;
- size_t ctrls_size = 0;
- void __user *user_ptr = NULL;
- ...
- /* 判断是否包含读写命令,如果是则将用户空间的参数值拷贝到内核 */
- if (_IOC_DIR(cmd) != _IOC_NONE) {
- /* 判断参数大小是否超过128字节 */
- if (_IOC_SIZE(cmd) sizeof(sbuf)) {
- parg = sbuf;
- } else {
- /* 如果超过128字节则从堆中申请 */
- mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL);
- if (NULL == mbuf)
- return -ENOMEM;
- parg = mbuf;
- }
- err = -EFAULT;
- /* 如果包含写命令 */
- if (_IOC_DIR(cmd) & _IOC_WRITE) {
- /* 计算需要拷贝的有效数据长度,有的命令不需要全部拷贝 */
- unsigned long n = cmd_input_size(cmd);
- /* 从用户空间拷贝参数值 */
- if (copy_from_user(parg, (void __user *)arg, n))
- goto out;
- /* 将剩下的空间清零 */
- if (n
- memset((u8 *)parg + n, 0, _IOC_SIZE(cmd) - n);
- } else {
- /* 如果是只读命令则将整个buffer清零 */
- memset(parg, 0, _IOC_SIZE(cmd));
- }
- }
- ...
- /* 调用 v4l2_ioctl_ops 的成员函数处理命令 */
- err = __video_do_ioctl(file, cmd, parg);
- if (err == -ENOIOCTLCMD)
- err = -EINVAL;
- ...
- if (err
- goto out;
- out_ext_ctrl:
- /* 如果包含读命令则将参数值拷贝到用户空间 */
- switch (_IOC_DIR(cmd)) {
- case _IOC_READ:
- case (_IOC_WRITE | _IOC_READ):
- if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
- err = -EFAULT;
- break;
- }
- out:
- kfree(mbuf);
- return err;
- }
- EXPORT_SYMBOL(video_ioctl2);
static unsigned long cmd_input_size(unsigned int cmd) { #define CMDINSIZE(cmd, type, field) \ case VIDIOC_##cmd: \ return offsetof(struct v4l2_##type, field) + \ /* 域的偏移 */ sizeof(((struct v4l2_##type *)0)->field); /* 域的长度 */ switch (cmd) { CMDINSIZE(ENUM_FMT, fmtdesc, type); CMDINSIZE(G_FMT, format, type); ... CMDINSIZE(ENUM_FRAMESIZES, frmsizeenum, pixel_format); CMDINSIZE(ENUM_FRAMEINTERVALS, frmivalenum, height); default: return _IOC_SIZE(cmd); /* 剩下的是需要全部拷贝的命令 */ } } long video_ioctl2(struct file *file, unsigned int cmd, unsigned long arg) { char sbuf[128]; /* 在栈中分配128个字节空间用来储存命令的参数 */ void *mbuf = NULL; void *parg = NULL; /* 参数存放的首地址 */ long err = -EINVAL; int is_ext_ctrl; size_t ctrls_size = 0; void __user *user_ptr = NULL; ... /* 判断是否包含读写命令,如果是则将用户空间的参数值拷贝到内核 */ if (_IOC_DIR(cmd) != _IOC_NONE) { /* 判断参数大小是否超过128字节 */ if (_IOC_SIZE(cmd)

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen

Haben Sie Probleme mit der Shazam-App auf dem iPhone? Shazam hilft Ihnen, Lieder zu finden, indem Sie sie anhören. Wenn Shazam jedoch nicht richtig funktioniert oder den Song nicht erkennt, müssen Sie den Fehler manuell beheben. Die Reparatur der Shazam-App wird nicht lange dauern. Befolgen Sie also, ohne noch mehr Zeit zu verlieren, die folgenden Schritte, um Probleme mit der Shazam-App zu beheben. Fix 1 – Deaktivieren Sie die Funktion für fetten Text. Fetter Text auf dem iPhone kann der Grund dafür sein, dass Shazam nicht richtig funktioniert. Schritt 1 – Sie können dies nur über Ihre iPhone-Einstellungen tun. Also, öffnen Sie es. Schritt 2 – Als nächstes öffnen Sie dort die Einstellungen „Anzeige & Helligkeit“. Schritt 3 – Wenn Sie feststellen, dass „Fetttext“ aktiviert ist

Stehen Sie vor einer Verzögerung oder einer langsamen mobilen Datenverbindung auf dem iPhone? Normalerweise hängt die Stärke des Mobilfunk-Internets auf Ihrem Telefon von mehreren Faktoren ab, wie z. B. der Region, dem Mobilfunknetztyp, dem Roaming-Typ usw. Es gibt einige Dinge, die Sie tun können, um eine schnellere und zuverlässigere Mobilfunk-Internetverbindung zu erhalten. Fix 1 – Neustart des iPhone erzwingen Manchmal werden durch einen erzwungenen Neustart Ihres Geräts viele Dinge zurückgesetzt, einschließlich der Mobilfunkverbindung. Schritt 1 – Drücken Sie einfach einmal die Lauter-Taste und lassen Sie sie los. Drücken Sie anschließend die Leiser-Taste und lassen Sie sie wieder los. Schritt 2 – Der nächste Teil des Prozesses besteht darin, die Taste auf der rechten Seite gedrückt zu halten. Lassen Sie das iPhone den Neustart abschließen. Aktivieren Sie Mobilfunkdaten und überprüfen Sie die Netzwerkgeschwindigkeit. Überprüfen Sie es erneut. Fix 2 – Datenmodus ändern 5G bietet zwar bessere Netzwerkgeschwindigkeiten, funktioniert jedoch besser, wenn das Signal schwächer ist

Kürzlich wurde die Militärwelt von der Nachricht überwältigt: US-Militärkampfflugzeuge können jetzt mithilfe von KI vollautomatische Luftkämpfe absolvieren. Ja, erst kürzlich wurde der KI-Kampfjet des US-Militärs zum ersten Mal der Öffentlichkeit zugänglich gemacht und sein Geheimnis gelüftet. Der vollständige Name dieses Jägers lautet „Variable Stability Simulator Test Aircraft“ (VISTA). Er wurde vom Minister der US-Luftwaffe persönlich geflogen, um einen Eins-gegen-eins-Luftkampf zu simulieren. Am 2. Mai startete US-Luftwaffenminister Frank Kendall mit einer X-62AVISTA auf der Edwards Air Force Base. Beachten Sie, dass während des einstündigen Fluges alle Flugaktionen autonom von der KI durchgeführt wurden! Kendall sagte: „In den letzten Jahrzehnten haben wir über das unbegrenzte Potenzial des autonomen Luft-Luft-Kampfes nachgedacht, aber es schien immer unerreichbar.“ Nun jedoch,

Das neueste Video von Teslas Roboter Optimus ist veröffentlicht und er kann bereits in der Fabrik arbeiten. Bei normaler Geschwindigkeit sortiert es Batterien (Teslas 4680-Batterien) so: Der Beamte hat auch veröffentlicht, wie es bei 20-facher Geschwindigkeit aussieht – auf einer kleinen „Workstation“, pflücken und pflücken und pflücken: Dieses Mal wird es freigegeben. Eines der Highlights Der Vorteil des Videos besteht darin, dass Optimus diese Arbeit in der Fabrik völlig autonom und ohne menschliches Eingreifen während des gesamten Prozesses erledigt. Und aus Sicht von Optimus kann es auch die krumme Batterie aufnehmen und platzieren, wobei der Schwerpunkt auf der automatischen Fehlerkorrektur liegt: In Bezug auf die Hand von Optimus gab der NVIDIA-Wissenschaftler Jim Fan eine hohe Bewertung ab: Die Hand von Optimus ist der fünffingrige Roboter der Welt am geschicktesten. Seine Hände sind nicht nur taktil

Beim Modell 70B können 1000 Token in Sekunden generiert werden, was fast 4000 Zeichen entspricht! Die Forscher haben Llama3 verfeinert und einen Beschleunigungsalgorithmus eingeführt. Im Vergleich zur nativen Version ist die Geschwindigkeit 13-mal höher! Es ist nicht nur schnell, seine Leistung bei Code-Rewriting-Aufgaben übertrifft sogar GPT-4o. Diese Errungenschaft stammt von anysphere, dem Team hinter dem beliebten KI-Programmierartefakt Cursor, und auch OpenAI beteiligte sich an der Investition. Sie müssen wissen, dass bei Groq, einem bekannten Framework zur schnellen Inferenzbeschleunigung, die Inferenzgeschwindigkeit von 70BLlama3 nur mehr als 300 Token pro Sekunde beträgt. Aufgrund der Geschwindigkeit von Cursor kann man sagen, dass eine nahezu sofortige vollständige Bearbeitung der Codedatei möglich ist. Manche Leute nennen es einen guten Kerl, wenn man Curs sagt

Letzte Woche wurde OpenAI inmitten der Welle interner Kündigungen und externer Kritik von internen und externen Problemen geplagt: - Der Verstoß gegen die Schwester der Witwe löste weltweit hitzige Diskussionen aus - Mitarbeiter, die „Overlord-Klauseln“ unterzeichneten, wurden einer nach dem anderen entlarvt – Internetnutzer listeten Ultramans „ Sieben Todsünden“ – Gerüchtebekämpfung: Laut durchgesickerten Informationen und Dokumenten, die Vox erhalten hat, war sich die leitende Führung von OpenAI, darunter Altman, dieser Eigenkapitalrückgewinnungsbestimmungen wohl bewusst und hat ihnen zugestimmt. Darüber hinaus steht OpenAI vor einem ernsten und dringenden Problem – der KI-Sicherheit. Die jüngsten Abgänge von fünf sicherheitsrelevanten Mitarbeitern, darunter zwei der prominentesten Mitarbeiter, und die Auflösung des „Super Alignment“-Teams haben die Sicherheitsprobleme von OpenAI erneut ins Rampenlicht gerückt. Das Fortune-Magazin berichtete, dass OpenA

Llama3, der majestätische König von Open Source, das ursprüngliche Kontextfenster ist nur ... 8k groß, was mich die Worte „es riecht so gut“ herunterschlucken lässt. Ist heute, wo 32.000 der Ausgangspunkt und 100.000 üblich sind, die Absicht, Raum für Beiträge zur Open-Source-Community zu lassen? Die Open-Source-Community hat sich diese Gelegenheit sicherlich nicht entgehen lassen: Jetzt kann jede fein abgestimmte Version von Llama370b mit nur 58 Codezeilen automatisch auf 1048.000 (eine Million) Kontexte skaliert werden. Hinter den Kulissen verbirgt sich eine LoRA, die aus einer fein abgestimmten Version von Llama370BInstruct extrahiert wurde, die einen guten Kontext erweitert, und die Datei ist nur 800 MB groß. Anschließend können Sie Mergekit verwenden, um es mit anderen Modellen derselben Architektur auszuführen oder es direkt mit dem Modell zusammenzuführen. 1048k-Kontext verwendet

Flackert Ihre iPhone-Kamera bei Innenbeleuchtung oder flackert sie zu stark? Videos, die Sie mit Ihrem iPhone aufnehmen, sehen nicht gut aus, weil die Lichter eingeschaltet sind. Das Flimmern, das Sie im Video sehen, ist auf die unterschiedlichen Bildwiederholraten zurückzuführen. Das ist nicht normal und es gibt Möglichkeiten, dies zu beheben. Dieser Fix hilft Ihnen, das kontinuierliche Flackern oder den Flimmereffekt in iPhone-Videos zu beheben. Fix – Videoausgabeformat ändern Der Grund für dieses Phänomen ist, dass es einen merklichen Unterschied zwischen der Bildwiederholfrequenz des Objekts und der Kameralinse gibt. Wenn Sie Ihren Bildschirm mit dem iPhone aufzeichnen, flackert oder flackert das Video normalerweise stark. Wenn Sie jedoch ein normales Video aufnehmen, sollte es nicht flackern. Dieses Phänomen ist hauptsächlich auf die Diskrepanz zwischen der Bildwiederholfrequenz des Bildschirms und der Bildfrequenz der Kamera zurückzuführen. Die Bildschirmaktualisierungsrate beträgt normalerweise
