第一章 V4L2简介

2024-06-17 07:38
文章标签 第一章 简介 v4l2

本文主要是介绍第一章 V4L2简介,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

http://work-blog.readthedocs.org/en/latest/v4l2%20intro.html


1.1、什么是v4l2

V4L2(Video4Linux的缩写)是Linux下关于视频采集相关设备的驱动框架,为驱动和应用程序提供了一套统一的接口规范。

V4L2支持的设备十分广泛,但是其中只有很少一部分在本质上是真正的视频设备:

  • Video capture device : 从摄像头等设备上获取视频数据。对很多人来讲,video capture是V4L2的基本应用。设备名称为/dev/video,主设备号81,子设备号0~63
  • Video output device : 将视频数据编码为模拟信号输出。与video capture设备名相同。
  • Video overlay device : 将同步锁相视频数据(如TV)转换为VGA信号,或者将抓取的视频数据直接存放到视频卡的显存中。
  • Video output overlay device :也被称为OSD(On-Screen Display)
  • VBI device : 提供对VBI(Vertical Blanking Interval)数据的控制,发送VBI数据或抓取VBI数据。设备名/dev/vbi0~vbi31,主设备号81,子设备号224~255
  • Radio device : FM/AM发送和接收设备。设备名/dev/radio0~radio63,主设备号81,子设备号64~127

V4L2在Linux系统中的结构图如下:

_images/V4L2框图.png

V4L2简单框图

1.2、从应用层看V4L2

从V4L2简单框图可以看出,V4L2是一个字符设备,而V4L2的大部分功能都是通过设备文件的ioctl导出的。

可以将这些ioctl分类如下

  1. Query Capability:查询设备支持的功能,只有VIDIOC_QUERY_CAP一个。
  2. 优先级相关:包括VIDIOC_G_PRIORITY,VIDIOC_S_PRIORITY,设置优先级。
  3. capture相关:视频捕获相关Ioctl。
capture ioctl list
ID 描述
VIDIOC_ENUM_FMT 枚举设备所支持的所有数据格式
VIDIOC_S_FMT 设置数据格式
VIDIOC_G_FMT 获取数据格式
VIDIOC_TRY_FMT 与VIDIOC_S_FMT一样,但不会改变设备的状态
VIDIOC_REQBUFS 向设备请求视频缓冲区,即初始化视频缓冲区
VIDIOC_QUERYBUF 查询缓冲区的状态
VIDIOC_QBUF 从设备获取一帧视频数据
VIDIOC_DQBUF 将视频缓冲区归回给设备,
VIDIOC_OVERLAY 开始或者停止overlay
VIDIOC_G_FBUF 获取video overlay设备或OSD设备的framebuffer参数
VIDIOC_S_FBUF 设置framebuffer参数
VIDIOC_STREAMON 开始流I/O操作,capture or output device
VIDIOC_STREAMOFF 关闭流I/O操作
  1. TV视频标准:
TV Standard
ID 描述
VIDIOC_ENUMSTD 枚举设备支持的所有标准
VIDIOC_G_STD 获取当前正在使用的标准
VIDIOC_S_STD 设置视频标准
VIDIOC_QUERYSTD 有的设备支持自动侦测输入源的视频标准,此时使用此ioctl查询侦测到的视频标准
  1. input/output:
Input / Output
ID 描述
VIDIOC_ENUMINPUT 枚举所有input端口
VIDIOC_G_INPUT 获取当前正在使用的input端口
VIDIOC_S_INPUT 设置将要使用的input端口
VIDIOC_ENUMOUTPUT 枚举所有output端口
VIDIOC_G_OUTPUT 获取当前正在使用的output端口
VIDIOC_S_OUTPUT 设置将要使用的output端口
VIDIOC_ENUMAUDIO 枚举所有audio input端口
VIDIOC_G_AUDIO 获取当前正在使用的audio input端口
VIDIOC_S_AUDIO 设置将要使用的audio input端口
VIDIOC_ENUMAUDOUT 枚举所有audio output端口
VIDIOC_G_AUDOUT 获取当前正在使用的audio output端口
VIDIOC_S_AUDOUT 设置将要使用的audio output端口
  1. controls:设备特定的控制,例如设置对比度,亮度
controls
ID 描述
VIDIOC_QUERYCTRL 查询指定control的详细信息
VIDIOC_G_CTRL 获取指定control的值
VIDIOC_S_CTRL 设置指定control的值
VIDIOC_G_EXT_CTRLS 获取多个control的值
VIDIOC_S_EXT_CTRLS 设置多个control的值
VIDIOC_TRY_EXT_CTRLS 与VIDIOC_S_EXT_CTRLS相同,但是不改变设备状态
VIDIOC_QUERYMENU 查询menu
  1. 其他杂项:
controls
ID 描述
VIDIOC_G_MODULATOR  
VIDIOC_S_MODULATOR  
VIDIOC_G_CROP  
VIDIOC_S_CROP  
VIDIOC_G_SELECTION  
VIDIOC_S_SELECTION  
VIDIOC_CROPCAP  
VIDIOC_G_ENC_INDEX  
VIDIOC_ENCODER_CMD  
VIDIOC_TRY_ENCODER_CMD  
VIDIOC_DECODER_CMD  
VIDIOC_TRY_DECODER_CMD  
VIDIOC_G_PARM  
VIDIOC_S_PARM  
VIDIOC_G_TUNER  
VIDIOC_S_TUNER  
VIDIOC_G_FREQUENCY  
VIDIOC_S_FREQUENCY  
VIDIOC_G_SLICED_VBI_CAP  
VIDIOC_LOG_STATUS  
VIDIOC_DBG_G_CHIP_IDENT  
VIDIOC_S_HW_FREQ_SEEK  
VIDIOC_ENUM_FRAMESIZES  
VIDIOC_ENUM_FRAMEINTERVALS  
VIDIOC_ENUM_DV_PRESETS  
VIDIOC_S_DV_PRESET  
VIDIOC_G_DV_PRESET  
VIDIOC_QUERY_DV_PRESET  
VIDIOC_S_DV_TIMINGS  
VIDIOC_G_DV_TIMINGS  
VIDIOC_DQEVENT  
VIDIOC_SUBSCRIBE_EVENT  
VIDIOC_UNSUBSCRIBE_EVENT  
VIDIOC_CREATE_BUFS  
VIDIOC_PREPARE_BUF  

v4l2设备的基本操作流程如下:

  1. 打开设备,例如 fd = open("/dev/video0",0)
  2. 查询设备能力. 例如:
struct capability cap;
ioctl(fd,VIDIOC_QUERYCAP,&cap)
  1. 设置优先级(可选).
  2. 配置设备。包括:
  • 视频输入源的视频标准,VIDIOC_*_STD
  • 视频数据的格式 , VIDIOC_*_FMT
  • 视频输入端口, VIDIOC_*_INPUT
  • 视频输出端口,VIDIOC_*_OUTPUT
  1. 启动设备开始I/O操作。V4L2支持一下三种I/O方式:

    • Read/Write:通过调用设备节点文件的Read/Write函数,与设备交互数据。打开设备后,默认使用的是此方法。
    • Stream I/O:流操作,只传递数据缓冲区指针,不拷贝数据。使用此方法,需要调用VIDIOC_REQBUFS ioctl来通知设备。流操作I/O有两种方式memory map和user buffer。(具体区别后面章节介绍)
    • overlay : 也可以理解为memory to memory 传输。将数据从内存拷贝到显存中。overlay设备独有的。

    对于Capture device可以以如下方式启动设备:

    • 调用VIDIOC_REQBUFS ioctl来分配缓冲区队列;
    • 调用VIDIOC_STREAMON ioctl通知设备开始stream IO
    • 调用VIDIOC_QBUF ioctl从设备获取一帧视频数据;
    • 使用完数据后,调用VIDIOC_DQBUF将缓冲区还给设备,以便设备填充下一帧数据。
  2. 释放资源并关闭设备。

1.3、从驱动层看V4L2

在驱动层,V4L2为驱动编写者做了很多工作。只需要实现硬件相关的代码,并且注册相关设备即可。

硬件相关代码的编写,除了编写具体硬件的控制代码外,最主要的就是将代码与V4L2框架绑定。绑定主要分为以下两个部分:

  • 关系绑定:也就是要将我们自己的结构体,与V4L2框架中相关连的结构体绑定在一起。
  • iocontrol等函数绑定:将V4L2所定义的空的函数指针,与自己的函数绑定在一起。

3.1 关系绑定

提到关系绑定,就必须介绍下V4L2几个重要结构体。

  • struct video_device:主要的任务就是负责向内核注册字符设备
  • struct v4l2_device:一个硬件设备可能包含多个子设备,比如一个电视卡除了有capture设备,可能还有VBI设备或者FM tunner。而v4l2_device就是所有这些设备的根节点,负责管理所有的子设备。
  • struct v4l2_subdev:子设备,负责实现具体的功能。

v4l2_device,v4l2_subdev可以看作所有设备和子设备的基类。我们在编写自己的驱动时,往往需要继承这些设备基类,添加一些自己的数据成员。例如第三章要讲到的soc_camera_host结构体,就是继承v4l2_device,并添加了互斥锁、子设备列表等成员变量。

_images/v4l2-intro.png

v4l2 framework 简略版

绑定的基本流程

  • 根据需要”重载”v4l2_device或v4l2_subdev结构体,添加需要的结构体成员。例如 :

    • linux/include/media/soc_camera.h文件中soc_camera_host重载了v4l2_device:

      struct soc_camera_host {
      struct v4l2_device v4l2_dev;
      struct list_head list;
      struct mutex host_lock;         /* Protect during probing */
      unsigned char nr;               /* Host number */
      void *priv;
      const char *drv_name;
      struct soc_camera_host_ops *ops;
      };
      
    • linux/drivers/media/video/Ml86v7667.c中ml86v7667_priv结构体”重载”了v4l2_subdev:

        struct ml86v7667_priv {
            struct v4l2_subdev                sd;
            struct v4l2_ctrl_handler  hdl;v4l2_std_id                       std;};
      
  • v4l2_device与V4L2框架的绑定:通过调用v4l2_device_register函数实现。例如,上面提到的soc_camera_host的绑定:

    int soc_camera_host_register(struct soc_camera_host *ici)
    {struct soc_camera_host *ix;int ret;if (!ici || !ici->ops ||!ici->ops->try_fmt ||!ici->ops->set_fmt ||!ici->ops->set_bus_param ||!ici->ops->querycap ||((!ici->ops->init_videobuf ||!ici->ops->reqbufs) &&!ici->ops->init_videobuf2) ||!ici->ops->add ||!ici->ops->remove ||!ici->ops->poll ||!ici->v4l2_dev.dev)return -EINVAL;if (!ici->ops->set_crop)ici->ops->set_crop = default_s_crop;if (!ici->ops->get_crop)ici->ops->get_crop = default_g_crop;if (!ici->ops->cropcap)ici->ops->cropcap = default_cropcap;if (!ici->ops->set_parm)ici->ops->set_parm = default_s_parm;if (!ici->ops->get_parm)ici->ops->get_parm = default_g_parm;if (!ici->ops->enum_fsizes)ici->ops->enum_fsizes = default_enum_fsizes;mutex_lock(&list_lock);list_for_each_entry(ix, &hosts, list) {if (ix->nr == ici->nr) {ret = -EBUSY;goto edevreg;}}      ret = v4l2_device_register(ici->v4l2_dev.dev, &ici->v4l2_dev);
          if (ret < 0)goto edevreg;list_add_tail(&ici->list, &hosts);mutex_unlock(&list_lock);mutex_init(&ici->host_lock);scan_add_host(ici);return 0;edevreg:mutex_unlock(&list_lock);return ret;}
    
  • v4l2_subdev与v4l2_device的绑定:通过v4l2_device_register_subdev函数,将subdev注册到根节点上。例如:

    static int soc_camera_platform_probe(struct platform_device *pdev)
    {struct soc_camera_host *ici;struct soc_camera_platform_priv *priv;struct soc_camera_platform_info *p = pdev->dev.platform_data;struct soc_camera_device *icd;int ret;if (!p)return -EINVAL;if (!p->icd) {dev_err(&pdev->dev,"Platform has not set soc_camera_device pointer!\n");return -EINVAL;}priv = kzalloc(sizeof(*priv), GFP_KERNEL);if (!priv)return -ENOMEM;icd = p->icd;/* soc-camera convention: control's drvdata points to the subdev */platform_set_drvdata(pdev, &priv->subdev);/* Set the control device reference */icd->control = &pdev->dev;ici = to_soc_camera_host(icd->parent);v4l2_subdev_init(&priv->subdev, &platform_subdev_ops);v4l2_set_subdevdata(&priv->subdev, p);strncpy(priv->subdev.name, dev_name(&pdev->dev), V4L2_SUBDEV_NAME_SIZE);ret = v4l2_device_register_subdev(&ici->v4l2_dev, &priv->subdev);if (ret)goto evdrs;return ret;evdrs:platform_set_drvdata(pdev, NULL);kfree(priv);return ret;
    }
    
  • video_device与v4l2_device的绑定:将v4l2_device的地址赋值给video_device的v4l2_dev即可。

此步不一定必要。只要有办法通过文件节点file(struct file)找到v4l2_device即可。

3.2 函数绑定

在v4l2 framework 简略版图中,绿色的方框都是需要我们绑定并实现的。

其中v4l2_file_operations和v4l2_ioctl_ops是必须实现的。而v4l2_subdev_ops下的八类ops中,v4l2_subdev_core_ops是必须实现的,其余需要根据设备类型选择实现的。比如video capture类设备需要实现v4l2_subdev_core_ops, v4l2_subdev_video_ops。

  • v4l2_file_operations:实现文件类操作,比如open,close,read,write,mmap等。但是ioctl是不需要实现的,一般都是用video_ioctl2代替。例如linux/drivers/media/video/soc_camera.c文件中soc_camera_fops的实现:
static struct v4l2_file_operations soc_camera_fops = {.owner          = THIS_MODULE,.open           = soc_camera_open,.release        = soc_camera_close,
    .unlocked_ioctl = video_ioctl2,
    .read           = soc_camera_read,.mmap           = soc_camera_mmap,.poll           = soc_camera_poll,
};
  • v4l2_ioctl_ops:V4L2导出给应用层使用的所有ioctl都是在这个地方实现的。但不必全部实现,只实现自己相关的ioctl即可。例如linux/drivers/media/video/soc_camera.c中soc_camera_ioctl_ops的实现:
static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = {.vidioc_querycap         = soc_camera_querycap,.vidioc_try_fmt_vid_cap  = soc_camera_try_fmt_vid_cap,.vidioc_g_fmt_vid_cap    = soc_camera_g_fmt_vid_cap,.vidioc_s_fmt_vid_cap    = soc_camera_s_fmt_vid_cap,.vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap,.vidioc_enum_input       = soc_camera_enum_input,.vidioc_g_input          = soc_camera_g_input,.vidioc_s_input          = soc_camera_s_input,.vidioc_s_std            = soc_camera_s_std,.vidioc_g_std            = soc_camera_g_std,.vidioc_enum_framesizes  = soc_camera_enum_fsizes,.vidioc_reqbufs          = soc_camera_reqbufs,.vidioc_querybuf         = soc_camera_querybuf,.vidioc_qbuf             = soc_camera_qbuf,.vidioc_dqbuf            = soc_camera_dqbuf,.vidioc_create_bufs      = soc_camera_create_bufs,.vidioc_prepare_buf      = soc_camera_prepare_buf,.vidioc_streamon         = soc_camera_streamon,.vidioc_streamoff        = soc_camera_streamoff,.vidioc_cropcap          = soc_camera_cropcap,.vidioc_g_crop           = soc_camera_g_crop,.vidioc_s_crop           = soc_camera_s_crop,.vidioc_g_parm           = soc_camera_g_parm,.vidioc_s_parm           = soc_camera_s_parm,.vidioc_g_chip_ident     = soc_camera_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG.vidioc_g_register       = soc_camera_g_register,.vidioc_s_register       = soc_camera_s_register,
#endif
};
  • v4l2_subdev_ops:v4l2_subdev有可能需要实现的ops的总合。分为8类,core,audio,video,vbi,tuner......等。例如,

    linuxdriversmediavideosoc_camera_platform.c中platform_subdev_ops的实现

static struct v4l2_subdev_video_ops platform_subdev_video_ops = {.s_stream       = soc_camera_platform_s_stream,.enum_mbus_fmt  = soc_camera_platform_enum_fmt,.cropcap        = soc_camera_platform_cropcap,.g_crop         = soc_camera_platform_g_crop,.try_mbus_fmt   = soc_camera_platform_fill_fmt,.g_mbus_fmt     = soc_camera_platform_fill_fmt,.s_mbus_fmt     = soc_camera_platform_fill_fmt,.g_mbus_config  = soc_camera_platform_g_mbus_config,
};static struct v4l2_subdev_ops platform_subdev_ops = {.core   = &platform_subdev_core_ops,.video  = &platform_subdev_video_ops,
};

函数绑定只是将驱动所实现的函数赋值给相关的变量即可。

这篇关于第一章 V4L2简介的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1068839

相关文章

ASIO网络调试助手之一:简介

多年前,写过几篇《Boost.Asio C++网络编程》的学习文章,一直没机会实践。最近项目中用到了Asio,于是抽空写了个网络调试助手。 开发环境: Win10 Qt5.12.6 + Asio(standalone) + spdlog 支持协议: UDP + TCP Client + TCP Server 独立的Asio(http://www.think-async.com)只包含了头文件,不依

业务协同平台--简介

一、使用场景         1.多个系统统一在业务协同平台定义协同策略,由业务协同平台代替人工完成一系列的单据录入         2.同时业务协同平台将执行任务推送给pda、pad等执行终端,通知各人员、设备进行作业执行         3.作业过程中,可设置完成时间预警、作业节点通知,时刻了解作业进程         4.做完再给你做过程分析,给出优化建议         就问你这一套下

容器编排平台Kubernetes简介

目录 什么是K8s 为什么需要K8s 什么是容器(Contianer) K8s能做什么? K8s的架构原理  控制平面(Control plane)         kube-apiserver         etcd         kube-scheduler         kube-controller-manager         cloud-controlle

【Tools】AutoML简介

摇来摇去摇碎点点的金黄 伸手牵来一片梦的霞光 南方的小巷推开多情的门窗 年轻和我们歌唱 摇来摇去摇着温柔的阳光 轻轻托起一件梦的衣裳 古老的都市每天都改变模样                      🎵 方芳《摇太阳》 AutoML(自动机器学习)是一种使用机器学习技术来自动化机器学习任务的方法。在大模型中的AutoML是指在大型数据集上使用自动化机器学习技术进行模型训练和优化。

SaaS、PaaS、IaaS简介

云计算、云服务、云平台……现在“云”已成了一个家喻户晓的概念,但PaaS, IaaS 和SaaS的区别估计还没有那么多的人分得清,下面就分别向大家普及一下它们的基本概念: SaaS 软件即服务 SaaS是Software-as-a-Service的简称,意思是软件即服务。随着互联网技术的发展和应用软件的成熟, 在21世纪开始兴起的一种完全创新的软件应用模式。 它是一种通过Internet提供

LIBSVM简介

LIBSVM简介 支持向量机所涉及到的数学知识对一般的化学研究者来说是比较难的,自己编程实现该算法难度就更大了。但是现在的网络资源非常发达,而且国际上的科学研究者把他们的研究成果已经放在网络上,免费提供给用于研究目的,这样方便大多数的研究者,不必要花费大量的时间理解SVM算法的深奥数学原理和计算机程序设计。目前有关SVM计算的相关软件有很多,如LIBSVM、mySVM、SVMLight等,这些

urllib与requests爬虫简介

urllib与requests爬虫简介 – 潘登同学的爬虫笔记 文章目录 urllib与requests爬虫简介 -- 潘登同学的爬虫笔记第一个爬虫程序 urllib的基本使用Request对象的使用urllib发送get请求实战-喜马拉雅网站 urllib发送post请求 动态页面获取数据请求 SSL证书验证伪装自己的爬虫-请求头 urllib的底层原理伪装自己的爬虫-设置代理爬虫coo

新一代车载(E/E)架构下的中央计算载体---HPC软件架构简介

老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节能减排。 无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事.而不是让内心的烦躁、焦虑、毁掉你本就不多的热情和定力。 时间不知不觉中,快要来到夏末秋初。一年又过去了一大半,成

AI学习指南深度学习篇-带动量的随机梯度下降法简介

AI学习指南深度学习篇 - 带动量的随机梯度下降法简介 引言 在深度学习的广阔领域中,优化算法扮演着至关重要的角色。它们不仅决定了模型训练的效率,还直接影响到模型的最终表现之一。随着神经网络模型的不断深化和复杂化,传统的优化算法在许多领域逐渐暴露出其不足之处。带动量的随机梯度下降法(Momentum SGD)应运而生,并被广泛应用于各类深度学习模型中。 在本篇文章中,我们将深入探讨带动量的随

OpenGL ES学习总结:基础知识简介

什么是OpenGL ES? OpenGL ES (为OpenGL for Embedded System的缩写) 为适用于嵌入式系统的一个免费二维和三维图形库。 为桌面版本OpenGL 的一个子集。 OpenGL ES管道(Pipeline) OpenGL ES 1.x 的工序是固定的,称为Fix-Function Pipeline,可以想象一个带有很多控制开关的机器,尽管加工