Пример драйвера режима мелкой фокусировки сегментации фона и взгляда глаз
Это пример реализации режима фоновой сегментации с мелким фокусом и режимом взгляда глаз. В Windows 11 версии 22H2 появились два новых битовых поля.
Эти элементы управления обычно реализуются в C++, как часть расширения пользовательского режима драйвера камеры Avstream в MFT устройства.
Примечание
Пример приложения UWP WinRT_ExtendedControlAndMetadataSample C# на GitHub позволяет просматривать камеру и взаимодействовать с ее расширенными элементами управления.
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;
}