4.13. 子裝置介面

V4L2 裝置的複雜性在於其硬體通常由多個積體電路組成,這些電路需要以受控方式相互互動,這導致了複雜的 V4L2 驅動。驅動通常在軟體中反映硬體模型,並將不同的硬體元件建模為稱為子裝置的軟體塊。

V4L2 子裝置通常是僅存在於核心中的物件。如果 V4L2 驅動實現了媒體裝置 API,它們將自動從媒體實體繼承。應用程式將能夠使用媒體實體、pad 和連結列舉 API 來列舉子裝置並發現硬體拓撲。

除了使子裝置可被發現外,驅動還可以選擇讓應用程式直接配置它們。當子裝置驅動和 V4L2 裝置驅動都支援此功能時,子裝置將提供一個字元裝置節點,可以在其上呼叫 ioctl 來

  • 查詢、讀取和寫入子裝置控制元件

  • 訂閱和取消訂閱事件並檢索它們

  • 在單獨的 pad 上協商影像格式

  • 檢查和修改同一實體內 pad 之間的內部資料路由

子裝置字元裝置節點,通常命名為 /dev/v4l-subdev*,使用主裝置號 81。

驅動可以選擇限制子裝置字元裝置,使其僅公開不修改裝置狀態的操作。在這種情況下,在本文件的其餘部分,這些子裝置被稱為 只讀,相關的限制在各個 ioctl 中有詳細說明。

4.13.1. 控制元件

大多數 V4L2 控制元件由子裝置硬體實現。驅動通常會合並所有控制元件,並透過影片裝置節點公開它們。應用程式可以透過單個介面控制所有子裝置。

複雜的裝置有時會在不同的硬體部件中實現相同的控制。這種情況在嵌入式平臺中很常見,其中感測器和影像處理硬體都實現了相同的功能,例如對比度調整、白平衡或壞點校正。由於 V4L2 控制元件 API 不支援單個裝置中有多個相同的控制,因此除了一個相同的控制外,其餘都被隱藏了。

應用程式可以透過子裝置節點,使用 使用者控制元件 中描述的 V4L2 控制 API 訪問這些隱藏控制元件。這些 ioctl 的行為與在 V4L2 裝置節點上呼叫時相同,不同之處在於它們僅處理子裝置中實現的控制元件。

根據驅動的不同,這些控制元件也可能透過一個(或多個)V4L2 裝置節點公開。

4.13.2. 事件

V4L2 子裝置可以按照 事件介面 中描述的方式通知應用程式事件。該 API 的行為與在 V4L2 裝置節點上使用時相同,不同之處在於它只處理由子裝置生成的事件。根據驅動的不同,這些事件也可能在一個(或多個)V4L2 裝置節點上報告。

4.13.3. Pad 級格式

警告

Pad 級格式僅適用於需要向用戶空間公開低階格式配置的非常複雜的裝置。通用 V4L2 應用程式不需要使用本節中描述的 API。

注意

就本節而言,術語“格式”指媒體匯流排資料格式、幀寬度和幀高度的組合。

影像格式通常在影片捕獲和輸出裝置上使用格式和 選擇 ioctl 進行協商。驅動負責根據管線輸入和/或輸出處請求的格式配置影片管線中的每個塊。

對於複雜的裝置,例如嵌入式系統中常見的裝置,管線輸出的相同影像尺寸可以透過不同的硬體配置實現。一個這樣的示例在 管線上的影像格式協商 中顯示,其中影像縮放可以在影片感測器和主機影像處理硬體上進行。

pipeline.dot

管線上的影像格式協商

高質量和高速管線配置

感測器縮放器通常質量低於主機縮放器,但在感測器上進行縮放是實現更高幀率所必需的。根據用例(質量 vs. 速度),管線必須進行不同的配置。應用程式需要顯式地配置管線中每個點的格式。

實現 媒體 API 的驅動可以將 pad 級的影像格式配置暴露給應用程式。當它們這樣做時,應用程式可以使用 VIDIOC_SUBDEV_G_FMTVIDIOC_SUBDEV_S_FMT ioctl 來按 pad 協商格式。

應用程式負責配置整個管線的連貫引數,並確保連線的 pad 具有相容的格式。在 VIDIOC_STREAMON 時,會檢查管線中的格式不匹配情況,如果配置無效,則返回 EPIPE 錯誤程式碼。

可以透過在 pad 0 上呼叫 ioctl VIDIOC_SUBDEV_G_FMT, VIDIOC_SUBDEV_S_FMT 來測試 pad 級影像格式配置支援。如果驅動返回 EINVAL 錯誤程式碼,則子裝置不支援 pad 級格式配置。

4.13.3.1. 格式協商

pad 上可接受的格式可能(並且通常會)取決於許多外部引數,例如其他 pad 上的格式、活動連結甚至控制元件。在影片管線中的所有 pad 上找到應用程式和驅動都可接受的格式組合,不能僅依靠格式列舉。需要一種格式協商機制。

格式協商機制的核心是獲取/設定格式操作。當呼叫時 which 引數設定為 V4L2_SUBDEV_FORMAT_TRYVIDIOC_SUBDEV_G_FMTVIDIOC_SUBDEV_S_FMT ioctl 將操作一組與硬體配置無關的格式引數。修改這些“嘗試”格式不會觸及裝置狀態(這適用於驅動中儲存的軟體狀態和裝置本身儲存的硬體狀態)。

雖然不作為裝置狀態的一部分儲存,但嘗試格式儲存在子裝置檔案控制代碼中。一次 VIDIOC_SUBDEV_G_FMT 呼叫將返回在同一子裝置檔案控制代碼上設定的最後一個嘗試格式。因此,多個應用程式同時查詢同一子裝置不會相互干擾。

為了確定裝置是否支援特定格式,應用程式使用 VIDIOC_SUBDEV_S_FMT ioctl。驅動會驗證並根據裝置要求(如果需要)更改請求的 format,並返回可能修改後的值。應用程式可以選擇嘗試不同的格式或接受返回的值並繼續。

驅動在協商迭代期間返回的格式保證得到裝置支援。特別是,驅動保證如果將返回的格式原樣傳遞給 VIDIOC_SUBDEV_S_FMT 呼叫,它將不會進一步改變(只要外部引數,如其他 pad 上的格式或連結配置未改變)。

驅動會自動在子裝置內部傳播格式。當在 pad 上設定嘗試或活動格式時,同一子裝置上其他 pad 的相應格式可以由驅動修改。驅動可以根據裝置要求自由修改格式。但是,如果可能,它們應遵守以下規則:

  • 格式應從 sink pad 傳播到 source pad。修改 source pad 上的格式不應修改任何 sink pad 上的格式。

  • 使用可變縮放因子縮放幀的子裝置在修改 sink pad 格式時,應將縮放因子重置為預設值。如果支援 1:1 縮放比例,這意味著 source pad 格式應重置為 sink pad 格式。

格式不會跨連結傳播,因為這會涉及將它們從一個子裝置檔案控制代碼傳播到另一個。因此,應用程式必須注意顯式地為每個連結的兩端配置相容的格式。連結兩端的相同格式保證相容。驅動可以自由接受符合裝置要求的不同格式作為相容格式。

管線配置示例 展示了 管線上的影像格式協商 中描述的管線的配置序列示例(表格列出實體名稱和 pad 編號)。

管線配置示例

感測器/0

格式

前端/0

格式

前端/1

格式

縮放器/0

格式

縮放器/0

組合選擇矩形

縮放器/1

格式

初始狀態

2048x1536

SGRBG8_1X8

(預設)

(預設)

(預設)

(預設)

(預設)

配置前端 sink 格式

2048x1536

SGRBG8_1X8

2048x1536

SGRBG8_1X8

2046x1534

SGRBG8_1X8

(預設)

(預設)

(預設)

配置縮放器 sink 格式

2048x1536

SGRBG8_1X8

2048x1536

SGRBG8_1X8

2046x1534

SGRBG8_1X8

2046x1534

SGRBG8_1X8

0,0/2046x1534

2046x1534

SGRBG8_1X8

配置縮放器 sink 組合選擇

2048x1536

SGRBG8_1X8

2048x1536

SGRBG8_1X8

2046x1534

SGRBG8_1X8

2046x1534

SGRBG8_1X8

0,0/1280x960

1280x960

SGRBG8_1X8

  1. 初始狀態。感測器 source pad 格式設定為其原生的 3MP 尺寸和 V4L2_MBUS_FMT_SGRBG8_1X8 媒體匯流排程式碼。主機前端和縮放器 sink 及 source pad 上的格式具有預設值,縮放器 sink pad 上的組合矩形也如此。

  2. 應用程式將前端 sink pad 格式的大小配置為 2048x1536,並將其媒體匯流排程式碼配置為 V4L2_MBUS_FMT_SGRBG_1X8。驅動將格式傳播到前端 source pad。

  3. 應用程式將縮放器 sink pad 格式的大小配置為 2046x1534,並將媒體匯流排程式碼配置為 V4L2_MBUS_FMT_SGRBG_1X8,以匹配前端源大小和媒體匯流排程式碼。sink pad 上的媒體匯流排程式碼設定為 V4L2_MBUS_FMT_SGRBG_1X8。驅動將大小傳播到縮放器 sink pad 上的組合選擇矩形,並將格式傳播到縮放器 source pad。

  4. 應用程式將縮放器 sink pad 的組合選擇矩形的大小配置為 1280x960。驅動將大小傳播到縮放器的 source pad 格式。

當對嘗試結果滿意時,應用程式可以透過將 which 引數設定為 V4L2_SUBDEV_FORMAT_ACTIVE 來設定活動格式。活動格式由驅動程式更改的方式與嘗試格式完全相同。為了避免在格式協商期間修改硬體狀態,應用程式應首先協商嘗試格式,然後使用上次協商迭代中返回的嘗試格式來修改活動設定。這保證了活動格式將由驅動程式原樣應用而不會被修改。

4.13.3.2. 選擇:裁剪、縮放和組合

許多子裝置支援在其輸入或輸出 pad 上(或者甚至在兩者上)裁剪幀。裁剪用於選擇影像中的感興趣區域,通常在影像感測器或影片解碼器上。它也可以用作數字變焦實現的一部分,以選擇將被放大的影像區域。

裁剪設定由裁剪矩形定義,並在 struct v4l2_rect 中表示,其中包含左上角座標和矩形大小。座標和大小均以畫素表示。

與 pad 格式一樣,驅動為選擇目標 常見選擇定義 儲存嘗試和活動矩形。

在 sink pad 上,裁剪是相對於當前 pad 格式應用的。pad 格式表示子裝置從管線中前一個塊接收到的影像大小,而裁剪矩形表示將進一步在子裝置內部傳輸以進行處理的子影像。

縮放操作透過將影像縮放到新的尺寸來改變影像的大小。縮放比例沒有明確指定,而是由原始影像和縮放影像的尺寸隱含得出。這兩種尺寸都由 struct v4l2_rect 表示。

縮放支援是可選的。當子裝置支援時,子裝置 sink pad 上的裁剪矩形將縮放為使用同一 pad 上的 V4L2_SEL_TGT_COMPOSE 選擇目標,透過 VIDIOC_SUBDEV_S_SELECTION IOCTL 配置的大小。如果子裝置支援縮放但不支援組合,則不使用 top 和 left 值,並且必須始終設定為零。

在 source pad 上,裁剪與 sink pad 類似,不同之處在於執行裁剪的源大小是 sink pad 上的 COMPOSE 矩形。在 sink pad 和 source pad 上,裁剪矩形必須完全包含在源影像大小之內才能進行裁剪操作。

除非另有明確說明,否則驅動應始終在所有選擇目標上使用使用者請求的最接近的矩形。V4L2_SEL_FLAG_GEV4L2_SEL_FLAG_LE 標誌可用於向上或向下舍入影像大小。選擇標誌

4.13.3.3. 選擇目標型別

4.13.3.3.1. 實際目標

實際目標(不帶字尾)反映了任何時間點的實際硬體配置。每個實際目標都有一個對應的 BOUNDS 目標。

4.13.3.3.2. BOUNDS 目標

BOUNDS 目標是包含所有有效實際矩形的最小矩形。然而,可能無法將實際矩形設定得與 BOUNDS 矩形一樣大。這可能是因為例如感測器的畫素陣列不是矩形而是十字形或圓形。最大尺寸也可能小於 BOUNDS 矩形。

4.13.3.4. 配置和格式傳播順序

在子裝置內部,影像處理步驟的順序總是從 sink pad 到 source pad。這也反映在使用者必須執行配置的順序中:所做的更改將傳播到任何後續階段。如果不需要這種行為,使用者必須設定 V4L2_SEL_FLAG_KEEP_CONFIG 標誌。此標誌導致在任何情況下都不允許傳播更改。這還可能導致被訪問的矩形被驅動調整,具體取決於底層硬體的特性。

一個步驟的座標總是指前一個步驟的實際大小。此規則的例外是 sink 組合矩形,它指的是 sink 組合邊界矩形——如果硬體支援的話。

  1. Sink pad 格式。使用者配置 sink pad 格式。此格式定義了實體透過該 pad 接收以進行進一步處理的影像引數。

  2. Sink pad 實際裁剪選擇。sink pad 裁剪定義了對 sink pad 格式執行的裁剪。

  3. Sink pad 實際組合選擇。sink pad 組合矩形的大小定義了與 sink pad 裁剪矩形大小相比的縮放比例。組合矩形的位置指定了實際 sink 組合矩形在 sink 組合邊界矩形中的位置。

  4. Source pad 實際裁剪選擇。source pad 上的裁剪定義了對 sink 組合邊界矩形中影像執行的裁剪。

  5. Source pad 格式。source pad 格式定義了子裝置的輸出畫素格式,以及除影像寬度和高度之外的其他引數。寬度和高度由 source pad 實際裁剪選擇的大小定義。

訪問子裝置不支援的任何上述矩形將返回 EINVAL。任何引用先前不支援的矩形座標的矩形將轉而引用先前支援的矩形。例如,如果不支援 sink 裁剪,則組合選擇將轉而引用 sink pad 格式尺寸。

subdev-image-processing-crop.svg

圖 4.5. 子裝置中的影像處理:簡單裁剪示例

在上面的示例中,子裝置支援在其 sink pad 上進行裁剪。要配置它,使用者在子裝置的 sink pad 上設定媒體匯流排格式。現在可以在 sink pad 上設定實際裁剪矩形——此矩形的位置和大小反映了要從 sink 格式中裁剪的矩形的位置和大小。sink 裁剪矩形的大小也將是子裝置 source pad 格式的大小。

subdev-image-processing-scaling-multi-source.svg

圖 4.6. 子裝置中的影像處理:多源縮放

在此示例中,子裝置能夠首先裁剪,然後縮放,最後為兩個 source pad 從生成的縮放影像中單獨裁剪。縮放影像在裁剪影像中的位置在 sink 組合目標中被忽略。兩個 source 裁剪矩形的位置都指的是 sink 縮放矩形,獨立地從其中裁剪出由 source 裁剪矩形指定位置的區域。

subdev-image-processing-full.svg

圖 4.7. 子裝置中的影像處理:多 sink 和 source 的縮放和組合

子裝置驅動支援兩個 sink pad 和兩個 source pad。來自兩個 sink pad 的影像被單獨裁剪,然後縮放並在組合邊界矩形上進一步組合。由此,兩個獨立的流被裁剪並從 source pad 從子裝置中傳送出去。

4.13.3.5. 流、複用媒體 pad 和內部路由

簡單的 V4L2 子裝置不支援多個不相關的影片流,並且只有一個流可以穿過媒體連結和媒體 pad。因此,每個 pad 包含該單個流的格式和選擇配置。子裝置可以進行流處理,將一個流分成兩個或將兩個流組合成一個,但子裝置的輸入和輸出仍然是每個 pad 一個流。

一些硬體,例如 MIPI CSI-2,支援複用流,即多個數據流在同一總線上進行傳輸,這由連線發射器 source pad 和接收器 sink pad 的媒體連結表示。例如,攝像頭感測器可以產生兩個不同的流,一個畫素流和一個元資料流,它們在複用資料匯流排上進行傳輸,由連線單個感測器 source pad 和接收器 sink pad 的媒體連結表示。支援流的接收器將對在其 sink pad 上接收到的流進行解複用,並允許將它們單獨路由到其一個 source pad。

支援複用流的子裝置驅動與非複用子裝置驅動相容。然而,如果連結 sink 端的驅動不支援流,則只能捕獲 source 端的流 0。可能還有特定於 sink 裝置的額外限制。

4.13.3.5.1. 理解流

流是內容(例如畫素資料或元資料)流,它透過媒體管線從源(例如感測器)流向最終的 sink(例如 SoC 中的接收器和解複用器)。每個媒體連結將所有啟用的流從連結的一端傳輸到另一端,子裝置具有路由表,描述瞭如何將來自 sink pad 的輸入流路由到 source pad。

流 ID 是流的媒體 pad 區域性識別符號。同一流的流 ID 在連結的兩端必須相等。換句話說,一個特定的流 ID 必須存在於媒體連結的兩側,但子裝置的另一側可以為同一流使用另一個流 ID。

媒體管線中特定點的一個流由子裝置和(pad,流)對標識。對於不支援複用流的子裝置,“流”欄位始終為 0。

4.13.3.5.2. 路由、流、格式和選擇之間的互動

在 V4L2 子裝置介面中增加流,將子裝置的格式和選擇從 pad 移動到(pad,流)對。除了通常的 pad 外,設定格式和選擇還需要提供流 ID。沿流配置格式和選擇的順序與沒有流時相同(參見 配置和格式傳播順序)。

與子裝置範圍內的所有 sink pad 的流向所有 source pad 合併不同,每條路由的資料流彼此獨立。從 sink pad 上的流到 source pad 上的流,允許任意數量的路由,只要驅動支援。然而,對於 source pad 上的每個流,只允許一條路由。

pad 內流的任何配置,例如格式或選擇,都獨立於其他流上的類似配置。這在將來可能會改變。

4.13.3.5.3. 裝置型別和路由設定

不同型別的子裝置在路由啟用方面的行為不同,這取決於硬體。然而,在所有情況下,只有設定了 V4L2_SUBDEV_STREAM_FL_ACTIVE 標誌的路由才是活動的。

生成流的裝置可能允許啟用和停用某些路由,或者具有固定的路由配置。如果路由可以被停用,則在 VIDIOC_SUBDEV_S_ROUTING 中不宣告路由(或宣告它們但未設定 V4L2_SUBDEV_STREAM_FL_ACTIVE 標誌)將停用這些路由。VIDIOC_SUBDEV_S_ROUTING 仍將在路由陣列中將這些路由返回給使用者,但 V4L2_SUBDEV_STREAM_FL_ACTIVE 標誌未設定。

傳輸流的裝置在路由方面幾乎總是具有更高的可配置性。通常,子裝置的 sink 和 source pad 之間的任何路由都是可能的,並且可以同時啟用多條路由(通常達到某個有限數量)。對於此類裝置,驅動不建立路由,並且當在子裝置上呼叫 VIDIOC_SUBDEV_S_ROUTING 時,使用者建立的路由會被完全替換。這些新建立的路由具有裝置預設的格式和選擇矩形配置。

4.13.3.5.4. 配置流

流的配置是針對每個子裝置單獨進行的,子裝置之間的流的有效性在管線啟動時進行驗證。

配置流有三個步驟:

  1. 設定連結。使用 媒體控制器 API 連線子裝置之間的 pad。

  2. 流。透過使用 VIDIOC_SUBDEV_S_ROUTING ioctl 為子裝置設定路由表來宣告流並配置其路由。請注意,設定路由表會將子裝置中的格式和選擇重置為預設值。

  3. 配置格式和選擇。每個流的格式和選擇單獨配置,如 配置和格式傳播順序 中對普通子裝置的說明。流 ID 設定為與使用 VIDIOC_SUBDEV_S_ROUTING ioctl 配置的路由的 sink 或 source pad 相關聯的相同流 ID。

4.13.3.5.5. 複用流設定示例

一個複用流設定的簡單示例如下:

  • 兩個相同的感測器(感測器 A 和感測器 B)。每個感測器都有一個單一的 source pad (pad 0),它承載一個畫素資料流。

  • 複用器橋(Bridge)。該橋有兩個連線到感測器的 sink pad (pad 0, 1),和一個輸出兩個流的 source pad (pad 2)。

  • SoC 中的接收器(Receiver)。該接收器有一個連線到橋的單一 sink pad (pad 0),以及兩個連線到 DMA 引擎的 source pad (pad 1-2)。接收器將傳入流解複用至 source pad。

  • SoC 中的 DMA 引擎(DMA Engine),每個流一個。每個 DMA 引擎都連線到接收器中的一個單一 source pad。

感測器、橋和接收器被建模為 V4L2 子裝置,透過 /dev/v4l-subdevX 裝置節點暴露給使用者空間。DMA 引擎被建模為 V4L2 裝置,透過 /dev/videoX 節點暴露給使用者空間。

要配置此管線,使用者空間必須執行以下步驟:

  1. 設定實體之間的媒體連結:將感測器連線到橋,將橋連線到接收器,並將接收器連線到 DMA 引擎。此步驟與正常的非複用媒體控制器設定沒有區別。

  2. 配置路由

橋路由表

Sink Pad/流

Source Pad/流

路由標誌

註釋

0/0

2/0

V4L2_SUBDEV_ROUTE_FL_ACTIVE

來自感測器 A 的畫素資料流

1/0

2/1

V4L2_SUBDEV_ROUTE_FL_ACTIVE

來自感測器 B 的畫素資料流

接收器路由表

Sink Pad/流

Source Pad/流

路由標誌

註釋

0/0

1/0

V4L2_SUBDEV_ROUTE_FL_ACTIVE

來自感測器 A 的畫素資料流

0/1

2/0

V4L2_SUBDEV_ROUTE_FL_ACTIVE

來自感測器 B 的畫素資料流

  1. 配置格式和選擇

    配置路由後,下一步是配置流的格式和選擇。這類似於在沒有流的情況下執行此步驟,只有一個例外:stream 欄位需要賦值為流 ID 的值。

    實現此目的的一種常見方法是從感測器開始,並沿著流將配置傳播到接收器,使用 VIDIOC_SUBDEV_S_FMT ioctl 配置每個子裝置中的每個流端點。