4.6. 原始 VBI 資料介面

VBI 是垂直消隱間隔的縮寫,是模擬影片訊號線序列中的一個間隙。在 VBI 期間不傳輸影像資訊,從而允許陰極射線管電視的電子束返回到螢幕頂部所需的時間。使用示波器,您會在這裡找到垂直同步脈衝和短資料包 ASK 調製 [1] 到影片訊號上。這些是 Teletext 或 Closed Caption 等服務的傳輸。

此介面型別的主題是原始 VBI 資料,它從影片訊號中取樣,或者新增到訊號以進行輸出。資料格式類似於未壓縮的影片影像,即若干行乘以每行的若干個樣本,我們稱之為 VBI 影像。

按照慣例,V4L2 VBI 裝置透過名為 /dev/vbi/dev/vbi0/dev/vbi31 的字元裝置特殊檔案訪問,主裝置號為 81,次裝置號為 224 到 255。/dev/vbi 通常是指向首選 VBI 裝置的符號連結。此約定適用於輸入和輸出裝置。

為了解決查詢相關影片和 VBI 裝置的問題,VBI 捕獲和輸出也可以作為 /dev/video 下的裝置功能使用。要使用這些裝置捕獲或輸出原始 VBI 資料,應用程式必須呼叫 VIDIOC_S_FMT ioctl。作為 /dev/vbi 訪問時,原始 VBI 捕獲或輸出是預設的裝置功能。

4.6.1. 查詢能力

支援原始 VBI 捕獲或輸出 API 的裝置分別在 v4l2_capability 結構的 capabilities 欄位中設定 V4L2_CAP_VBI_CAPTUREV4L2_CAP_VBI_OUTPUT 標誌,該結構由 ioctl VIDIOC_QUERYCAP ioctl 返回。必須支援至少一種讀取/寫入或流式 I/O 方法。VBI 裝置可能有也可能沒有調諧器或調製器。

4.6.2. 補充功能

VBI 裝置應根據需要支援 影片輸入或輸出調諧器或調製器控制元件 ioctl。影片標準 ioctl 提供對程式設計 VBI 裝置至關重要的資訊,因此必須支援。

4.6.3. 原始 VBI 格式協商

原始 VBI 取樣能力可能會有所不同,尤其是取樣頻率。為了正確解釋資料,V4L2 指定了一個 ioctl 來查詢取樣引數。此外,為了允許一定的靈活性,應用程式還可以建議不同的引數。

與往常一樣,這些引數在 open()不會 重置,以允許 Unix 工具鏈,程式設計裝置,然後像讀取普通檔案一樣從中讀取。編寫良好的 V4L2 應用程式應始終確保它們真正獲得所需的內容,請求合理的引數,然後檢查實際引數是否合適。

要查詢當前的原始 VBI 捕獲引數,應用程式將 v4l2_format 結構的 type 欄位設定為 V4L2_BUF_TYPE_VBI_CAPTUREV4L2_BUF_TYPE_VBI_OUTPUT,並使用指向此結構的指標呼叫 VIDIOC_G_FMT ioctl。驅動程式填充 fmt 聯合體的 v4l2_vbi_format vbi 成員。

要請求不同的引數,應用程式如上所述設定 v4l2_format 結構的 type 欄位,並初始化 fmt 聯合體的 v4l2_vbi_format vbi 成員的所有欄位,或者最好只是修改 VIDIOC_G_FMT 的結果,並使用指向此結構的指標呼叫 VIDIOC_S_FMT ioctl。僅當給定的引數不明確時,驅動程式才返回 EINVAL 錯誤程式碼,否則它們會根據硬體功能修改引數並返回實際引數。當驅動程式在此點分配資源時,它可能會返回 EBUSY 錯誤程式碼,以指示返回的引數有效,但當前無法使用所需的資源。例如,當要捕獲的影片和 VBI 區域重疊時,或者當驅動程式支援多個開啟並且另一個程序已請求 VBI 捕獲或輸出時,可能會發生這種情況。無論如何,應用程式必須預期其他資源分配點可能會返回 EBUSY,在 ioctl VIDIOC_STREAMON, VIDIOC_STREAMOFF ioctl 和第一個 read()write()select() 呼叫時。

VBI 裝置必須同時實現 VIDIOC_G_FMTVIDIOC_S_FMT ioctl,即使 VIDIOC_S_FMT 忽略所有請求並且始終返回預設引數,如 VIDIOC_G_FMT 所做的一樣。VIDIOC_TRY_FMT 是可選的。

type v4l2_vbi_format
struct v4l2_vbi_format

__u32

sampling_rate

每秒樣本數,即單位為 1 Hz。

__u32

offset

VBI 影像的水平偏移量,相對於線路同步脈衝的前沿,以樣本計數:VBI 影像中的第一個樣本將位於前沿之後 offset / sampling_rate 秒。另請參見 圖 4.1. 線路同步

__u32

samples_per_line

__u32

sample_format

定義 影像格式 中的樣本格式,四字元程式碼。[2] 通常這是 V4L2_PIX_FMT_GREY,即每個樣本由 8 位組成,較低的值面向黑色級別。不要假定值與訊號電平之間存在任何其他相關性。例如,MSB 不一定指示訊號是“高”還是“低”,因為 128 可能不是訊號的平均值。驅動程式不得透過軟體轉換樣本格式。

__u32

start[2]

這是與 VBI 影像的第一行關聯的掃描系統行號,分別是第一場和第二場。有關有效值,請參見 圖 4.2. ITU-R 525 行編號 (M/NTSC 和 M/PAL)圖 4.3. ITU-R 625 行編號V4L2_VBI_ITU_525_F1_START, V4L2_VBI_ITU_525_F2_START, V4L2_VBI_ITU_625_F1_STARTV4L2_VBI_ITU_625_F2_START 定義為了方便起見,給出了每種 525 或 625 行格式的每個場的起始行號。不要忘記 ITU 行編號從 1 開始,而不是 0。如果硬體無法可靠地識別掃描線,VBI 輸入驅動程式可以返回起始值 0,VBI 獲取可能不需要此資訊。

__u32

count[2]

第一場和第二場影像中的行數,分別。

驅動程式應儘可能靈活。例如,可以將 VBI 捕獲視窗向下擴充套件或移動到影像區域,從而實現“全場模式”以捕獲嵌入在影像中的資料服務傳輸。

如果不需要來自相應場的資料,應用程式可以將第一個或第二個 count 值設定為零;如果掃描系統是逐行的,即不是隔行的,則 count[1]。相應的起始值應被應用程式和驅動程式忽略。無論如何,驅動程式可能不支援單場捕獲,並返回兩個非零計數器值。

兩個 count 值都設定為零,或者行號在描繪的範圍之外[4],或者覆蓋兩個場的行的場影像,都是無效的,不應由驅動程式返回。

要初始化 startcount 欄位,應用程式必須首先確定當前選擇的影片標準。可以為此目的評估 v4l2_std_idv4l2_standard 結構的 framelines 欄位。

__u32

flags

請參見下面的 原始 VBI 格式標誌。當前只有驅動程式設定標誌,應用程式必須將此欄位設定為零。

__u32

reserved[2]

此陣列保留用於將來的擴充套件。驅動程式和應用程式必須將其設定為零。

原始 VBI 格式標誌

V4L2_VBI_UNSYNC

0x0001

此標誌指示無法正確區分場的硬體。通常,VBI 影像首先在記憶體中儲存第一場(較低的掃描線號)。這可能是頂部或底部場,具體取決於影片標準。設定此標誌後,可以首先儲存第一場或第二場,但是這些場仍然按照正確的時序順序排列,較舊的場首先儲存在記憶體中。[3]

V4L2_VBI_INTERLACED

0x0002

預設情況下,兩個場影像將依次傳遞;第一場的所有行後跟第二場的所有行(比較 場順序 V4L2_FIELD_SEQ_TBV4L2_FIELD_SEQ_BT,頂部或底部場是否首先儲存在記憶體中取決於影片標準)。設定此標誌後,兩個場將交織在一起(參見 V4L2_FIELD_INTERLACED)。第一場的第一行後跟第二場的第一行,然後是第二行的兩行,依此類推。當已將硬體程式設計為捕獲或輸出隔行掃描影片影像並且無法同時分離場以進行 VBI 捕獲時,可能需要這種佈局。為簡單起見,設定此標誌意味著兩個 count 值相等且非零。

vbi_hsync.svg

圖 4.1. 線路同步

vbi_525.svg

圖 4.2. ITU-R 525 行編號 (M/NTSC 和 M/PAL)

vbi_625.svg

圖 4.3. ITU-R 625 行編號

請記住,VBI 影像格式取決於所選的影片標準,因此應用程式必須首先選擇新標準或查詢當前標準。驅動程式應拒絕在格式協商之前或之後讀取或寫入資料的嘗試,或在切換可能使協商的 VBI 引數無效的影片標準之後進行嘗試。活動 I/O 期間不允許格式更改。

4.6.4. 讀取和寫入 VBI 影像

為了確保與場號同步並簡化實現,一次傳遞的最小資料單位是一個幀,該幀由立即在記憶體中跟隨的 VBI 影像的兩個場組成。

幀的總大小計算如下

(count[0] + count[1]) * samples_per_line * sample size in bytes

樣本大小最有可能始終為一個位元組,應用程式必須檢查 sample_format 欄位,以便與其他驅動程式正常工作。

VBI 裝置可能支援 讀取/寫入 和/或流式傳輸(記憶體對映使用者指標)I/O。後者具有透過使用緩衝區時間戳同步影片和 VBI 資料的可能性。

請記住,如果所需的硬體資源暫時不可用,例如裝置已被另一個程序使用,則 VIDIOC_STREAMON ioctl 和第一個 read()write()select() 呼叫可以是資源分配點,從而返回 EBUSY 錯誤程式碼。