4.5.1. 記憶體到記憶體有狀態影片解碼器介面

有狀態影片解碼器接收完整的位元組流塊(例如 Annex-B H.264/HEVC 流,原始 VP8/9 流)並將它們解碼為顯示順序的原始影片幀。解碼器應該不需要來自客戶端的任何附加資訊來處理這些緩衝區。

強烈不建議在驅動程式中執行軟體解析、處理等流操作以支援此介面。如果需要此類操作,強烈建議使用無狀態影片解碼器介面(正在開發中)。

4.5.1.1. 本文件中使用的約定和符號

  1. 如果本文件中沒有另外指定,則適用通用的 V4L2 API 規則。

  2. “必須”、“可以”、“應該”等詞的含義符合 RFC 2119

  3. 所有未標記為“可選”的步驟都是必需的。

  4. VIDIOC_G_EXT_CTRLS()VIDIOC_S_EXT_CTRLS() 可以與 VIDIOC_G_CTRL()VIDIOC_S_CTRL() 互換使用,除非另有說明。

  5. 單平面 API(參見 單平面和多平面 API)和適用的結構可以與多平面 API 互換使用,除非另有說明,具體取決於解碼器功能並遵循通用的 V4L2 指南。

  6. i = [a..b]: 從 a 到 b 的整數序列,包括 a 和 b,即 i = [0..2]: i = 0, 1, 2。

  7. 給定一個 OUTPUT 緩衝區 A,則 A' 表示 CAPTURE 佇列上的緩衝區,其中包含處理緩衝區 A 產生的資料。

4.5.1.2. 術語表

CAPTURE

目標緩衝區佇列;對於解碼器,包含解碼幀的緩衝區佇列;對於編碼器,包含編碼位元組流的緩衝區佇列;V4L2_BUF_TYPE_VIDEO_CAPTUREV4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;資料從硬體捕獲到 CAPTURE 緩衝區中。

client

與實現此介面的解碼器或編碼器通訊的應用程式。

coded format

編碼/壓縮的影片位元組流格式(例如 H.264、VP8 等);另請參見:raw format。

coded height

給定編碼解析度的高度。

coded resolution

畫素流解析度,與編解碼器和硬體要求對齊;通常可見解析度向上舍入到完整宏塊;另請參見:visible resolution。

coded width

給定編碼解析度的寬度。

coding tree unit

HEVC 編解碼器的處理單元(對應於 H.264、VP8、VP9 中的宏塊單元),可以使用高達 64×64 畫素的塊結構。擅長將圖片細分為可變大小的結構。

decode order

幀的解碼順序;如果編碼格式包含幀重新排序的功能,則可能與顯示順序不同;對於解碼器,OUTPUT 緩衝區必須由客戶端按解碼順序排隊;對於編碼器,CAPTURE 緩衝區必須由編碼器按解碼順序返回。

destination

解碼過程產生的資料;參見 CAPTURE

display order

幀必須顯示的順序;對於編碼器,OUTPUT 緩衝區必須由客戶端按顯示順序排隊;對於解碼器,CAPTURE 緩衝區必須由解碼器按顯示順序返回。

DPB

解碼圖片緩衝區;H.264/HEVC 術語,用於儲存解碼後的原始幀,可在進一步的解碼步驟中用作參考。

EOS

流結束。

IDR

即時解碼器重新整理;H.264/HEVC 編碼流中一種型別的關鍵幀,它清除早期參考幀 (DPB) 的列表。

keyframe

不參考之前解碼的幀的編碼幀,即可以完全獨立解碼。

macroblock

基於線性塊變換的影像和影片壓縮格式(例如 H.264、VP8、VP9)中的處理單元;特定於編解碼器,但對於大多數流行的編解碼器,大小為 16x16 樣本(畫素)。HEVC 編解碼器使用稍微靈活的處理單元,稱為編碼樹單元 (CTU)。

OUTPUT

源緩衝區佇列;對於解碼器,包含編碼位元組流的緩衝區佇列;對於編碼器,包含原始幀的緩衝區佇列;V4L2_BUF_TYPE_VIDEO_OUTPUTV4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;硬體從 OUTPUT 緩衝區獲取資料。

PPS

圖片引數集;H.264/HEVC 位元組流中的一種元資料實體。

raw format

包含原始畫素資料(例如 YUV、RGB 格式)的未壓縮格式。

resume point

位元組流中的一個點,可以從該點開始/繼續解碼,而無需任何先前的狀態/資料,例如:關鍵幀 (VP8/VP9) 或 SPS/PPS/IDR 序列 (H.264/HEVC);需要一個恢復點才能開始解碼新流,或在查詢後恢復解碼。

source

饋送到解碼器或編碼器的資料;參見 OUTPUT

source height

給定源解析度的畫素高度;僅與編碼器相關。

source resolution

源幀的畫素解析度,作為編碼器的源,並受進一步裁剪到可見解析度範圍的限制;僅與編碼器相關。

source width

給定源解析度的畫素寬度;僅與編碼器相關。

SPS

序列引數集;H.264/HEVC 位元組流中的一種元資料實體。

stream metadata

編碼位元組流中包含的附加(非視覺)資訊;例如:編碼解析度、可見解析度、編解碼器配置檔案。

visible height

給定可見解析度的高度;顯示高度。

visible resolution

可見圖片的流解析度,以畫素為單位,用於顯示目的;必須小於或等於編碼解析度;顯示解析度。

visible width

給定可見解析度的寬度;顯示寬度。

4.5.1.3. 狀態機

DOT digraph of decoder state machine

解碼器狀態機

4.5.1.4. 查詢功能

  1. 要列舉解碼器支援的編碼格式集,客戶端可以在 OUTPUT 上呼叫 VIDIOC_ENUM_FMT()

    • 無論在 CAPTURE 上設定的格式如何,都將返回完整的支援格式集。

    • 檢查 v4l2_fmtdesc 的標誌欄位,以獲取有關解碼器在每種編碼格式方面的功能的更多資訊。特別是解碼器是否具有成熟的位元組流解析器,以及解碼器是否支援動態解析度更改。

  2. 要列舉支援的原始格式集,客戶端可以在 CAPTURE 上呼叫 VIDIOC_ENUM_FMT()

    • 僅返回當前在 OUTPUT 上活動的格式支援的格式。

    • 為了列舉給定編碼格式支援的原始格式,客戶端必須首先在 OUTPUT 上設定該編碼格式,然後在 CAPTURE 上列舉格式。

  3. 客戶端可以使用 VIDIOC_ENUM_FRAMESIZES() 來檢測給定格式支援的解析度,在 v4l2_frmsizeenum pixel_format 中傳遞所需的畫素格式。

    • VIDIOC_ENUM_FRAMESIZES() 為編碼畫素格式返回的值將包括解碼器為給定編碼畫素格式支援的所有可能的編碼解析度。

    • VIDIOC_ENUM_FRAMESIZES() 為原始畫素格式返回的值將包括解碼器為給定原始畫素格式和當前在 OUTPUT 上設定的編碼格式支援的所有可能的幀緩衝區解析度。

  4. 可以使用各自的控制元件透過 VIDIOC_QUERYCTRL() 查詢當前在 OUTPUT 上設定的編碼格式支援的配置檔案和級別(如果適用)。

4.5.1.5. 初始化

  1. 透過 VIDIOC_S_FMT()OUTPUT 上設定編碼格式。

    • 必填欄位

      type

      適用於 OUTPUTV4L2_BUF_TYPE_* 列舉。

      pixelformat

      編碼畫素格式。

      width, height

      流的編碼解析度;僅當無法從給定編碼格式的流中解析時才需要;否則,解碼器將使用此解析度作為佔位符解析度,一旦可以從流中解析實際編碼解析度,該解析度很可能會更改。

      sizeimage

      所需的 OUTPUT 緩衝區大小;解碼器可以調整它以匹配硬體要求。

      other fields

      遵循標準語義。

    • 返回欄位

      sizeimage

      調整後的 OUTPUT 緩衝區大小。

    • CAPTURE 格式將立即根據 VIDIOC_S_FMT() 返回的寬度和高度更新為適當的幀緩衝區解析度。但是,對於包含流解析度資訊的編碼格式,在解碼器完成從流中解析資訊後,它將使用新值更新 CAPTURE 格式併發出源更改事件訊號,無論它們是否與客戶端設定的值匹配。

    Important

    更改 OUTPUT 格式可能會更改當前設定的 CAPTURE 格式。如何確定新的 CAPTURE 格式由解碼器決定,客戶端必須確保之後滿足其需求。

  2. 透過 OUTPUT 上的 VIDIOC_REQBUFS() 分配源(位元組流)緩衝區。

    • 必填欄位

      count

      請求分配的緩衝區數量;大於零。

      type

      適用於 OUTPUTV4L2_BUF_TYPE_* 列舉。

      memory

      遵循標準語義。

    • 返回欄位

      count

      實際分配的緩衝區數量。

    Warning

    實際分配的緩衝區數量可能與給定的 count 不同。客戶端必須在呼叫返回後檢查 count 的更新值。

    或者,可以使用 OUTPUT 佇列上的 VIDIOC_CREATE_BUFS() 來更好地控制緩衝區分配。

    • 必填欄位

      count

      請求分配的緩衝區數量;大於零。

      type

      適用於 OUTPUTV4L2_BUF_TYPE_* 列舉。

      memory

      遵循標準語義。

      format

      遵循標準語義。

    • 返回欄位

      count

      調整為分配的緩衝區數量。

    Warning

    實際分配的緩衝區數量可能與給定的 count 不同。客戶端必須在呼叫返回後檢查 count 的更新值。

  3. 透過 VIDIOC_STREAMON()OUTPUT 佇列上啟動流。

  4. 此步驟僅適用於在流中包含解析度資訊的編碼格式。 繼續透過 VIDIOC_QBUF()VIDIOC_DQBUF() 將位元組流緩衝區排隊/出隊到/從 OUTPUT 佇列。將處理緩衝區並按順序返回給客戶端,直到找到配置 CAPTURE 佇列所需的元資料。這由解碼器傳送 V4L2_EVENT_SOURCE_CHANGE 事件指示,其中 changes 設定為 V4L2_EVENT_SRC_CH_RESOLUTION

    • 如果第一個緩衝區沒有包含足夠的資料來發生這種情況,則不會出錯。只要需要更多資料,緩衝區的處理就會繼續。

    • 如果需要觸發事件的緩衝區中的資料來解碼第一幀,則在初始化序列完成並解碼幀之前,不會將其返回給客戶端。

    • 如果客戶端沒有自己設定流的編碼解析度,則在 CAPTURE 佇列上呼叫 VIDIOC_G_FMT()VIDIOC_S_FMT()VIDIOC_TRY_FMT()VIDIOC_REQBUFS() 不會返回流的實際值,直到發出 V4L2_EVENT_SOURCE_CHANGE 事件,其中 changes 設定為 V4L2_EVENT_SRC_CH_RESOLUTION

    Important

    在解碼器將事件排隊後發出的任何客戶端查詢都將返回適用於剛剛解析的流的值,包括佇列格式、選擇矩形和控制元件。

    Note

    有能力從位元組流中自行獲取流引數的客戶端可以嘗試將 OUTPUT 格式的寬度和高度設定為與流的編碼大小匹配的非零值,跳過此步驟並繼續執行捕獲設定序列。但是,它不能依賴任何關於流引數的驅動程式查詢,例如選擇矩形和控制元件,因為解碼器尚未從流中解析它們。如果客戶端配置的值與解碼器解析的值不匹配,則將觸發動態解析度更改以重新配置它們。

    Note

    在此階段不會生成解碼幀。

  5. 繼續執行捕獲設定序列。

4.5.1.6. 捕獲設定

  1. CAPTURE 佇列上呼叫 VIDIOC_G_FMT() 以獲取從位元組流中解析/解碼的目標緩衝區的格式。

    • 必填欄位

      type

      適用於 CAPTUREV4L2_BUF_TYPE_* 列舉。

    • 返回欄位

      width, height

      解碼幀的幀緩衝區解析度。

      pixelformat

      解碼幀的畫素格式。

      num_planes(僅適用於 _MPLANE type

      畫素格式的平面數量。

      sizeimage, bytesperline

      按照標準語義;匹配幀緩衝區格式。

    Note

    pixelformat 的值可以是解碼器為當前流支援的任何畫素格式。解碼器應為預設配置選擇首選/最佳格式。例如,如果後者需要額外的轉換步驟,則 YUV 格式可能優於 RGB 格式。

  2. 可選。 透過 VIDIOC_G_SELECTION() 獲取可見解析度。

    • 必填欄位

      type

      適用於 CAPTUREV4L2_BUF_TYPE_* 列舉。

      target

      設定為 V4L2_SEL_TGT_COMPOSE

    • 返回欄位

      r.left, r.top, r.width, r.height

      可見矩形;它必須適合 CAPTUREVIDIOC_G_FMT() 返回的幀緩衝區解析度。

    • 以下選擇目標在 CAPTURE 上受支援

      V4L2_SEL_TGT_CROP_BOUNDS

      對應於流的編碼解析度。

      V4L2_SEL_TGT_CROP_DEFAULT

      覆蓋 CAPTURE 緩衝區中包含有意義的圖片資料(可見區域)的部分的矩形;寬度和高度將等於流的可見解析度。

      V4L2_SEL_TGT_CROP

      要輸出到 CAPTURE 的編碼解析度內的矩形;預設為 V4L2_SEL_TGT_CROP_DEFAULT;在沒有額外合成/縮放功能的硬體上是隻讀的。

      V4L2_SEL_TGT_COMPOSE_BOUNDS

      裁剪幀可以合成到 CAPTURE 緩衝區中的最大矩形;如果硬體不支援合成/縮放,則等於 V4L2_SEL_TGT_CROP

      V4L2_SEL_TGT_COMPOSE_DEFAULT

      等於 V4L2_SEL_TGT_CROP

      V4L2_SEL_TGT_COMPOSE

      CAPTURE 緩衝區內寫入裁剪幀的矩形;預設為 V4L2_SEL_TGT_COMPOSE_DEFAULT;在沒有額外合成/縮放功能的硬體上是隻讀的。

      V4L2_SEL_TGT_COMPOSE_PADDED

      CAPTURE 緩衝區內被硬體覆蓋的矩形;如果硬體不寫入填充畫素,則等於 V4L2_SEL_TGT_COMPOSE

    Warning

    僅當解碼器成功解析流元資料後,才能保證這些值有意義。客戶端在此之前不得依賴查詢。

  3. 可選。 透過 CAPTURE 佇列上的 VIDIOC_ENUM_FMT() 列舉 CAPTURE 格式。一旦解析並知道流資訊,客戶端就可以使用此 ioctl 來發現給定流支援哪些原始格式,並透過 VIDIOC_S_FMT() 選擇其中一種格式。

    Important

    解碼器將僅返回當前建立的編碼格式支援的格式,按照 OUTPUT 格式和/或在此初始化序列中解析的流元資料,即使解碼器通常可能支援更多格式。換句話說,返回的集合將是查詢功能部分中提到的初始查詢的子集。

    例如,解碼器可能支援 1920x1088 及更低解析度的 YUV 和 RGB 格式,但僅支援更高解析度的 YUV(由於硬體限制)。在解析 1920x1088 或更低解析度後,VIDIOC_ENUM_FMT() 可能會返回一組 YUV 和 RGB 畫素格式,但在解析高於 1920x1088 的解析度後,解碼器將不會返回此解析度不支援的 RGB。

    但是,在發現同一流中的解析度更改後觸發的後續解析度更改事件可能會將流切換到較低的解析度,並且在這種情況下,VIDIOC_ENUM_FMT() 將再次返回 RGB 格式。

  4. 可選。 透過 CAPTURE 佇列上的 VIDIOC_S_FMT() 設定 CAPTURE 格式。客戶端可以選擇與解碼器在 VIDIOC_G_FMT() 中選擇/建議的格式不同的格式。

    • 必填欄位

      type

      適用於 CAPTUREV4L2_BUF_TYPE_* 列舉。

      pixelformat

      原始畫素格式。

      width, height

      解碼流的幀緩衝區解析度;通常與 VIDIOC_G_FMT() 返回的解析度相同,但如果硬體支援合成和/或縮放,則可能會有所不同。

  • 設定 CAPTURE 格式會將合成選擇矩形重置為基於新解析度的預設值,如前一步所述。

  1. 可選。 如果需要並且解碼器具有合成和/或縮放功能,則透過 CAPTURE 佇列上的 VIDIOC_S_SELECTION() 設定合成矩形。

    • 必填欄位

      type

      適用於 CAPTUREV4L2_BUF_TYPE_* 列舉。

      target

      設定為 V4L2_SEL_TGT_COMPOSE

      r.left, r.top, r.width, r.height

      CAPTURE 緩衝區內寫入裁剪幀的矩形;預設為 V4L2_SEL_TGT_COMPOSE_DEFAULT;在沒有額外合成/縮放功能的硬體上是隻讀的。

    • 返回欄位

      r.left, r.top, r.width, r.height

      可見矩形;它必須適合 CAPTUREVIDIOC_G_FMT() 返回的幀緩衝區解析度。

    Warning

    解碼器可能會將合成矩形調整為最接近支援的矩形,以滿足編解碼器和硬體要求。客戶端需要檢查 VIDIOC_S_SELECTION() 返回的調整後的矩形。

  2. 如果滿足以下所有條件,客戶端可以立即恢復解碼

    • 新格式的 sizeimage(在前幾步中確定)小於或等於當前分配的緩衝區的大小,

    • 當前分配的緩衝區數量大於或等於先前步驟中獲取的最小緩衝區數量。為了滿足此要求,客戶端可以使用 VIDIOC_CREATE_BUFS() 新增新緩衝區。

    在這種情況下,其餘步驟不適用,客戶端可以透過以下操作之一恢復解碼

    • 如果 CAPTURE 佇列正在流式傳輸,則呼叫帶有 V4L2_DEC_CMD_START 命令的 VIDIOC_DECODER_CMD()

    • 如果 CAPTURE 佇列未流式傳輸,則在 CAPTURE 佇列上呼叫 VIDIOC_STREAMON()

    但是,如果客戶端打算更改緩衝區集,以降低記憶體使用率或出於任何其他原因,可以透過以下步驟實現。

  3. 如果 CAPTURE 佇列正在流式傳輸, 則繼續在 CAPTURE 佇列上排隊和出隊緩衝區,直到出隊帶有 V4L2_BUF_FLAG_LAST 標誌的緩衝區。

  4. 如果 CAPTURE 佇列正在流式傳輸, 則在 CAPTURE 佇列上呼叫 VIDIOC_STREAMOFF() 以停止流式傳輸。

    Warning

    OUTPUT 佇列必須保持流式傳輸。在其上呼叫 VIDIOC_STREAMOFF() 將中止序列並觸發查詢。

  5. 如果 CAPTURE 佇列已分配緩衝區, 則使用 VIDIOC_REQBUFS() 釋放 CAPTURE 緩衝區。

    • 必填欄位

      count

      設定為 0。

      type

      適用於 CAPTUREV4L2_BUF_TYPE_* 列舉。

      memory

      遵循標準語義。

  6. 透過 CAPTURE 佇列上的 VIDIOC_REQBUFS() 分配 CAPTURE 緩衝區。

    • 必填欄位

      count

      請求分配的緩衝區數量;大於零。

      type

      適用於 CAPTUREV4L2_BUF_TYPE_* 列舉。

      memory

      遵循標準語義。

    • 返回欄位

      count

      實際分配的緩衝區數量。

    Warning

    實際分配的緩衝區數量可能與給定的 count 不同。客戶端必須在呼叫返回後檢查 count 的更新值。

    Note

    為了分配多於最小數量的緩衝區(用於管道深度),客戶端可以查詢 V4L2_CID_MIN_BUFFERS_FOR_CAPTURE 控制元件以獲取所需的最小緩衝區數量,並將獲得的值加上 VIDIOC_REQBUFS()count 欄位中所需的額外緩衝區數量。

    或者,可以使用 VIDIOC_CREATE_BUFS()CAPTURE 佇列上更靈活地控制緩衝區分配。例如,透過分配比當前 CAPTURE 格式更大的緩衝區,可以適應未來的解析度更改。

    • 必填欄位

      count

      請求分配的緩衝區數量;大於零。

      type

      適用於 CAPTUREV4L2_BUF_TYPE_* 列舉。

      memory

      遵循標準語義。

      format

      一種格式,表示新分配的緩衝區可以容納的最大幀緩衝區解析度。

    • 返回欄位

      count

      調整為分配的緩衝區數量。

    Warning

    實際分配的緩衝區數量可能與給定的 count 不同。客戶端必須在呼叫返回後檢查 count 的更新值。

    Note

    要為與從流元資料解析的格式不同的格式分配緩衝區,客戶端必須在啟動元資料解析之前按以下步驟操作

    • OUTPUT 格式的寬度和高度設定為所需的編碼解析度,以便解碼器正確配置 CAPTURE 格式,

    • 使用 VIDIOC_G_FMT() 查詢 CAPTURE 格式,並將其儲存到此步驟。

    查詢中獲得的格式可以與此步驟中的 VIDIOC_CREATE_BUFS() 一起使用以分配緩衝區。

  7. CAPTURE 佇列上呼叫 VIDIOC_STREAMON() 以啟動幀解碼。

4.5.1.7. 解碼

成功完成“採集設定”序列後,將達到此狀態。在此狀態下,客戶端透過 VIDIOC_QBUF()VIDIOC_DQBUF() 將緩衝區排隊和出隊到兩個佇列,遵循標準語義。

OUTPUT 緩衝區的內容取決於活動的編碼畫素格式,並且可能受到編解碼器特定的擴充套件控制的影響,如每種格式的文件中所述。

兩個佇列獨立執行,遵循 V4L2 緩衝區佇列和記憶體到記憶體裝置的標準行為。此外,由於所選編碼格式的屬性(例如幀重新排序),從 CAPTURE 佇列中出隊的解碼幀的順序可能與編碼幀排隊到 OUTPUT 佇列的順序不同。

客戶端不得假設 CAPTUREOUTPUT 緩衝區之間存在任何直接關係,以及緩衝區變為可出隊的任何特定時間。具體來說

  • 排隊到 OUTPUT 的緩衝區可能不會在 CAPTURE 上產生任何緩衝區(例如,如果它不包含編碼資料,或者如果其中只存在元資料語法結構),

  • 排隊到 OUTPUT 的緩衝區可能會在 CAPTURE 上產生多個緩衝區(如果編碼資料包含多個幀,或者如果返回解碼幀允許解碼器返回在解碼中位於其之前,但在顯示順序中位於其之後的幀),

  • 排隊到 OUTPUT 的緩衝區可能會導致緩衝區在稍後的解碼過程中和/或在處理其他 OUTPUT 緩衝區之後在 CAPTURE 上產生,或者亂序返回,例如,如果使用顯示重新排序,

  • 緩衝區可能會在沒有額外緩衝區排隊到 OUTPUT 的情況下在 CAPTURE 佇列上變為可用(例如,在排空或 EOS 期間),這是因為過去排隊的 OUTPUT 緩衝區的解碼結果僅在稍後時間可用,這是由於解碼過程的特殊性。

Note

為了允許將解碼的 CAPTURE 緩衝區與它們所源自的 OUTPUT 緩衝區匹配,客戶端可以在排隊 OUTPUT 緩衝區時設定 v4l2_buffer 結構體的 timestamp 欄位。由解碼該 OUTPUT 緩衝區產生的 CAPTURE 緩衝區將在出隊時將其 timestamp 欄位設定為相同的值。

除了一個 OUTPUT 緩衝區產生一個 CAPTURE 緩衝區的簡單情況之外,還定義了以下情況

  • 一個 OUTPUT 緩衝區生成多個 CAPTURE 緩衝區:相同的 OUTPUT 時間戳將被複制到多個 CAPTURE 緩衝區。

  • 多個 OUTPUT 緩衝區生成一個 CAPTURE 緩衝區:將複製第一個排隊的 OUTPUT 緩衝區的時間戳。

  • 解碼順序與顯示順序不同(即,CAPTURE 緩衝區與 OUTPUT 緩衝區相比是亂序的):CAPTURE 時間戳將不保留 OUTPUT 時間戳的順序。

Note

用作流的參考幀的 CAPTURE 緩衝區的後備記憶體甚至可以在它們出隊後被硬體讀取。因此,客戶端應避免在 CAPTURE 佇列正在流式傳輸時寫入此記憶體。不遵守此規定可能會導致解碼幀損壞。

類似地,當使用 V4L2_MEMORY_MMAP 以外的記憶體型別時,客戶端應確保每個 CAPTURE 緩衝區始終以相同的後備記憶體排隊,只要 CAPTURE 佇列正在流式傳輸。原因是 V4L2 緩衝區索引可以被驅動程式用來識別幀。因此,如果在不同的緩衝區 ID 下提交參考幀的後備記憶體,則驅動程式可能會錯誤地識別它並將新幀解碼到其中,而該幀仍在被使用,從而導致以下幀損壞。

在解碼期間,解碼器可能會啟動以下列出的特殊序列之一。這些序列將導致解碼器返回所有 CAPTURE 緩衝區,這些緩衝區源自序列開始之前處理的所有 OUTPUT 緩衝區。最後一個緩衝區將設定 V4L2_BUF_FLAG_LAST 標誌。為了確定要遵循的序列,客戶端必須檢查是否存在任何掛起的事件,並且

  • 如果存在 V4L2_EVENT_SOURCE_CHANGE 事件,其中 changes 設定為 V4L2_EVENT_SRC_CH_RESOLUTION,則需要遵循“動態解析度更改”序列,

  • 如果存在 V4L2_EVENT_EOS 事件,則需要遵循“流結束”序列。

某些序列可以相互混合,並且需要按發生的情況進行處理。每個序列的確切操作都有文件記錄。

如果發生解碼錯誤,將向客戶端報告,詳細程度取決於解碼器的功能。具體來說

  • 包含失敗的解碼操作結果的 CAPTURE 緩衝區將返回,並設定 V4L2_BUF_FLAG_ERROR 標誌,

  • 如果解碼器能夠精確地報告觸發錯誤的 OUTPUT 緩衝區,則此類緩衝區將返回,並設定 V4L2_BUF_FLAG_ERROR 標誌。

如果發生不允許繼續解碼的致命故障,則對相應解碼器檔案控制代碼的任何進一步操作都將返回 -EIO 錯誤程式碼。客戶端可以關閉檔案控制代碼並開啟一個新控制代碼,或者透過停止兩個佇列上的流式傳輸、釋放所有緩衝區並再次執行初始化序列來重新初始化例項。

4.5.1.8. 搜尋

搜尋由 OUTPUT 佇列控制,因為它是編碼資料的來源。搜尋不需要對 CAPTURE 佇列執行任何特定操作,但可能會按照正常的解碼器操作受到影響。

  1. 透過 VIDIOC_STREAMOFF() 停止 OUTPUT 佇列以開始搜尋序列。

    • 必填欄位

      type

      適用於 OUTPUTV4L2_BUF_TYPE_* 列舉。

    • 解碼器將刪除所有掛起的 OUTPUT 緩衝區,並且必須將它們視為返回給客戶端(遵循標準語義)。

  2. 透過 VIDIOC_STREAMON() 重新啟動 OUTPUT 佇列。

    • 必填欄位

      type

      適用於 OUTPUTV4L2_BUF_TYPE_* 列舉。

    • 呼叫返回後,解碼器將開始接受新的源位元組流緩衝區。

  3. 在搜尋到 OUTPUT 佇列之後,開始排隊包含編碼資料的緩衝區,直到找到合適的恢復點。

    Note

    沒有要求從恢復點(例如 SPS 或關鍵幀)開始精確地排隊編碼資料。任何排隊的 OUTPUT 緩衝區都將被處理並返回給客戶端,直到找到合適的恢復點。在尋找恢復點時,解碼器不應在 CAPTURE 緩衝區中生成任何解碼幀。

    已知某些硬體會錯誤地處理搜尋到非恢復點的情況。此類操作可能會導致在 CAPTURE 佇列上提供未指定數量的損壞的解碼幀。驅動程式必須確保不會發生致命的解碼錯誤或崩潰,並實現任何必要的處理和解決方法來解決與搜尋操作相關的硬體問題。

    Warning

    對於 H.264/HEVC 編解碼器,客戶端必須注意不要搜尋 SPS/PPS 的更改。即使目標幀可能是關鍵幀,解碼器狀態中的陳舊 SPS/PPS 也會導致解碼時出現不確定的結果。儘管解碼器必須在沒有崩潰或致命解碼錯誤的情況下處理這種情況,但客戶端不得期望有合理的解碼輸出。

    如果硬體可以檢測到此類損壞的解碼幀,則相應的緩衝區將返回給客戶端,並設定 V4L2_BUF_FLAG_ERROR。有關解碼錯誤報告的進一步說明,請參見“解碼”部分。

  4. 找到恢復點後,解碼器將開始返回包含解碼幀的 CAPTURE 緩衝區。

Important

搜尋可能會導致啟動“動態解析度更改”序列,這是因為搜尋目標具有與搜尋之前解碼的流部分不同的解碼引數。該序列必須按照正常的解碼器操作進行處理。

Warning

未指定 CAPTURE 佇列何時開始生成包含來自搜尋後排隊的 OUTPUT 緩衝區的解碼資料的緩衝區,因為它與 OUTPUT 佇列獨立執行。

解碼器可能會返回許多剩餘的 CAPTURE 緩衝區,這些緩衝區包含源自搜尋序列執行之前排隊的 OUTPUT 緩衝區的解碼幀。

VIDIOC_STREAMOFF 操作會丟棄任何剩餘的排隊 OUTPUT 緩衝區,這意味著並非所有在搜尋序列之前排隊的 OUTPUT 緩衝區都可能生成匹配的 CAPTURE 緩衝區。例如,給定 OUTPUT 佇列上的操作序列

QBUF(A)、QBUF(B)、STREAMOFF()、STREAMON()、QBUF(G)、QBUF(H),

允許在 CAPTURE 佇列上執行以下任何結果

{A’、B’、G’、H’}、{A’、G’、H’}、{G’、H’}。

為了確定包含搜尋後第一個解碼幀的 CAPTURE 緩衝區,客戶端可以觀察時間戳以匹配 CAPTURE 和 OUTPUT 緩衝區,或者使用 V4L2_DEC_CMD_STOP 和 V4L2_DEC_CMD_START 來排空解碼器。

Note

為了實現即時搜尋,客戶端也可以重新啟動 CAPTURE 佇列上的流式傳輸,以丟棄已解碼但尚未出隊的緩衝區。

4.5.1.9. 動態解析度更改

在位元組流中包含解析度元資料的流可能需要在解碼期間切換到不同的解析度。

Note

並非所有解碼器都能檢測到解析度更改。那些能夠檢測到的解碼器會在呼叫 VIDIOC_ENUM_FMT() 時為編碼格式設定 V4L2_FMT_FLAG_DYN_RESOLUTION 標誌。

當解碼器檢測到編碼幀具有與先前建立的幀不同的以下一個或多個引數(並由相應的查詢反映)時,該序列開始

  • 編碼解析度(OUTPUT 寬度和高度),

  • 可見解析度(選擇矩形),

  • 解碼所需的最小緩衝區數,

  • 位元流的位深已更改。

每當發生這種情況時,解碼器必須按如下方式進行

  1. 在流中遇到解析度更改後,解碼器會發送一個 V4L2_EVENT_SOURCE_CHANGE 事件,其中 changes 設定為 V4L2_EVENT_SRC_CH_RESOLUTION

    Important

    在解碼器對事件進行排隊之後發出的任何客戶端查詢都將返回適用於解析度更改後流的值,包括佇列格式、選擇矩形和控制元件。

  2. 然後,解碼器將處理和解碼解析度更改點之前的所有剩餘緩衝區。

    • 來自更改之前的最後一個緩衝區必須使用 V4L2_BUF_FLAG_LAST 標誌標記,類似於上面的“排空”序列。

    Warning

    最後一個緩衝區可能為空(v4l2_buffer bytesused = 0),在這種情況下,客戶端必須忽略它,因為它不包含解碼幀。

    Note

    任何嘗試將更多 CAPTURE 緩衝區出隊到標記有 V4L2_BUF_FLAG_LAST 的緩衝區之外的嘗試都將導致來自 VIDIOC_DQBUF() 的 -EPIPE 錯誤。

客戶端必須按照以下描述繼續該序列以繼續解碼過程。

  1. 使源更改事件出隊。

    Important

    源更改會觸發隱式解碼器排空,類似於顯式“排空”序列。解碼器在完成後停止。必須透過在 CAPTURE 佇列上呼叫一對 VIDIOC_STREAMOFF()VIDIOC_STREAMON(),或者使用 V4L2_DEC_CMD_START 命令呼叫 VIDIOC_DECODER_CMD() 來恢復解碼過程。

  2. 繼續執行捕獲設定序列。

Note

在解析度更改序列期間,OUTPUT 佇列必須保持流式傳輸。在 OUTPUT 佇列上呼叫 VIDIOC_STREAMOFF() 將中止序列並啟動搜尋。

原則上,OUTPUT 佇列與 CAPTURE 佇列分開執行,並且這在整個解析度更改序列期間仍然成立。

客戶端應該為了獲得最佳效能和簡單性,甚至在處理此序列時也保持將緩衝區排隊/從 OUTPUT 隊列出隊。

4.5.1.10. 排空

為了確保已處理所有排隊的 OUTPUT 緩衝區,並且相關的 CAPTURE 緩衝區已提供給客戶端,客戶端必須遵循下面描述的排空序列。在排空序列結束後,客戶端已收到在序列開始之前排隊的所有 OUTPUT 緩衝區的全部解碼幀。

  1. 透過發出 VIDIOC_DECODER_CMD() 開始排空。

    • 必填欄位

      cmd

      設定為 V4L2_DEC_CMD_STOP

      flags

      設定為 0。

      pts

      設定為 0。

    Warning

    只有當 OUTPUTCAPTURE 佇列都在流式傳輸時,才能啟動該序列。出於相容性原因,即使任何一個佇列未流式傳輸,對 VIDIOC_DECODER_CMD() 的呼叫也不會失敗,但同時它不會啟動“排空”序列,因此下面描述的步驟將不適用。

  2. 客戶端在發出 VIDIOC_DECODER_CMD() 之前排隊的任何 OUTPUT 緩衝區都將像往常一樣被處理和解碼。客戶端必須繼續獨立處理兩個佇列,類似於正常的解碼操作。這包括

    • 在繼續排空序列之前,處理由於處理這些緩衝區而觸發的任何操作,例如“動態解析度更改”序列,

    • 排隊和出隊 CAPTURE 緩衝區,直到出隊標記有 V4L2_BUF_FLAG_LAST 標誌的緩衝區,

      Warning

      最後一個緩衝區可能為空(v4l2_buffer bytesused = 0),在這種情況下,客戶端必須忽略它,因為它不包含解碼幀。

      Note

      任何嘗試將更多 CAPTURE 緩衝區出隊到標記有 V4L2_BUF_FLAG_LAST 的緩衝區之外的嘗試都將導致來自 VIDIOC_DQBUF() 的 -EPIPE 錯誤。

    • 出隊已處理的 OUTPUT 緩衝區,直到所有在 V4L2_DEC_CMD_STOP 命令之前排隊的緩衝區都出隊,

    • 如果客戶端訂閱了 V4L2_EVENT_EOS 事件,則出隊該事件。

    Note

    為了向後相容,當最後一個幀已被解碼並且所有幀都已準備好出隊時,解碼器將發出 V4L2_EVENT_EOS 事件的訊號。這是一種已棄用的行為,客戶端不得依賴它。應該改用 V4L2_BUF_FLAG_LAST 緩衝區標誌。

  3. 一旦出隊了所有在呼叫 V4L2_DEC_CMD_STOP 之前排隊的 OUTPUT 緩衝區,並且最後一個 CAPTURE 緩衝區已出隊,解碼器將停止並且它將接受但不會處理任何新排隊的 OUTPUT 緩衝區,直到客戶端發出以下任何操作

    • V4L2_DEC_CMD_START - 解碼器不會被重置並且將正常恢復操作,並保留排空之前的所有狀態,

    • CAPTURE 佇列上的一對 VIDIOC_STREAMOFF()VIDIOC_STREAMON() - 解碼器將正常恢復操作,但是佇列中仍有的任何 CAPTURE 緩衝區都將返回給客戶端,

    • OUTPUT 佇列上的一對 VIDIOC_STREAMOFF()VIDIOC_STREAMON() - 任何掛起的源緩衝區都將返回給客戶端,並且將觸發“搜尋”序列。

Note

一旦啟動排空序列,客戶端就需要將其驅動到完成,如上面的步驟所述,除非它透過在任何 OUTPUTCAPTURE 佇列上發出 VIDIOC_STREAMOFF() 來中止該過程。不允許客戶端在排空序列正在進行時再次發出 V4L2_DEC_CMD_STARTV4L2_DEC_CMD_STOP,並且如果嘗試這樣做,它們將失敗並顯示 -EBUSY 錯誤程式碼。

儘管不是強制性的,但可以使用 VIDIOC_TRY_DECODER_CMD() 查詢解碼器命令的可用性。

4.5.1.11. 流結束

如果解碼器在流中遇到流結束標記,則解碼器將啟動“排空”序列,客戶端必須按照上面的描述處理該序列,跳過初始 VIDIOC_DECODER_CMD()

4.5.1.12. 提交點

設定格式和分配緩衝區會觸發解碼器行為的更改。

  1. OUTPUT 佇列上設定格式可能會更改在 CAPTURE 佇列上支援/公佈的格式集。特別是,它也意味著 CAPTURE 格式可能會被重置,並且客戶端不得依賴於先前設定的格式被保留。

  2. CAPTURE 佇列上列舉格式始終僅返回當前 OUTPUT 格式支援的格式。

  3. CAPTURE 佇列上設定格式不會更改 OUTPUT 佇列上可用的格式列表。嘗試設定不支援當前選擇的 OUTPUT 格式的 CAPTURE 格式將導致解碼器將請求的 CAPTURE 格式調整為支援的格式。

  4. OUTPUT 佇列上列舉格式始終返回完整的支援編碼格式集,而與當前的 CAPTURE 格式無關。

  5. 當在任何 OUTPUTCAPTURE 佇列上分配緩衝區時,客戶端不得更改 OUTPUT 佇列上的格式。對於任何此類格式更改嘗試,驅動程式將返回 -EBUSY 錯誤程式碼。

總而言之,設定格式和分配必須始終從 OUTPUT 佇列開始,並且 OUTPUT 佇列是管理 CAPTURE 佇列的支援格式集的主佇列。