Share via


배경 구분 단순 포커스 모드 및 시선 응시 응시 모드 드라이버 샘플

이는 백그라운드 구분 단순 포커스 모드 및 시선 응시 응시 모드의 구현 예제로, Windows 11 버전 22H2에 도입되는 두 개의 새 비트 필드입니다.

이러한 컨트롤은 일반적으로 디바이스 MFT에서 Avstream 카메라 드라이버의 사용자 모드 확장의 일부로 C++에서 구현됩니다.

참고

GitHub의 WinRT_ExtendedControlAndMetadataSample C# UWP 애플리케이션 샘플은 카메라를 미리 보며 확장된 컨트롤과 상호 작용합니다.

SampleMFT.h

Class CSampleMFT //Snipped from SampleDeviceMFT Implementation
{
...
Private:
...
    VOID SetBackgroundSegmentationShallowFocus(BOOLEAN enabled)
    {
        m_backgroundSegmentationShallowFocusEnabled = enabled;
    }
    BOOLEAN GetBackgroundSegmentationShallowFocus()
    {
        return m_backgroundSegmentationShallowFocusEnabled;
    }
    constexpr ULONGLONG SupportedBackgroundSegmentation()
    {
        return  KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_BLUR |
                KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_MASK |
                KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_SHALLOWFOCUS;
    }

    VOID SetEyeGazeCorrectionMode(DWORD flags)
    {
        m_eyeGazeCorrectionMode = flags;
    }
    DWORD GetEyeGazeCorrectionMode()
    {
        return m_eyeGazeCorrectionMode;
    }
    BOOLEAN m_backgroundSegmentationShallowFocusEnabled;
    DWORD m_eyeGazeCorrectionMode;
};

SampleMFT.cpp

// KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_SHALLOWFOCUS
HRESULT CSampleMft::BackgroundSegmentationHandler(
    _In_ PKSPROPERTY property,
    _In_ LPVOID data,
    _In_ ULONG outputBufferLength,
    _Inout_ PULONG bytesReturned)
{
    *bytesReturned = 0;
    if (property->Flags & KSPROPERTY_TYPE_SET)
    {
        if (outputBufferLength == 0)
        {
            *bytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_EXTENDEDPROP_VALUE);
            RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_MORE_DATA));
        }
        else if (outputBufferLength < sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_EXTENDEDPROP_VALUE))
        {
            RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_MORE_DATA));
        }
        else if (data && outputBufferLength >= sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_EXTENDEDPROP_VALUE))
        {
            PBYTE payload = (PBYTE)data;
            PKSCAMERA_EXTENDEDPROP_HEADER extendedHeader = (PKSCAMERA_EXTENDEDPROP_HEADER)payload;
            // The extended value is unused for SET with this control, only flags are expected
            PKSCAMERA_EXTENDEDPROP_VALUE extendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(payload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
            if (extendedHeader->Flags & ~SupportedBackgroundSegmentation())
            {
                RETURN_HR(E_INVALIDARG);
            }

            bool shallowFocus = WI_IsFlagSet((extendedHeader->Flags, KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_SHALLOWFOCUS);
            bool blur = WI_IsFlagSet((extendedHeader->Flags, KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_BLUR);
            bool mask = WI_IsFlagSet((extendedHeader->Flags, KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_MASK);

            // If you ask for shallow focus, you must also ask for blur.
            if (shallowFocus && !blur)
            {
                RETURN_HR(E_INVALIDARG);
            }
            SetBackgroundSegmentationShallowFocus(shallowFocus);
            SetBackgroundSegmentationBlur(blur);
            SetBackgroundSegmentationMask(mask);
        }
        else
        {
            RETURN_IF_FAILED(E_INVALIDARG);
        }
    }
    else if (property->Flags & KSPROPERTY_TYPE_GET)
    {
        if (outputBufferLength == 0)
        {
            *bytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(m_configCaps);
            RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_MORE_DATA));
        }
        else if (outputBufferLength < sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(m_configCaps))
        {
            RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_MORE_DATA));
        }
        else if (data && outputBufferLength >= sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(m_configCaps))
        {
            PBYTE payload = (PBYTE)data;
            PKSCAMERA_EXTENDEDPROP_HEADER extendedHeader = (PKSCAMERA_EXTENDEDPROP_HEADER)(payload);
            extendedHeader->Capability = KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_MASK |
                                         KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_BLUR |
                                         KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_SHALLOWFOCUS |
                                         KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_OFF;

            if (GetBackgroundSegmentationMask())
            {
                extendedHeader->Flags |= KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_MASK;
            }

            if (GetBackgroundSegmentationBlur())
            {
                extendedHeader->Flags |= KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_BLUR;
            }
            else if (GetBackgroundSegmentationShallowFocus())
            {
                extendedHeader->Flags |= KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_BLUR | KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_SHALLOWFOCUS;
            }
            else
            {
                extendedHeader->Flags = KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_OFF;
            }
            extendedHeader->Result = 0;
            extendedHeader->Size = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(m_configCaps);
            extendedHeader->Version = 1;
            
            PKSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_CONFIGCAPS configCap = (PKSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_CONFIGCAPS)( payload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER)));
            memcpy(configCap, m_configCaps, sizeof(m_configCaps));
            *bytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(m_configCaps);
        }
    }

    return S_OK;
}

// KSCAMERA_EXTENDEDPROP_EYEGAZECORRECTION_STARE 
HRESULT CSampleMft::EyeGazeCorrectionHandler(   
    _In_       PKSPROPERTY property,   
    _In_       LPVOID      data,   
    _In_       ULONG       outputBufferLength,   
    _Inout_    PULONG      bytesReturned   
)   
{   
    HRESULT hr = S_OK;   
    *bytesReturned = 0;   

    if (property->Flags & KSPROPERTY_TYPE_SET)   
    {   
        if (outputBufferLength == 0) 
        {   
            *bytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_EXTENDEDPROP_VALUE);   
            RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_MORE_DATA));   
        }   
        else if (outputBufferLength < sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_EXTENDEDPROP_VALUE))   
        {   
            RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_MORE_DATA));   
        }   
        else if (data && outputBufferLength >= sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_EXTENDEDPROP_VALUE))   
        {   
            PBYTE payload = (PBYTE)data;   
            PKSCAMERA_EXTENDEDPROP_HEADER extendedHeader = (PKSCAMERA_EXTENDEDPROP_HEADER)payload;   
            //   
            // Use the extended value to make changes to the property.. refer documentation   
            // PKSCAMERA_EXTENDEDPROP_VALUE extendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(payload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));   
            //
            if ( (extendedHeader->Flags == KSCAMERA_EXTENDEDPROP_EYEGAZECORRECTION_ON) ||
                 (extendedHeader->Flags == (KSCAMERA_EXTENDEDPROP_EYEGAZECORRECTION_ON | KSCAMERA_EXTENDEDPROP_EYEGAZECORRECTION_STAREMODE)) ||
                 (extendedHeader->Flags == KSCAMERA_EXTENDEDPROP_EYEGAZECORRECTION_OFF) )
            {
                SetEyeGazeCorrectionMode (extendedHeader->Flags);   
            }
            else
            {
                RETURN_HR(E_INVALIDARG);
            } 
            *bytesReturned = sizeof(PKSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_EXTENDEDPROP_VALUE);   
        }   
        else  
        {  
            RETURN_IF_FAILED(E_INVALIDARG);  
        }  
    }   
    else if (property->Flags & KSPROPERTY_TYPE_GET)   
    {   
        if (outputBufferLength == 0)   
        {   
            *bytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_EXTENDEDPROP_VALUE);   
            RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_MORE_DATA));  
        }   
        else if (outputBufferLength < sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_EXTENDEDPROP_VALUE)) 
        {   
            RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_MORE_DATA));  
        }   
        else if (data && outputBufferLength >= sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_EXTENDEDPROP_VALUE))   
        {         
            PBYTE payload = (PBYTE)data;   
            PKSCAMERA_EXTENDEDPROP_HEADER extendedHeader = (PKSCAMERA_EXTENDEDPROP_HEADER)(payload);   
            //   
            // Use the extended value to make changes to the property.. refer documentation   
            // PKSCAMERA_EXTENDEDPROP_VALUE extendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(payload +sizeof(KSCAMERA_EXTENDEDPROP_HEADER));   
            //   
            extendedHeader->Capability = KSCAMERA_EXTENDEDPROP_EYEGAZECORRECTION_OFF |  
                                         KSCAMERA_EXTENDEDPROP_EYEGAZECORRECTION_ON |   
                                         KSCAMERA_EXTENDEDPROP_EYEGAZECORRECTION_STAREMODE;   

            extendedHeader->Flags = GetEyeGazeCorrectionMode();
            extendedHeader->Result = 0;   
            extendedHeader->Size = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_EXTENDEDPROP_VALUE);   
            extendedHeader->Version = 1;   

            *bytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_EXTENDEDPROP_VALUE);   
        }   
    }   
    return S_OK;   
}

추가 정보

KSPROPERTY_CAMERACONTROL_EXTENDED_BACKGROUNDSEGMENTATION

KSPROPERTY_CAMERACONTROL_EXTENDED_EYEGAZECORRECTION