[Linux 基础] -- Linux media 子系统

一、为什么会有 media 这样的一个子系统?

在多媒体的框架中,总是复杂多样的,为了解决多媒体设备的复杂性和数据流动性,创建了 media 子系统。Media 使用一个树状结构,将多媒体数据通路的各个设备连接在一起,方便各个设备的管理和控制。

二、media 框架

在开机的时候,将会在 [ media-devnode.c ] 中,通过 media_devnode_init() 函数为 media 设备分配一个主设备号,次设备号从 0-255,同时注册一个名字 “media” 的 bus 总线。这个时候,只是申请分配了一个名为 media 的设备号而已,具体的 media 设备注册,将在相应的设备驱动中进行注册登记。

下面以 camera 为例,介绍 media 框架流程。在了解 media 框架前,先了解 camera 设备的注册流程,在注册 /dev/videoX 节点时,主要操作流程如下:

1、通过 platform probe,初始化各个 v4l2_subdevice;

2、先通过 v4l2_device_register() 函数,注册 v4l2_device;

3、先后通过调用 media_device_init()、media_device_register() 函数,注册 /dev/mediaX 设备,这个时候,将 v4l2_dev->mdev = media_dev;

4、注册各 v4l2_subdevice,同时,在注册各个 subdevice 时,subdevice 将会作为一个 entity,登记到media_dev;

5、通过 video_register_device() 函数注册 /dev/videoX 节点,到目前为止,各个 v4l2_subdevice 已经注册完成,接下来将是根据各个子设备的需求,进行相应的连接,设置数据通路;

三、media 设备与 entity

实际上 /dev/mediaX 设备是一个字符设备,只不过是通过 media 框架的一层封装,只是注册设备的主设备号与次设备号都是从之前预分配的 media 设备获取。

怎么理解 media deivce 与 entity,可以简单的理解,media device 是一个部门的主管,而 entity 是各个下属,media device 将负责统筹 entity,管理各个数据通路的流向。所以,下面再来看看,entity 又是怎样注册的。

我们是以 camera 为例了解 media 框架的,在 /dev/videoX 节点设备中,通过 struct video_device 结构体管理节点,而在该结构体中,又将会包含 v4l2_device 的结构体 struct v4l2_device,而在v4l2 device 的结构体中,又将会包含 media device 的结构体 struct  media_device, 就是这样,层层包含。

在通过 v4l2_device_register_subdev() 函数注册 v4l2 subdevice 时,将会调用 media_device_register_entity() 函数,将该 v4l2 subdevice 当成一个 entity 注册到 media device,与此同时,还将会有 entity 的 pads 初始化等操作。

media 框架的目标之一是发现设备内部拓扑,实时配置。为了实现这个目标,硬件设备被建模为一些图形积木,称为用垫子(pads)连接的实体(entity)。一个 entity 是一个基本的媒体硬件积木。它可以和大量的逻辑模块 -- 譬如物理硬件设备(CMOS 传感器),逻辑硬件设备(一个 SOC 图形处理流水先积木),DMA 通道或者物理连接器通信。pad 是用于 entity 和其他 entity 互通的连接端点。entity 产生的数据(不仅是 video)从该 entity 的输出流向一个或多个 entity 的输入。pads 不能与芯片的物理 pin 脚弄混了。一个 link 是两个 pads 之间的点对点连接,各个 entity 都已经注册到 media,那么,接下来看看 entity 间的 link 又是怎样操作的。

四、entity link

media entity link 是通过 media_create_pad_link(struct media_entity *source, u16 source_pad, struct media_entity *sink, u16 sink_pad, u32 flags) 函数完成的。如该函数的声明,需要输入 source entity 以及 source pad、sink entity 以及 sink pad。各个 entity pad 数目是预先已知的,所以在连接的时候,自然知道需要使用哪个 pad。link 时,其实就是分别针对 source、sink 创建一个 media link,都添加到 media device 中,并将赋值 link 到 source 与 sink。到这里,简单的理解了 media device、entity、pad、link,那么,我们究竟使用这一套框架干嘛呢,继续往下看。

五、media 框架有什么用?

5.1、协商

我们知道,在使用 camera 的过程中,有各个模块需要互相协作,简单的数据流如下:

sensor ---> CPHY ---> csi ---> isp ---> stream

那么,我们在设置 camera 的图像输出格式时,将会需要确认,整个 pipeline 都是支持该格式的,这个时候,我们就可以通过 media 框架提供的函数 media_entity_graph_walk_init()、media_entity_graph_walk_start()、media_entity_graph_walk_next() 等函数开始遍历 pipeline 的各个 entity,确认每个 entity 都是支持该格式的,完成一个数据的协商过程。

同时,当平台支持 scaler 缩放时,又可以从同一个源,经过 scaler 之后,输出不同的分辨率大小等,这样的一个 entity,多个输出,这样也是很方便通过 media 框架进行数据的管理。

5.2、控制

大部分 soc 厂商,对自己的 ISP 算法是不开源的,但是 linux 内核是开源的,这个时候,soc 厂商会将自己的 ISP 算法放在应用层,这个时候,就需要通过应用层操作到内核,而 media 框架管理着数据的整条通路,所以,在这里,通过 media 框架操作 ISP 等硬件是非常便捷的。

在注册 media 设备时,在 _media_device_register() 函数,赋值 media devnode fops 为 media_device_fops。而 media_device_fops 主要是通过 ioctl 操作 media 设备。支持以下操作:

static const struct meida_ioctl_info ioctl_info[] = {
    MEDIA_IOC(DEVICE_INFO, media_device_get_info, MEDIA_IOC_FL_GRAPH_MUTEX),
    MEDIA_IOC(ENUM_ENTITIES, media_device_enum_entities, MEDIA_IOC_FL_GRAPH_MUTEX),
    MEDIA_IOC(ENUM_LINKS, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX),
    MEDIA_IOC(SETUP_LINK, media_device_setup_link, MEDIA_IOC_GRAPH_MUTEX),
    MEDIA_IOC(G_TOPOLOGY, media_device_get_topology, MEIDA_IOC_FL_GRAPH_MUTEX),
};

通过这些 ioctl,可以获取操作相应 entity 的句柄,今儿控制相应的模块操作。

同时,在应用层打开各个 entity,通过 VIDIOC_SUBSCRIBE_EVENT 设置事件的监听,当在内核中产生相应的事件时,通过 v4l2_event_queue() 函数,将事件传递到应用层。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/u014674293/article/details/111318314