배경 구분 단순 포커스 모드 및 시선 응시 응시 모드 드라이버 샘플
이는 백그라운드 구분 단순 포커스 모드 및 시선 응시 응시 모드의 구현 예제로, 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;
}