本文對(duì) V4L2 的運(yùn)行時(shí)數(shù)據(jù)流設(shè)備管理做一個(gè)詳細(xì)的介紹吩屹,包括什么叫「運(yùn)行時(shí)設(shè)備管理」,它是干什么用的,怎么使用等等。本文的目標(biāo)是掌握 media device 的編碼使用方法以及功能運(yùn)用苛茂。
01 - V4L2框架-v4l2 device
00 - V4L2框架概述
media framework
簡(jiǎn)介
相關(guān)的控制 API 在Documentation/DocBook/media/v4l/media-controller.xml
,本文檔聚焦于內(nèi)核測(cè)的media框架實(shí)現(xiàn)身害。注意:直接查看是看不出啥的味悄,在內(nèi)核的根目錄下make htmldocs
或者其它格式的都行草戈,易于查看塌鸯。運(yùn)行時(shí)設(shè)備控制
也就是設(shè)備啟動(dòng)之后的數(shù)據(jù)流線路控制,就像一個(gè)工廠流水線一樣唐片,流水線上面的一個(gè)個(gè)節(jié)點(diǎn)(貼商標(biāo)丙猬、噴絲印涨颜、打包)就形同于輸入設(shè)備中的一個(gè)個(gè)子設(shè)備,運(yùn)行時(shí)設(shè)備控制就是要達(dá)到能夠控制節(jié)點(diǎn)的效果茧球,比如貼商標(biāo)的機(jī)器有好幾臺(tái)庭瑰,應(yīng)該選擇哪一臺(tái)進(jìn)行此次流水線處理,要不要把噴絲印加上去抢埋,加哪一個(gè)機(jī)子等等弹灭。作用
提供實(shí)時(shí)的 pipeline 管理,pipeline 就理解為管道揪垄,想象一下水管穷吮,里面的水就是數(shù)據(jù)流,輸入設(shè)備中的 csi->isp->video 就組成了一個(gè) pipeline 線路饥努。media framework 提供 pipeline 的開(kāi)啟捡鱼、關(guān)停、效果控制酷愧、節(jié)點(diǎn)控制等功能驾诈。如何使用
內(nèi)核當(dāng)中主要利用四個(gè)結(jié)構(gòu)體把眾多的節(jié)點(diǎn)組織起來(lái):media_device
,media_entity
,media_link
,media_pad
。整個(gè) media framework 都是圍繞這四個(gè)結(jié)構(gòu)體來(lái)進(jìn)行使用的溶浴,下文會(huì)對(duì)這些進(jìn)行詳細(xì)介紹乍迄。抽象設(shè)備模型
media framework 其中一個(gè)目的是:在運(yùn)行時(shí)狀態(tài)下發(fā)現(xiàn)設(shè)備拓?fù)洳?duì)其進(jìn)行配置。為了達(dá)到這個(gè)目的士败,media framework將
硬件設(shè)備抽象為一個(gè)個(gè)的entity就乓,它們之間通過(guò)links連接。
- entity:硬件設(shè)備模塊抽象(類(lèi)比電路板上面的各個(gè)元器件拱烁、芯片)
- pad:硬件設(shè)備端口抽象(類(lèi)比元器件生蚁、芯片上面的管腳)
- link:硬件設(shè)備的連線抽象,link的兩端是pad(類(lèi)比元器件管腳之間的連線)
#------------# #------------#
| __|__ __|__ |
| | | | link | | | |
| | pad |<-------->| pad | |
| |__|__| |__|__| |
| | | |
| entity | | entity |
#------------# #------------#
可以想象一下戏自,如果各個(gè) entity 之間需要建立連接的話邦投,就需要在 pad 中存儲(chǔ) link 以及 entity 信息,link 中需要存儲(chǔ) pad 與 entity 信息擅笔,entity 里面需要存儲(chǔ) link 與 pad 信息志衣,屬于你中有我,我中有你的情況猛们。
media 設(shè)備
一個(gè) media 設(shè)備用一個(gè) media_device
結(jié)構(gòu)體來(lái)表示念脯,通常情況下該結(jié)構(gòu)體要嵌入到一個(gè)更大的設(shè)備自定義的結(jié)構(gòu)體里面,并且大多數(shù)時(shí)候 media_device
與 v4l2_device
是處于并列的級(jí)別弯淘,還是以 omap3isp 的代碼為例:
struct isp_device {
struct v4l2_device v4l2_dev;
struct v4l2_async_notifier notifier;
struct media_device media_dev;
struct device *dev;
u32 revision;
... ...
}
使用以下函數(shù)進(jìn)行 meida 設(shè)備的注冊(cè):media_device_register(struct media_device *mdev);
函數(shù)的調(diào)用者需要在注冊(cè)之前設(shè)置以下結(jié)構(gòu)體成員(提前初始化該結(jié)構(gòu)體是調(diào)用者的責(zé)任):
- dev:必須指向一個(gè)父設(shè)備绿店,通常是平臺(tái)設(shè)備的device成員。
- model:模型名字。
以下的成員是可選的: - serial:序列號(hào)假勿,必須是唯一的
- bus_info:總線信息借嗽,如果是PCI設(shè)備的話就可以設(shè)置成"PCI:"
- hw_revision:硬件版本∽啵可以的話恶导,應(yīng)該用KERNEL_VERSION宏定義進(jìn)行格式化
- driver_version:驅(qū)動(dòng)版本。最終生成的設(shè)備節(jié)點(diǎn)的名稱是media[0-9]浸须,節(jié)點(diǎn)號(hào)由內(nèi)核自動(dòng)生成惨寿。
使用以下函數(shù)進(jìn)行設(shè)備卸載:media_device_unregister(struct media_device *mdev);
需要注意的是,卸載一個(gè)并沒(méi)有注冊(cè)過(guò)的設(shè)備是不安全的删窒。個(gè)人查看代碼猜想不安全的原因主要有幾個(gè):1. 如果沒(méi)有被注冊(cè)缤沦,那么 media_device
內(nèi)部的 entity 成員就有可能沒(méi)有被初始化,如果其值為一個(gè)不確定的值易稠,那么就會(huì)引起非法訪問(wèn)缸废;2. 如果沒(méi)有注冊(cè),內(nèi)部的 devnode
成員就沒(méi)有初始化驶社,卸載時(shí)就會(huì)出現(xiàn)問(wèn)題企量。
「entities、pads亡电、links」
entities
entities 用一個(gè) media_entity
結(jié)構(gòu)體來(lái)表示届巩,該結(jié)構(gòu)體通常被嵌入到一個(gè)更大的結(jié)構(gòu)體里面,比如 v4l2_subdev
或者 video_device
結(jié)構(gòu)體(不必自行分配空間份乒,結(jié)構(gòu)體內(nèi)部已經(jīng)包含)恕汇,當(dāng)然也可以直接分配一個(gè) entities。使用以下函數(shù)對(duì) entity 進(jìn)行初始化:
media_entity_init(struct media_entity *entity, u16 num_pads, struct
media_pad *pads, u16 extra_links);
在執(zhí)行初始化函數(shù)之前需要注意的參數(shù)有:
- num_pads:pad的數(shù)量或辖,與驅(qū)動(dòng)子設(shè)備結(jié)構(gòu)相關(guān)瘾英。
- pads:media_pad結(jié)構(gòu)體數(shù)組,通常pad被嵌入到驅(qū)動(dòng)自定義的結(jié)構(gòu)體里面颂暇,數(shù)組地址被傳遞給該參數(shù)缺谴,pad需提前初始化。
- extra_links:該函數(shù)會(huì)根據(jù)num_pads分配link數(shù)目耳鸯,該參數(shù)則指明除了預(yù)分配的數(shù)量之外還需要多少額外的links湿蛔。
- entity:
media_entity
的name、type县爬、flags阳啥、revision和group_id
需要在初始化之前或者之后進(jìn)行設(shè)置,如果結(jié)構(gòu)體被嵌入到更高級(jí)的結(jié)構(gòu)體里面财喳,這些成員也可能被更高級(jí)的框架代碼所設(shè)置察迟,entity的id在注冊(cè)的時(shí)候被填充(如果提前設(shè)置了id成員,則注冊(cè)的時(shí)候就保持預(yù)設(shè)的值)。entity有相關(guān)的標(biāo)志位「flags」來(lái)標(biāo)識(shí)它的狀態(tài)與功能卷拘,MEDIA_ENT_FL_DEFAULT
就表示這是一個(gè)默認(rèn)的 entity喊废∽8撸可以設(shè)置多個(gè) entity 的組 ID 為同一個(gè)整數(shù)來(lái)標(biāo)識(shí)它們是屬于同一類(lèi)別的栗弟,對(duì)于內(nèi)核來(lái)說(shuō),組ID是沒(méi)有用處的工闺,但是組 ID 會(huì)在枚舉 entity 的時(shí)候被傳遞到用戶空間乍赫,可能在用戶空間的某種情況下用得上。
pads
pad 使用一個(gè) media_pad
結(jié)構(gòu)體來(lái)表示陆蟆,pads 數(shù)據(jù)被驅(qū)動(dòng)程序管理(數(shù)組形式)雷厂。pads 使用 entity 與數(shù)組下標(biāo)來(lái)進(jìn)行唯一標(biāo)識(shí),entity 內(nèi)部的 id 不會(huì)重復(fù)叠殷,但是不同 entity 之間的 pad id 可能會(huì)重復(fù)改鲫,所以 pad 的索引要 entity 與 id 聯(lián)合確認(rèn)。
由于 pads 的數(shù)量是提前獲知的(你做的芯片林束,你肯定知道它有幾個(gè)管腳)像棘,所以 media_pad
結(jié)構(gòu)體不再動(dòng)態(tài)分配,并且驅(qū)動(dòng)應(yīng)負(fù)責(zé)對(duì)該結(jié)構(gòu)體數(shù)組進(jìn)行管理(避免動(dòng)態(tài)分配)壶冒。驅(qū)動(dòng)必須在 media_entity_init
函數(shù)被調(diào)用之前對(duì) pads 的方向?qū)傩赃M(jìn)行設(shè)置缕题,pads 有 flags
位來(lái)標(biāo)識(shí)它的屬性,在初始化的時(shí)候僅需要設(shè)置該成員即可胖腾,其余的交由 media_entity_init
函數(shù)來(lái)完成:
MEDIA_PAD_FL_SINK:目的pad
MEDIA_PAD_FL_SOURCE:源pad
links
links 用一個(gè) media_link
結(jié)構(gòu)體來(lái)表示烟零,每一個(gè) entity 的所有 pads 里面都存儲(chǔ)了與之相關(guān)的所有 links,一個(gè) link 會(huì)分別被源 pad 以及目的 pad 存儲(chǔ)咸作,以便實(shí)現(xiàn)正反兩個(gè)方向的遍歷锨阿。使用以下函數(shù)創(chuàng)建 links:
media_entity_create_link(struct media_entity *source, u16 source_pad,
struct media_entity *sink, u16 sink_pad, u32 flags);
links 有一些 flags
位來(lái)標(biāo)識(shí)其屬性:
MEDIA_LNK_FL_ENABLED:link被使能,可以用來(lái)傳輸數(shù)據(jù)记罚,多個(gè)link連接到同一個(gè)sink pad時(shí)群井,只有一個(gè)link可以被使能。
MEDIA_LNK_FL_IMMUTABLE:link的使能狀態(tài)不能在運(yùn)行時(shí)被改變毫胜,一般情況下這兩個(gè)標(biāo)志位同時(shí)被設(shè)置书斜。
MEDIA_LNK_FL_DYNAMIC:link的狀態(tài)是動(dòng)態(tài)可變的。
和 pads 不一樣酵使,links 的數(shù)量并不總是提前確定的(電路板上面有時(shí)候你也無(wú)法完全確認(rèn)需要管腳連到多少個(gè)設(shè)備上面荐吉,極有可能出現(xiàn)臨時(shí)變更的情況),所以 media_entity_init
函數(shù)根據(jù)傳入的參數(shù)預(yù)分配一定數(shù)量的 media_link
結(jié)構(gòu)體口渔,如果不夠用的話會(huì)在 media_entity_create_link
中動(dòng)態(tài)分配(如果 link 數(shù)量大于等于 max_link 的話就會(huì)擴(kuò)充 link 數(shù)量)样屠。
注冊(cè)與卸載
驅(qū)動(dòng)需要使用以下函數(shù)對(duì) entity 進(jìn)行注冊(cè)與卸載(不需要手動(dòng)執(zhí)行,在 v4l2_device_un/register_subdev
函數(shù)里面完成):
media_device_register_entity(struct media_device *mdev, struct
media_entity *entity);
media_device_unregister_entity(struct media_entity *entity);
內(nèi)核里面使用一個(gè)唯一的正整數(shù)來(lái)表示每一個(gè) entity(同一個(gè) media_device
下唯一),驅(qū)動(dòng)也可以通過(guò)填充 media_entity->id
成員來(lái)指定 entity 的 ID 值痪欲,但是必須保證唯一悦穿。如果 ID 由內(nèi)核自動(dòng)生成,則不能保證它們是連續(xù)的业踢,事實(shí)上內(nèi)核自動(dòng)生成的 id 是由 entity 的 media_device->entity_id++
來(lái)實(shí)現(xiàn)賦值的栗柒,該值在 media_device_register
函數(shù)里面被初始化為1。
在卸載 entity 之后需要調(diào)用以下函數(shù)來(lái)釋放申請(qǐng)到的相關(guān)資源知举,主要是釋放動(dòng)態(tài)分配的 media_link
結(jié)構(gòu)體內(nèi)存:
media_entity_cleanup(struct media_entity *entity); //與media_entity_init結(jié)對(duì)使用
要想遍歷 entities 可以在用戶空間進(jìn)行 MEDIA_IOC_ENUM_ENTITIES
系統(tǒng)調(diào)用瞬沦,需要設(shè)置 media_entity_desc
的 id 為 (0|MEDIA_ENT_ID_FLAG_NEXT)
,循環(huán)的過(guò)程中只需要設(shè)置 id |= MEDIA_ENT_ID_FLAG_NEXT
即可完成 entity 的遍歷過(guò)程雇锡,如果需要枚舉指定的 entitiy逛钻,需要設(shè)置 id 為指定 entity 的 id 值(內(nèi)核 entity 的 id 是從1開(kāi)始),這個(gè)在 entity 注冊(cè)函數(shù)里面可以看到锰提。代碼實(shí)例如下曙痘,我盡量精簡(jiǎn)了貼出來(lái)的代碼,防止占用過(guò)大篇幅:
int enum_media_device_entities(int iFd)
{
int iRet;
struct media_entity_desc desc;
desc.id = 0 | MEDIA_ENT_ID_FLAG_NEXT;
while (1) {
iRet = ioctl(iFd, MEDIA_IOC_ENUM_ENTITIES, &desc);
if (iRet < 0) {
MODULE_WRN("enum media entities end\n");
break;
}
MODULE_DBG("entity name[%s]\n", desc.name);
desc.id |= MEDIA_ENT_ID_FLAG_NEXT;
}
return 0;
}
int main(int argc, char *argv[])
{
int iErr = 0, ivFd;
ivFd = open("/dev/media0", O_RDWR);
iErr = enum_media_device_entities(ivFd);
close(ivFd);
open_err:
return iErr;
}
圖遍歷(深度優(yōu)先)
圖遍歷是干嘛的立肘?它為我們提供在運(yùn)行時(shí)訪問(wèn)每一個(gè)画切、指定的 entities 的方法己单,至于為什么需要訪問(wèn)病苗,是因?yàn)槲覀兛赡軙?huì)需要在運(yùn)行時(shí)去管理它們浪耘。
可以使用下面的函數(shù)對(duì)同屬于一個(gè)media設(shè)備的entities進(jìn)行遍歷(線性遍歷,非典型圖遍歷踢故,也就是跟鏈表一樣的遍歷方式):
struct media_entity *entity;
media_device_for_each_entity(entity, mdev) {
/* entity will point to each entity in turn */
...
}
驅(qū)動(dòng)可能需要從一個(gè)給定的 entity文黎,通過(guò)使能的 links 對(duì)所有的可訪問(wèn)到的 entities 進(jìn)行遍歷,meida 框架提供了一個(gè)深度優(yōu)先的 API 來(lái)完成這個(gè)任務(wù)殿较。需要注意的是耸峭,要避免對(duì)閉環(huán)的圖進(jìn)行遍歷,否則會(huì)陷入死循環(huán)淋纲,為了避免這種情況劳闹,函數(shù)限制了最大遍歷深度為 MEDIA_ENTITY_ENUM_MAX_DEPTH
,該宏最新的定義是16「截至 Linux-4.4.138」洽瞬。
media_entity_graph_walk_start(struct media_entity_graph *graph,
struct media_entity *entity);
media_entity_graph_walk_next(struct media_entity_graph *graph);
使用時(shí)先用第一個(gè)函數(shù)初始化圖本涕,然后循環(huán)調(diào)用第二個(gè)函數(shù)進(jìn)行遍歷,遍歷全部完成之后第二個(gè)函數(shù)會(huì)返回NULL伙窃。遍歷過(guò)程可以在任意一個(gè)時(shí)刻中斷菩颖,并且無(wú)需調(diào)用清理函數(shù)。
有相應(yīng)的幫助函數(shù)用來(lái)尋找兩個(gè)給定的 pads 的 link为障,或者通過(guò)一個(gè) pad 來(lái)找到與之相連的另一個(gè) pad晦闰。
media_entity_find_link(struct media_pad *source, struct media_pad *sink);
media_entity_remote_pad(struct media_pad *pad);
補(bǔ)充 links 的設(shè)置
link 的屬性可以在運(yùn)行時(shí)被改變放祟,調(diào)用以下函數(shù)即可完成:media_entity_setup_link(struct media_link *link, u32 flags);
flags
參數(shù)用來(lái)設(shè)置指定的 link 的屬性,允許被配置的屬性是從 MEDIA_LNK_FL_ENABLED
屬性到 MEDIA_LNK_FL_ENABLE
或者 MEDIA_LNK_FL_DISABLE
標(biāo)志呻右,如果 link 設(shè)置了 MEDIA_LNK_FL_IMMUTABLE
標(biāo)志的話跪妥,就不能夠使能或者關(guān)閉。當(dāng)一個(gè) link 使能或者關(guān)閉時(shí)声滥,meida framework 會(huì)分兩次調(diào)用 sink 以及 source 端的 link_setup
來(lái)進(jìn)行相關(guān)的設(shè)置眉撵,如果第二次調(diào)用失敗的話,第一個(gè)調(diào)用也會(huì)被復(fù)原醒串。
media 設(shè)備驅(qū)動(dòng)可以設(shè)置 media_device->link_notify
指向一個(gè)回調(diào)函數(shù)执桌,此函數(shù)會(huì)在 link_setup
操作完成之后被調(diào)用鄙皇。如果有任何的 link 是 non-immutable 的話芜赌,entity 驅(qū)動(dòng)就需要自己實(shí)現(xiàn) link_setup
操作。一個(gè) link 的配置不應(yīng)該影響到其他 link伴逸,如果一個(gè) link 連接在 sink pad 上缠沈,并且該 link 被使能了,那么其他連接到該 pad 的 link 就不能再被使能错蝴,此時(shí)應(yīng)該返回 -EBUSY
洲愤。
-
pipeline與media流
pipeline 的概念前面已經(jīng)介紹過(guò)了,不再重復(fù)顷锰,這里給一副說(shuō)明圖(其實(shí)這個(gè)不是非常的清晰易懂柬赐,還有更加清晰易懂的由于某些原因不能放出,請(qǐng)讀者發(fā)揮想象官紫,根據(jù)圖中以及上面的描述自行抽象出來(lái)一個(gè)圖肛宋,只要緊緊圍繞一點(diǎn)-pipeline 就是數(shù)據(jù)流鏈路的抽象,我相信你):
當(dāng)開(kāi)啟 streaming 時(shí)束世,驅(qū)動(dòng)應(yīng)當(dāng)通知 pipeline 上所有的 entity 來(lái)維護(hù)當(dāng)前狀態(tài)不被改變酝陈,可以調(diào)用下面的函數(shù)完成通知(該函數(shù)只會(huì)調(diào)用 sink 端的 validate 回調(diào)):
media_entity_pipeline_start(struct media_entity *entity, struct media_pipeline *pipe);
該函數(shù)將會(huì)標(biāo)記所有的處在使能 link 連線上的 entity 為 streaming 狀態(tài),不管是直接還是間接毁涉。第二個(gè)參數(shù)指向的 media_pipeline 結(jié)構(gòu)體會(huì)被傳遞給 pipeline 上面的所有 entity沉帮,驅(qū)動(dòng)需要把 media_pipeline 結(jié)構(gòu)體嵌入到一個(gè)更高級(jí)的結(jié)構(gòu)體里面,并且可以從 media_entity 結(jié)構(gòu)體訪問(wèn)到 pipeline贫堰。等到需要停止 streaming 時(shí)穆壕,需要調(diào)用:
media_entity_pipeline_stop(struct media_entity *entity);
由于start函數(shù)可以嵌套調(diào)用,所以與之對(duì)應(yīng)其屏,stop函數(shù)也應(yīng)該保持相應(yīng)數(shù)量的調(diào)用喇勋。media_entity_pipeline_start
函數(shù)會(huì)進(jìn)行 link 有效性的檢驗(yàn),此時(shí) media_entity
的 link_validate
成員會(huì)被調(diào)用用來(lái)完成檢驗(yàn)漫玄。下面一幅圖是遍歷的說(shuō)明:
上圖中的圓圈序號(hào)指的是訪問(wèn)的先后順序茄蚯。值得一提的是內(nèi)核關(guān)于廣度優(yōu)先圖遍歷的實(shí)現(xiàn)很耐人尋味压彭,很具有參考價(jià)值,值得自己去找到內(nèi)核代碼探究一番渗常。其中用到了棧壮不、位圖等概念。具體的代碼在 media-entity.c/media_entity_pipeline_start
函數(shù)里面皱碘。
由于上面的遍歷是廣度優(yōu)先的询一,并且是全部遍歷,也就是說(shuō)如果你的 isp 有兩個(gè)輸入源癌椿,那這兩個(gè)輸入源可能會(huì)同時(shí)被打開(kāi)健蕊,更多時(shí)候我們并不希望這種情況發(fā)生,我們期望的是指定的輸入源踢俄、指定的單鏈路的 pipeline 被打開(kāi)缩功,此時(shí)就需要自行去管理 pipeline,可以實(shí)現(xiàn)一個(gè)自己的 pipeline 結(jié)構(gòu)體進(jìn)行相關(guān)的管理都办。實(shí)現(xiàn)方式就很簡(jiǎn)單嫡锌,這個(gè) pipeline 結(jié)構(gòu)體類(lèi)似下面:
struct spec_pipeline {
struct list_head entities; // pipeline 線上的 entity 鏈表頭
struct media_entity entities[PIPE_LENGTH]; //與上一個(gè)類(lèi)似,隨自己想法去實(shí)現(xiàn)
int (*open_fun)(struct media_entity entity, int onoff);
int (*s_stream)(struct media_entity entity, int onoff);
... ...
};
接下來(lái)就不用多說(shuō)了吧琳钉,思維趕緊發(fā)散一下势木、擴(kuò)展一下,很容易實(shí)現(xiàn)一個(gè)易用的自己特定的 pipeline歌懒,可以實(shí)現(xiàn)指定同源不同目的的數(shù)據(jù)流區(qū)分管理啦桌,不同源不同目的的數(shù)據(jù)流區(qū)分管理等等。
Tips
- 從
media_entity
找到v4l2_subdev
可以使用media_entity_to_v4l2_subdev
函數(shù)來(lái)完成及皂。 - 可以在 video 模塊的 streamon 部分加入對(duì)link的使能標(biāo)記甫男,
media_entity_pipeline_start
函數(shù)會(huì)對(duì)entity.stream_count
成員進(jìn)行增值操作,并且會(huì)將第二個(gè)參數(shù)中的 pipe 傳遞給 link 線上的entity.pipe
成員躲庄。使能標(biāo)記完成之后可以對(duì)各個(gè) entity 進(jìn)行圖遍歷來(lái)調(diào)用其set_stream
成員開(kāi)啟 stream查剖。事實(shí)上在s_param,s_fmt
等 ioctl 調(diào)用時(shí)就需要進(jìn)行圖遍歷以調(diào)用整個(gè) pipeline 上面的各個(gè) entity 的回調(diào)函數(shù)進(jìn)行相關(guān)的設(shè)置。 - 在子設(shè)備節(jié)點(diǎn)都注冊(cè)完畢之后可以通過(guò)
media_entity_create_link
來(lái)完成各個(gè) entity 的連接噪窘,以待之后整個(gè)數(shù)據(jù)流的開(kāi)啟笋庄。 - 為什么要有 media framework?因?yàn)閮H僅有 subdev 的話倔监,各個(gè)子設(shè)備類(lèi)是處于平級(jí)狀態(tài)直砂,并沒(méi)有數(shù)據(jù)流的流向之分,如果需要建立數(shù)據(jù)流 pipeline 的話需要自行去實(shí)現(xiàn)浩习,這樣會(huì)比較麻煩静暂,而有了 media framework 的話這些管理就會(huì)方便很多,因?yàn)樗峁┝?pipeline 的一切管理操作谱秽,這樣就可以把眾多的 subdev 串聯(lián)成為一個(gè)完整的數(shù)據(jù)流洽蛀,從而進(jìn)行正確摹迷、有向的數(shù)據(jù)傳遞。
-
v4l2_subdev
與video_device
內(nèi)部都有一個(gè)media_entity
結(jié)構(gòu)體(非指針類(lèi)型)郊供,video_device
內(nèi)部的entity會(huì)隨著video 設(shè)備的注冊(cè)而注冊(cè)峡碉,名字沿用video_deivce
的名字,這兩個(gè)是有所區(qū)別的驮审,使用的時(shí)候需要特別注意下鲫寄。
結(jié)束語(yǔ):本文到此結(jié)束,希望你已經(jīng)能夠完成一個(gè)完整功能的 pipeline疯淫,能夠進(jìn)行 open/close, s_stream 等操作了地来,并且可以實(shí)現(xiàn)自定義的設(shè)備數(shù)據(jù)流串聯(lián),實(shí)時(shí)管理等功能熙掺。下文預(yù)告-videobuf2 的實(shí)現(xiàn)與使用未斑。