V4L2框架-media device

本文對(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連接。

  1. entity:硬件設(shè)備模塊抽象(類(lèi)比電路板上面的各個(gè)元器件拱烁、芯片)
  2. pad:硬件設(shè)備端口抽象(類(lèi)比元器件生蚁、芯片上面的管腳)
  3. 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_devicev4l2_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_entityname、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洲愤。

  1. pipeline與media流
    pipeline 的概念前面已經(jīng)介紹過(guò)了,不再重復(fù)顷锰,這里給一副說(shuō)明圖(其實(shí)這個(gè)不是非常的清晰易懂柬赐,還有更加清晰易懂的由于某些原因不能放出,請(qǐng)讀者發(fā)揮想象官紫,根據(jù)圖中以及上面的描述自行抽象出來(lái)一個(gè)圖肛宋,只要緊緊圍繞一點(diǎn)-pipeline 就是數(shù)據(jù)流鏈路的抽象,我相信你):


    pipeline 抽象圖

當(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_entitylink_validate 成員會(huì)被調(diào)用用來(lái)完成檢驗(yàn)漫玄。下面一幅圖是遍歷的說(shuō)明:

pipeline 遍歷

上圖中的圓圈序號(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

  1. media_entity 找到 v4l2_subdev 可以使用 media_entity_to_v4l2_subdev 函數(shù)來(lái)完成及皂。
  2. 可以在 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è)置。
  3. 在子設(shè)備節(jié)點(diǎn)都注冊(cè)完畢之后可以通過(guò) media_entity_create_link 來(lái)完成各個(gè) entity 的連接噪窘,以待之后整個(gè)數(shù)據(jù)流的開(kāi)啟笋庄。
  4. 為什么要有 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ù)傳遞。
  5. v4l2_subdevvideo_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)與使用未斑。


想做的事情就去做吧
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市适掰,隨后出現(xiàn)的幾起案子颂碧,更是在濱河造成了極大的恐慌荠列,老刑警劉巖类浪,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異肌似,居然都是意外死亡费就,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)川队,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)力细,“玉大人,你說(shuō)我怎么就攤上這事固额∶呗欤” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵斗躏,是天一觀的道長(zhǎng)逝慧。 經(jīng)常有香客問(wèn)我,道長(zhǎng)啄糙,這世上最難降的妖魔是什么笛臣? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮隧饼,結(jié)果婚禮上沈堡,老公的妹妹穿的比我還像新娘。我一直安慰自己燕雁,他們只是感情好诞丽,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布鲸拥。 她就那樣靜靜地躺著,像睡著了一般僧免。 火紅的嫁衣襯著肌膚如雪崩泡。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天猬膨,我揣著相機(jī)與錄音角撞,去河邊找鬼。 笑死勃痴,一個(gè)胖子當(dāng)著我的面吹牛谒所,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播沛申,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼劣领,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了铁材?” 一聲冷哼從身側(cè)響起尖淘,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎著觉,沒(méi)想到半個(gè)月后村生,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饼丘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年趁桃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肄鸽。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡卫病,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出典徘,到底是詐尸還是另有隱情蟀苛,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布逮诲,位于F島的核電站帜平,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏汛骂。R本人自食惡果不足惜罕模,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望帘瞭。 院中可真熱鬧淑掌,春花似錦、人聲如沸蝶念。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至担敌,卻和暖如春摔敛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背全封。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工马昙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刹悴。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓行楞,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親土匀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子子房,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容