首页 > 系统相关 >Linux v4l2子系统(一):概述

Linux v4l2子系统(一):概述

时间:2024-04-06 13:11:23浏览次数:41  
标签:name .. media entity 子系统 Linux v4l2 id

 本文从硬件框架、软件框架、Buildroot配置、相关源码、创建Video设备及其关系图,来对整个RK3588 VI有所了解。

1 RK3588 VI硬件框架

RK3588的VI(Video Input)硬件框架包括如下部分:

  • 外部MIPI/LVDS/DVP Camera采集数据,最对支持7路输入(6 MIPI + 1 DVP)。
  • MIPI接口:
    • CSI-2是MIPI针对摄像头芯片接口协议。
    • D/C-PHY同时支持D-PHY和C-PHY。
    • D-PHY支持1路4Lane,或者2路2Lane组合。
  • DVP接口或称为Camera并口,一般支持BT601/BT656/BT1120数据的传输。
  • VICAP负责将从MIPI获取的数据搬运到DDR。
  • ISP对Camera Sensor输出的图像信号进行后处理,最多支持4路数据源输入。VICAP数据到ISP支持直通和回读两种模式:
    • 直通:指数据经过VICAP采集,直接发送给ISP处理,不存储到DDR。需要注意的是hdr直通时,只有短帧是真正的直通,长帧需要存在DDR,ISP再从DDR读取。
    • 回读:指数据经过VICAP采集到DDR,应用获取到数据后,将buffer地址推送给ISP,ISP再从DDR获取图像数据。
  • FEC(Fish Eye Correction)负责鱼眼校正。

参考文档《Rockchip_Development_Guide_ISP30_CN_v1.2.3.pdf》。

2 RK3588 MIPI VI软件架构

如下是RK3588 VI链路框图:

  • DPHY0/1可以两种模式运行:
    • full mode:以节点csi2_dphy0/csi2_dphy3提供4 Lane MIPI接口。
    • split mode:以节点csi2_dphy1/csi2_dphy2/csi2_dphy4/csi2_dphy5提供2 Lane MIPI接口。
  • VICAP支持同时输入6路MIPI及1路DVP数据输入。
  • ISP支持同时4路输入,虚拟出4个设备节点。

以OV13850为例,详细解释数据链路:

  • OV13850由IC接口进行配置,需要MIPI 4 Lane将数据送到MIPI DPHY。
  • DPHY0 csi2_dphy0作为输入端,将数据送到CSI HOST2。
  • VICAP虚拟出多个设备,通过rkcif_mipi_lvds2设备接收数据,通过rkcif_mipi_lvds2_sditf输出到ISP0。
  • ISOP0虚拟出4个设备,通过rkisp0_vir0接收数据进行处理。

以OV13850为例,整个软硬件框架分为:

  • 硬件层:包含I2C Master、OV13850、DPHY、CSI2、VICAP、ISP等。
  • 内核驱动层:I2C Master Driver、OV13850 Driver、DPHY Driver、CSI2 Host Driver、RKCIF Driver、ISP Driver、v4l2 Subsystem、I2C Subsystem、Media Subsystem等。
  • 用户层:基于/dev/videoX设备的用户程序以及测试程序等。

3 RK3588 MIPI Camera配置

 RK3588 MIPI Camera以OV13850为例,配置如下:

  • 使能Media Support,以及v4l2。
  • 打开OV13850 Camera。
  • 打开RK I2C功能。
Device Drivers
  Multimedia support
    Media core support
      Video4Linux core
      Media Controller API
    Video4Linux options
      V4L2 sub-device userspace API
    Media ancillary drivers
      Camera sensor devices
        OmniVision OV13850 sensor support

4 RK3588 MIPI Camera文件

Camera通过I2C接口配置:

drivers/i2c/
├── algos
│   ├── i2c-algo-bit.c
├── busses
│   ├── i2c-rk3x.c
├── i2c-boardinfo.c
├── i2c-core-base.c
├── i2c-core-of.c
├── i2c-core-smbus.c
├── i2c-dev.c
├── i2c-mux.c

 v4l2 Core以及Camera文件:

drivers/media/
├── cec
│   ├── core
│   │   ├── cec-adap.c
│   │   ├── cec-api.c
│   │   ├── cec-core.c
│   │   ├── cec-notifier.c
├── common
│   └── videobuf2--v4l2内存管理。
│       ├── vb2-trace.c
│       ├── videobuf2-cma-sg.c
│       ├── videobuf2-core.c
│       ├── videobuf2-dma-contig.c
│       ├── videobuf2-dma-sg.c
│       ├── videobuf2-dvb.c
│       ├── videobuf2-memops.c
│       ├── videobuf2-v4l2.c
│       ├── videobuf2-vmalloc.c
├── i2c
│   ├── ov13850.c--OV13850驱动。
├── mc
│   ├── mc-dev-allocator.c
│   ├── mc-device.c
│   ├── mc-devnode.c
│   ├── mc-entity.c
│   ├── mc-request.c
├── platform
│   ├── rockchip
│   │   ├── cif--RKCIF驱动。
│   │   │   ├── capture.c
│   │   │   ├── cif-luma.c
│   │   │   ├── cif-scale.c
│   │   │   ├── cif-tools.c
│   │   │   ├── common.c
│   │   │   ├── dev.c
│   │   │   ├── hw.c
│   │   │   ├── mipi-csi2.c--RK3588 CSI2 Host驱动。
│   │   │   ├── procfs.c
│   │   │   ├── subdev-itf.c
│   │   ├── isp--RKISP驱动。
│   │   │   ├── bridge.c
│   │   │   ├── bridge_v30.c
│   │   │   ├── capture.c
│   │   │   ├── capture_v1x.c
│   │   │   ├── capture_v21.c
│   │   │   ├── capture_v30.c
│   │   │   ├── common.c
│   │   │   ├── csi.c
│   │   │   ├── dev.c
│   │   │   ├── dmarx.c
│   │   │   ├── hw.c
│   │   │   ├── isp_dvbm.c
│   │   │   ├── isp_params.c
│   │   │   ├── isp_params_v1x.c
│   │   │   ├── isp_params_v21.c
│   │   │   ├── isp_params_v32.c
│   │   │   ├── isp_params_v3x.c
│   │   │   ├── isp_rockit.c
│   │   │   ├── isp_stats.c
│   │   │   ├── isp_stats_v1x.c
│   │   │   ├── isp_stats_v21.c
│   │   │   ├── isp_stats_v2x.c
│   │   │   ├── isp_stats_v2x.h
│   │   │   ├── isp_stats_v32.c
│   │   │   ├── isp_stats_v32.h
│   │   │   ├── isp_stats_v3x.c
│   │   │   ├── procfs.c
│   │   │   ├── regs.c
│   │   │   ├── rkisp.c
│   │   └── rga
│   │       ├── rga-buf.c
│   │       ├── rga.c
│   │       ├── rga-hw.c
└── v4l2-core--v4l2核心。
    ├── tuner-core.c
    ├── v4l2-async.c
    ├── v4l2-clk.c
    ├── v4l2-common.c
    ├── v4l2-compat-ioctl32.c
    ├── v4l2-ctrls.c
    ├── v4l2-dev.c
    ├── v4l2-device.c
    ├── v4l2-dv-timings.c
    ├── v4l2-event.c
    ├── v4l2-fh.c
    ├── v4l2-flash-led-class.c
    ├── v4l2-fwnode.c
    ├── v4l2-h264.c
    ├── v4l2-i2c.c
    ├── v4l2-ioctl.c
    ├── v4l2-mc.c
    ├── v4l2-mem2mem.c
    ├── v4l2-spi.c
    ├── v4l2-subdev.c
    ├── v4l2-trace.c

 使用到的MIPI DPHY驱动:

drivers/phy/rockchip/
├── phy-rockchip-csi2-dphy.c--注册DPHY v4l2设备驱动。 ├── phy-rockchip-csi2-dphy-hw.c--获取DPHY硬件参数驱动。 

5 用户空间设备节点

v4l2设备:

v4l-subdev0 -> ../../devices/platform/fdd30000.mipi2-csi2/video4linux/v4l-subdev0
    rockchip-mipi-csi2
v4l-subdev1 -> ../../devices/platform/csi2-dphy0/video4linux/v4l-subdev1
    rockchip-csi2-dphy0
v4l-subdev2 -> ../../devices/platform/feab0000.i2c/i2c-3/3-0010/video4linux/v4l-subdev2
    m02_b_ov13850 3-0010
v4l-subdev3 -> ../../devices/platform/rkisp0-vir0/video4linux/v4l-subdev3
    rkisp-isp-subdev
v4l-subdev4 -> ../../devices/platform/rkcif-mipi-lvds2-sditf/video4linux/v4l-subdev4
    rkcif-mipi-lvds2

video0 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video0
    stream_cif_mipi_id0
video1 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video1
    stream_cif_mipi_id1
video2 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video2
    stream_cif_mipi_id2
video3 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video3
    stream_cif_mipi_id3

video4 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video4
    rkcif_scale_ch0
video5 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video5
    rkcif_scale_ch1
video6 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video6
    rkcif_scale_ch2
video7 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video7
    rkcif_scale_ch3

video8 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video8
    rkcif_tools_id0
video9 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video9
    rkcif_tools_id1
video10 -> ../../devices/platform/rkcif-mipi-lvds2/video4linux/video10
    rkcif_tools_id2

video11 -> ../../devices/platform/rkisp0-vir0/video4linux/video11
    rkisp_mainpath
video12 -> ../../devices/platform/rkisp0-vir0/video4linux/video12
    rkisp_selfpath
video13 -> ../../devices/platform/rkisp0-vir0/video4linux/video13
    rkisp_fbcpath
video14 -> ../../devices/platform/rkisp0-vir0/video4linux/video14
    rkisp_iqtool

video15 -> ../../devices/platform/rkisp0-vir0/video4linux/video15
    rkisp_rawrd0_m
video16 -> ../../devices/platform/rkisp0-vir0/video4linux/video16
    rkisp_rawrd2_s
video17 -> ../../devices/platform/rkisp0-vir0/video4linux/video17
    rkisp_rawrd1_l

video18 -> ../../devices/platform/rkisp0-vir0/video4linux/video18
    rkisp-statistics
video19 -> ../../devices/platform/rkisp0-vir0/video4linux/video19
    rkisp-input-params
video20 -> ../../devices/platform/fdee0000.hdmirx-controller/video4linux/video20
    stream_hdmirx

5.1 通过media_gobj_create函数创建Media Graph

根据media_gobj_create()输出的log,使用如下脚本生成dot文件:

import re

dmesg_name = "rk3588-v4l2-boot.txt"
#interested_device_name = "rkcif-mipi-lvds2"
interested_device_name = "rkisp0-vir0"

entity_dict = {}
media_graph = {}
if __name__ == '__main__':
    print("strict digraph \"%s\" {"%(interested_device_name))
    print("\trankdir=LR")
    print("\tnodesep=1")
    print("\tranksep=1")
    with open(dmesg_name, 'r') as dmesg:
        for line in dmesg:
            if "media_gobj_create" in line:
                #[    5.170297] rkisp rkisp0-vir0: media_gobj_create id 1: entity 'rkisp-isp-subdev'
                #print(line)
                #m = re.match('\[ *(?P<time>.*)\] (?P<module>.*) (?P<device>.*): media_gobj_create id (?P<id>.[0-9]): (?P<t>.*)', line)
                #m = re.match('\[ *(?P<time>.*)\] (?P<module>[a-zA-Z0-9]*) (?P<device>.*): media_gobj_create id (?P<else>.*)', line)
                m = re.match('\[ *(?P<time>.*)\] (?P<module>[a-zA-Z0-9]*) (?P<device>.*): media_gobj_create id (?P<id>[0-9]*): (?P<else>.*)',line)
                if(m):
                    #device, id, t = m.group('device', 'id', 't')
                    #print("Device=%s, ID=%s, String=%s"%(device, id, t))
                    module_name = m.group("module")
                    device_name = m.group("device")
                    if device_name != interested_device_name:
                        continue
                    id_num = m.group("id")
                    media_graph_item = m.group("else")
                    #print("%s %s %s: %s"%(module_name, device_name, id_num, media_graph_item))
                    if "entity" in media_graph_item:
                        m = re.match("entity \'(?P<entity>.*)\'", media_graph_item)
                        if(m):
                            entity_name = m.group("entity")
                            print("\t%s[label=\"%s\", shape=box, fontcolor=Red, group=g%s];"%(id_num, entity_name, id_num))
                            entity_dict[entity_name]={"entity":id_num, "sink":[], "source":[]}
                        else:
                            print("Error in Entity: %s"%(media_graph_item))
                            sys.exit(1)
                    elif "intf_devnode" in media_graph_item:
                        m = re.match("intf_devnode (?P<video>.*) - major: (?P<major>[0-9]*), minor: (?P<minor>[0-9]*)", media_graph_item)
                        if(m):
                            video_name = m.group("video")
                            major_name = m.group("major")
                            minor_name = m.group("minor")
                            if video_name == "v4l-video":
                                print("\t%s[label=\"IntfDevnode:%s%s\", fontcolor=Blue];"%(id_num, "/dev/video", minor_name))
                            elif video_name == "v4l-subdev":
                                print("\t%s[label=\"IntfDevnode:%s%s\", fontcolor=Blue];"%(id_num, "/dev/v4l-subdev", minor_name))
                            else:
                                sys.exit(1)
                        else:
                            print("Error in IntfDevnode: %s"%(media_graph_item))
                            sys.exit(1)
                    elif "sink pad" in media_graph_item:
                        m = re.match("sink pad \'(?P<entity>.*)\':(?P<id>[0-9]*)", media_graph_item)
                        if(m):
                            entity_name = m.group("entity")
                            sink_id = m.group("id")
                            print("\t%s[label=\"SinkPad:%s-%s\", shape=cds, group=g%s];"%(id_num, entity_name, sink_id, entity_dict[entity_name]["entity"]))
                            print("\t%s->%s;"%(id_num, entity_dict[entity_name]["entity"]))
                            entity_dict[entity_name]["sink"].append(id_num)
                        else:
                            print("Error in SinkPad: %s"%(media_graph_item))
                            sys.exit(1)
                    elif "source pad" in media_graph_item:
                        m = re.match("source pad \'(?P<entity>.*)\':(?P<id>[0-9]*)", media_graph_item)
                        if(m):
                            entity_name = m.group("entity")
                            sink_id = m.group("id")
                            print("\t%s[label=\"SourcePad:%s-%s\", shape=cds, group=g%s];"%(id_num, entity_name, sink_id, entity_dict[entity_name]["entity"]))
                            print("\t%s->%s;"%(entity_dict[entity_name]["entity"], id_num))
                            entity_dict[entity_name]["source"].append(id_num)
                        else:
                            print("Error in SourcePad: %s"%(media_graph_item))
                            sys.exit(1)
                    elif "interface link" in media_graph_item:
                        m = re.match("interface link id (?P<src>[0-9]*) ==> id (?P<dst>[0-9]*)", media_graph_item)
                        if(m):
                            src_id=m.group("src")
                            dst_id=m.group("dst")
                            print("\t%s->%s;"%(src_id, dst_id))
                        else:
                            print("Error in InterfaceLink: %s"%(media_graph_item))
                            sys.exit(1)
                    elif "data link" in media_graph_item:
                        m = re.match("data link id (?P<src>[0-9]*) ==> id (?P<dst>[0-9]*)", media_graph_item)
                        if (m):
                            src_id = m.group("src")
                            dst_id = m.group("dst")
                            print("\t%s->%s;" % (src_id, dst_id))
                        else:
                            print("Error in DataLink: %s"%(media_graph_item))
                            sys.exit(1)
                    else:
                        print("Error in: "%(media_graph_item))
                        sys.exit(1)
                else:
                    sys.exit(1)
                    print("Error:", line)
    print("}")
View Code

得到的Media Graph如下:

5.2 通过media-ctl生成dot创建Media Graph图

后来发现media-ctl生成更好的Media Graph图:

  • Entity用绿色框表示,输入Port为Entity Sink,输出Port为Entity Source。
  • 虚线表示可能的链路,实线表示当前激活链路。
  • IntfDevnode用黄色框表示。

通过如下命令生成dot,然后转成png:

media-ctl --d /dev/media0 --print-dot
dot -Tpng media0.dot  -o media0.png

 

 

参考资料:《RK3588-Camera:MIPI-CSI调试之通路解析》、《camera调试:RK3588 MIPI/DVP camera关键配置》、《RK3588s imx415相机适配及ISP调优系列(一)_rk_evb_imx415连接器》、《

RK3588s imx415相机适配及ISP调优系列(二)--- mipi相机适配_rk3588 imx415》、《RK3588s imx415相机适配及ISP调优系列(三)--- RKISP调试环境配置》。

标签:name,..,media,entity,子系统,Linux,v4l2,id
From: https://www.cnblogs.com/arnoldlu/p/18107354

相关文章

  • Linux下载编译ntfs-3g、安装移植、挂载ntfs格式的U盘
    目录前言1、NTFS-3G 简要说明2、NTFS-3G工具安装2.1离线下载ntfs-3g2.2在线下载ntfs-3g(推荐优先) 2.3解压安装ntfs-3g3、NTFS-3G工具移植到文件系统(rootfs)4、NTFS-3G工具挂载 4.1 查看U盘盘符4.2 U盘挂载 5、NTFS-3G源码编译报错问题记录5.1问题1:参......
  • Linux初学(十二)AWK进阶
    一、AWK1.1简介AWK是Linux中重要的文本处理工具Linux三剑客只一处理的对象可以是一个具体的文件,也可以是一个命令的执行结果AWK按行读取文件,将每一行视为一条记录案例一:获取系统中每个用户的uid方法一:cat/etc/passwd|awk-F":"'{print$3}'方法二:awk-F":"'{pr......
  • 在Linux中,什么是网络接口配置?如何配置IP地址?
    在Linux系统中,网络接口配置是指设置和调整系统网络接口的参数,以便系统能够正确地连接到网络并进行通信。网络接口可以是物理的,如以太网端口,也可以是虚拟的,如虚拟机的虚拟网络接口或VPN连接。1.网络接口配置的作用网络连接:配置网络接口使得Linux系统能够连接到局域网(LAN)或广域......
  • FFmpeg开发笔记(十二)Linux环境给FFmpeg集成libopus和libvpx
    ​MP4是最常见的视频封装格式,在《FFmpeg开发实战:从零基础到短视频上线》一书的“1.2.3 自行编译与安装FFmpeg”介绍了如何给FFmpeg集成x264和x265两个库,从而支持H.264和H.265两种标准的编解码。视频的封装格式除了古老的MP4和ASF之外,还有较新的WebM格式,该格式的音频编码主要采......
  • 在Linux中,如何检查磁盘使用情况和剩余空间?
    在Linux系统中,检查磁盘使用情况和剩余空间是系统管理和维护的常见任务。有多种命令可以帮助你获取磁盘空间的详细信息。以下是一些常用的方法:1.df命令df(DiskFree)命令用于显示文件系统的磁盘空间使用情况。它可以报告各个挂载点的总空间、已用空间、可用空间和挂载信息。基本......
  • 在Linux中,虚拟内存和交换空间作用是什么?
    在Linux系统中,虚拟内存和交换空间是用于扩展物理内存(RAM)容量的两种机制。它们允许系统在物理内存不足时继续运行程序和处理数据,从而提高了系统的可用性和稳定性。1.虚拟内存(VirtualMemory)概念:虚拟内存是一种内存管理技术,它使得系统可以访问比物理内存更多的内存空间。虚拟......
  • 在Linux中,SELinux和AppArmor安全模块作用是什么?
    在Linux中,SELinux(Security-EnhancedLinux)和AppArmor(ApplicationArmor)是两种强制访问控制(MAC)安全模块,它们用于提供额外的安全层,以限制程序和用户的权限,从而保护系统免受恶意软件和未授权访问的威胁。1.SELinux(Security-EnhancedLinux)作用:强制访问控制:SELinux通过强制执行......
  • 在Linux中,什么是系统调用?举例说明其作用是什么?
    在Linux中,系统调用(SystemCall)是用户空间程序与内核空间进行交互的一种机制。当用户程序需要执行诸如文件操作、网络通信、进程管理等不能直接由用户空间代码执行的操作时,它们会通过系统调用来请求内核代为完成这些操作。系统调用的作用主要体现在以下几个方面:抽象硬件操作:系......
  • [转帖]如何在Ubuntu Linux上使用SNAP安装Docker
    https://zhuanlan.zhihu.com/p/633483748 2人赞同了该文章在UbuntuLinux上安装Docker的最快捷的方法之一是使用SNAP命令。在这里,我们将学习如何使用它。对于那些处理容器化应用程序的人来说,Docker无需介绍。它已经被全球数百家企业和开发人员使用。然而,那些想要......
  • 详细介绍Linux SSH远程免密登陆实现方法
    目录概述1安装工具2产生pub_key以及相关文件2.1在本机上产生pub_key2.2在linux生成key2.3追加.pub2.4修改authorized_keys的权限3windows平台上添加秘钥4验证 4.1登录文件管理系统4.2登录控制台概述本文主要介绍使用WinScp和putty工具搭建一个ssh......