다음을 통해 공유


카메라 방향에 대한 드라이버 지원

중요

이 항목의 뒷부분에서 설명하는 자동 수정 방법은 카메라 센서의 비참조 방향 탑재에 권장 되는 솔루션입니다. 이는 카메라 피드를 사용하기 위해 이미 작성된 대부분의 애플리케이션이 검사 알지 못하거나 회전 정보를 수정할 수 없으므로 앱 호환성을 보장하기 위한 것입니다. 아래의 자동 수정 섹션에서 정보를 주의 깊게 검토하세요.

다양한 폼 팩터 컴퓨팅 디바이스가 도입됨에 따라 일부 물리적 제약 조건으로 인해 카메라 센서가 기존의 방향이 아닌 방향으로 탑재됩니다. 이 때문에 OS 및 애플리케이션에 센서를 탑재하여 결과 비디오를 제대로 렌더링/녹화할 수 있는 방법을 제대로 설명해야 합니다.

Windows 10 버전 1607부터 모든 카메라 드라이버는 최소 하드웨어 요구 사항에 따라 카메라가 탑재되었는지에 관계없이 카메라 방향을 명시적으로 지정해야 합니다. 특히 카메라 드라이버는 캡처 디바이스 인터페이스와 연결된 ACPI _PLD 구조에서 새로 도입된 필드 회전을 설정해야 합니다.

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', 90°의 경우 '2', 180°의 경우 '4', 270°의 경우 '6')를 지정합니다.

회전 필드의 값에 따라 애플리케이션은 캡처된 프레임을 올바르게 렌더링하기 위해 필요한 경우 추가 회전을 수행할 수 있습니다.

회전 값

카메라와 디스플레이가 동일한 하우징(또는 인클로저/대/소문자)을 공유하는 디바이스의 경우 이러한 주변 장치를 각기 다른 표면에 탑재할 수 있으며 각 주변 장치를 해당 평면에서 고정된 임의 각도로 회전할 수 있습니다. 따라서 애플리케이션에는 캡처된 프레임을 올바른 방향으로 렌더링 표면으로 변환할 수 있도록 두 주변 장치 간의 공간 관계를 설명하는 메커니즘이 필요합니다.

문제를 해결하는 한 가지 방법은 이미 표면 의 개념과 회전 정도 가 정의된 ACPI _PLD 구조를 사용하는 것입니다. 예를 들어 _PLD 구조체에는 주변 장치가 있는 표면을 지정하는 패널 필드가 이미 있습니다.

ACPI PLD 패널 필드입니다.

ACPI _PLD 패널 필드 정의(Rev. 5.0a)

다음 두 다이어그램은 각 패널의 정의를 시각적으로 보여 줍니다.

데스크톱 PC 및 대부분의 디바이스에 대한 패널 정의

패널 정의 - 데스크톱.

폴더블 디바이스에 대한 패널 정의

패널 정의 - 폴더블 디바이스.

실제로 ACPI "패널"의 개념은 다음과 같은 Windows에서 이미 채택되었습니다.

  • 카메라 디바이스 인터페이스는 캡처 디바이스가 고정된 위치에 정적으로 탑재된 경우 그에 따라 패널 필드가 설정되는 _PLD 구조와 연결됩니다.

  • 애플리케이션은 Windows.Devices.Enumeration.DeviceInformation.EnclosureLocation.Panel 속성을 호출하여 캡처 디바이스가 있는 패널을 검색할 수 있습니다.

ACPI _PLD 구조체에는 다음과 같이 정의된 회전 필드도 있습니다.

ACPI _PLD 회전 필드 정의(Rev 5.0a)

ACPI _PLD 회전 필드 정의.

위의 정의를 있는 그대로 사용하는 대신 모호성을 방지하기 위해 추가로 구체화합니다.

  • 카메라의 경우 ACPI _PLD 구조의 회전 필드는 디스플레이가 기본 방향인 동안 캡처된 프레임이 화면을 기준으로 회전되는 각도(0°의 경우 '0', 90°의 경우 '2', 180°의 경우 '4', 270°의 경우 '6')를 지정합니다.

가로 기본 및 세로 기본

Windows에서는 가로 또는 세로를 반환하는 Windows.Graphics.Display.DisplayInformation.NativeOrientation 속성을 호출하여 네이티브 디스플레이 방향을 쿼리할 수 있습니다.

네이티브 방향 검사 패턴을 표시합니다.

NativeOrientation이 반환하는 값에 관계없이 논리적 디스플레이 검사 패턴은 디스플레이의 왼쪽 위 모서리에서 왼쪽에서 오른쪽으로 아래로 이동하면서 시작됩니다(그림 5 참조). 기본 물리적 방향이 설명이 아닌 디바이스의 경우 이 속성은 ACPI Top 패널의 위치를 의미할 뿐만 아니라 카메라 출력 버퍼와 렌더링 표면 간의 공간 관계를 제공합니다.

카메라와 달리 NativeOrientation 속성은 ACPI를 기반으로 하지 않으므로 _PLD 구조가 없습니다. 디스플레이가 디바이스에 정적으로 탑재된 경우에도 마찬가지입니다.

세로 기본 디바이스에 탑재할 때 카메라 드라이버는 대부분의 애플리케이션이 실제 카메라 출력 버퍼 방향에 관계없이 디바이스를 가로 카메라 출력 버퍼를 출력하는 것으로 처리한다는 점에 유의해야 합니다. 이 때문에 카메라 드라이버는 세로 기본 디바이스에 있을 때 NativeOrientation 세로에서 90도 방향 오프셋이 있는 카메라 버퍼를 출력하는 것이 좋습니다. 그러면 세로 디바이스에서 이 추가 회전을 수행하는 애플리케이션이 회전을 예상된 방향으로 수정할 수 있습니다. 회전 샘플과 함께 카메라 애플리케이션을 사용하여 확인할 수 있습니다.

오프셋 탑재

IHV/OEM은 앱 호환성을 유지하기 위해 센서를 0도가 아닌 오프셋으로 탑재하지 않도록 하는 것이 좋습니다. 많은 기존 및 레거시 앱은 ACPI의 PLD 테이블을 찾는 것을 모르거나 0도가 아닌 오프셋을 수정하려고 시도하지 않습니다. 따라서 이러한 앱의 경우 결과 비디오가 잘못 렌더링됩니다.

IHV/OEM이 위에서 설명한 대로 센서를 0도 방향으로 탑재할 수 없는 경우 기본 설정 순서대로 다음 완화 단계를 권장합니다.

  1. 결과 출력 프레임이 0도 방향이 되도록 카메라 드라이버 내에서(AV 스트림 미니포트 드라이버가 있는 커널 모드 또는 디바이스 MFT 또는 MFT0과 같은 플러그 인을 사용하여 사용자 모드에서) 0도가 아닌 방향을 자동으로 수정합니다.

  2. 카메라 파이프라인이 캡처된 이미지를 수정할 수 있도록 FSSensorOrientation 태그를 통해 0도가 아닌 방향을 선언합니다.

  3. 위에서 설명한 대로 ACPI의 PLD 테이블에서 0도가 아닌 방향을 선언합니다.

압축/인코딩된 미디어 형식

압축 및/또는 인코딩된 미디어 형식(예: MJPG, JPEG, H264, HEVC)의 경우 파이프라인 올바른 을 사용할 수 없습니다. 이 때문에 FSSensorOrientation이 0이 아닌 값으로 설정된 경우 압축/인코딩된 미디어 형식이 필터링됩니다.

MJPG 미디어 형식(예: UVC 카메라의 미디어 형식)의 경우 프레임 서버 파이프라인은 자동 디코딩된 미디어 유형(DShow 기반 애플리케이션의 경우 NV12 또는 YUY2)을 제공합니다. 자동 디코딩 및 수정된 미디어 형식이 표시되지만 원래 MJPG 형식은 표시되지 않습니다.

[! 참고!] 압축/인코딩된 미디어 형식을 애플리케이션에 노출해야 하는 경우 IHV/ODM은 FSSensorOrientation 수정을 활용해서는 안 됩니다. 대신, 카메라 드라이버(AV Stream 드라이버를 통한 커널 모드 또는 DMFT/MFT0를 통한 사용자 모드)에서 수정을 수행해야 합니다.

AV Stream 미니포트/디바이스 MFT/MFT0을 통해 자동 수정

센서를 0도 오프셋으로 탑재할 수 없는 경우 권장되는 시나리오는 AV Stream 미니포트 드라이버(또는 DMFT 또는 MFT0 형식의 사용자 모드 플러그 인)가 결과 캡처된 프레임을 수정하여 0도 오프셋으로 파이프라인에 노출되도록 하는 것입니다.

AV Stream Miniport 및/또는 Device 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 메시지가 실행되면 플러그 인에서 생성된 다음 프레임은 요청된 메모리 유형(즉, DXGI 관리자가 제공된 경우 GPU, 그렇지 않으면 CPU)에 해당해야 합니다.
  • AV Stream 드라이버(또는 사용자 모드 플러그 인)가 회전 수정을 처리하는 경우 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 OS 설명자 1.0

USB 기반 카메라의 경우 FSSensorOrientation은 MSOS 설명자를 통해 게시될 수도 있습니다.

MS OS 설명자 1.0에는 두 가지 구성 요소가 있습니다.

  • 고정 길이 헤더 섹션
  • 헤더 섹션을 따르는 하나 이상의 가변 길이 사용자 지정 속성 섹션

MS OS 설명자 1.0 헤더 섹션

헤더 섹션에서는 단일 사용자 지정 속성(얼굴 인증 프로필)을 설명합니다.

Offset 필드 크기(바이트) Description
0 dwLength 4 <>
4 bcdVersion 2 0x0100 버전 1.0
6 wIndex 2 0x0005 확장 속성 OS 설명자
8 wCount 2 0x0001 하나의 사용자 지정 속성

사용자 지정 MS OS 설명자 1.0 속성 섹션

Offset 필드 크기(바이트) Description
0 dwSize 4 0x00000036 (54) 이 속성의 총 크기(바이트)입니다.
4 dwPropertyDataType 4 0x00000004 REG_DWORD_LITTLE_ENDIAN
8 wPropertyNameLength 2 0x00000024 (36) 속성 이름의 크기(바이트)입니다.
10 bPropertyName 50 UVC-FSSensorOrientation 유니코드의 "UVC-FSSensorOrientation" 문자열입니다.
60 dwPropertyDataLength 4 0x00000004 속성 데이터(sizeof(DWORD))의 경우 4바이트입니다.
64 bPropertyData 4 시계 방향으로 각도를 오프셋합니다. 유효한 값은 90, 180 및 270입니다.

MS OS 설명자 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 회전 필드의 값을 보여 줍니다.

회전: 시계 방향으로 0도

0도 회전 그림입니다.

위 그림에서 다음을 수행합니다.

  • 왼쪽 그림은 캡처할 장면을 보여 줍니다.

  • 가운데 그림은 왼쪽 아래 모서리에서 왼쪽으로 오른쪽으로 이동하는 물리적 읽기 순서가 시작되는 CMOS 센서에서 장면을 보는 방법을 보여 줍니다.

  • 오른쪽 그림은 카메라 드라이버의 출력을 나타냅니다. 이 예제에서는 디스플레이가 추가 회전 없이 기본 방향인 동안 미디어 버퍼의 콘텐츠를 직접 렌더링할 수 있습니다. 따라서 ACPI _PLD 회전 필드의 값은 0입니다.

회전: 시계 방향으로 90도

90도 회전 그림입니다.

이 경우 미디어 버퍼의 콘텐츠는 원래 장면에 비해 시계 방향으로 90도 회전됩니다. 결과적으로 ACPI _PLD 회전 필드의 값은 2입니다.

회전: 시계 방향으로 180도

180도 회전 그림입니다.

이 경우 미디어 버퍼의 콘텐츠는 원래 장면에 비해 시계 방향으로 180도 회전됩니다. 결과적으로 ACPI _PLD 회전 필드의 값은 4입니다.

회전: 시계 방향으로 270도

270도 회전 그림입니다.

이 경우 미디어 버퍼의 콘텐츠는 원래 장면에 비해 시계 방향으로 270도 회전됩니다. 결과적으로 ACPI _PLD 회전 필드의 값은 6입니다.