From 68cc5fa78e1c7cdf8841bee497594d0478b15033 Mon Sep 17 00:00:00 2001 From: Frank Cheng Date: Wed, 24 Sep 2025 14:18:02 +0800 Subject: [PATCH 1/7] Handling KsEvent, KSCAMERAPROFILE_FaceAuth_Mode for different streaming behavior on camera DMFT. --- avstream/avscamera/DMFT/AvsCameraDMFT.cpp | 185 ++++++++++++++++-- avstream/avscamera/DMFT/AvsCameraDMFT.h | 21 ++ avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj | 12 ++ .../DMFT/AvsCameraDMFT.vcxproj.Filters | 3 + avstream/avscamera/DMFT/packages.config | 2 +- 5 files changed, 208 insertions(+), 15 deletions(-) diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.cpp b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp index e12cff652..e0417769b 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.cpp +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp @@ -6,6 +6,14 @@ #ifdef MF_WPP #include "AvsCameraDMFT.tmh" //--REF_ANALYZER_DONT_REMOVE-- #endif + +// TODO: required to avoid bug OS bug 36971659 in extended property handling that introduces a 16 bytes cookie +typedef struct +{ + //byte cookieBuffer[16]; + KSCAMERA_EXTENDEDPROP_HEADER header; +} KSCAMERA_EXTENDEDPROP_HEADER_BUFFERED, * PKSCAMERA_EXTENDEDPROP_HEADER_BUFFERED; + // // This DeviceMFT is a stripped down implementation of the device MFT Sample present in the sample Repo // The original DMFT is present at https://github.com/microsoft/Windows-driver-samples/tree/main/avstream/sampledevicemft @@ -29,6 +37,7 @@ CMultipinMft::CMultipinMft() DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MF_SA_D3D_AWARE, TRUE ), done); DMFTCHECKHR_GOTO(pAttributes->SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"SampleMultiPinMft" ),done); m_spAttributes = pAttributes; + m_selectedProfileId = { KSCAMERAPROFILE_Legacy, 0, 0 }; done: DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); } @@ -638,6 +647,10 @@ IFACEMETHODIMP CMultipinMft::ProcessInput( goto done; } + if (m_selectedProfileId.Type == KSCAMERAPROFILE_FaceAuth_Mode) + { + // DMFT might switch to different behavior when profile, KSCAMERAPROFILE_FaceAuth_Mode is selected. + } DMFTCHECKHR_GOTO(spInPin->SendSample( pSample ), done ); done: DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr ); @@ -990,13 +1003,23 @@ IFACEMETHODIMP CMultipinMft::KsProperty( --*/ { HRESULT hr = S_OK; + + /// PDMFT only cares about ExtendedCameraControls, all others + /// are just blindly forwarded to the upstream DMFTs. + if (!IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl)) + { + DMFTCHECKHR_GOTO(m_spIkscontrol->KsProperty(pProperty, ulPropertyLength, pvPropertyData, + ulDataLength, pulBytesReturned), done); + goto done; + } - DMFTCHECKHR_GOTO(m_spIkscontrol->KsProperty(pProperty, - ulPropertyLength, - pvPropertyData, - ulDataLength, - pulBytesReturned),done); + if (pProperty->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE) + { + DMFTCHECKHR_GOTO(ProfilePropertyHandler(pProperty, ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned), done); + goto done; + } done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); return hr; } @@ -1040,15 +1063,53 @@ IFACEMETHODIMP CMultipinMft::KsEvent( --*/ { - HRESULT hr = S_OK; - // Handle the events here if you want, This sample passes the events to the driver - DMFTCHECKHR_GOTO(m_spIkscontrol->KsEvent(pEvent, - ulEventLength, - pEventData, - ulDataLength, - pBytesReturned), done); -done: - return hr; + //HRESULT hr = S_OK; + // handle the event if it is to set profile + if (pEvent != nullptr + && ulEventLength >= sizeof(KSEVENT) + && pEvent->Set == KSEVENTSETID_ExtendedCameraControl + && pEventData != nullptr + && ulDataLength >= sizeof(KSEVENTDATA) + && (pEvent->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE)) + { + + m_hSelectedProfileKSEvent.reset(); + RETURN_IF_WIN32_BOOL_FALSE(DuplicateHandle( + GetCurrentProcess(), + ((KSEVENTDATA*)(pEventData))->EventHandle.Event, + GetCurrentProcess(), + &m_hSelectedProfileKSEvent, + 0, + FALSE, + DUPLICATE_SAME_ACCESS)); + + if (m_isProfileDDISupportedInBaseDriver.value_or(true)) + { + RETURN_IF_FAILED(m_hSelectedProfileKSEventSentToDriver.create()); + KSEVENTDATA driverEventData = {}; + driverEventData.NotificationType = KSEVENTF_EVENT_HANDLE; + driverEventData.EventHandle.Event = m_hSelectedProfileKSEventSentToDriver.get(); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Handling profile set KsEvent, created profile KsEvent handle for driver: %p", m_hSelectedProfileKSEventSentToDriver.get()); + + // defer to source device + auto hr = m_spIkscontrol->KsEvent(pEvent, ulEventLength, (void*)(&driverEventData), ulDataLength, pBytesReturned); + if (FAILED(hr)) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Failed to send profile KsEvent handle to driver: %p | hr=0x%08x", m_hSelectedProfileKSEventSentToDriver.get(), hr); + m_hSelectedProfileKSEventSentToDriver.reset(); + m_isProfileDDISupportedInBaseDriver = false; + } + } + } + else { + // Pass the events to the driver + RETURN_IF_FAILED(m_spIkscontrol->KsEvent(pEvent, + ulEventLength, + pEventData, + ulDataLength, + pBytesReturned)); + } + return S_OK; } // @@ -1293,6 +1354,102 @@ IFACEMETHODIMP CMultipinMft::Shutdown( return ShutdownEventGenerator(); } +/*++ +Description: +Implements the KsProperty KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE handler. +--*/ + +HRESULT CMultipinMft::ProfilePropertyHandler( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _In_ LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Inout_ PULONG pulBytesReturned) try +{ + + UNREFERENCED_PARAMETER(ulPropertyLength); + HRESULT hr = S_OK; + + if (pProperty->Flags & KSPROPERTY_TYPE_SET) + { + DMFTCHECKNULL_GOTO(pulBytesReturned, done, E_POINTER); + *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER_BUFFERED) + sizeof(KSCAMERA_EXTENDEDPROP_PROFILE); + if (ulDataLength < *pulBytesReturned) + { + return HRESULT_FROM_WIN32(ERROR_MORE_DATA); + } + if (pPropertyData) + { + + PBYTE pPayload = (PBYTE)pPropertyData; + PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = &((PKSCAMERA_EXTENDEDPROP_HEADER_BUFFERED)pPayload)->header; + KSCAMERA_EXTENDEDPROP_PROFILE* pProfile = (PKSCAMERA_EXTENDEDPROP_PROFILE)(pExtendedHeader + 1); + + m_selectedProfileId.Type = pProfile->ProfileId; + m_selectedProfileId.Index = pProfile->Index; + m_selectedProfileId.Unused = pProfile->Reserved; + + if (m_selectedProfileId.Type == GUID_NULL) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_WARNING, "The caller incorrectly sets GUID_NULL, default back to legacy."); + m_selectedProfileId = { KSCAMERAPROFILE_Legacy, 0, 0 }; + } + + // signal we are done + if (m_hSelectedProfileKSEvent.get() != nullptr) + { + if (m_hSelectedProfileKSEventSentToDriver != nullptr) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Waiting for driver profile KsEvent handle: %p", m_hSelectedProfileKSEventSentToDriver.get()); + if (!m_hSelectedProfileKSEventSentToDriver.wait(kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT)) + { + + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, + "Waiting for driver profile KsEvent handle: %p timed out after %i ms, failing", + m_hSelectedProfileKSEventSentToDriver.get(), + kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT); + m_hSelectedProfileKSEvent.SetEvent(); + RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_TIMEOUT)); + } + m_hSelectedProfileKSEventSentToDriver.reset(); + } + m_hSelectedProfileKSEvent.SetEvent(); + m_hSelectedProfileKSEvent.reset(); + } + } + } + else if (pProperty->Flags & KSPROPERTY_TYPE_GET) + { + DMFTCHECKNULL_GOTO(pulBytesReturned, done, E_POINTER); + *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER_BUFFERED) + sizeof(KSCAMERA_EXTENDEDPROP_PROFILE); + if (ulDataLength < *pulBytesReturned) + { + return HRESULT_FROM_WIN32(ERROR_MORE_DATA); + } + if (pPropertyData) + { + if (!m_isProfileDDISupportedInBaseDriver.has_value()) + { + hr = m_spIkscontrol->KsProperty(pProperty, ulPropertyLength, pPropertyData, ulDataLength, pulBytesReturned); + m_isProfileDDISupportedInBaseDriver = SUCCEEDED(hr); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Profile DDI GET support on base driver: %d, hr=0x%08x", m_isProfileDDISupportedInBaseDriver.value(), hr); + *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER_BUFFERED) + sizeof(KSCAMERA_EXTENDEDPROP_PROFILE); + } + } + } + // --GETPAYLOAD-- + else if (pProperty->Flags & KSPROPERTY_TYPE_GETPAYLOADSIZE) + { + RETURN_HR_IF_NULL(E_POINTER, pulBytesReturned); + *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER_BUFFERED) + sizeof(PKSCAMERA_EXTENDEDPROP_PROFILE); + } + +done: + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); + return hr; +} CATCH_RETURN() + + // // Static method to create an instance of the MFT. // diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.h b/avstream/avscamera/DMFT/AvsCameraDMFT.h index 27b8607b5..3c51571af 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.h +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.h @@ -7,6 +7,10 @@ #include "mftpeventgenerator.h" #include "basepin.h" +#include +#include +#include + // // The Below GUID is needed to transfer photoconfirmation sample successfully in the pipeline // It is used to propagate the mediatype of the sample to the pipeline which will consume the sample @@ -19,6 +23,8 @@ DEFINE_GUID(MFSourceReader_SampleAttribute_MediaType_priv, interface IDirect3DDeviceManager9; +constexpr int kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT = 3000;// ms, amount of time to wait for the profile DDI KsEvent sent to the driver + // // Forward declarations // @@ -275,9 +281,18 @@ class CMultipinMft : _In_opt_ IMFMediaType *pMediaType, _In_ DeviceStreamState newState ); + HRESULT BridgeInputPinOutputPin( _In_ CInPin* pInPin, _In_ COutPin* pOutPin); + + HRESULT ProfilePropertyHandler( + _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, + _In_ ULONG ulPropertyLength, + _Inout_updates_to_(ulDataLength, *pulBytesReturned) LPVOID pPropertyData, + _In_ ULONG ulDataLength, + _Inout_ PULONG pulBytesReturned); + // //Inline functions // @@ -320,8 +335,14 @@ class CMultipinMft : UINT32 m_punValue; ComPtr m_spIkscontrol; ComPtr m_spAttributes; + map m_outputPinMap; // How output pins are connected to input pins i-><0..outpins> PWCHAR m_SymbolicLink; + wil::unique_event_nothrow m_hSelectedProfileKSEvent; + wil::unique_event_nothrow m_hSelectedProfileKSEventSentToDriver; + std::optional m_isProfileDDISupportedInBaseDriver; + SENSORPROFILEID m_selectedProfileId; + }; diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj index 3f6180f26..a27ea60d0 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj @@ -162,6 +162,7 @@ %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD $(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common + stdcpp17 %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD @@ -178,6 +179,7 @@ %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD $(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common + stdcpp17 %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD @@ -194,6 +196,7 @@ %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD $(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common + stdcpp17 %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD @@ -210,6 +213,7 @@ %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD $(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common + stdcpp17 %(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD @@ -237,6 +241,7 @@ + @@ -247,4 +252,11 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters index c3679c843..854d9e635 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters @@ -54,4 +54,7 @@ Header Files + + + \ No newline at end of file diff --git a/avstream/avscamera/DMFT/packages.config b/avstream/avscamera/DMFT/packages.config index 26065b144..d690ede8a 100644 --- a/avstream/avscamera/DMFT/packages.config +++ b/avstream/avscamera/DMFT/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file From bc6eda8cc2497829a8c5f14ced38195b80c4a1a2 Mon Sep 17 00:00:00 2001 From: Frank Cheng Date: Thu, 25 Sep 2025 04:21:10 +0800 Subject: [PATCH 2/7] Remove Wil dependancy from AvsCameraDMFT.vcxproj to fix CI/CD issue. --- avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj | 7 ------- 1 file changed, 7 deletions(-) diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj index a27ea60d0..7970a1d77 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj @@ -252,11 +252,4 @@ - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - \ No newline at end of file From 93a14884c8a54775766b1ad41b7f0d20db7331d8 Mon Sep 17 00:00:00 2001 From: Frank Cheng Date: Thu, 25 Sep 2025 11:45:54 +0800 Subject: [PATCH 3/7] Eliminate WIL dependancy on AvsCameraDMFT.h/cpp. --- avstream/avscamera/DMFT/AvsCameraDMFT.cpp | 73 ++++++++++++++--------- avstream/avscamera/DMFT/AvsCameraDMFT.h | 7 +-- 2 files changed, 47 insertions(+), 33 deletions(-) diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.cpp b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp index e0417769b..0e36af0d0 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.cpp +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp @@ -26,8 +26,11 @@ CMultipinMft::CMultipinMft() m_lWorkQueuePriority ( 0 ), m_spAttributes( nullptr ), m_spSourceTransform( nullptr ), - m_SymbolicLink(nullptr) - + m_SymbolicLink(nullptr), + m_hSelectedProfileKSEvent { nullptr }, + m_hSelectedProfileKSEventSentToDriver { nullptr}, + m_isProfileDDISupportedInBaseDriver{}, + m_selectedProfileId { KSCAMERAPROFILE_Legacy, 0, 0 } { HRESULT hr = S_OK; ComPtr pAttributes = nullptr; @@ -37,7 +40,7 @@ CMultipinMft::CMultipinMft() DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MF_SA_D3D_AWARE, TRUE ), done); DMFTCHECKHR_GOTO(pAttributes->SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"SampleMultiPinMft" ),done); m_spAttributes = pAttributes; - m_selectedProfileId = { KSCAMERAPROFILE_Legacy, 0, 0 }; + done: DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); } @@ -1063,7 +1066,7 @@ IFACEMETHODIMP CMultipinMft::KsEvent( --*/ { - //HRESULT hr = S_OK; + HRESULT hr = S_OK; // handle the event if it is to set profile if (pEvent != nullptr && ulEventLength >= sizeof(KSEVENT) @@ -1073,42 +1076,56 @@ IFACEMETHODIMP CMultipinMft::KsEvent( && (pEvent->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE)) { - m_hSelectedProfileKSEvent.reset(); - RETURN_IF_WIN32_BOOL_FALSE(DuplicateHandle( + m_hSelectedProfileKSEvent = nullptr; + if (DuplicateHandle( GetCurrentProcess(), ((KSEVENTDATA*)(pEventData))->EventHandle.Event, GetCurrentProcess(), &m_hSelectedProfileKSEvent, 0, FALSE, - DUPLICATE_SAME_ACCESS)); - + DUPLICATE_SAME_ACCESS) == false) + { + return E_INVALIDARG; + } if (m_isProfileDDISupportedInBaseDriver.value_or(true)) { - RETURN_IF_FAILED(m_hSelectedProfileKSEventSentToDriver.create()); + m_hSelectedProfileKSEventSentToDriver = CreateEventExW( + nullptr, + nullptr, + 0, + EVENT_ALL_ACCESS); + + DMFTCHECKNULL_GOTO(m_hSelectedProfileKSEventSentToDriver, done, E_INVALIDARG); + KSEVENTDATA driverEventData = {}; driverEventData.NotificationType = KSEVENTF_EVENT_HANDLE; - driverEventData.EventHandle.Event = m_hSelectedProfileKSEventSentToDriver.get(); - DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Handling profile set KsEvent, created profile KsEvent handle for driver: %p", m_hSelectedProfileKSEventSentToDriver.get()); + driverEventData.EventHandle.Event = m_hSelectedProfileKSEventSentToDriver; + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Handling profile set KsEvent, created profile KsEvent handle for driver: %p", m_hSelectedProfileKSEventSentToDriver); // defer to source device - auto hr = m_spIkscontrol->KsEvent(pEvent, ulEventLength, (void*)(&driverEventData), ulDataLength, pBytesReturned); + hr = m_spIkscontrol->KsEvent(pEvent, ulEventLength, (void*)(&driverEventData), ulDataLength, pBytesReturned); if (FAILED(hr)) { - DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Failed to send profile KsEvent handle to driver: %p | hr=0x%08x", m_hSelectedProfileKSEventSentToDriver.get(), hr); - m_hSelectedProfileKSEventSentToDriver.reset(); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Failed to send profile KsEvent handle to driver: %p | hr=0x%08x", m_hSelectedProfileKSEventSentToDriver, hr); + m_hSelectedProfileKSEventSentToDriver = nullptr; m_isProfileDDISupportedInBaseDriver = false; } } } else { // Pass the events to the driver - RETURN_IF_FAILED(m_spIkscontrol->KsEvent(pEvent, + hr = m_spIkscontrol->KsEvent(pEvent, ulEventLength, pEventData, ulDataLength, - pBytesReturned)); + pBytesReturned); + if FAILED(hr) + { + return hr; + } } +done: return S_OK; } @@ -1364,7 +1381,7 @@ HRESULT CMultipinMft::ProfilePropertyHandler( _In_ ULONG ulPropertyLength, _In_ LPVOID pPropertyData, _In_ ULONG ulDataLength, - _Inout_ PULONG pulBytesReturned) try + _Inout_ PULONG pulBytesReturned) { UNREFERENCED_PARAMETER(ulPropertyLength); @@ -1396,25 +1413,25 @@ HRESULT CMultipinMft::ProfilePropertyHandler( } // signal we are done - if (m_hSelectedProfileKSEvent.get() != nullptr) + if (m_hSelectedProfileKSEvent != nullptr) { if (m_hSelectedProfileKSEventSentToDriver != nullptr) { - DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Waiting for driver profile KsEvent handle: %p", m_hSelectedProfileKSEventSentToDriver.get()); - if (!m_hSelectedProfileKSEventSentToDriver.wait(kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT)) + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Waiting for driver profile KsEvent handle: %p", m_hSelectedProfileKSEventSentToDriver); + if ( WaitForSingleObjectEx(m_hSelectedProfileKSEventSentToDriver, kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT, FALSE) != WAIT_OBJECT_0) { DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, "Waiting for driver profile KsEvent handle: %p timed out after %i ms, failing", - m_hSelectedProfileKSEventSentToDriver.get(), + m_hSelectedProfileKSEventSentToDriver, kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT); - m_hSelectedProfileKSEvent.SetEvent(); - RETURN_IF_FAILED(HRESULT_FROM_WIN32(ERROR_TIMEOUT)); + SetEvent(m_hSelectedProfileKSEvent); + return HRESULT_FROM_WIN32(ERROR_TIMEOUT); } - m_hSelectedProfileKSEventSentToDriver.reset(); + m_hSelectedProfileKSEventSentToDriver = nullptr; } - m_hSelectedProfileKSEvent.SetEvent(); - m_hSelectedProfileKSEvent.reset(); + SetEvent(m_hSelectedProfileKSEvent); + m_hSelectedProfileKSEvent = nullptr; } } } @@ -1440,14 +1457,14 @@ HRESULT CMultipinMft::ProfilePropertyHandler( // --GETPAYLOAD-- else if (pProperty->Flags & KSPROPERTY_TYPE_GETPAYLOADSIZE) { - RETURN_HR_IF_NULL(E_POINTER, pulBytesReturned); + DMFTCHECKNULL_GOTO(pulBytesReturned, done, E_POINTER); *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER_BUFFERED) + sizeof(PKSCAMERA_EXTENDEDPROP_PROFILE); } done: DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); return hr; -} CATCH_RETURN() +} // diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.h b/avstream/avscamera/DMFT/AvsCameraDMFT.h index 3c51571af..7de644d1b 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.h +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.h @@ -6,9 +6,6 @@ #include "common.h" #include "mftpeventgenerator.h" #include "basepin.h" - -#include -#include #include // @@ -338,8 +335,8 @@ class CMultipinMft : map m_outputPinMap; // How output pins are connected to input pins i-><0..outpins> PWCHAR m_SymbolicLink; - wil::unique_event_nothrow m_hSelectedProfileKSEvent; - wil::unique_event_nothrow m_hSelectedProfileKSEventSentToDriver; + HANDLE m_hSelectedProfileKSEvent; + HANDLE m_hSelectedProfileKSEventSentToDriver; std::optional m_isProfileDDISupportedInBaseDriver; SENSORPROFILEID m_selectedProfileId; From 0960a1ec9fdb159c96a3313bee1391ec1d68dc20 Mon Sep 17 00:00:00 2001 From: Frank Cheng Date: Wed, 1 Oct 2025 14:29:24 +0800 Subject: [PATCH 4/7] Rollback to use WIL. --- avstream/avscamera/DMFT/AvsCameraDMFT.cpp | 69 ++++++++++--------- avstream/avscamera/DMFT/AvsCameraDMFT.h | 11 +-- avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj | 7 ++ avstream/avscamera/DMFT/packages.config | 2 +- 4 files changed, 53 insertions(+), 36 deletions(-) diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.cpp b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp index 0e36af0d0..6229709ba 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.cpp +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp @@ -10,7 +10,6 @@ // TODO: required to avoid bug OS bug 36971659 in extended property handling that introduces a 16 bytes cookie typedef struct { - //byte cookieBuffer[16]; KSCAMERA_EXTENDEDPROP_HEADER header; } KSCAMERA_EXTENDEDPROP_HEADER_BUFFERED, * PKSCAMERA_EXTENDEDPROP_HEADER_BUFFERED; @@ -28,7 +27,7 @@ CMultipinMft::CMultipinMft() m_spSourceTransform( nullptr ), m_SymbolicLink(nullptr), m_hSelectedProfileKSEvent { nullptr }, - m_hSelectedProfileKSEventSentToDriver { nullptr}, + m_hSelectedProfileKSEventSentToDriver { nullptr }, m_isProfileDDISupportedInBaseDriver{}, m_selectedProfileId { KSCAMERAPROFILE_Legacy, 0, 0 } { @@ -40,7 +39,6 @@ CMultipinMft::CMultipinMft() DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MF_SA_D3D_AWARE, TRUE ), done); DMFTCHECKHR_GOTO(pAttributes->SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"SampleMultiPinMft" ),done); m_spAttributes = pAttributes; - done: DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); } @@ -649,7 +647,26 @@ IFACEMETHODIMP CMultipinMft::ProcessInput( { goto done; } - + if (pSample != nullptr && m_selectedProfileId.Type != KSCAMERAPROFILE_FaceAuth_Mode) + { + IMFMediaBuffer* pMediaBuff{ nullptr }; + hr = pSample->ConvertToContiguousBuffer(&pMediaBuff); + if (SUCCEEDED(hr)) + { + DWORD bufferSize = 0; + BYTE* pBuffer = nullptr; + hr = pMediaBuff->Lock(&pBuffer, nullptr, &bufferSize); + if (SUCCEEDED(hr)) + { + // Process the buffer here + //int start = bufferSize / 2; + //memset(pBuffer+start, 0xAB, bufferSize - start); // Example processing: flip 2nd half of image buffer into 0xAB + memset(pBuffer, 0xAB, bufferSize); // Example processing: flip 2nd half of image buffer into 0xAB + hr = pMediaBuff->Unlock(); + pMediaBuff->Release(); + } + } + } if (m_selectedProfileId.Type == KSCAMERAPROFILE_FaceAuth_Mode) { // DMFT might switch to different behavior when profile, KSCAMERAPROFILE_FaceAuth_Mode is selected. @@ -1005,6 +1022,7 @@ IFACEMETHODIMP CMultipinMft::KsProperty( if it needs to be propogated to the driver or not --*/ { + CAutoLock Lock(m_critSec); HRESULT hr = S_OK; /// PDMFT only cares about ExtendedCameraControls, all others @@ -1016,7 +1034,7 @@ IFACEMETHODIMP CMultipinMft::KsProperty( goto done; } - if (pProperty->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE) + if (pProperty->Set == KSPROPERTYSETID_ExtendedCameraControl && pProperty->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE) { DMFTCHECKHR_GOTO(ProfilePropertyHandler(pProperty, ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned), done); goto done; @@ -1065,7 +1083,7 @@ IFACEMETHODIMP CMultipinMft::KsEvent( Implements IKSProperty::KsEvent function. --*/ { - + CAutoLock Lock(m_critSec); HRESULT hr = S_OK; // handle the event if it is to set profile if (pEvent != nullptr @@ -1076,7 +1094,7 @@ IFACEMETHODIMP CMultipinMft::KsEvent( && (pEvent->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE)) { - m_hSelectedProfileKSEvent = nullptr; + m_hSelectedProfileKSEvent.reset(); if (DuplicateHandle( GetCurrentProcess(), ((KSEVENTDATA*)(pEventData))->EventHandle.Event, @@ -1090,25 +1108,18 @@ IFACEMETHODIMP CMultipinMft::KsEvent( } if (m_isProfileDDISupportedInBaseDriver.value_or(true)) { - m_hSelectedProfileKSEventSentToDriver = CreateEventExW( - nullptr, - nullptr, - 0, - EVENT_ALL_ACCESS); - - DMFTCHECKNULL_GOTO(m_hSelectedProfileKSEventSentToDriver, done, E_INVALIDARG); - + RETURN_IF_FAILED(m_hSelectedProfileKSEventSentToDriver.create()); KSEVENTDATA driverEventData = {}; driverEventData.NotificationType = KSEVENTF_EVENT_HANDLE; - driverEventData.EventHandle.Event = m_hSelectedProfileKSEventSentToDriver; - DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Handling profile set KsEvent, created profile KsEvent handle for driver: %p", m_hSelectedProfileKSEventSentToDriver); + driverEventData.EventHandle.Event = m_hSelectedProfileKSEventSentToDriver.get(); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Handling profile set KsEvent, created profile KsEvent handle for driver: %p", m_hSelectedProfileKSEventSentToDriver.get()); // defer to source device hr = m_spIkscontrol->KsEvent(pEvent, ulEventLength, (void*)(&driverEventData), ulDataLength, pBytesReturned); if (FAILED(hr)) { - DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Failed to send profile KsEvent handle to driver: %p | hr=0x%08x", m_hSelectedProfileKSEventSentToDriver, hr); - m_hSelectedProfileKSEventSentToDriver = nullptr; + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Failed to send profile KsEvent handle to driver: %p | hr=0x%08x", m_hSelectedProfileKSEventSentToDriver.get(), hr); + m_hSelectedProfileKSEventSentToDriver.reset(); m_isProfileDDISupportedInBaseDriver = false; } } @@ -1120,10 +1131,7 @@ IFACEMETHODIMP CMultipinMft::KsEvent( pEventData, ulDataLength, pBytesReturned); - if FAILED(hr) - { - return hr; - } + DMFTCHECKHR_GOTO(hr, done); } done: return S_OK; @@ -1417,21 +1425,20 @@ HRESULT CMultipinMft::ProfilePropertyHandler( { if (m_hSelectedProfileKSEventSentToDriver != nullptr) { - DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Waiting for driver profile KsEvent handle: %p", m_hSelectedProfileKSEventSentToDriver); - if ( WaitForSingleObjectEx(m_hSelectedProfileKSEventSentToDriver, kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT, FALSE) != WAIT_OBJECT_0) + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Waiting for driver profile KsEvent handle: %p", m_hSelectedProfileKSEventSentToDriver.get()); + if (!m_hSelectedProfileKSEventSentToDriver.wait(kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT)) { - DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, "Waiting for driver profile KsEvent handle: %p timed out after %i ms, failing", - m_hSelectedProfileKSEventSentToDriver, + m_hSelectedProfileKSEventSentToDriver.get(), kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT); - SetEvent(m_hSelectedProfileKSEvent); + m_hSelectedProfileKSEvent.SetEvent(); return HRESULT_FROM_WIN32(ERROR_TIMEOUT); } - m_hSelectedProfileKSEventSentToDriver = nullptr; + m_hSelectedProfileKSEventSentToDriver.reset(); } - SetEvent(m_hSelectedProfileKSEvent); - m_hSelectedProfileKSEvent = nullptr; + m_hSelectedProfileKSEvent.SetEvent(); + m_hSelectedProfileKSEvent.reset(); } } } diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.h b/avstream/avscamera/DMFT/AvsCameraDMFT.h index 7de644d1b..ceb58c00e 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.h +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.h @@ -7,7 +7,9 @@ #include "mftpeventgenerator.h" #include "basepin.h" #include - +#include +//#include +#include // // The Below GUID is needed to transfer photoconfirmation sample successfully in the pipeline // It is used to propagate the mediatype of the sample to the pipeline which will consume the sample @@ -22,6 +24,7 @@ interface IDirect3DDeviceManager9; constexpr int kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT = 3000;// ms, amount of time to wait for the profile DDI KsEvent sent to the driver + // // Forward declarations // @@ -314,6 +317,7 @@ class CMultipinMft : return (InterlockedCompareExchange((LONG*)&m_StreamingState, DeviceStreamState_Run, DeviceStreamState_Run) == DeviceStreamState_Run); } + private: ULONG m_InputPinCount; ULONG m_OutputPinCount; @@ -335,8 +339,8 @@ class CMultipinMft : map m_outputPinMap; // How output pins are connected to input pins i-><0..outpins> PWCHAR m_SymbolicLink; - HANDLE m_hSelectedProfileKSEvent; - HANDLE m_hSelectedProfileKSEventSentToDriver; + wil::unique_event_nothrow m_hSelectedProfileKSEvent; + wil::unique_event_nothrow m_hSelectedProfileKSEventSentToDriver; std::optional m_isProfileDDISupportedInBaseDriver; SENSORPROFILEID m_selectedProfileId; @@ -349,4 +353,3 @@ inline HRESULT MFT_CreateInstance(REFIID riid, void **ppv) return CMultipinMft::CreateInstance(riid, ppv); } - diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj index 7970a1d77..637c6bf60 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj @@ -252,4 +252,11 @@ + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + \ No newline at end of file diff --git a/avstream/avscamera/DMFT/packages.config b/avstream/avscamera/DMFT/packages.config index d690ede8a..26065b144 100644 --- a/avstream/avscamera/DMFT/packages.config +++ b/avstream/avscamera/DMFT/packages.config @@ -1,4 +1,4 @@  - + \ No newline at end of file From 4ff5b33afafc2b6088516c266cc49606eeef647f Mon Sep 17 00:00:00 2001 From: Frank Cheng Date: Thu, 9 Oct 2025 05:25:24 +0800 Subject: [PATCH 5/7] 1. PR review results enhancements. 2. On event handling, removed blocking wait, use MFPutWaitingWorkItem instead. --- avstream/avscamera/DMFT/AvsCameraDMFT.cpp | 124 +++++++++++----------- avstream/avscamera/DMFT/AvsCameraDMFT.h | 72 +++++++++++-- 2 files changed, 129 insertions(+), 67 deletions(-) diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.cpp b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp index 6229709ba..93f4a3422 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.cpp +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp @@ -29,7 +29,9 @@ CMultipinMft::CMultipinMft() m_hSelectedProfileKSEvent { nullptr }, m_hSelectedProfileKSEventSentToDriver { nullptr }, m_isProfileDDISupportedInBaseDriver{}, - m_selectedProfileId { KSCAMERAPROFILE_Legacy, 0, 0 } + m_selectedProfileId { KSCAMERAPROFILE_Legacy, 0, 0 }, + m_profileCallback {this, &CMultipinMft::ProfileAsyncResultCallback }, + m_profileAsyncResult {nullptr} { HRESULT hr = S_OK; ComPtr pAttributes = nullptr; @@ -647,26 +649,6 @@ IFACEMETHODIMP CMultipinMft::ProcessInput( { goto done; } - if (pSample != nullptr && m_selectedProfileId.Type != KSCAMERAPROFILE_FaceAuth_Mode) - { - IMFMediaBuffer* pMediaBuff{ nullptr }; - hr = pSample->ConvertToContiguousBuffer(&pMediaBuff); - if (SUCCEEDED(hr)) - { - DWORD bufferSize = 0; - BYTE* pBuffer = nullptr; - hr = pMediaBuff->Lock(&pBuffer, nullptr, &bufferSize); - if (SUCCEEDED(hr)) - { - // Process the buffer here - //int start = bufferSize / 2; - //memset(pBuffer+start, 0xAB, bufferSize - start); // Example processing: flip 2nd half of image buffer into 0xAB - memset(pBuffer, 0xAB, bufferSize); // Example processing: flip 2nd half of image buffer into 0xAB - hr = pMediaBuff->Unlock(); - pMediaBuff->Release(); - } - } - } if (m_selectedProfileId.Type == KSCAMERAPROFILE_FaceAuth_Mode) { // DMFT might switch to different behavior when profile, KSCAMERAPROFILE_FaceAuth_Mode is selected. @@ -1022,22 +1004,15 @@ IFACEMETHODIMP CMultipinMft::KsProperty( if it needs to be propogated to the driver or not --*/ { - CAutoLock Lock(m_critSec); HRESULT hr = S_OK; - - /// PDMFT only cares about ExtendedCameraControls, all others - /// are just blindly forwarded to the upstream DMFTs. - if (!IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl)) - { - DMFTCHECKHR_GOTO(m_spIkscontrol->KsProperty(pProperty, ulPropertyLength, pvPropertyData, - ulDataLength, pulBytesReturned), done); - goto done; - } - if (pProperty->Set == KSPROPERTYSETID_ExtendedCameraControl && pProperty->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE) { DMFTCHECKHR_GOTO(ProfilePropertyHandler(pProperty, ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned), done); - goto done; + } + else + { + DMFTCHECKHR_GOTO(m_spIkscontrol->KsProperty(pProperty, ulPropertyLength, pvPropertyData, + ulDataLength, pulBytesReturned), done); } done: DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); @@ -1104,19 +1079,20 @@ IFACEMETHODIMP CMultipinMft::KsEvent( FALSE, DUPLICATE_SAME_ACCESS) == false) { - return E_INVALIDARG; + hr = E_INVALIDARG; + DMFTCHECKHR_GOTO(hr, done); } if (m_isProfileDDISupportedInBaseDriver.value_or(true)) { - RETURN_IF_FAILED(m_hSelectedProfileKSEventSentToDriver.create()); + hr = m_hSelectedProfileKSEventSentToDriver.create(); + DMFTCHECKHR_GOTO(hr, done); KSEVENTDATA driverEventData = {}; driverEventData.NotificationType = KSEVENTF_EVENT_HANDLE; driverEventData.EventHandle.Event = m_hSelectedProfileKSEventSentToDriver.get(); DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Handling profile set KsEvent, created profile KsEvent handle for driver: %p", m_hSelectedProfileKSEventSentToDriver.get()); - // defer to source device - hr = m_spIkscontrol->KsEvent(pEvent, ulEventLength, (void*)(&driverEventData), ulDataLength, pBytesReturned); - if (FAILED(hr)) + HRESULT hr2 = m_spIkscontrol->KsEvent(pEvent, ulEventLength, (void*)(&driverEventData), ulDataLength, pBytesReturned); + if (FAILED(hr2)) { DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Failed to send profile KsEvent handle to driver: %p | hr=0x%08x", m_hSelectedProfileKSEventSentToDriver.get(), hr); m_hSelectedProfileKSEventSentToDriver.reset(); @@ -1134,7 +1110,7 @@ IFACEMETHODIMP CMultipinMft::KsEvent( DMFTCHECKHR_GOTO(hr, done); } done: - return S_OK; + return hr; } // @@ -1387,25 +1363,23 @@ Implements the KsProperty KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE handler. HRESULT CMultipinMft::ProfilePropertyHandler( _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty, _In_ ULONG ulPropertyLength, - _In_ LPVOID pPropertyData, + _Inout_updates_to_(ulDataLength, *pulBytesReturned) LPVOID pPropertyData, _In_ ULONG ulDataLength, - _Inout_ PULONG pulBytesReturned) + _Inout_ PULONG pulBytesReturned) try { - UNREFERENCED_PARAMETER(ulPropertyLength); HRESULT hr = S_OK; - + CAutoLock Lock(m_critSec); if (pProperty->Flags & KSPROPERTY_TYPE_SET) { DMFTCHECKNULL_GOTO(pulBytesReturned, done, E_POINTER); *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER_BUFFERED) + sizeof(KSCAMERA_EXTENDEDPROP_PROFILE); if (ulDataLength < *pulBytesReturned) { - return HRESULT_FROM_WIN32(ERROR_MORE_DATA); + DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done); } if (pPropertyData) { - PBYTE pPayload = (PBYTE)pPropertyData; PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = &((PKSCAMERA_EXTENDEDPROP_HEADER_BUFFERED)pPayload)->header; KSCAMERA_EXTENDEDPROP_PROFILE* pProfile = (PKSCAMERA_EXTENDEDPROP_PROFILE)(pExtendedHeader + 1); @@ -1419,24 +1393,36 @@ HRESULT CMultipinMft::ProfilePropertyHandler( DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_WARNING, "The caller incorrectly sets GUID_NULL, default back to legacy."); m_selectedProfileId = { KSCAMERAPROFILE_Legacy, 0, 0 }; } - - // signal we are done - if (m_hSelectedProfileKSEvent != nullptr) + // if we should relay this SET call down to base driver + if (m_isProfileDDISupportedInBaseDriver.value_or(true)) { - if (m_hSelectedProfileKSEventSentToDriver != nullptr) + hr = m_spIkscontrol->KsProperty(pProperty, ulPropertyLength, pPropertyData, ulDataLength, pulBytesReturned); + // if base camera does not support the provided profile, set the base camera ksevent right away in case it did accept it so that we don't await it later on + if (FAILED(hr)) { - DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Waiting for driver profile KsEvent handle: %p", m_hSelectedProfileKSEventSentToDriver.get()); - if (!m_hSelectedProfileKSEventSentToDriver.wait(kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT)) + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_WARNING, "Failed Profile DDI SET, base camera hr=0x%08x", hr); + if (m_hSelectedProfileKSEventSentToDriver != nullptr) { - DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, - "Waiting for driver profile KsEvent handle: %p timed out after %i ms, failing", - m_hSelectedProfileKSEventSentToDriver.get(), - kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT); - m_hSelectedProfileKSEvent.SetEvent(); - return HRESULT_FROM_WIN32(ERROR_TIMEOUT); + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Completing driver profile KsEvent handle: %p", m_hSelectedProfileKSEventSentToDriver.get()); + m_hSelectedProfileKSEventSentToDriver.SetEvent(); + m_hSelectedProfileKSEventSentToDriver.reset(); } - m_hSelectedProfileKSEventSentToDriver.reset(); } + } + // signal we are done + // Queue an MF work item which will get invoked when the event is fired + DMFTCHECKNULL_GOTO(m_hSelectedProfileKSEvent, done, E_POINTER); + if (m_hSelectedProfileKSEventSentToDriver != nullptr) + { + m_profileAsyncResult.Reset(); + DMFTCHECKHR_GOTO(MFCreateAsyncResult(nullptr, &m_profileCallback, nullptr, &m_profileAsyncResult), done); + //KSCAMERAPROFILE is not cancelable. Not need to track MFWORKITEM_KEY + DMFTCHECKHR_GOTO(MFPutWaitingWorkItem(m_hSelectedProfileKSEventSentToDriver.get(), 0, m_profileAsyncResult.Get(), nullptr), done); + } + else + { + // if the profile set event was not sent to the driver, we can set our event right away + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Completing profile KsEvent handle: %p", m_hSelectedProfileKSEvent.get()); m_hSelectedProfileKSEvent.SetEvent(); m_hSelectedProfileKSEvent.reset(); } @@ -1448,7 +1434,7 @@ HRESULT CMultipinMft::ProfilePropertyHandler( *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER_BUFFERED) + sizeof(KSCAMERA_EXTENDEDPROP_PROFILE); if (ulDataLength < *pulBytesReturned) { - return HRESULT_FROM_WIN32(ERROR_MORE_DATA); + DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done); } if (pPropertyData) { @@ -1471,7 +1457,7 @@ HRESULT CMultipinMft::ProfilePropertyHandler( done: DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); return hr; -} +} CATCH_RETURN() // @@ -1490,3 +1476,21 @@ HRESULT CMultipinMft::CreateInstance(REFIID iid, void **ppMFT) DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); return hr; } + +HRESULT CMultipinMft::ProfileAsyncResultCallback(_In_ IMFAsyncResult* pResult) +{ + HRESULT hr = S_OK; + if (FAILED(pResult->GetStatus())) + { + DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, + "Waiting for driver profile KsEvent handle: %p timed out, failing", + m_hSelectedProfileKSEventSentToDriver.get()); + m_hSelectedProfileKSEvent.SetEvent(); + m_hSelectedProfileKSEvent.reset(); + hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT); + } + m_hSelectedProfileKSEventSentToDriver.reset(); + return hr; +} + + diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.h b/avstream/avscamera/DMFT/AvsCameraDMFT.h index ceb58c00e..5dce37239 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.h +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.h @@ -8,7 +8,7 @@ #include "basepin.h" #include #include -//#include +#include #include // // The Below GUID is needed to transfer photoconfirmation sample successfully in the pipeline @@ -19,17 +19,73 @@ DEFINE_GUID(MFSourceReader_SampleAttribute_MediaType_priv, 0x0ea5c1e8, 0x9845, 0x41e0, 0xa2, 0x43, 0x72, 0x32, 0x07, 0xfc, 0x78, 0x1f); - interface IDirect3DDeviceManager9; -constexpr int kMAX_WAIT_TIME_DRIVER_PROFILE_KSEVENT = 3000;// ms, amount of time to wait for the profile DDI KsEvent sent to the driver - - // // Forward declarations // class CMFAttributes; class CPinCreationFactory; + +// T: Type of the parent object +template +class MFAsyncCallback : public IMFAsyncCallback { +public: + typedef HRESULT(T::* InvokeFn)(IMFAsyncResult* pAsyncResult); + + MFAsyncCallback(T* pParent, InvokeFn fn) : + m_pParent(pParent), + m_pInvokeFn(fn) + { + } + // IUnknown methods + STDMETHODIMP QueryInterface(REFIID iid, void** ppv) override { + if (!ppv) return E_POINTER; + if (iid == __uuidof(IUnknown)) + { + *ppv = static_cast(static_cast(this)); + } + else if (iid == __uuidof(IMFAsyncCallback)) + { + *ppv = static_cast(this); + } + else + { + *ppv = NULL; + return E_NOINTERFACE; + } + AddRef(); + return S_OK; + } + + STDMETHODIMP_(ULONG) AddRef() override { + return InterlockedIncrement(&m_refCount); + } + + STDMETHODIMP_(ULONG) Release() override { + ULONG count = InterlockedDecrement(&m_refCount); + if (count == 0) delete this; + return count; + } + + // IMFAsyncCallback methods + STDMETHODIMP GetParameters(DWORD* pdwFlags, DWORD* pdwQueue) override { + if (pdwFlags) *pdwFlags = 0; + if (pdwQueue) *pdwQueue = MFASYNC_CALLBACK_QUEUE_STANDARD; + return S_OK; + } + + STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult) override { + UNREFERENCED_PARAMETER(pAsyncResult); + return (m_pParent->*m_pInvokeFn)(pAsyncResult); + } + +private: + LONG m_refCount = 1; + T* m_pParent; + InvokeFn m_pInvokeFn; +}; + // // CMultipinMft class: // Implements a device proxy MFT. @@ -259,6 +315,8 @@ class CMultipinMft : _In_ UINT32 ); + HRESULT ProfileAsyncResultCallback(_In_ IMFAsyncResult* pResult); + protected: // @@ -317,7 +375,6 @@ class CMultipinMft : return (InterlockedCompareExchange((LONG*)&m_StreamingState, DeviceStreamState_Run, DeviceStreamState_Run) == DeviceStreamState_Run); } - private: ULONG m_InputPinCount; ULONG m_OutputPinCount; @@ -343,7 +400,8 @@ class CMultipinMft : wil::unique_event_nothrow m_hSelectedProfileKSEventSentToDriver; std::optional m_isProfileDDISupportedInBaseDriver; SENSORPROFILEID m_selectedProfileId; - + MFAsyncCallbackm_profileCallback; + ComPtr m_profileAsyncResult; }; From 9ce1c2fdb7eceedb7cd8227ae7fd11513b4be829 Mon Sep 17 00:00:00 2001 From: Frank Cheng Date: Thu, 9 Oct 2025 10:51:06 +0800 Subject: [PATCH 6/7] Fix CI/CD nuget built failure. --- avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj | 2 +- avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj index 637c6bf60..50cdbcd93 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj @@ -136,7 +136,7 @@ AvsCameraDMFT - $(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\wil\include + $(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\..\wil\include diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters index 854d9e635..c3679c843 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters @@ -54,7 +54,4 @@ Header Files - - - \ No newline at end of file From 0f0734bfaf3e37c1a88585eeca270a6c82d784dc Mon Sep 17 00:00:00 2001 From: Frank Cheng Date: Thu, 9 Oct 2025 11:25:54 +0800 Subject: [PATCH 7/7] Remove nuget package settings from AvsCameraDMFT.vcxproj --- avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj | 8 -------- 1 file changed, 8 deletions(-) diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj index 50cdbcd93..4243d22bb 100644 --- a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj +++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj @@ -241,7 +241,6 @@ - @@ -252,11 +251,4 @@ - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - \ No newline at end of file