LINUX&UVC元数据(MetaData)节点
2024-03-28
128
0
LINUX的V4L2提供了除视频节点的另一个种节点,叫做元数据节点(MetaDataNode)。
元数据是V4L2的一个特性,它允许驱动程序和应用程序传递关于视频流的元数据。LINUX&UVC驱动对V4L2提供了USB总线级的回调支持。
元数据可以包含各种信息,例如关于帧速率、比特率、编解码器类型、场景变化检测(SCM)的结果等的信息。
在LINUX&UVC驱动中。通过uvc_register_video注册视频节点,而通过uvc_meta_register注册元数据节点。注册的函数由uvc_register_terms实现。
/*
* Register all video devices in all chains.
*/
static int uvc_register_terms(struct uvc_device *dev,
struct uvc_video_chain *chain)
{
struct uvc_streaming *stream;
struct uvc_entity *term;
int ret;
list_for_each_entry(term, &chain->entities, chain) {
if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING)
continue;
stream = uvc_stream_by_id(dev, term->id);
if (stream == NULL) {
uvc_printk(KERN_INFO, "No streaming interface found "
"for terminal %u.", term->id);
continue;
}
stream->chain = chain;
//注册视频节点
ret = uvc_register_video(dev, stream);
if (ret < 0)
return ret;
/* Register a metadata node, but ignore a possible failure,
* complete registration of video nodes anyway.
*/
//注册元数据节点
uvc_meta_register(stream);
term->vdev = &stream->vdev;
}
return 0;
}
相当于视频数据提供的v4l2_ioctl_ops,详见:LINUX&UVC驱动向V4L2提供的回调接口v4l2_ioctl_ops https://www.usbzh.com/article/detail-1343.html
元数据提使用相同的结构体,但提供的回调函数就少了很多。
static const struct v4l2_ioctl_ops uvc_meta_ioctl_ops = {
.vidioc_querycap = uvc_meta_v4l2_querycap,
.vidioc_g_fmt_meta_cap = uvc_meta_v4l2_get_format,
.vidioc_s_fmt_meta_cap = uvc_meta_v4l2_set_format,
.vidioc_try_fmt_meta_cap = uvc_meta_v4l2_try_format,
.vidioc_enum_fmt_meta_cap = uvc_meta_v4l2_enum_formats,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
};
这些回调函数都对应于在应用层的ioctl请求。所以在应用层也是使用2个节点来进行区分。
如使用命令查看电脑中的一个UVC视频设备,可以看到2个节点:
这里出现了两个设备节点:dev/video0、dev/video1,是因为一个是图像/视频采集,一个是metadata采集。
metadata节点可以像正常的视频节点打开,然后进行元数据的传输。
应用代码
使用数下代码,可以打开视频节点。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>
int main(int argc, char**argv)
{
if(argc != 2)
{
printf("%s </dev/video0,1...>\n", argv[0]);
return -1;
}
//打开摄像头设备
int fd = open(argv[1], O_RDWR);
if(fd < 0)
{
perror("打开设备失败");
return -1;
}
//获取摄像头支持格式,使用ioctl函数int ioctl(int fd, unsigned long request, ...);
struct v4l2_fmtdesc v4fmt;
struct v4l2_capability cap;
v4fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //选择视频抓取
int i = 0;
while(1)
{
v4fmt.index = i;
i++;
int ret = ioctl(fd, VIDIOC_ENUM_FMT, &v4fmt);
if(ret < 0)
{
perror("获取格式失败");
break;
}
printf("index = %d\n", v4fmt.index);
printf("flags = %d\n", v4fmt.flags);
printf("descrrption = %s\n", v4fmt.description);
unsigned char *p = (unsigned char*)&v4fmt.pixelformat;
printf("pixelformat = %c%c%c%c\n", p[0],p[1],p[2],p[3]);
printf("reserved = %d\n", v4fmt.reserved[0]);
}
int ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);
if(ret < 0)
perror("获取功能失败");
printf("drivers:%s\n", cap.driver);//读取驱动名字
if(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)
printf("%s 支持视频捕获\n", argv[1]);
if(cap.capabilities & V4L2_CAP_STREAMING)
printf("%s 支持流读写\n", argv[1]);
close(fd);
return 0;
}
其输出结果如下:
- 运行结果说明我的摄像头视频节点支持视频捕获,同时支持流读写支持两种像素格式YUYV和MJPG。
- 读不到video1支持的像素格式,说明该摄像头的两个设备节点仅video0用于视频采集,video0用于元数据传输。
本文部分内容来源于:https://blog.csdn.net/qq_41007891/article/details/134619621