這很重要
稍後在本主題中討論的自動校正方法是針對相機感應器非正常方向安裝的推薦解決方案。 這是為了確保應用程式的相容性,因為大多數已經編寫為使用相機鏡頭的程式,不知道要檢查或修正旋轉資訊。 請仔細查看下面自動更正部分中的信息。
隨著不同外形尺寸的計算設備的推出,一些物理限制導致相機傳感器以非傳統方向安裝。 因此,有必要向作業系統和應用程式正確描述如何安裝感測器,以便正確呈現/錄製產生的視訊。
從 Window 10 版本 1607 開始,無論相機是否根據 最低硬體需求掛接,所有相機驅動程式都必須明確指定相機方向。 具體而言,相機驅動程式必須在與擷取裝置介面相關聯的 ACPI _PLD 結構中設定新引進的欄位 Rotation:
typedef struct _ACPI_PLD_V2_BUFFER {
UINT32 Revision:7;
UINT32 IgnoreColor:1;
UINT32 Color:24;
// …
UINT32 Panel:3; // Already supported by camera.
// …
UINT32 CardCageNumber:8;
UINT32 Reference:1;
UINT32 Rotation:4; // 0 – Rotate by 0° clockwise
// 1 – Rotate by 45° clockwise (N/A to camera)
// 2 – Rotate by 90° clockwise
// 3 – Rotate by 135° clockwise (N/A to camera)
// 4 – Rotate by 180° clockwise
// 5 – Rotate by 225° clockwise (N/A to camera)
// 6 – Rotate by 270° clockwise
UINT32 Order:5;
UINT32 Reserved:4;
//
// _PLD v2 definition fields.
//
USHORT VerticalOffset;
USHORT HorizontalOffset;
} ACPI_PLD_V2_BUFFER, *PACPI_PLD_V2_BUFFER;
針對相機,ACPI _PLD結構中的 [旋轉] 欄位會指定度數 ('0' 代表 0°、'2' 代表 90°、'4' 代表 180°,'6' 代表 270°) 當顯示器處於其原生方向時,擷取的畫面會相對於螢幕旋轉。
根據 [旋轉] 欄位中的值,應用程式可以視需要執行其他旋轉,以正確轉譯擷取的畫面。
旋轉值
對於那些相機和顯示器共用相同外殼的設備,可以將這些外圍設備安裝在不同的表面上,每個設備在各自的平面上以固定但任意的度數進行旋轉。 因此,應用程式需要一種機制來描述兩個周邊裝置之間的空間關聯性,以便以正確的方向將捕獲的幀轉置到轉譯介面上。
解決此問題的其中一種方法是使用 ACPI _PLD結構,該結構已定義 表面 和 旋轉度 的概念。 例如,_PLD結構已經具有 面板 欄位,該欄位指定周邊裝置所在的表面:
ACPI _PLD 面板欄位的定義 (修訂版 5.0a)
接下來的兩個圖表直觀地說明了每個面板的定義:
桌上型電腦和大部分裝置的面板定義
摺疊式裝置的面板定義
事實上,Windows 已經採用了 ACPI「面板」的概念,其中:
相機裝置介面與_PLD結構相關聯,如果擷取裝置靜態掛載在固定位置,則會相應地設定 Panel 欄位。
應用程式可以呼叫 Windows.Devices.Enumeration.DeviceInformation.EnclosureLocation.Panel 屬性來擷取擷取裝置所在的面板。
ACPI _PLD 結構中也定義了一個 Rotation 欄位,如下:
ACPI _PLD 輪換欄位的定義 (Rev 5.0a)
我們沒有按原樣使用上述定義,而是進一步完善它以避免歧義:
- 針對相機,ACPI _PLD結構中的 [旋轉] 欄位會指定度數 ('0' 代表 0°、'2' 代表 90°、'4' 代表 180°,'6' 代表 270°) 當顯示器處於其原生方向時,擷取的畫面會相對於螢幕旋轉。
橫向優先 vs 縱向優先
在 Windows 中,可以呼叫屬性 Windows.Graphics.Display.DisplayInformation.NativeOrientation 來查詢原生顯示方向,該屬性會傳回 Landscape 或Portrait:
無論 NativeOrientation 傳回哪個值,邏輯顯示掃描模式都會從顯示器的左上角開始,從左到右向下移動 (請參閱圖 5) 。 對於預設實體方向不明確的裝置,此屬性不僅表示 ACPI 頂端 面板的位置,也提供相機輸出緩衝區與轉譯介面之間的空間關聯性。
請注意,與相機不同, NativeOrientation 屬性不是以 ACPI 為基礎,因此沒有_PLD結構。 即使顯示器靜態掛載到裝置上也是如此。
當安裝在以直向為主的裝置上時,相機驅動程式必須知道,多數應用程式會將裝置視為輸出橫向相機緩衝區,不論相機實際的輸出緩衝區方向。 因此,我們建議相機驅動程序在 Portrait 主要裝置上,輸出與 NativeOrientation Portrait 具有 90 度方向位移的相機緩衝區。 然後,這可以讓原本在直向裝置上執行額外旋轉的應用程式將旋轉校正到預期的方向。 這可以使用 具有旋轉範例的相機應用程式進行驗證。
偏置安裝
強烈建議 IHV/OEM 避免將感測器掛接在非 0 度位移中,以維護應用程式相容性。 許多現有和舊版應用程式不知道要尋找 ACPI 的 PLD 數據表,也不會嘗試更正非 0 度位移。 因此,對於此類應用程序,生成的視頻將被錯誤地呈現。
如果 IHV/OEM 無法如上所述以 0 度方向掛接感測器,建議依喜好設定順序執行下列風險降低步驟:
自動更正相機驅動程式內的非 0 度方向 (在核心模式中使用 AV 串流迷你埠驅動程式,或在使用者模式中使用外掛程式,例如裝置 MFT 或 MFT0) ,讓產生的輸出畫面處於 0 度方向。
透過 FSSensorOrientation 標籤宣告非 0 度方向,讓相機管線可以修正擷取的影像。
如上所述,在 ACPI 的 PLD 數據表中宣告非 0 度方向。
壓縮/編碼媒體類型
對於壓縮和/或編碼的媒體類型(例如 MJPG、JPEG、H264、HEVC),無法使用管道校正。 因此,如果 FSSensorOrientation 設定為非零值,則會篩選出壓縮/編碼的媒體類型。
在 MJPG 媒體類型的情況下 (例如來自 UVC 相機的媒體類型) ,框架伺服器管線會提供自動解碼的媒體類型 (NV12 或 YUY2 適用於 DShow 型應用程式) 。 將顯示自動解碼和更正的媒體類型,但不會顯示原始 MJPG 格式。
[!筆記! 如果壓縮/編碼的媒體類型必須公開給應用程式,IHV/ODM 不得使用 FSSensorOrientation 更正。 相反地,更正必須由相機驅動程式完成 (透過 AV 串流驅動程式在核心模式中,或透過 DMFT/MFT0 在使用者模式中) 完成。
透過 AV 流迷你端口/裝置 MFT/MFT0 進行自動更正
如果感應器無法以 0 度位移掛接,建議的方案 是讓 AV 資料流迷你埠驅動程式(或以 DMFT 或 MFT0 形式存在的使用者模式外掛程式)修正擷取後的畫面,使其以 0 度位移傳遞至管線。
在更正來自 AV 資料流小埠和/或裝置 MFT/MFT0 插件的視訊畫面時,生成的媒體類型宣告必須以更正後的畫面為基礎。 如果感應器掛載在 90 度位移處,因此產生的視訊與感應器的外觀比例為 9:16,但更正的視訊會是 16:9,則媒體類型必須宣告 16:9 外觀比例。
這包括產生的步幅資訊。 這是必要的,因為負責執行更正的元件是由 IHV/OEM 控制,而且相機管線無法看到視訊畫面,除非已更正之後。
強烈建議在使用者模式下進行更正,並且必須遵循管道與使用者模式外掛程式之間的 API 合約。 具體而言,使用 DMFT 或 MFT0 時,當 IMFDeviceTransform::P rocessMessage 或 IMFTransform::P rocessMessage 與MFT_MESSAGE_SET_D3D_MANAGER訊息一起叫用時,使用者模式外掛程式必須遵守下列指導方針:
- 如果未提供 D3D 管理員 (訊息的 ulParam 為 0) ,使用者模式外掛程式不得叫用任何 GPU 作業來處理旋轉修正。 產生的影格必須存放於系統記憶體中。
- 如果提供 D3D 管理員 (訊息的 ulParam 是 DXGI 管理員的 IUnknown) ,則該 DXGI 管理員必須用於旋轉修正,而產生的畫面必須是 GPU 記憶體。
- 使用者模式外掛程式也必須在執行階段期間處理 D3D 管理員訊息。 發出MFT_MESSAGE_SET_D3D_MANAGER訊息時,外掛程式所產生的下一個畫面必須對應至要求的記憶體類型 (,也就是 GPU,如果提供 DXGI 管理員,否則為 CPU) 。
- 當 AV 流驅動程式(或使用者模式外掛程式)處理旋轉校正時,ACPI 的 PLD 結構中的旋轉欄位必須設定為 0。
備註
使用自動更正時,OEM 和 IHV 不得透過 [_PLD 旋轉 ] 欄位公告感應器的實際方向。 在此情況下, 「旋轉」 欄位必須指出校正後的方向:0 度。
透過 FSSensorOrientation 宣告
; Defines the sensor mounting orientation offset angle in
; degrees clockwise.
FSSensorOrientation: REG_DWORD: 90, 180, 270
藉由透過 FSSensorOrientation 登錄標籤宣告感應器的非 0 度方向,相機管線可以在將擷取的畫面呈現給應用程式之前更正它。
管線將根據使用案例和應用程式請求/案例,利用 GPU 或 CPU 資源來優化輪換邏輯。
ACPI PLD 輪替
ACPI PLD 結構的 [旋轉] 欄位必須是 0。 這是為了避免混淆可能使用 PLD 資訊來更正框架的應用程式。
媒體類型資訊
驅動程式所呈現的媒體類型必須是未更正的媒體類型。 使用 FSSensorOrientation 專案通知相機管線非 0 度位移時,感應器所呈現的媒體類型資訊必須是未更正的媒體類型。 例如,如果感應器以順時針偏移 90 度安裝,因此產生的影片顯示比例不是 16:9,而是 9:16,則必須將 9:16 的顯示比例媒體類型呈現給相機處理流程。
這是確保管線可以正確設定計數器旋轉程式的必要條件:管線需要應用程式的輸入媒體類型和所需的輸出媒體類型。
這包括步幅資訊。 必須將未修正的媒體類型的跨距資訊呈現至相機管線。
登錄子鍵
FSSensorOrientation 登錄項必須在裝置介面節點上公佈。 建議的方法是在相機驅動程式 INF 中的 AddInterface 指示詞宣告期間,將此宣告為 AddReg 指示詞。
FSSensorOrientation 中呈現的資料必須是REG_DWORD,而且唯一接受的有效值是 90、180 和 270。 任何其他值都會被視為 0 度偏移 (即忽略)。
每個值代表感測器方向,以順時針方向為單位。 相機管線將通過逆時針反旋轉視頻來糾正生成的視頻幀:即,順時針 90 度聲明將導致逆時針旋轉 90 度,以使生成的視頻幀恢復到 0 度偏移。
MS 作業系統描述符 1.0
對於 USB 型相機,FSSensorOrientation 也可以透過 MSOS 描述元發佈。
MS OS 描述符 1.0 有兩個元件:
- 固定長度標頭區段
- 一或多個可變長度的自定義屬性區段,其遵循標頭區段
MS OS 描述符 1.0 標頭區段
標頭區段描述單一自訂屬性 (臉部驗證設定檔) 。
| Offset | 領域 | 大小 (位元組) | 價值觀 | 說明 |
|---|---|---|---|---|
| 0 | dwLength | 4 | <> | |
| 4 | bcdVersion | 2 | 0x0100 | 1.0 版 |
| 6 | wIndex | 2 | 0x0005 | 擴充屬性OS描述元 |
| 8 | wCount | 2 | 0x0001 | 一個自定義屬性 |
自訂 MS OS DESCRIPTOR 1.0 屬性區段
| Offset | 領域 | 大小 (位元組) | 價值觀 | 說明 |
|---|---|---|---|---|
| 0 | dwSize | 4 | 0x00000036 (54) | 此屬性的總大小 (以位元組為單位)。 |
| 4 | dwPropertyDataType | 4 | 0x00000004 | REG_DWORD_LITTLE_ENDIAN |
| 8 | wPropertyNameLength | 2 | 0x00000024 (36) | 屬性名稱的大小 (以位元組為單位)。 |
| 10 | bPropertyName | 50 | UVC-FSSensorOrientation | Unicode 中的 “UVC-FSSensorOrientation” 字串。 |
| 六十 | dwPropertyDataLength | 4 | 0x00000004 | 屬性資料的 4 個位元組 (sizeof(DWORD))。 |
| 64 | bPropertyData | 4 | 順時針偏移角度(以度為單位)。 | 有效值為 90、180 和 270。 |
MS 作業系統描述符 2.0
MSOS 擴充描述元 2.0 可用來定義登錄值,以新增 FSSensorOrientation 支援。 這是使用 Microsoft OS 2.0 登錄屬性描述元完成的。
針對 UVC-FSSensorOrientation 登錄項目,下列顯示一個範例的 MSOS 2.0 描述子集:
UCHAR Example2_MSOS20DescriptorSet_UVCFSSensorOrientationForFutureWindows[0x3C] =
{
//
// Microsoft OS 2.0 Descriptor Set Header
//
0x0A, 0x00, // wLength - 10 bytes
0x00, 0x00, // MSOS20_SET_HEADER_DESCRIPTOR
0x00, 0x00, 0x0?, 0x06, // dwWindowsVersion – 0x060?0000 for future Windows version
0x4A, 0x00, // wTotalLength – 74 bytes
//
// Microsoft OS 2.0 Registry Value Feature Descriptor
//
0x40, 0x00, // wLength - 64 bytes
0x04, 0x00, // wDescriptorType – 4 for Registry Property
0x04, 0x00, // wPropertyDataType - 4 for REG_DWORD_LITTLE_ENDIAN
0x32, 0x00, // wPropertyNameLength – 50 bytes
0x55, 0x00, 0x56, 0x00, // Property Name - "UVC-FSSensorOrientation"
0x43, 0x00, 0x2D, 0x00,
0x46, 0x00, 0x53, 0x00,
0x53, 0x00, 0x65, 0x00,
0x6E, 0x00, 0x73, 0x00,
0x6F, 0x00, 0x72, 0x00,
0x4F, 0x00, 0x72, 0x00,
0x69, 0x00, 0x65, 0x00,
0x6E, 0x00, 0x74, 0x00,
0x61, 0x00, 0x74, 0x00,
0x69, 0x00, 0x6F, 0x00,
0x6E, 0x00, 0x00, 0x00,
0x00, 0x00,
0x04, 0x00, // wPropertyDataLength – 4 bytes
0x5A, 0x00, 0x00, 0x00 // PropertyData – 0x0000005A (90 degrees offset)
}
透過 ACPI PLD 資訊宣告
作為最後的選擇,可以如上所述利用 PLD 資訊,向應用程式指出在轉譯/編碼之前必須更正視訊影格。 不過,如前所述,許多現有應用程式不使用 PLD 資訊,也不處理畫面旋轉,因此在某些情況下,應用程式可能無法正確呈現產生的視訊。
下圖說明每個硬體組態的 _PLD Rotation 欄位值:
旋轉:順時針 0 度
在上圖中:
左圖說明了要捕捉的場景。
中間的圖片描繪了 CMOS 傳感器如何查看場景,其物理讀出順序從左下角開始,從左到右向上移動。
右圖代表相機驅動程式的輸出。 在此範例中,媒體緩衝區的內容可以直接轉譯,而顯示器是其原生方向,而不需要額外的旋轉。 因此,ACPI _PLD [輪替] 欄位的值為 0。
旋轉:順時針 90 度
在此情況下,媒體緩衝區的內容會相較於原始場景順時針旋轉 90 度。 因此,ACPI _PLD [輪替] 欄位的值為 2。
旋轉:順時針 180 度
在此情況下,媒體緩衝區的內容會相較於原始場景順時針旋轉 180 度。 因此,ACPI _PLD [輪替] 欄位的值為 4。
旋轉:順時針 270 度
在此情況下,媒體緩衝區的內容會相較於原始場景順時針旋轉 270 度。 因此,ACPI _PLD [輪替] 欄位的值為 6。