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)

Alat AI Hot

Undresser.AI Undress
Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover
Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool
Gambar buka pakaian secara percuma

Clothoff.io
Penyingkiran pakaian AI

AI Hentai Generator
Menjana ai hentai secara percuma.

Artikel Panas

Alat panas

Notepad++7.3.1
Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina
Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1
Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6
Alat pembangunan web visual

SublimeText3 versi Mac
Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Topik panas



Menghadapi masalah dengan apl Shazam pada iPhone? Shazam membantu anda mencari lagu dengan mendengarnya. Walau bagaimanapun, jika Shazam tidak berfungsi dengan betul atau tidak mengenali lagu itu, anda perlu menyelesaikannya secara manual. Membaiki apl Shazam tidak akan mengambil masa yang lama. Jadi, tanpa membuang masa lagi, ikut langkah di bawah untuk menyelesaikan isu dengan aplikasi Shazam. Betulkan 1 – Lumpuhkan Ciri Teks Tebal Teks tebal pada iPhone mungkin menjadi sebab mengapa Shazam tidak berfungsi dengan betul. Langkah 1 – Anda hanya boleh melakukan ini daripada tetapan iPhone anda. Jadi, bukalah. Langkah 2 - Seterusnya, buka tetapan "Paparan & Kecerahan" di sana. Langkah 3 - Jika anda mendapati bahawa "Teks Tebal" didayakan

Menghadapi ketinggalan, sambungan data mudah alih perlahan pada iPhone? Biasanya, kekuatan internet selular pada telefon anda bergantung pada beberapa faktor seperti rantau, jenis rangkaian selular, jenis perayauan, dsb. Terdapat beberapa perkara yang boleh anda lakukan untuk mendapatkan sambungan Internet selular yang lebih pantas dan boleh dipercayai. Betulkan 1 – Paksa Mulakan Semula iPhone Kadangkala, paksa memulakan semula peranti anda hanya menetapkan semula banyak perkara, termasuk sambungan selular. Langkah 1 – Hanya tekan kekunci naikkan kelantangan sekali dan lepaskan. Seterusnya, tekan kekunci Turun Kelantangan dan lepaskannya semula. Langkah 2 - Bahagian seterusnya proses adalah untuk menahan butang di sebelah kanan. Biarkan iPhone selesai dimulakan semula. Dayakan data selular dan semak kelajuan rangkaian. Semak semula Betulkan 2 – Tukar mod data Walaupun 5G menawarkan kelajuan rangkaian yang lebih baik, ia berfungsi lebih baik apabila isyarat lemah

Baru-baru ini, bulatan tentera telah terharu dengan berita: jet pejuang tentera AS kini boleh melengkapkan pertempuran udara automatik sepenuhnya menggunakan AI. Ya, baru-baru ini, jet pejuang AI tentera AS telah didedahkan buat pertama kali, mendedahkan misterinya. Nama penuh pesawat pejuang ini ialah Variable Stability Simulator Test Aircraft (VISTA). Ia diterbangkan sendiri oleh Setiausaha Tentera Udara AS untuk mensimulasikan pertempuran udara satu lawan satu. Pada 2 Mei, Setiausaha Tentera Udara A.S. Frank Kendall berlepas menggunakan X-62AVISTA di Pangkalan Tentera Udara Edwards Ambil perhatian bahawa semasa penerbangan selama satu jam, semua tindakan penerbangan telah diselesaikan secara autonomi oleh AI! Kendall berkata - "Sejak beberapa dekad yang lalu, kami telah memikirkan tentang potensi tanpa had pertempuran udara-ke-udara autonomi, tetapi ia sentiasa kelihatan di luar jangkauan." Namun kini,

Video terbaru robot Tesla Optimus dikeluarkan, dan ia sudah boleh berfungsi di kilang. Pada kelajuan biasa, ia mengisih bateri (bateri 4680 Tesla) seperti ini: Pegawai itu juga mengeluarkan rupanya pada kelajuan 20x - pada "stesen kerja" kecil, memilih dan memilih dan memilih: Kali ini ia dikeluarkan Salah satu sorotan video itu ialah Optimus menyelesaikan kerja ini di kilang, sepenuhnya secara autonomi, tanpa campur tangan manusia sepanjang proses. Dan dari perspektif Optimus, ia juga boleh mengambil dan meletakkan bateri yang bengkok, memfokuskan pada pembetulan ralat automatik: Berkenaan tangan Optimus, saintis NVIDIA Jim Fan memberikan penilaian yang tinggi: Tangan Optimus adalah robot lima jari di dunia paling cerdik. Tangannya bukan sahaja boleh disentuh

Minggu lalu, di tengah gelombang peletakan jawatan dalaman dan kritikan luar, OpenAI dibelenggu oleh masalah dalaman dan luaran: - Pelanggaran kakak balu itu mencetuskan perbincangan hangat global - Pekerja menandatangani "fasal tuan" didedahkan satu demi satu - Netizen menyenaraikan " Ultraman " tujuh dosa maut" ” Pembasmi khabar angin: Menurut maklumat dan dokumen bocor yang diperolehi oleh Vox, kepimpinan kanan OpenAI, termasuk Altman, sangat mengetahui peruntukan pemulihan ekuiti ini dan menandatanganinya. Di samping itu, terdapat isu serius dan mendesak yang dihadapi oleh OpenAI - keselamatan AI. Pemergian lima pekerja berkaitan keselamatan baru-baru ini, termasuk dua pekerjanya yang paling terkemuka, dan pembubaran pasukan "Penjajaran Super" sekali lagi meletakkan isu keselamatan OpenAI dalam perhatian. Majalah Fortune melaporkan bahawa OpenA

Model 70B, 1000 token boleh dijana dalam beberapa saat, yang diterjemahkan kepada hampir 4000 aksara! Para penyelidik memperhalusi Llama3 dan memperkenalkan algoritma pecutan Berbanding dengan versi asli, kelajuannya adalah 13 kali lebih pantas! Bukan sahaja ia pantas, prestasinya pada tugas menulis semula kod malah mengatasi GPT-4o. Pencapaian ini datang dari mana-mana, pasukan di belakang Kursor artifak pengaturcaraan AI yang popular, dan OpenAI turut mengambil bahagian dalam pelaburan. Anda mesti tahu bahawa pada Groq, rangka kerja pecutan inferens pantas yang terkenal, kelajuan inferens 70BLlama3 hanyalah lebih daripada 300 token sesaat. Dengan kelajuan Kursor, boleh dikatakan bahawa ia mencapai penyuntingan fail kod lengkap hampir serta-merta. Sesetengah orang memanggilnya lelaki yang baik, jika anda meletakkan Curs

Llama3, raja sumber terbuka yang agung, tetingkap konteks asal hanya... 8k, yang membuatkan saya menelan kembali perkataan "ia bau sangat sedap". Hari ini, apabila 32k adalah titik permulaan dan 100k adalah perkara biasa, adakah ini sengaja memberi ruang untuk sumbangan kepada komuniti sumber terbuka? Komuniti sumber terbuka pastinya tidak melepaskan peluang ini: kini dengan hanya 58 baris kod, mana-mana versi Llama370b yang diperhalusi boleh berskala secara automatik kepada 1048k (satu juta) konteks. Di sebalik tabir ialah LoRA, diekstrak daripada versi Llama370BInstruct yang diperhalusi yang memanjangkan konteks yang baik, dan failnya hanya 800mb. Seterusnya, menggunakan Mergekit, anda boleh menjalankannya dengan model lain dengan seni bina yang sama atau menggabungkannya terus ke dalam model. 1048k konteks digunakan

Menurut berita pada 26 Jun, pada majlis perasmian Persidangan Komunikasi Mudah Alih Dunia 2024 Shanghai (MWC Shanghai), Pengerusi Mudah Alih China Yang Jie menyampaikan ucapan. Beliau berkata, pada masa ini, masyarakat manusia memasuki revolusi industri keempat, yang dikuasai oleh maklumat dan sangat bersepadu dengan maklumat dan tenaga, iaitu "revolusi kecerdasan digital", dan pembentukan kuasa produktif baru semakin pesat. Yang Jie percaya bahawa daripada "revolusi mekanisasi" yang digerakkan oleh enjin wap, kepada "revolusi elektrifikasi" yang didorong oleh elektrik dan enjin pembakaran dalaman, kepada "revolusi maklumat" yang didorong oleh komputer dan Internet, setiap pusingan revolusi perindustrian adalah berdasarkan "maklumat dan "Tenaga" adalah barisan utama, membawa pembangunan produktiviti
