summaryrefslogtreecommitdiff
path: root/avstream/avscamera/DMFT
diff options
context:
space:
mode:
authorAdonais Romero González <[email protected]>2024-05-06 16:21:31 -0700
committerGitHub <[email protected]>2024-05-06 16:21:31 -0700
commita74a241c664c4e1d7c0838287b34076c19d9858a (patch)
tree6ff7562612967b122acf8acf8a69c4dcfd5905db /avstream/avscamera/DMFT
parentdef8e8e34ed2b7b1deb2fc9112ac4255f1a0f2ba (diff)
parent15477ce52bbb6b42ca591ecdfb484cac089f89ab (diff)
Merge develop changes prior to upcoming WDK release (May 2024)
Diffstat (limited to 'avstream/avscamera/DMFT')
-rw-r--r--avstream/avscamera/DMFT/AvsCameraDMFT.cpp1311
-rw-r--r--avstream/avscamera/DMFT/AvsCameraDMFT.h334
-rw-r--r--avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj250
-rw-r--r--avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters57
-rw-r--r--avstream/avscamera/DMFT/AvsCameraDMFTutils.cpp805
-rw-r--r--avstream/avscamera/DMFT/Source.def5
-rw-r--r--avstream/avscamera/DMFT/basepin.cpp625
-rw-r--r--avstream/avscamera/DMFT/basepin.h568
-rw-r--r--avstream/avscamera/DMFT/common.h360
-rw-r--r--avstream/avscamera/DMFT/dllmain.cpp354
-rw-r--r--avstream/avscamera/DMFT/mftpeventgenerator.cpp234
-rw-r--r--avstream/avscamera/DMFT/mftpeventgenerator.h94
-rw-r--r--avstream/avscamera/DMFT/packages.config4
-rw-r--r--avstream/avscamera/DMFT/stdafx.h47
-rw-r--r--avstream/avscamera/DMFT/stdafxsrc.cpp4
15 files changed, 5052 insertions, 0 deletions
diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.cpp b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp
new file mode 100644
index 00000000..e12cff65
--- /dev/null
+++ b/avstream/avscamera/DMFT/AvsCameraDMFT.cpp
@@ -0,0 +1,1311 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+
+#include "stdafx.h"
+#ifdef MF_WPP
+#include "AvsCameraDMFT.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+//
+// 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
+//
+CMultipinMft::CMultipinMft()
+: m_nRefCount( 0 ),
+ m_InputPinCount( 0 ),
+ m_OutputPinCount( 0 ),
+ m_dwWorkQueueId ( MFASYNC_CALLBACK_QUEUE_MULTITHREADED ),
+ m_lWorkQueuePriority ( 0 ),
+ m_spAttributes( nullptr ),
+ m_spSourceTransform( nullptr ),
+ m_SymbolicLink(nullptr)
+
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFAttributes> pAttributes = nullptr;
+ MFCreateAttributes( &pAttributes, 0 );
+ DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MF_TRANSFORM_ASYNC, TRUE ),done);
+ DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE ),done);
+ 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);
+}
+
+CMultipinMft::~CMultipinMft( )
+{
+ m_OutPins.clear();
+ SAFE_ARRAYDELETE(m_SymbolicLink);
+ m_spSourceTransform = nullptr;
+
+}
+
+IFACEMETHODIMP_(ULONG) CMultipinMft::AddRef(
+ void
+ )
+{
+ return InterlockedIncrement(&m_nRefCount);
+}
+
+IFACEMETHODIMP_(ULONG) CMultipinMft::Release(
+ void
+ )
+{
+ ULONG uCount = InterlockedDecrement(&m_nRefCount);
+
+ if ( uCount == 0 )
+ {
+ delete this;
+ }
+ return uCount;
+}
+
+IFACEMETHODIMP CMultipinMft::QueryInterface(
+ _In_ REFIID iid,
+ _COM_Outptr_ void** ppv
+ )
+{
+
+ HRESULT hr = S_OK;
+ *ppv = NULL;
+
+ if ((iid == __uuidof(IMFDeviceTransform)) || (iid == __uuidof(IUnknown)))
+ {
+ *ppv = static_cast< IMFDeviceTransform* >(this);
+ }
+ else if ( iid == __uuidof( IMFMediaEventGenerator ) )
+ {
+ *ppv = static_cast< IMFMediaEventGenerator* >(this);
+ }
+ else if ( iid == __uuidof( IMFShutdown ) )
+ {
+ *ppv = static_cast< IMFShutdown* >( this );
+ }
+ else if ( iid == __uuidof( IKsControl ) )
+ {
+ *ppv = static_cast< IKsControl* >( this );
+ }
+ else if ( iid == __uuidof( IMFRealTimeClientEx ) )
+ {
+ *ppv = static_cast< IMFRealTimeClientEx* >( this );
+ }
+ else
+ {
+ hr = E_NOINTERFACE;
+ goto done;
+ }
+ AddRef();
+done:
+ return hr;
+}
+
+/*++
+ Description:
+ This function is the entry point of the transform
+ The following things may be initialized here
+ 1) Query for MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL on the attributes supplied
+ 2) From the IUnknown acquired get the IMFTransform interface.
+ 3) Get the stream count.. The output streams are of consequence to the tranform.
+ The input streams should correspond to the output streams exposed by the source transform
+ acquired from the Attributes supplied.
+ 4) Get the IKSControl which is used to send KSPROPERTIES, KSEVENTS and KSMETHODS to the driver for the filer level. Store it in your filter class
+ 5) Get the OutPutStreamAttributes for the output pins of the source transform. This can further be used to QI and acquire
+ the IKSControl related to the specific pin. This can be used to send PIN level KSPROPERTIES, EVENTS and METHODS to the pins
+ 6) Create the output pins
+
+--*/
+
+IFACEMETHODIMP CMultipinMft::InitializeTransform (
+ _In_ IMFAttributes *pAttributes
+ )
+{
+ HRESULT hr = S_OK;
+ ComPtr<IUnknown> spFilterUnk = nullptr;
+ DWORD *pcInputStreams = NULL, *pcOutputStreams = NULL;
+ DWORD inputStreams = 0;
+ DWORD outputStreams = 0;
+ GUID* outGuids = NULL;
+ GUID streamCategory = GUID_NULL;
+ ULONG ulOutPinIndex = 0;
+ UINT32 uiSymLinkLen = 0;
+ DMFTCHECKNULL_GOTO( pAttributes, done, E_INVALIDARG );
+ //
+ // The attribute passed with MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL is the source transform. This generally represents a filter
+ // This needs to be stored so that we know the device properties. We cache it. We query for the IKSControl which is used to send
+ // controls to the driver.
+ //
+ DMFTCHECKHR_GOTO( pAttributes->GetUnknown( MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL,IID_PPV_ARGS( &spFilterUnk ) ),done );
+
+ if (SUCCEEDED(pAttributes->GetStringLength(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &uiSymLinkLen))) // Not available prior to RS5
+ {
+ m_SymbolicLink = new (std::nothrow) WCHAR[++uiSymLinkLen];
+ DMFTCHECKNULL_GOTO(m_SymbolicLink, done, E_OUTOFMEMORY);
+ DMFTCHECKHR_GOTO(pAttributes->GetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, m_SymbolicLink, uiSymLinkLen, &uiSymLinkLen), done);
+ }
+
+ DMFTCHECKHR_GOTO( spFilterUnk.As( &m_spSourceTransform ), done );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform.As( &m_spIkscontrol ), done );
+
+ DMFTCHECKHR_GOTO(m_spSourceTransform->GetStreamCount(&inputStreams, &outputStreams), done);
+
+ spFilterUnk = nullptr;
+
+ //
+ //The number of input pins created by the device transform should match the pins exposed by
+ //the source transform i.e. outputStreams from SourceTransform or DevProxy = Input pins of the Device MFT
+ //
+
+ if ( inputStreams > 0 || outputStreams > 0 )
+ {
+ pcInputStreams = new (std::nothrow) DWORD[ inputStreams ];
+ DMFTCHECKNULL_GOTO( pcInputStreams, done, E_OUTOFMEMORY);
+
+ pcOutputStreams = new (std::nothrow) DWORD[ outputStreams ];
+ DMFTCHECKNULL_GOTO( pcOutputStreams, done, E_OUTOFMEMORY );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform->GetStreamIDs( inputStreams, pcInputStreams,
+ outputStreams,
+ pcOutputStreams ),done );
+
+ for ( ULONG ulIndex = 0; ulIndex < outputStreams; ulIndex++ )
+ {
+ ComPtr<IMFAttributes> spInAttributes;
+ ComPtr<CInPin> spInPin;
+
+ DMFTCHECKHR_GOTO(m_spSourceTransform->GetOutputStreamAttributes(ulIndex, &spInAttributes),done);
+ spInPin = new (std::nothrow) CInPin(spInAttributes.Get(), ulIndex, this);
+ DMFTCHECKNULL_GOTO(spInPin.Get(), done, E_OUTOFMEMORY);
+
+ hr = ExceptionBoundary([&]()
+ {
+ m_InPins.push_back(spInPin.Get());
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ DMFTCHECKHR_GOTO(spInPin->Init(m_spSourceTransform.Get()), done);
+ }
+
+ //
+ // Create one on one mapping
+ //
+ for (ULONG ulIndex = 0; ulIndex < m_InPins.size(); ulIndex++)
+ {
+
+ ComPtr<CInPin> spInPin = (CInPin*)m_InPins[ulIndex].Get();
+
+ if (spInPin.Get())
+ {
+ ComPtr<COutPin> spOutPin;
+ ComPtr<IKsControl> spKscontrol;
+ GUID pinGuid = GUID_NULL;
+ UINT32 uiFrameSourceType = 0;
+
+ DMFTCHECKHR_GOTO(spInPin.As(&spKscontrol), done); // Grab the IKSControl off the input pin
+ DMFTCHECKHR_GOTO(spInPin->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &pinGuid), done); // Get the Stream Category. Advertise on the output pin
+
+
+ spOutPin = new (std::nothrow) COutPin(
+ ulIndex,
+ this,
+ spKscontrol.Get()); // Create the output pin
+ DMFTCHECKNULL_GOTO(spOutPin.Get(), done, E_OUTOFMEMORY);
+
+ DMFTCHECKHR_GOTO(spOutPin->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, pinGuid), done); // Advertise the Stream category to the Pipeline
+ DMFTCHECKHR_GOTO(spOutPin->SetUINT32(MF_DEVICESTREAM_STREAM_ID, ulIndex), done);
+ if (SUCCEEDED(spInPin->GetUINT32(MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES, &uiFrameSourceType)))
+ {
+ DMFTCHECKHR_GOTO(spOutPin->SetUINT32(MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES, uiFrameSourceType), done);
+ }
+
+ hr = BridgeInputPinOutputPin(spInPin.Get(), spOutPin.Get());
+ if (SUCCEEDED(hr))
+ {
+ DMFTCHECKHR_GOTO(ExceptionBoundary([&]()
+ {
+ m_OutPins.push_back(spOutPin.Get());
+ }), done);
+ ulOutPinIndex++;
+ }
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+ }
+
+ }
+
+ m_InputPinCount = ULONG ( m_InPins.size() );
+ m_OutputPinCount = ULONG ( m_OutPins.size() );
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!",hr,hr);
+
+ if ( pcInputStreams )
+ {
+ delete[ ] ( pcInputStreams );
+ }
+ if ( pcOutputStreams )
+ {
+ delete[ ] ( pcOutputStreams );
+ }
+ if ( outGuids )
+ {
+ delete [] ( outGuids );
+ }
+ if ( FAILED( hr ) )
+ {
+ //Release the pins and the resources acquired
+ m_InPins.clear();
+ m_OutPins.clear();
+ //
+ // Simply clear the custom pins since the input pins must have deleted the pin
+ //
+ m_spSourceTransform = nullptr;
+ m_spIkscontrol = nullptr;
+ }
+ return hr;
+}
+
+
+IFACEMETHODIMP CMultipinMft::SetWorkQueueEx(
+ _In_ DWORD dwWorkQueueId,
+ _In_ LONG lWorkItemBasePriority
+ )
+/*++
+ Description:
+
+ Implements IMFRealTimeClientEx::SetWorkQueueEx function
+
+--*/
+{
+ CAutoLock lock( m_critSec );
+ //
+ // Cache the WorkQueuId and WorkItemBasePriority. This is called once soon after the device MFT is initialized
+ //
+ m_dwWorkQueueId = dwWorkQueueId;
+ m_lWorkQueuePriority = lWorkItemBasePriority;
+ // Set it on the pins
+ for (DWORD dwIndex = 0; dwIndex < (DWORD)m_InPins.size(); dwIndex++)
+ {
+ m_InPins[dwIndex]->SetWorkQueue(dwWorkQueueId);
+ }
+ for (DWORD dwIndex = 0; dwIndex < (DWORD)m_OutPins.size(); dwIndex++)
+ {
+ m_OutPins[dwIndex]->SetWorkQueue(dwWorkQueueId);
+ }
+ return S_OK;
+
+}
+
+//
+// IMFDeviceTransform functions
+//
+IFACEMETHODIMP CMultipinMft::GetStreamCount(
+ _Inout_ DWORD *pdwInputStreams,
+ _Inout_ DWORD *pdwOutputStreams
+ )
+/*++
+ Description: Implements IMFTransform::GetStreamCount function
+--*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+ DMFTCHECKNULL_GOTO(pdwInputStreams, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(pdwOutputStreams, done, E_INVALIDARG);
+ *pdwInputStreams = m_InputPinCount;
+ *pdwOutputStreams = m_OutputPinCount;
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+done:
+ return hr;
+}
+
+//
+//Doesn't strictly conform to the GetStreamIDs on IMFTransform Interface!
+//
+IFACEMETHODIMP CMultipinMft::GetStreamIDs(
+ _In_ DWORD dwInputIDArraySize,
+ _When_(dwInputIDArraySize >= m_InputPinCount, _Out_writes_(dwInputIDArraySize)) DWORD* pdwInputIDs,
+ _In_ DWORD dwOutputIDArraySize,
+ _When_(dwOutputIDArraySize >= m_OutputPinCount && (pdwInputIDs && (dwInputIDArraySize > 0)),
+ _Out_writes_(dwOutputIDArraySize)) _On_failure_(_Valid_) DWORD* pdwOutputIDs
+ )
+/*++
+ Description:
+ Implements IMFTransform::GetStreamIDs function
+--*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+ if ( ( dwInputIDArraySize < m_InputPinCount ) && ( dwOutputIDArraySize < m_OutputPinCount ) )
+ {
+ hr = MF_E_BUFFERTOOSMALL;
+ goto done;
+ }
+
+ if ( dwInputIDArraySize )
+ {
+ DMFTCHECKNULL_GOTO( pdwInputIDs, done, E_POINTER );
+ for ( DWORD dwIndex = 0; dwIndex < ((dwInputIDArraySize > m_InputPinCount) ? m_InputPinCount:
+ dwInputIDArraySize); dwIndex++ )
+ {
+ pdwInputIDs[ dwIndex ] = ( m_InPins[dwIndex] )->streamId();
+ }
+ }
+
+ if ( dwOutputIDArraySize )
+ {
+ DMFTCHECKNULL_GOTO( pdwOutputIDs, done, E_POINTER );
+ for ( DWORD dwIndex = 0; dwIndex < ((dwOutputIDArraySize > m_OutputPinCount)? m_OutputPinCount:
+ dwOutputIDArraySize); dwIndex++ )
+ {
+ pdwOutputIDs[ dwIndex ] = (m_OutPins[ dwIndex ])->streamId();
+ }
+ }
+done:
+ return hr;
+}
+
+/*++
+Name: CMultipinMft::GetInputAvailableType
+Description:
+Implements IMFTransform::GetInputAvailableType function. This function
+gets the media type supported by the specified stream based on the
+index dwTypeIndex.
+--*/
+IFACEMETHODIMP CMultipinMft::GetInputAvailableType(
+ _In_ DWORD dwInputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppMediaType
+ )
+{
+ HRESULT hr = S_OK;
+
+ ComPtr<CInPin> spiPin = GetInPin( dwInputStreamID );
+ DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO( spiPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ *ppMediaType = nullptr;
+
+ hr = spiPin->GetOutputAvailableType( dwTypeIndex,ppMediaType );
+
+ if (FAILED(hr))
+ {
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!",
+ dwInputStreamID,
+ dwTypeIndex,
+ hr);
+ }
+
+done:
+ return hr;
+}
+
+IFACEMETHODIMP CMultipinMft::GetOutputAvailableType(
+ _In_ DWORD dwOutputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppMediaType
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::GetOutputAvailableType function. This function
+ gets the media type supported by the specified stream based on the
+ index dwTypeIndex.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock Lock(m_critSec);
+
+ ComPtr<COutPin> spoPin = GetOutPin( dwOutputStreamID );
+
+ DMFTCHECKNULL_GOTO( spoPin.Get(), done, MF_E_INVALIDSTREAMNUMBER );
+ DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG);
+
+ *ppMediaType = nullptr;
+
+ hr = spoPin->GetOutputAvailableType( dwTypeIndex, ppMediaType );
+
+ if ( FAILED( hr ) )
+ {
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!",
+ dwOutputStreamID,
+ dwTypeIndex,
+ hr );
+ }
+
+done:
+ return hr;
+}
+
+IFACEMETHODIMP CMultipinMft::GetInputCurrentType(
+ _In_ DWORD dwInputStreamID,
+ _COM_Outptr_result_maybenull_ IMFMediaType** ppMediaType
+ )
+/*++
+ Description:
+ Implements IMFTransform::GetInputCurrentType function. This function
+ returns the current media type set on the specified stream.
+--*/
+{
+ //
+ // The input current types will not come to this transform.
+ // The outputs of this transform matter. The DTM manages the
+ // output of this transform and the inptuts of the source transform
+ //
+ UNREFERENCED_PARAMETER(dwInputStreamID);
+ UNREFERENCED_PARAMETER(ppMediaType);
+ return S_OK;
+}
+
+IFACEMETHODIMP CMultipinMft::GetOutputCurrentType(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ IMFMediaType** ppMediaType
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::GetOutputCurrentType function. This function
+ returns the current media type set on the specified stream.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ ComPtr<COutPin> spoPin;
+ CAutoLock lock( m_critSec );
+
+ DMFTCHECKNULL_GOTO( ppMediaType, done, E_INVALIDARG );
+
+ *ppMediaType = nullptr;
+
+ spoPin = GetOutPin( dwOutputStreamID );
+
+ DMFTCHECKNULL_GOTO(spoPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ DMFTCHECKHR_GOTO(spoPin->getMediaType( ppMediaType ),done );
+
+ DMFTCHECKNULL_GOTO( *ppMediaType, done, MF_E_TRANSFORM_TYPE_NOT_SET );
+
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+
+IFACEMETHODIMP CMultipinMft::ProcessEvent(
+ _In_ DWORD dwInputStreamID,
+ _In_ IMFMediaEvent* pEvent
+ )
+ /*++
+ Description:
+
+ Implements IMFTransform::ProcessEvent function. This function
+ processes events that come to the MFT.
+
+ --*/
+{
+ UNREFERENCED_PARAMETER(dwInputStreamID);
+ UNREFERENCED_PARAMETER(pEvent);
+ return S_OK;
+}
+
+
+
+IFACEMETHODIMP CMultipinMft::ProcessMessage(
+ _In_ MFT_MESSAGE_TYPE eMessage,
+ _In_ ULONG_PTR ulParam
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::ProcessMessage function. This function
+ processes messages coming to the MFT.
+
+--*/
+{
+ HRESULT hr = S_OK;
+
+ UNREFERENCED_PARAMETER(ulParam);
+
+ CAutoLock _lock( m_critSec );
+
+ switch ( eMessage )
+ {
+ case MFT_MESSAGE_COMMAND_FLUSH:
+ //
+ // This is MFT wide flush.. Flush all output pins
+ //
+ (VOID)FlushAllStreams();
+ break;
+ case MFT_MESSAGE_COMMAND_DRAIN:
+ //
+ // There is no draining for Device MFT. Just kept here for reference
+ //
+ break;
+ case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
+ //
+ // No op for device MFTs
+ //
+ break;
+ case MFT_MESSAGE_SET_D3D_MANAGER:
+ {
+ if ( ulParam )
+ {
+ ComPtr< IDirect3DDeviceManager9 > spD3D9Manager;
+ ComPtr< IMFDXGIDeviceManager > spDXGIManager;
+
+ hr = ( ( IUnknown* ) ulParam )->QueryInterface( IID_PPV_ARGS( &spD3D9Manager ) );
+ if ( SUCCEEDED( hr ) )
+ {
+ m_spDeviceManagerUnk = ( IUnknown* )ulParam;
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! IDirect3DDeviceManager9 %p, is passed", spD3D9Manager.Get() );
+ }
+ else
+ {
+ hr = ( ( IUnknown* ) ulParam )->QueryInterface( IID_PPV_ARGS( &spDXGIManager ) );
+ if ( SUCCEEDED(hr) )
+ {
+ m_spDeviceManagerUnk = (IUnknown*)ulParam;
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! IMFDXGIDeviceManager %p, is passed", spDXGIManager.Get());
+ }
+ }
+ }
+ else
+ {
+ m_spDeviceManagerUnk = nullptr;
+ hr = S_OK;
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC!IDirect3DDeviceManager9 was not passed in");
+ }
+ //
+ // set it on the pins. Can happen anytime
+ //
+ for (DWORD dwIndex = 0; dwIndex < (DWORD)m_InPins.size(); dwIndex++)
+ {
+ m_InPins[dwIndex]->SetD3DManager(m_spDeviceManagerUnk.Get());
+ }
+ for (DWORD dwIndex = 0; dwIndex < (DWORD)m_OutPins.size(); dwIndex++)
+ {
+ m_OutPins[dwIndex]->SetD3DManager(m_spDeviceManagerUnk.Get());
+ }
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ {
+ SetStreamingState( DeviceStreamState_Run );
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_END_STREAMING:
+ {
+ SetStreamingState(DeviceStreamState_Stop);
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
+ {
+ SetStreamingState(DeviceStreamState_Stop);
+ }
+ break;
+ default:
+ ;
+ }
+
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+IFACEMETHODIMP CMultipinMft::ProcessInput(
+ _In_ DWORD dwInputStreamID,
+ _In_ IMFSample* pSample,
+ _In_ DWORD dwFlags
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::ProcessInput function.This function is called
+ when the sourcetransform has input to feed. the pins will try to deliver the
+ samples to the active output pins conencted. if none are connected then just
+ returns the sample back to the source transform
+
+--*/
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( dwFlags );
+ CAutoLock lock(m_critSec);
+
+ ComPtr<CInPin> spInPin = GetInPin( dwInputStreamID );
+ DMFTCHECKNULL_GOTO(spInPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ if ( !IsStreaming() )
+ {
+ goto done;
+ }
+
+ DMFTCHECKHR_GOTO(spInPin->SendSample( pSample ), done );
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ //
+ //@@@@ README : There is a bug in the sample that the device transform manager which manages the
+ // device MFT does not release the sample after passing it to Device MFT in processInput like it should. The
+ // Device MFT therefore unfortunately has to make sure that the sample that leaves processoutput has a reference count of 1
+ //
+ SAFE_RELEASE(pSample);
+ return hr;
+
+}
+
+IFACEMETHODIMP CMultipinMft::ProcessOutput(
+ _In_ DWORD dwFlags,
+ _In_ DWORD cOutputBufferCount,
+ _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples,
+ _Out_ DWORD *pdwStatus
+)
+/*++
+Description:
+
+Implements IMFTransform::ProcessOutput function. This is called by the DTM when
+the DT indicates it has samples to give. The DTM will send enough MFT_OUTPUT_DATA_BUFFER
+pointers to be filled up as is the number of output pins available. The DT should traverse its
+output pins and populate the corresponding MFT_OUTPUT_DATA_BUFFER with the samples available
+
+--*/
+{
+ HRESULT hr = S_OK;
+ BOOL gotOne = false;
+ ComPtr<COutPin> spOpin;
+ UNREFERENCED_PARAMETER( dwFlags );
+
+ if (cOutputBufferCount > m_OutputPinCount )
+ {
+ DMFTCHECKHR_GOTO( E_INVALIDARG, done );
+ }
+ *pdwStatus = 0;
+
+ for ( DWORD i = 0; i < cOutputBufferCount; i++ )
+ {
+ DWORD dwStreamID = pOutputSamples[i].dwStreamID;
+ {
+ CAutoLock _lock(m_critSec);
+ spOpin = nullptr;
+ spOpin = GetOutPin(dwStreamID);
+ GUID pinGuid = GUID_NULL;
+ DMFTCHECKNULL_GOTO(spOpin.Get(), done, E_INVALIDARG);
+ }
+ if ( SUCCEEDED(spOpin->ProcessOutput( dwFlags, &pOutputSamples[i],
+ pdwStatus ) ) )
+ {
+ if (pOutputSamples[i].pSample)
+ {
+ ProcessMetadata(pOutputSamples[i].pSample);
+ }
+ gotOne = true;
+ }
+ }
+ if (gotOne)
+ {
+ hr = S_OK;
+ }
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+IFACEMETHODIMP CMultipinMft::GetInputStreamAttributes(
+ _In_ DWORD dwInputStreamID,
+ _COM_Outptr_result_maybenull_ IMFAttributes** ppAttributes
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::GetInputStreamAttributes function. This function
+ gets the specified input stream's attributes.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ ComPtr<CInPin> spIPin;
+ CAutoLock Lock(m_critSec);
+
+ DMFTCHECKNULL_GOTO( ppAttributes, done, E_INVALIDARG );
+ *ppAttributes = nullptr;
+
+ spIPin = GetInPin( dwInputStreamID );
+
+ DMFTCHECKNULL_GOTO(spIPin, done, E_INVALIDARG );
+
+ hr = spIPin->getPinAttributes(ppAttributes);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+IFACEMETHODIMP CMultipinMft::GetOutputStreamAttributes(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ IMFAttributes** ppAttributes
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::GetOutputStreamAttributes function. This function
+ gets the specified output stream's attributes.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ ComPtr<COutPin> spoPin;
+ CAutoLock Lock(m_critSec);
+
+ DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG);
+
+ *ppAttributes = nullptr;
+
+ spoPin = GetOutPin(dwOutputStreamID);
+
+ DMFTCHECKNULL_GOTO(spoPin, done, E_INVALIDARG );
+
+ DMFTCHECKHR_GOTO(spoPin->getPinAttributes(ppAttributes), done );
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+_Requires_no_locks_held_
+IFACEMETHODIMP CMultipinMft::SetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::SetInputStreamState function.
+ Sets the input stream state.
+
+ The control lock is not taken here. The lock is taken for operations on
+ output pins. This operation is a result of the DT notifying the DTM that
+ output pin change has resulted in the need for the input to be changed. In
+ this case the DTM sends a getpreferredinputstate and then this call
+
+ --*/
+{
+ HRESULT hr = S_OK;
+ ComPtr<CInPin> spiPin = GetInPin(dwStreamID);
+ CAutoLock Lock(m_critSec);
+
+ DMFTCHECKNULL_GOTO(spiPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ DMFTCHECKHR_GOTO(spiPin->SetInputStreamState(pMediaType, value, dwFlags),done);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+IFACEMETHODIMP CMultipinMft::GetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value
+ )
+{
+ HRESULT hr = S_OK;
+ ComPtr<CInPin> piPin = GetInPin(dwStreamID);
+
+ DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ *value = piPin->GetState();
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+IFACEMETHODIMP CMultipinMft::SetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState state,
+ _In_ DWORD dwFlags
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::SetOutputStreamState function.
+ Sets the output stream state. This is called whenever the stream
+ is selected or deslected i.e. started or stopped.
+
+ The control lock taken here and this operation should be atomic.
+ This function should check the input pins connected to the output pin
+ switch off the state of the input pin. Check if any other Pin connected
+ to the input pin is in a conflicting state with the state requested on this
+ output pin. Accordinly it calculates the media type to be set on the input pin
+ and the state to transition into. It then might recreate the other output pins
+ connected to it
+ --*/
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(dwFlags);
+ CAutoLock Lock(m_critSec);
+
+ DMFTCHECKHR_GOTO(ChangeMediaTypeEx(dwStreamID, pMediaType, state),done);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+IFACEMETHODIMP CMultipinMft::GetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *pState
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::GetOutputStreamState function.
+ Gets the output stream state.
+ Called by the DTM to checks states. Atomic operation. needs a lock
+ --*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+
+ ComPtr<COutPin> spoPin = GetOutPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(pState, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(spoPin, done, MF_E_INVALIDSTREAMNUMBER);
+ *pState = spoPin->GetState();
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+IFACEMETHODIMP CMultipinMft::GetInputStreamPreferredState(
+ _In_ DWORD dwStreamID,
+ _Inout_ DeviceStreamState *value,
+ _Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::GetInputStreamPreferredState function.
+ Gets the preferred state and the media type to be set on the input pin.
+ The lock is not held as this will always be called only when we notify
+ DTM to call us. We notify DTM only from the context on operations
+ happening on the output pin
+ --*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+ ComPtr<CInPin> spiPin = GetInPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(spiPin, done, MF_E_INVALIDSTREAMNUMBER);
+ hr = spiPin->GetInputStreamPreferredState(value, ppMediaType);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+IFACEMETHODIMP CMultipinMft::FlushInputStream(
+ _In_ DWORD dwStreamIndex,
+ _In_ DWORD dwFlags
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::FlushInputStream function.
+ --*/
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(dwStreamIndex);
+ UNREFERENCED_PARAMETER(dwFlags);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+IFACEMETHODIMP CMultipinMft::FlushOutputStream(
+ _In_ DWORD dwStreamIndex,
+ _In_ DWORD dwFlags
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::FlushOutputStream function.
+ Called by the DTM to flush streams
+ --*/
+{
+
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(dwFlags);
+ CAutoLock Lock(m_critSec);
+
+ ComPtr<COutPin> spoPin = GetOutPin(dwStreamIndex);
+ DMFTCHECKNULL_GOTO(spoPin, done, E_INVALIDARG);
+ DeviceStreamState oldState = spoPin->SetState(DeviceStreamState_Disabled);
+ DMFTCHECKHR_GOTO(spoPin->FlushQueues(),done);
+ spoPin->SetState(oldState);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+/*++
+ Description:
+
+ Called when the Device Transform gets a MFT_MESSAGE_COMMAND_FLUSH. We drain all the queues.
+ This is called in device source when the source gets end of streaming.
+ --*/
+IFACEMETHODIMP_(VOID) CMultipinMft::FlushAllStreams(
+ VOID
+ )
+{
+ DeviceStreamState oldState;
+ CAutoLock Lock(m_critSec);
+ for ( DWORD dwIndex = 0, dwSize = (DWORD)m_OutPins.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ ComPtr<COutPin> spoPin = (COutPin *)m_OutPins[dwIndex].Get();
+ oldState = spoPin->SetState(DeviceStreamState_Disabled);
+ spoPin->FlushQueues();
+ //
+ //Restore state
+ //
+ spoPin->SetState(oldState);
+ }
+}
+
+//
+// IKsControl interface functions
+//
+IFACEMETHODIMP CMultipinMft::KsProperty(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pvPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pulBytesReturned
+ )
+ /*++
+ Description:
+
+ Implements IKSProperty::KsProperty function.
+ used to pass control commands to the driver (generally)
+ This can be used to intercepted the control to figure out
+ if it needs to be propogated to the driver or not
+ --*/
+{
+ HRESULT hr = S_OK;
+
+ DMFTCHECKHR_GOTO(m_spIkscontrol->KsProperty(pProperty,
+ ulPropertyLength,
+ pvPropertyData,
+ ulDataLength,
+ pulBytesReturned),done);
+done:
+ return hr;
+}
+
+IFACEMETHODIMP CMultipinMft::KsMethod(
+ _In_reads_bytes_(ulPropertyLength) PKSMETHOD pMethod,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pvPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pulBytesReturned
+ )
+ /*++
+ Description:
+
+ Implements IKSProperty::KsMethod function. We can trap ksmethod calls here.
+ --*/
+{
+ HRESULT hr = S_OK;
+
+ DMFTCHECKHR_GOTO(m_spIkscontrol->KsMethod(
+ pMethod,
+ ulPropertyLength,
+ pvPropertyData,
+ ulDataLength,
+ pulBytesReturned
+ ), done);
+done:
+ return hr;
+}
+
+IFACEMETHODIMP CMultipinMft::KsEvent(
+ _In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ )
+ /*++
+ Description:
+
+ Implements IKSProperty::KsEvent function.
+ --*/
+{
+
+ 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;
+}
+
+//
+// HELPER FUNCTIONS
+//
+
+//
+// A lock here could mean a deadlock because this will be called when the lock is already held
+// in another thread.
+//
+CInPin* CMultipinMft::GetInPin(
+ _In_ DWORD dwStreamId
+)
+{
+ CInPin *inPin = NULL;
+ for (DWORD dwIndex = 0, dwSize = (DWORD)m_InPins.size(); dwIndex < dwSize; dwIndex++)
+ {
+ inPin = (CInPin *)m_InPins[dwIndex].Get();
+ if (dwStreamId == inPin->streamId())
+ {
+ break;
+ }
+ inPin = NULL;
+ }
+ return inPin;
+}
+
+COutPin* CMultipinMft::GetOutPin(
+ _In_ DWORD dwStreamId
+ )
+{
+ COutPin *outPin = NULL;
+ for ( DWORD dwIndex = 0, dwSize = (DWORD) m_OutPins.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ outPin = ( COutPin * )m_OutPins[ dwIndex ].Get();
+
+ if ( dwStreamId == outPin->streamId() )
+ {
+ break;
+ }
+
+ outPin = NULL;
+ }
+
+ return outPin;
+}
+_Requires_lock_held_(m_Critsec)
+HRESULT CMultipinMft::GetConnectedInpin(_In_ ULONG ulOutpin, _Out_ ULONG &ulInPin)
+{
+ HRESULT hr = S_OK;
+ map<int, int>::iterator it = m_outputPinMap.find(ulOutpin);
+ if (it != m_outputPinMap.end())
+ {
+ ulInPin = it->second;
+ }
+ else
+ {
+ hr = MF_E_INVALIDSTREAMNUMBER;
+ }
+ return hr;
+}
+
+//
+// The Below function changes media type on the pins exposed by device MFT
+//
+__requires_lock_held(m_critSec)
+HRESULT CMultipinMft::ChangeMediaTypeEx(
+ _In_ ULONG pinId,
+ _In_opt_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState reqState
+)
+{
+ HRESULT hr = S_OK;
+ ComPtr<COutPin> spoPin = GetOutPin(pinId);
+ ComPtr<CInPin> spinPin;
+ DeviceStreamState oldOutPinState, oldInputStreamState, newOutStreamState, newRequestedInPinState;
+ ComPtr<IMFMediaType> pFullType, pInputMediaType;
+ ULONG ulInPinId = 0;
+ DWORD dwFlags = 0;
+
+
+ DMFTCHECKNULL_GOTO(spoPin, done, E_INVALIDARG);
+
+ if (pMediaType)
+ {
+ if (!spoPin->IsMediaTypeSupported(pMediaType, &pFullType))
+ {
+ DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done);
+ }
+ }
+
+ DMFTCHECKHR_GOTO(GetConnectedInpin(pinId, ulInPinId), done);
+ spinPin = GetInPin(ulInPinId); // Get the input pin
+
+ (VOID)spinPin->getMediaType(&pInputMediaType);
+ oldInputStreamState = spinPin->SetState(DeviceStreamState_Disabled); // Disable input pin
+ oldOutPinState = spoPin->SetState(DeviceStreamState_Disabled); // Disable output pin
+ (void)spoPin->FlushQueues(); // Flush the output queues
+ (void)spinPin->FlushQueues(); // Flush the input queues
+ newOutStreamState = pinStateTransition[oldOutPinState][reqState]; // New state needed
+
+ // The Old input and the output pin states should be the same
+ newRequestedInPinState = newOutStreamState;
+
+ if ((newOutStreamState != oldOutPinState) /*State change*/
+ ||((pFullType.Get() != nullptr) && (pInputMediaType.Get()!=nullptr) && (S_OK != (pFullType->IsEqual(pInputMediaType.Get(), &dwFlags)))) /*Media Types dont match*/
+ ||((pFullType == nullptr)||(pInputMediaType == nullptr))/*Either one of the mediatypes is null*/
+ )
+ {
+ //
+ // State has change or media type has changed so we need to change the media type on the
+ // underlying kernel pin
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Changing Mediatype on the input ");
+ spinPin->setPreferredMediaType(pFullType.Get());
+ spinPin->setPreferredStreamState(newRequestedInPinState);
+ // Let the pipline know that the input needs to be changed.
+ SendEventToManager(METransformInputStreamStateChanged, GUID_NULL, spinPin->streamId());
+ //
+ // The media type will be set on the input pin by the time we return from the wait
+ //
+ m_critSec.Unlock();
+ hr = spinPin->WaitForSetInputPinMediaChange();
+ m_critSec.Lock();
+ // Change the media type on the output..
+ DMFTCHECKHR_GOTO(spoPin->ChangeMediaTypeFromInpin( pMediaType , reqState), done);
+ //
+ // Notify the pipeline that the output stream media type has changed
+ //
+ DMFTCHECKHR_GOTO(SendEventToManager(MEUnknown, MEDeviceStreamCreated, spoPin->streamId()), done);
+ spoPin->SetFirstSample(TRUE);
+ }
+ else
+ {
+ // Restore back old states as we have nothing to do
+ spinPin->SetState(oldInputStreamState);
+ spoPin->SetState(oldOutPinState);
+ }
+
+
+done:
+ return hr;
+}
+
+//
+// The below function sends events to the pipeline.
+//
+
+HRESULT CMultipinMft::SendEventToManager(
+ _In_ MediaEventType eventType,
+ _In_ REFGUID pGuid,
+ _In_ UINT32 context
+ )
+ /*++
+ Description:
+ Used to send the event to DTM.
+ --*/
+ {
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaEvent> pEvent = nullptr;
+
+ DMFTCHECKHR_GOTO(MFCreateMediaEvent(eventType, pGuid, S_OK, NULL, &pEvent ),done);
+ DMFTCHECKHR_GOTO(pEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, (ULONG)context),done);
+ DMFTCHECKHR_GOTO(QueueEvent(pEvent.Get()),done);
+ done:
+
+ return hr;
+ }
+/*++
+Description:
+This function connects the input and output pins.
+Any media type filtering can happen here
+--*/
+HRESULT CMultipinMft::BridgeInputPinOutputPin(
+ _In_ CInPin* piPin,
+ _In_ COutPin* poPin
+ )
+{
+ HRESULT hr = S_OK;
+ ULONG ulIndex = 0;
+ ULONG ulAddedMediaTypeCount = 0;
+ ComPtr<IMFMediaType> spMediaType;
+
+ DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG );
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+
+ while ( SUCCEEDED( hr = piPin->GetMediaTypeAt( ulIndex++, spMediaType.ReleaseAndGetAddressOf() )))
+ {
+ DMFTCHECKHR_GOTO(hr = poPin->AddMediaType(NULL, spMediaType.Get() ), done );
+ ulAddedMediaTypeCount++;
+ }
+
+ if (ulAddedMediaTypeCount == 0)
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Make Sure Pin %d has one media type exposed ", piPin->streamId());
+ DMFTCHECKHR_GOTO( MF_E_INVALID_STREAM_DATA, done );
+ }
+ //
+ //Add the Input Pin to the output Pin
+ //
+ DMFTCHECKHR_GOTO(poPin->AddPin(piPin->streamId()), done);
+ hr = ExceptionBoundary([&](){
+ //
+ // Add the output pin to the input pin.
+ // Create the pin map. So that we know which pin input pin is connected to which output pin
+ //
+ piPin->ConnectPin(poPin);
+ m_outputPinMap.insert(std::pair< int, int >(poPin->streamId(), piPin->streamId()));
+ });
+done:
+ //
+ //Failed adding media types
+ //
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ }
+ return hr;
+}
+
+//
+// IMFShutdown interface functions
+//
+
+/*++
+Description:
+Implements the Shutdown from IMFShutdown
+--*/
+IFACEMETHODIMP CMultipinMft::Shutdown(
+ void
+ )
+{
+ CAutoLock Lock(m_critSec);
+
+ for (ULONG ulIndex = 0, ulSize = (ULONG)m_InPins.size(); ulIndex < ulSize; ulIndex++ )
+ {
+ CInPin *pInPin = static_cast<CInPin *>(m_InPins[ulIndex].Get());
+
+ // Deref on the connected outpins to break reference loop
+ (VOID)pInPin->ShutdownPin();
+ }
+ return ShutdownEventGenerator();
+}
+
+//
+// Static method to create an instance of the MFT.
+//
+HRESULT CMultipinMft::CreateInstance(REFIID iid, void **ppMFT)
+{
+ HRESULT hr = S_OK;
+ ComPtr<CMultipinMft> spMFT;
+ DMFTCHECKNULL_GOTO(ppMFT, done, E_POINTER);
+ spMFT = new (std::nothrow) CMultipinMft();
+ DMFTCHECKNULL_GOTO(spMFT.Get(), done, E_OUTOFMEMORY);
+
+ DMFTCHECKHR_GOTO(spMFT->QueryInterface(iid, ppMFT), done);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.h b/avstream/avscamera/DMFT/AvsCameraDMFT.h
new file mode 100644
index 00000000..27b8607b
--- /dev/null
+++ b/avstream/avscamera/DMFT/AvsCameraDMFT.h
@@ -0,0 +1,334 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+
+#pragma once
+#include "common.h"
+#include "mftpeventgenerator.h"
+#include "basepin.h"
+
+//
+// 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
+// This attribute is known to the OS, but not publicly defined.
+//
+
+DEFINE_GUID(MFSourceReader_SampleAttribute_MediaType_priv,
+ 0x0ea5c1e8, 0x9845, 0x41e0, 0xa2, 0x43, 0x72, 0x32, 0x07, 0xfc, 0x78, 0x1f);
+
+
+interface IDirect3DDeviceManager9;
+
+//
+// Forward declarations
+//
+class CMFAttributes;
+class CPinCreationFactory;
+//
+// CMultipinMft class:
+// Implements a device proxy MFT.
+//
+class CMultipinMft :
+ public IMFDeviceTransform
+ , public IMFShutdown
+ , public CMediaEventGenerator
+ , public IMFRealTimeClientEx
+ , public IKsControl
+ , public CDMFTModuleLifeTimeManager
+{
+ friend class CPinCreationFactory;
+public:
+ CMultipinMft(
+ void );
+
+ virtual ~CMultipinMft();
+
+ //
+ // IUnknown
+ //
+ IFACEMETHODIMP_(ULONG) AddRef(
+ void );
+
+ IFACEMETHODIMP_(ULONG) Release(
+ void );
+
+ IFACEMETHODIMP QueryInterface(
+ _In_ REFIID iid,
+ _COM_Outptr_ void** ppv);
+
+
+ //
+ // IMFDeviceTransform functions
+ //
+ IFACEMETHODIMP GetStreamCount (
+ _Inout_ DWORD *pdwInputStreams,
+ _Inout_ DWORD *pdwOutputStreams);
+
+
+ IFACEMETHODIMP GetStreamIDs (
+ _In_ DWORD dwInputIDArraySize,
+ _When_(dwInputIDArraySize >= m_InputPinCount, _Out_writes_(dwInputIDArraySize)) DWORD* pdwInputIDs,
+ _In_ DWORD dwOutputIDArraySize,
+ _When_(dwOutputIDArraySize >= m_OutputPinCount && (pdwInputIDs && (dwInputIDArraySize > 0)),
+ _Out_writes_(dwOutputIDArraySize)) _On_failure_(_Valid_) DWORD* pdwOutputIDs
+ );
+
+ IFACEMETHODIMP GetInputStreamAttributes(
+ _In_ DWORD dwInputStreamID,
+ _COM_Outptr_result_maybenull_ IMFAttributes** ppAttributes);
+
+ IFACEMETHODIMP GetOutputStreamAttributes(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ IMFAttributes** ppAttributes);
+
+ IFACEMETHODIMP GetInputAvailableType(
+ _In_ DWORD dwInputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppType);
+
+ IFACEMETHODIMP GetOutputAvailableType(
+ _In_ DWORD dwOutputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppMediaType);
+
+ IFACEMETHODIMP GetInputCurrentType(
+ _In_ DWORD dwInputStreamID,
+ _COM_Outptr_result_maybenull_ IMFMediaType** ppMediaType);
+
+ IFACEMETHODIMP GetOutputCurrentType(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ IMFMediaType** ppMediaType);
+
+ IFACEMETHODIMP ProcessMessage(
+ _In_ MFT_MESSAGE_TYPE eMessage,
+ _In_ ULONG_PTR ulParam );
+
+ IFACEMETHODIMP ProcessEvent(
+ _In_ DWORD dwInputStreamID,
+ _In_ IMFMediaEvent *pEvent);
+
+
+ IFACEMETHODIMP ProcessInput(
+ _In_ DWORD dwInputStreamID,
+ _In_ IMFSample* pSample,
+ _In_ DWORD dwFlags );
+
+ IFACEMETHODIMP ProcessOutput(
+ _In_ DWORD dwFlags,
+ _In_ DWORD cOutputBufferCount,
+ _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples,
+ _Out_ DWORD *pdwStatus );
+
+ //
+ // IMFRealTimeClientEx
+ //
+ IFACEMETHODIMP RegisterThreadsEx(
+ _Inout_ DWORD* pdwTaskIndex,
+ _In_ LPCWSTR wszClassName,
+ _In_ LONG lBasePriority )
+ {
+ UNREFERENCED_PARAMETER(pdwTaskIndex);
+ UNREFERENCED_PARAMETER(wszClassName);
+ UNREFERENCED_PARAMETER(lBasePriority);
+ return S_OK;
+ }
+
+ IFACEMETHODIMP UnregisterThreads()
+ {
+ return S_OK;
+ }
+
+ IFACEMETHODIMP SetWorkQueueEx(
+ _In_ DWORD dwWorkQueueId,
+ _In_ LONG lWorkItemBasePriority );
+
+ //
+ // IMFShutdown
+ //
+ IFACEMETHODIMP Shutdown(
+ void );
+
+ IFACEMETHODIMP GetShutdownStatus(
+ MFSHUTDOWN_STATUS *pStatus)
+ {
+ UNREFERENCED_PARAMETER(pStatus);
+ return(m_eShutdownStatus);
+ };
+
+ //
+ // IMFDeviceTransform function declarations
+ //
+ IFACEMETHODIMP InitializeTransform(
+ _In_ IMFAttributes *pAttributes );
+
+ _Requires_no_locks_held_
+ IFACEMETHODIMP SetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags );
+
+ IFACEMETHODIMP GetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value );
+
+ IFACEMETHODIMP SetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags );
+
+ IFACEMETHODIMP GetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value );
+
+ IFACEMETHODIMP GetInputStreamPreferredState(
+ _In_ DWORD dwStreamID,
+ _Inout_ DeviceStreamState *value,
+ _Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType );
+
+ IFACEMETHODIMP FlushInputStream(
+ _In_ DWORD dwStreamIndex,
+ _In_ DWORD dwFlags );
+
+ IFACEMETHODIMP FlushOutputStream(
+ _In_ DWORD dwStreamIndex,
+ _In_ DWORD dwFlags );
+
+ IFACEMETHODIMP_(VOID) FlushAllStreams(
+ VOID
+ );
+
+ //
+ //IKSControl Inferface function declarations
+ //
+ IFACEMETHODIMP KsEvent(
+ _In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ );
+ IFACEMETHODIMP KsProperty(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ );
+ IFACEMETHODIMP KsMethod(
+ _In_reads_bytes_(ulPropertyLength) PKSMETHOD pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ );
+
+ static HRESULT CreateInstance(
+ REFIID iid, void **ppMFT);
+
+ __inline BOOL isPhotoModePhotoSequence()
+ {
+ return m_PhotoModeIsPhotoSequence;
+ }
+
+ __inline DWORD GetQueueId()
+ {
+ return m_dwWorkQueueId;
+ }
+
+ //
+ //Will be used from Pins to get the D3D manager once set!!!
+ //
+ __inline IFACEMETHODIMP_(VOID) GetD3DDeviceManager(
+ IUnknown** ppDeviceManagerUnk
+ )
+ {
+ m_spDeviceManagerUnk.CopyTo( ppDeviceManagerUnk );
+ }
+
+ HRESULT SendEventToManager(
+ _In_ MediaEventType,
+ _In_ REFGUID,
+ _In_ UINT32
+ );
+
+protected:
+
+ //
+ //Helper functions
+ //
+
+ CInPin* GetInPin(
+ _In_ DWORD dwStreamID
+ );
+
+ COutPin* GetOutPin(
+ _In_ DWORD dwStreamID
+ );
+
+ HRESULT GetConnectedInpin(_In_ ULONG ulOutpin, _Out_ ULONG &ulInPin);
+
+ __requires_lock_held(m_critSec)
+ HRESULT ChangeMediaTypeEx(
+ _In_ ULONG pinId,
+ _In_opt_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState newState
+ );
+ HRESULT BridgeInputPinOutputPin(
+ _In_ CInPin* pInPin,
+ _In_ COutPin* pOutPin);
+ //
+ //Inline functions
+ //
+
+ __inline IMFDeviceTransform* Parent()
+ {
+ return m_spSourceTransform.Get();
+ }
+
+ __inline VOID SetStreamingState(DeviceStreamState state)
+ {
+ InterlockedExchange((LONG*)&m_StreamingState, state);
+ }
+
+ __inline DeviceStreamState GetStreamingState()
+ {
+ return (DeviceStreamState)InterlockedCompareExchange((LONG*)&m_StreamingState, 0L, 0L);
+ }
+
+ __inline BOOL IsStreaming()
+ {
+ return (InterlockedCompareExchange((LONG*)&m_StreamingState, DeviceStreamState_Run, DeviceStreamState_Run) == DeviceStreamState_Run);
+ }
+
+private:
+ ULONG m_InputPinCount;
+ ULONG m_OutputPinCount;
+ ULONG m_CustomPinCount;
+ DeviceStreamState m_StreamingState;
+ CBasePinArray m_OutPins;
+ CBasePinArray m_InPins;
+ BOOL m_PhotoModeIsPhotoSequence; // used to store if the filter is in photo sequence or not
+ long m_nRefCount; // Reference count
+ CCritSec m_critSec; // Control lock.. taken only durign state change operations
+ ComPtr <IUnknown> m_spDeviceManagerUnk; // D3D Manager set, when MFT_MESSAGE_SET_D3D_MANAGER is called through ProcessMessage
+ ComPtr<IMFDeviceTransform> m_spSourceTransform; // The sources transform. This is the pipeline DevProxy
+ MFSHUTDOWN_STATUS m_eShutdownStatus;
+ DWORD m_dwWorkQueueId;
+ LONG m_lWorkQueuePriority;
+ UINT32 m_punValue;
+ ComPtr<IKsControl> m_spIkscontrol;
+ ComPtr<IMFAttributes> m_spAttributes;
+ map<int, int> m_outputPinMap; // How output pins are connected to input pins i-><0..outpins>
+ PWCHAR m_SymbolicLink;
+};
+
+
+
+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
new file mode 100644
index 00000000..3f6180f2
--- /dev/null
+++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj
@@ -0,0 +1,250 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|ARM64">
+ <Configuration>Debug</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|ARM64">
+ <Configuration>Release</Configuration>
+ <Platform>ARM64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{E77657CD-A270-49E1-823A-8A14FF8596C8}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <SupportsPackaging>false</SupportsPackaging>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{D6CB33D6-DEF2-497E-A72D-6E6E29C67F48}</SampleGuid>
+ <ProjectName>AvsCameraDMFT</ProjectName>
+ <WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>False</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
+ <TargetVersion>Windows10</TargetVersion>
+ <UseDebugLibraries>True</UseDebugLibraries>
+ <DriverTargetPlatform>Universal</DriverTargetPlatform>
+ <DriverType />
+ <PlatformToolset>WindowsApplicationForDrivers10.0</PlatformToolset>
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <OutDir>$(IntDir)</OutDir>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ItemGroup Label="WrappedTaskItems">
+ <ClCompile Include="mftpeventgenerator.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ <WppScanConfigurationData>common.h</WppScanConfigurationData>
+ </ClCompile>
+ <ClCompile Include="AvsCameraDMFT.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ <WppScanConfigurationData>common.h</WppScanConfigurationData>
+ </ClCompile>
+ <ClCompile Include="basepin.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ <WppScanConfigurationData>common.h</WppScanConfigurationData>
+ </ClCompile>
+ <ClCompile Include="AvsCameraDMFTutils.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ <WppScanConfigurationData>common.h</WppScanConfigurationData>
+ </ClCompile>
+ <ClCompile Include="dllmain.cpp">
+ <WppEnabled>true</WppEnabled>
+ <WppDllMacro>true</WppDllMacro>
+ <WppTraceFunction>DMFTRACE(FLAG,LEVEL,MSG,...)</WppTraceFunction>
+ <WppGenerateUsingTemplateFile>{um-default.tpl}*.tmh</WppGenerateUsingTemplateFile>
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Use</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ <WppScanConfigurationData>common.h</WppScanConfigurationData>
+ </ClCompile>
+ </ItemGroup>
+ <PropertyGroup>
+ <TargetName>AvsCameraDMFT</TargetName>
+ <IncludePath>$(VC_IncludePath);$(WindowsSDK_IncludePath);..\..\wil\include</IncludePath>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories);..\..\common;..\common</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Midl>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </Midl>
+ <ResourceCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </ResourceCompile>
+ <Link>
+ <AdditionalDependencies>%(AdditionalDependencies);D2d1.lib;mf.lib;mfplat.lib;mfuuid.lib;uuid.lib</AdditionalDependencies>
+ <ModuleDefinitionFile>Source.def</ModuleDefinitionFile>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="stdafxsrc.cpp">
+ <AdditionalIncludeDirectories>;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreCompiledHeaderFile>stdafx.h</PreCompiledHeaderFile>
+ <PreCompiledHeader>Create</PreCompiledHeader>
+ <PreCompiledHeaderOutputFile>$(IntDir)\stdafx.h.pch</PreCompiledHeaderOutputFile>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <Inf Exclude="@(Inf)" Include="*.inf" />
+ <FilesToPackage Include="$(TargetPath)" Condition="'$(ConfigurationType)'=='Driver' or '$(ConfigurationType)'=='DynamicLibrary'" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Exclude="@(None)" Include="*.txt;*.htm;*.html" />
+ <None Exclude="@(None)" Include="*.ico;*.cur;*.bmp;*.dlg;*.rct;*.gif;*.jpg;*.jpeg;*.wav;*.jpe;*.tiff;*.tif;*.png;*.rc2" />
+ <None Include="Source.def" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="basepin.h" />
+ <ClInclude Include="common.h" />
+ <ClInclude Include="mftpeventgenerator.h" />
+ <ClInclude Include="AvsCameraDMFT.h" />
+ <ClInclude Include="stdafx.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters
new file mode 100644
index 00000000..c3679c84
--- /dev/null
+++ b/avstream/avscamera/DMFT/AvsCameraDMFT.vcxproj.Filters
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx;*</Extensions>
+ <UniqueIdentifier>{39379DB7-5CE0-407A-A6D4-F2F23BB3BF3C}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{05E63691-6953-4F79-BEC2-1CF881B618BA}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Resource Files">
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms;man;xml</Extensions>
+ <UniqueIdentifier>{B10F4398-9892-4AA8-8653-E5A7F4726726}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="basepin.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dllmain.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="mftpeventgenerator.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="AvsCameraDMFT.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="AvsCameraDMFTutils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="stdafxsrc.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <None Include="Source.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="basepin.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="common.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="mftpeventgenerator.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="AvsCameraDMFT.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="stdafx.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/avstream/avscamera/DMFT/AvsCameraDMFTutils.cpp b/avstream/avscamera/DMFT/AvsCameraDMFTutils.cpp
new file mode 100644
index 00000000..4a4c75fc
--- /dev/null
+++ b/avstream/avscamera/DMFT/AvsCameraDMFTutils.cpp
@@ -0,0 +1,805 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#include "stdafx.h"
+
+#pragma comment(lib, "d2d1")
+#ifdef MF_WPP
+#include "AvsCameraDMFTutils.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+
+// Critical sections
+
+CCritSec::CCritSec()
+{
+ InitializeCriticalSection(&m_criticalSection);
+}
+
+CCritSec::~CCritSec()
+{
+ DeleteCriticalSection(&m_criticalSection);
+}
+
+_Requires_lock_not_held_(m_criticalSection) _Acquires_lock_(m_criticalSection)
+void CCritSec::Lock()
+{
+ EnterCriticalSection(&m_criticalSection);
+}
+
+_Requires_lock_held_(m_criticalSection) _Releases_lock_(m_criticalSection)
+void CCritSec::Unlock()
+{
+ LeaveCriticalSection(&m_criticalSection);
+}
+
+
+_Acquires_lock_(this->m_pCriticalSection->m_criticalSection)
+CAutoLock::CAutoLock(CCritSec& crit)
+{
+ m_pCriticalSection = &crit;
+ m_pCriticalSection->Lock();
+}
+_Acquires_lock_(this->m_pCriticalSection->m_criticalSection)
+CAutoLock::CAutoLock(CCritSec* crit)
+{
+ m_pCriticalSection = crit;
+ m_pCriticalSection->Lock();
+}
+_Releases_lock_(this->m_pCriticalSection->m_criticalSection)
+CAutoLock::~CAutoLock()
+{
+ m_pCriticalSection->Unlock();
+}
+
+//
+//Some utility functions..
+/*++
+ Description:
+ Helper function to return back if the Pin is in stopped stateo or not
+--*/
+STDMETHODIMP_(BOOL) IsPinStateInActive( _In_ DeviceStreamState state)
+{
+ if ((state == DeviceStreamState_Disabled) ||
+ (state == DeviceStreamState_Stop))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+#ifndef IF_EQUAL_RETURN
+#define IF_EQUAL_RETURN(param, val) if(val == param) return #val
+#endif
+
+#define checkAdjustBufferCap(a,len){\
+ char* tStore = NULL; \
+if (a && strlen(a) > ((len * 7) / 10)){\
+ tStore = a; \
+ len *= 2; \
+ a = new (std::nothrow) char[len]; \
+if (!a){\
+goto done;}\
+ a[0] = 0; \
+ strcat_s(a, len, tStore); \
+ delete(tStore); }\
+}
+
+//
+// Queue implementation
+//
+CPinQueue::CPinQueue(_In_ DWORD dwPinId, _In_ IMFDeviceTransform* pParent) :
+ m_dwInPinId(dwPinId), m_pTransform(pParent), m_cRef(1)
+
+/*
+Description
+dwPinId is the input pin Id to which this queue corresponds
+*/
+{
+ m_streamCategory = GUID_NULL;
+}
+CPinQueue::~CPinQueue()
+{
+}
+
+/*++
+Description:
+ Insert sample into the list once we reach the open queue
+--*/
+STDMETHODIMP CPinQueue::Insert(_In_ IMFSample* pSample)
+{
+ HRESULT hr = ExceptionBoundary([&]() {
+ m_sampleList.push_back(pSample);
+ });
+
+ if (SUCCEEDED(hr) && m_pTransform)
+ {
+ hr = reinterpret_cast<CMultipinMft*>(m_pTransform)->QueueEvent(METransformHaveOutput, GUID_NULL, S_OK, NULL);
+ }
+
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ // There is a bug in the pipeline that doesn't release the sample fed from processinput. We have to explicitly release the sample here
+ SAFE_RELEASE(pSample);
+ }
+ return hr;
+}
+
+
+/*++
+Description:
+ This extracts the first sample from the queue. called from Pin's ProcessOutput
+--*/
+
+STDMETHODIMP CPinQueue::Remove(_Outptr_result_maybenull_ IMFSample** ppSample)
+{
+ HRESULT hr = S_OK;
+ DMFTCHECKNULL_GOTO(ppSample, done, E_INVALIDARG);
+ *ppSample = nullptr;
+
+ if (!m_sampleList.empty())
+ {
+ *ppSample = m_sampleList.front().Detach();
+ }
+
+ DMFTCHECKNULL_GOTO(*ppSample, done, MF_E_TRANSFORM_NEED_MORE_INPUT);
+ m_sampleList.erase(m_sampleList.begin());
+done:
+ return hr;
+}
+
+/*++
+Description:
+ Empties the Queue. used by the flush
+--*/
+VOID CPinQueue::Clear()
+{
+ while (!Empty())
+ {
+ ComPtr<IMFSample> spSample;
+ Remove(spSample.GetAddressOf());
+ }
+}
+
+// Handle Metadata
+
+#if (NTDDI_VERSION >= NTDDI_WINBLUE)
+/////////////////////////////////////////////////////////////////////
+//
+// Handle the Metadata with the buffer
+//
+
+HRESULT ParseMetadata_FaceDetection(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes* pMetaDataAttributes
+);
+
+HRESULT ParseMetadata_PreviewAggregation(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes* pMetaDataAttributes
+);
+
+HRESULT ParseMetadata_ImageAggregation(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes* pMetaDataAttributes
+);
+
+HRESULT ParseMetadata_Histogram(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes* pMetaDataAttributes
+);
+
+HRESULT ProcessMetadata(_In_ IMFSample* pSample)
+{
+ ComPtr<IMFAttributes> spMetadata;
+ ComPtr<IMFSample> spSample = pSample;
+ HRESULT hr = spSample->GetUnknown(MFSampleExtension_CaptureMetadata, IID_PPV_ARGS(spMetadata.ReleaseAndGetAddressOf()));
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ ComPtr<IMFMediaBuffer> spBuffer;
+ hr = spMetadata->GetUnknown(MF_CAPTURE_METADATA_FRAME_RAWSTREAM, IID_PPV_ARGS(spBuffer.ReleaseAndGetAddressOf()));
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ MediaBufferLock bufferLock(spBuffer.Get());
+ BYTE* pData = NULL;
+ DWORD dwLength = 0;
+ hr = bufferLock.LockBuffer(&pData, NULL, &dwLength);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ // OEM put meta data passing logic here,
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+
+ LONG lBufferLeft = static_cast<LONG>(dwLength);
+ if (lBufferLeft < sizeof(KSCAMERA_METADATA_ITEMHEADER))
+ {
+ return E_UNEXPECTED;
+ }
+
+ PKSCAMERA_METADATA_ITEMHEADER pItem = (PKSCAMERA_METADATA_ITEMHEADER)pData;
+
+ while (lBufferLeft > 0)
+ {
+ switch (pItem->MetadataId)
+ {
+ case MetadataId_Custom_PreviewAggregation:
+ hr = ParseMetadata_PreviewAggregation(pItem, spMetadata.Get());
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ break;
+ case MetadataId_Custom_ImageAggregation:
+ hr = ParseMetadata_ImageAggregation(pItem, spMetadata.Get());
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ break;
+ case MetadataId_Custom_Histogram:
+ hr = ParseMetadata_Histogram(pItem, spMetadata.Get());
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ break;
+ case MetadataId_Custom_FaceDetection:
+ hr = ParseMetadata_FaceDetection(pItem, spMetadata.Get());
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (!pItem->Size)
+ {
+ // 0 size item will cause the loop to break and
+ // we will report buffer malformated
+ break;
+ }
+ lBufferLeft -= (LONG)pItem->Size;
+ if (lBufferLeft < sizeof(KSCAMERA_METADATA_ITEMHEADER))
+ {
+ break;
+ }
+ pItem = reinterpret_cast<PKSCAMERA_METADATA_ITEMHEADER>
+ (reinterpret_cast<PBYTE>(pItem) + pItem->Size);
+ }
+
+ if (lBufferLeft != 0)
+ {
+ //Check and log for malformated data
+ return E_UNEXPECTED;
+ }
+
+ return S_OK;
+}
+
+HRESULT ParseMetadata_PreviewAggregation(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes* pMetaDataAttributes
+)
+{
+ HRESULT hr = S_OK;
+ if (pItem->Size < sizeof(CAMERA_METADATA_PREVIEWAGGREGATION))
+ {
+ return E_UNEXPECTED;
+ }
+
+ PCAMERA_METADATA_PREVIEWAGGREGATION pFixedStruct =
+ (PCAMERA_METADATA_PREVIEWAGGREGATION)pItem;
+
+ if (pFixedStruct->Data.FocusState.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_FOCUSSTATE,
+ pFixedStruct->Data.FocusState.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.ExposureTime.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT64(
+ MF_CAPTURE_METADATA_EXPOSURE_TIME,
+ pFixedStruct->Data.ExposureTime.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.ISOSpeed.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_ISO_SPEED,
+ pFixedStruct->Data.ISOSpeed.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.LensPosition.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_LENS_POSITION,
+ pFixedStruct->Data.LensPosition.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.FlashOn.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_FLASH,
+ pFixedStruct->Data.FlashOn.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.WhiteBalanceMode.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_WHITEBALANCE,
+ pFixedStruct->Data.WhiteBalanceMode.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.EVCompensation.Set)
+ {
+ CapturedMetadataExposureCompensation EVCompensation;
+
+ EVCompensation.Flags = pFixedStruct->Data.EVCompensation.Flags;
+ EVCompensation.Value = pFixedStruct->Data.EVCompensation.Value;
+
+ hr = pMetaDataAttributes->SetBlob(
+ MF_CAPTURE_METADATA_EXPOSURE_COMPENSATION,
+ (const UINT8*)&EVCompensation,
+ sizeof(EVCompensation));
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.SensorFrameRate.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT64(
+ MF_CAPTURE_METADATA_SENSORFRAMERATE,
+ pFixedStruct->Data.SensorFrameRate.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.IsoAnalogGain.Set ||
+ pFixedStruct->Data.IsoDigitalGain.Set)
+ {
+ CapturedMetadataISOGains IsoGains;
+
+ if (pFixedStruct->Data.IsoAnalogGain.Set)
+ {
+ IsoGains.AnalogGain =
+ FLOAT(pFixedStruct->Data.IsoAnalogGain.Numerator) /
+ FLOAT(pFixedStruct->Data.IsoAnalogGain.Denominator);
+ }
+ if (pFixedStruct->Data.IsoDigitalGain.Set)
+ {
+ IsoGains.DigitalGain =
+ FLOAT(pFixedStruct->Data.IsoDigitalGain.Numerator) /
+ FLOAT(pFixedStruct->Data.IsoDigitalGain.Denominator);
+ }
+
+ hr = pMetaDataAttributes->SetBlob(
+ MF_CAPTURE_METADATA_ISO_GAINS,
+ (const UINT8*)&IsoGains,
+ sizeof(IsoGains));
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.WhiteBalanceGain_R.Set ||
+ pFixedStruct->Data.WhiteBalanceGain_G.Set ||
+ pFixedStruct->Data.WhiteBalanceGain_B.Set)
+ {
+ CapturedMetadataWhiteBalanceGains WhiteBalanceGains;
+
+ if (pFixedStruct->Data.WhiteBalanceGain_R.Set)
+ {
+ WhiteBalanceGains.R =
+ FLOAT(pFixedStruct->Data.WhiteBalanceGain_R.Numerator) /
+ FLOAT(pFixedStruct->Data.WhiteBalanceGain_R.Denominator);
+ }
+ if (pFixedStruct->Data.WhiteBalanceGain_G.Set)
+ {
+ WhiteBalanceGains.G =
+ FLOAT(pFixedStruct->Data.WhiteBalanceGain_G.Numerator) /
+ FLOAT(pFixedStruct->Data.WhiteBalanceGain_G.Denominator);
+ }
+ if (pFixedStruct->Data.WhiteBalanceGain_B.Set)
+ {
+ WhiteBalanceGains.B =
+ FLOAT(pFixedStruct->Data.WhiteBalanceGain_B.Numerator) /
+ FLOAT(pFixedStruct->Data.WhiteBalanceGain_B.Denominator);
+ }
+
+ hr = pMetaDataAttributes->SetBlob(
+ MF_CAPTURE_METADATA_WHITEBALANCE_GAINS,
+ (const UINT8*)&WhiteBalanceGains,
+ sizeof(WhiteBalanceGains));
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT ParseMetadata_ImageAggregation(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes* pMetaDataAttributes
+)
+{
+ HRESULT hr = S_OK;
+ if (pItem->Size < sizeof(CAMERA_METADATA_IMAGEAGGREGATION))
+ {
+ return E_UNEXPECTED;
+ }
+
+ PCAMERA_METADATA_IMAGEAGGREGATION pFixedStruct =
+ (PCAMERA_METADATA_IMAGEAGGREGATION)pItem;
+
+ if (pFixedStruct->Data.FrameId.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_REQUESTED_FRAME_SETTING_ID,
+ pFixedStruct->Data.FrameId.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.ExposureTime.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT64(
+ MF_CAPTURE_METADATA_EXPOSURE_TIME,
+ pFixedStruct->Data.ExposureTime.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.ISOSpeed.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_ISO_SPEED,
+ pFixedStruct->Data.ISOSpeed.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.LensPosition.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_LENS_POSITION,
+ pFixedStruct->Data.LensPosition.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.SceneMode.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT64(
+ MF_CAPTURE_METADATA_SCENE_MODE,
+ pFixedStruct->Data.SceneMode.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.FlashOn.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_FLASH,
+ pFixedStruct->Data.FlashOn.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.FlashPower.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_FLASH_POWER,
+ pFixedStruct->Data.FlashPower.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.WhiteBalanceMode.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_WHITEBALANCE,
+ pFixedStruct->Data.WhiteBalanceMode.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.ZoomFactor.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_ZOOMFACTOR,
+ pFixedStruct->Data.ZoomFactor.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.EVCompensation.Set)
+ {
+ CapturedMetadataExposureCompensation EVCompensation;
+
+ EVCompensation.Flags = pFixedStruct->Data.EVCompensation.Flags;
+ EVCompensation.Value = pFixedStruct->Data.EVCompensation.Value;
+
+ hr = pMetaDataAttributes->SetBlob(
+ MF_CAPTURE_METADATA_EXPOSURE_COMPENSATION,
+ (const UINT8*)&EVCompensation,
+ sizeof(EVCompensation));
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+
+ if (pFixedStruct->Data.FocusState.Set)
+ {
+ hr = pMetaDataAttributes->SetUINT32(
+ MF_CAPTURE_METADATA_FOCUSSTATE,
+ pFixedStruct->Data.FocusState.Value);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ }
+ return S_OK;
+}
+#endif // (NTDDI_VERSION >= NTDDI_WINBLUE)
+struct HistogramData
+{
+ HistogramDataHeader Header;
+ ULONG Color[256];
+
+ HistogramData()
+ {
+ Header.Size = sizeof(*this);
+ Header.ChannelMask = 0;
+ Header.Linear = 1;
+ RtlZeroMemory(Color, sizeof(Color));
+ }
+};
+
+// This is the blob we pass back every time.
+template <ULONG I>
+struct Histogram
+{
+ HistogramBlobHeader Blob;
+ // RGB or YUV Histograms.
+ HistogramHeader Header;
+ HistogramData Data[I];
+
+ Histogram(
+ _In_ ULONG Width = 0,
+ _In_ ULONG Height = 0
+ )
+ {
+ Blob.Histograms = 1;
+ Blob.Size = sizeof(*this);
+
+ Header.Size = sizeof(Header) + sizeof(Data);
+ Header.Bins = 256;
+ Header.Grid.Height = Height;
+ Header.Grid.Width = Width;
+ Header.Grid.Region.top = 0;
+ Header.Grid.Region.left = 0;
+ Header.Grid.Region.bottom = Height - 1;
+ Header.Grid.Region.right = Width - 1;
+ }
+};
+
+#if (NTDDI_VERSION >= NTDDI_WINBLUE)
+#define MF_HISTOGRAM_RGB (MF_HISTOGRAM_CHANNEL_R | MF_HISTOGRAM_CHANNEL_G | MF_HISTOGRAM_CHANNEL_B )
+#define MF_HISTOGRAM_YCrCb (MF_HISTOGRAM_CHANNEL_Y | MF_HISTOGRAM_CHANNEL_Cr | MF_HISTOGRAM_CHANNEL_Cb)
+
+HRESULT ParseMetadata_Histogram(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes* pMetaDataAttributes
+)
+{
+ if (pItem->Size < sizeof(CAMERA_METADATA_HISTOGRAM))
+ {
+ return E_UNEXPECTED;
+ }
+
+ PCAMERA_METADATA_HISTOGRAM pHistogram = (PCAMERA_METADATA_HISTOGRAM)pItem;
+
+ if ((pHistogram->Data.ChannelMask & MF_HISTOGRAM_RGB) == MF_HISTOGRAM_RGB)
+ {
+ Histogram<4> Blob(pHistogram->Data.Width, pHistogram->Data.Height);
+
+ Blob.Header.FourCC = pHistogram->Data.FourCC;
+ Blob.Header.ChannelMasks = pHistogram->Data.ChannelMask;
+
+ // For a RGB Histogram, we fake the Y channel by copying the G channel.
+ Blob.Data[0].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_Y;
+ RtlCopyMemory(Blob.Data[0].Color, pHistogram->Data.P1Data, sizeof(Blob.Data[0].Color));
+
+ // Now just copy the RGB channels normally.
+ Blob.Data[1].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_R;
+ RtlCopyMemory(Blob.Data[1].Color, pHistogram->Data.P0Data, sizeof(Blob.Data[1].Color));
+ Blob.Data[2].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_G;
+ RtlCopyMemory(Blob.Data[2].Color, pHistogram->Data.P1Data, sizeof(Blob.Data[2].Color));
+ Blob.Data[3].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_B;
+ RtlCopyMemory(Blob.Data[3].Color, pHistogram->Data.P2Data, sizeof(Blob.Data[3].Color));
+
+ return pMetaDataAttributes->SetBlob(
+ MF_CAPTURE_METADATA_HISTOGRAM,
+ (PBYTE)&Blob,
+ sizeof(Blob)
+ );
+ }
+ else if ((pHistogram->Data.ChannelMask & MF_HISTOGRAM_YCrCb) == MF_HISTOGRAM_YCrCb)
+ {
+ Histogram<3> Blob(pHistogram->Data.Width, pHistogram->Data.Height);
+
+ Blob.Header.FourCC = pHistogram->Data.FourCC;
+ Blob.Header.ChannelMasks = pHistogram->Data.ChannelMask;
+
+ Blob.Data[0].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_Y;
+ RtlCopyMemory(Blob.Data[0].Color, pHistogram->Data.P0Data, sizeof(Blob.Data[0].Color));
+ Blob.Data[1].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_Cr;
+ RtlCopyMemory(Blob.Data[1].Color, pHistogram->Data.P1Data, sizeof(Blob.Data[1].Color));
+ Blob.Data[2].Header.ChannelMask = MF_HISTOGRAM_CHANNEL_Cb;
+ RtlCopyMemory(Blob.Data[2].Color, pHistogram->Data.P2Data, sizeof(Blob.Data[2].Color));
+
+ //TODO:
+ return pMetaDataAttributes->SetBlob(
+ MF_CAPTURE_METADATA_HISTOGRAM,
+ (PBYTE)&Blob,
+ sizeof(Blob)
+ );
+ }
+ return E_UNEXPECTED;
+}
+
+HRESULT ParseMetadata_FaceDetection(
+ _In_ PKSCAMERA_METADATA_ITEMHEADER pItem,
+ _In_ IMFAttributes* pMetaDataAttributes
+)
+{
+ HRESULT hr = S_OK;
+
+ if (pItem->Size < sizeof(CAMERA_METADATA_FACEHEADER))
+ {
+ return E_UNEXPECTED;
+ }
+
+ PCAMERA_METADATA_FACEHEADER pFaceHeader = (PCAMERA_METADATA_FACEHEADER)pItem;
+
+ if (pItem->Size < (sizeof(CAMERA_METADATA_FACEHEADER) + (sizeof(METADATA_FACEDATA) * pFaceHeader->Count)))
+ {
+ return E_UNEXPECTED;
+ }
+ PMETADATA_FACEDATA pFaceData = (PMETADATA_FACEDATA)(pFaceHeader + 1);
+ UINT32 cbRectSize = sizeof(FaceRectInfoBlobHeader) + (sizeof(FaceRectInfo) * (pFaceHeader->Count));
+ BYTE* pRectBuf = new (std::nothrow) BYTE[cbRectSize];
+ if (pRectBuf == NULL)
+ {
+ return E_OUTOFMEMORY;
+ }
+
+ UINT32 cbCharSize = sizeof(FaceCharacterizationBlobHeader) + (sizeof(FaceCharacterization) * (pFaceHeader->Count));
+ BYTE* pCharBuf = new (std::nothrow) BYTE[cbCharSize];
+ if (pCharBuf == NULL)
+ {
+ delete[] pRectBuf;
+ return E_OUTOFMEMORY;
+ }
+
+ FaceRectInfoBlobHeader* pFaceRectHeader = (FaceRectInfoBlobHeader*)pRectBuf;
+ pFaceRectHeader->Size = cbRectSize;
+ pFaceRectHeader->Count = pFaceHeader->Count;
+
+ FaceCharacterizationBlobHeader* pFaceCharHeader = (FaceCharacterizationBlobHeader*)pCharBuf;
+ pFaceCharHeader->Size = cbCharSize;
+ pFaceCharHeader->Count = pFaceHeader->Count;
+
+ FaceRectInfo* FaceRegions = (FaceRectInfo*)(pFaceRectHeader + 1);
+ FaceCharacterization* FaceChars = (FaceCharacterization*)(pFaceCharHeader + 1);
+
+ for (UINT i = 0; i < pFaceHeader->Count; i++)
+ {
+ FaceRegions[i].Region = pFaceData[i].Region;
+ FaceRegions[i].confidenceLevel = pFaceData[i].confidenceLevel;
+
+ FaceChars[i].BlinkScoreLeft = pFaceData[i].BlinkScoreLeft;
+ FaceChars[i].BlinkScoreRight = pFaceData[i].BlinkScoreRight;
+ FaceChars[i].FacialExpression = (pFaceData[i].FacialExpression == EXPRESSION_SMILE) ? MF_METADATAFACIALEXPRESSION_SMILE : 0;
+ FaceChars[i].FacialExpressionScore = pFaceData[i].FacialExpressionScore;
+ }
+
+ hr = pMetaDataAttributes->SetBlob(MF_CAPTURE_METADATA_FACEROIS, pRectBuf, cbRectSize);
+ if (FAILED(hr))
+ {
+ goto done;
+ }
+
+ MetadataTimeStamps timestamp;
+ timestamp.Flags = MF_METADATATIMESTAMPS_DEVICE;
+ timestamp.Device = pFaceHeader->Timestamp;
+
+ hr = pMetaDataAttributes->SetBlob(MF_CAPTURE_METADATA_FACEROITIMESTAMPS, (const UINT8*)&timestamp, sizeof(MetadataTimeStamps));
+ if (FAILED(hr))
+ {
+ goto done;
+ }
+
+#if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
+ // Include characterization data if any of the associated bits were set.
+ if (pFaceHeader->Flags & KSCAMERA_EXTENDEDPROP_FACEDETECTION_ADVANCED_MASK)
+ {
+ hr = pMetaDataAttributes->SetBlob(MF_CAPTURE_METADATA_FACEROICHARACTERIZATIONS, pCharBuf, cbCharSize);
+ }
+#endif // (NTDDI_VERSION >= NTDDI_WINTHRESHOLD)
+
+done:
+ delete[] pRectBuf;
+ delete[] pCharBuf;
+
+ return hr;
+}
+#endif
diff --git a/avstream/avscamera/DMFT/Source.def b/avstream/avscamera/DMFT/Source.def
new file mode 100644
index 00000000..752ef2ea
--- /dev/null
+++ b/avstream/avscamera/DMFT/Source.def
@@ -0,0 +1,5 @@
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
+ DllGetClassObject PRIVATE
diff --git a/avstream/avscamera/DMFT/basepin.cpp b/avstream/avscamera/DMFT/basepin.cpp
new file mode 100644
index 00000000..e0178390
--- /dev/null
+++ b/avstream/avscamera/DMFT/basepin.cpp
@@ -0,0 +1,625 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+#include "stdafx.h"
+
+#ifdef MF_WPP
+#include "basepin.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+/* -------> New STATE
+ |
+ |old State
+DeviceStreamState_Stop DeviceStreamState_Pause DeviceStreamState_Run DeviceStreamState_Disabled
+DeviceStreamState_Pause
+DeviceStreamState_Run
+DeviceStreamState_Disabled
+*/
+
+DeviceStreamState pinStateTransition[4][4] = {
+ { DeviceStreamState_Stop, DeviceStreamState_Pause, DeviceStreamState_Run, DeviceStreamState_Disabled },
+ { DeviceStreamState_Stop, DeviceStreamState_Pause, DeviceStreamState_Run, DeviceStreamState_Disabled },
+ { DeviceStreamState_Stop, DeviceStreamState_Pause, DeviceStreamState_Run, DeviceStreamState_Disabled },
+ { DeviceStreamState_Disabled, DeviceStreamState_Disabled, DeviceStreamState_Disabled, DeviceStreamState_Disabled }
+};
+
+CBasePin::CBasePin( _In_ ULONG id, _In_ CMultipinMft *parent) :
+ m_StreamId(id)
+ , m_Parent(parent)
+ , m_setMediaType(nullptr)
+ , m_nRefCount(0)
+ , m_state(DeviceStreamState_Stop)
+ , m_dwWorkQueueId(MFASYNC_CALLBACK_QUEUE_UNDEFINED)
+{
+
+}
+
+CBasePin::~CBasePin()
+{
+ m_listOfMediaTypes.clear();
+ m_spAttributes = nullptr;
+}
+
+IFACEMETHODIMP_(DeviceStreamState) CBasePin::GetState()
+{
+ return (DeviceStreamState) InterlockedCompareExchange((PLONG)&m_state, 0L,0L);
+}
+
+IFACEMETHODIMP_(DeviceStreamState) CBasePin::SetState(_In_ DeviceStreamState state)
+{
+ return (DeviceStreamState) InterlockedExchange((LONG*)&m_state, state);
+}
+
+HRESULT CBasePin::AddMediaType( _Inout_ DWORD *pos, _In_ IMFMediaType *pMediaType)
+{
+ HRESULT hr = S_OK;
+ CAutoLock Lock(lock());
+
+ DMFTCHECKNULL_GOTO(pMediaType, done, E_INVALIDARG);
+ hr = ExceptionBoundary([&]()
+ {
+ m_listOfMediaTypes.push_back(pMediaType);
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ if (pos)
+ {
+ *pos = (DWORD)(m_listOfMediaTypes.size() - 1);
+ }
+
+done:
+ return hr;
+}
+
+HRESULT CBasePin::GetMediaTypeAt( _In_ DWORD pos, _Outptr_result_maybenull_ IMFMediaType **ppMediaType )
+{
+ HRESULT hr = S_OK;
+ CAutoLock Lock(lock());
+ ComPtr<IMFMediaType> spMediaType;
+ DMFTCHECKNULL_GOTO(ppMediaType,done,E_INVALIDARG);
+ *ppMediaType = nullptr;
+ if (pos >= m_listOfMediaTypes.size())
+ {
+ DMFTCHECKHR_GOTO(MF_E_NO_MORE_TYPES,done);
+ }
+ spMediaType = m_listOfMediaTypes[pos];
+ *ppMediaType = spMediaType.Detach();
+done:
+ return hr;
+}
+
+IFACEMETHODIMP_(BOOL) CBasePin::IsMediaTypeSupported
+(
+ _In_ IMFMediaType *pMediaType,
+ _When_(ppIMFMediaTypeFull != nullptr, _Outptr_result_maybenull_)
+ IMFMediaType **ppIMFMediaTypeFull
+)
+{
+ HRESULT hr = S_OK;
+ BOOL bFound = FALSE;
+ CAutoLock Lock(lock());
+ DMFTCHECKNULL_GOTO(pMediaType,done,E_INVALIDARG);
+ if (ppIMFMediaTypeFull)
+ {
+ *ppIMFMediaTypeFull = nullptr;
+ }
+
+ for (UINT uIIndex = 0, uISize = (UINT)m_listOfMediaTypes.size(); uIIndex < uISize ; uIIndex++ )
+ {
+ DWORD dwResult = 0;
+ hr = m_listOfMediaTypes[ uIIndex ]->IsEqual( pMediaType, &dwResult );
+ if (hr == S_FALSE)
+ {
+
+ if ((dwResult & MF_MEDIATYPE_EQUAL_MAJOR_TYPES) &&
+ (dwResult& MF_MEDIATYPE_EQUAL_FORMAT_TYPES) &&
+ (dwResult& MF_MEDIATYPE_EQUAL_FORMAT_DATA))
+ {
+ hr = S_OK;
+ }
+ }
+ if (hr == S_OK)
+ {
+ bFound = TRUE;
+ if (ppIMFMediaTypeFull) {
+ DMFTCHECKHR_GOTO(m_listOfMediaTypes[uIIndex].CopyTo(ppIMFMediaTypeFull), done);
+ }
+ break;
+ }
+ else if (FAILED(hr))
+ {
+ DMFTCHECKHR_GOTO(hr,done);
+ }
+ }
+done:
+ return SUCCEEDED(hr) ? TRUE : FALSE;
+}
+
+IFACEMETHODIMP CBasePin::GetOutputAvailableType(
+ _In_ DWORD dwTypeIndex,
+ _Out_opt_ IMFMediaType** ppType)
+{
+ return GetMediaTypeAt( dwTypeIndex, ppType );
+}
+
+HRESULT CBasePin::QueryInterface(
+ _In_ REFIID iid,
+ _Outptr_result_maybenull_ void** ppv
+ )
+{
+ HRESULT hr = S_OK;
+
+ DMFTCHECKNULL_GOTO(ppv, done, E_POINTER);
+ *ppv = nullptr;
+ if ( iid == __uuidof( IUnknown ) )
+ {
+ *ppv = static_cast<VOID*>(this);
+ }
+ else if ( iid == __uuidof( IMFAttributes ) )
+ {
+ *ppv = static_cast< IMFAttributes* >( this );
+ }
+ else if ( iid == __uuidof( IKsControl ) )
+ {
+ *ppv = static_cast< IKsControl* >( this );
+ }
+ else
+ {
+ hr = E_NOINTERFACE;
+ goto done;
+ }
+ AddRef();
+done:
+ return hr;
+}
+
+VOID CBasePin::SetD3DManager(_In_opt_ IUnknown* pManager)
+{
+ //
+ // Should release the old dxgi manager.. We will not invalidate the pins or allocators
+ // We will recreate all allocator when the media types are set, so we should be fine
+ // And the pipeline will not set the dxgimanager when the pipeline is already built
+ //
+ CAutoLock Lock(lock());
+ m_spDxgiManager = pManager;
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting D3DManager on pin %d", m_StreamId);
+}
+//
+//Input Pin implementation
+//
+CInPin::CInPin(
+ _In_opt_ IMFAttributes *pAttributes,
+ _In_ ULONG ulPinId,
+ _In_ CMultipinMft *pParent)
+ :
+ CBasePin(ulPinId, pParent),
+ m_stStreamType(GUID_NULL),
+ m_waitInputMediaTypeWaiter(NULL),
+ m_preferredStreamState(DeviceStreamState_Stop)
+{
+ setAttributes(pAttributes);
+}
+
+CInPin::~CInPin()
+{
+ setAttributes( nullptr );
+ m_spSourceTransform = nullptr;
+
+ if (m_waitInputMediaTypeWaiter)
+ {
+ CloseHandle(m_waitInputMediaTypeWaiter);
+ }
+}
+
+IFACEMETHODIMP CInPin::Init(
+ _In_ IMFDeviceTransform* pTransform
+ )
+{
+
+ HRESULT hr = S_OK;
+
+ DMFTCHECKNULL_GOTO( pTransform, done, E_INVALIDARG );
+
+ m_spSourceTransform = pTransform;
+
+ DMFTCHECKHR_GOTO( GetGUID( MF_DEVICESTREAM_STREAM_CATEGORY, &m_stStreamType ), done );
+
+ //
+ //Get the DevProxy IKSControl.. used to send the KSControls or the device control IOCTLS over to devproxy and finally on to the driver!!!!
+ //
+ DMFTCHECKHR_GOTO( m_spAttributes.As( &m_spIkscontrol ), done );
+
+ m_waitInputMediaTypeWaiter = CreateEvent( NULL,
+ FALSE,
+ FALSE,
+ nullptr
+ );
+ DMFTCHECKNULL_GOTO( m_waitInputMediaTypeWaiter, done, E_OUTOFMEMORY );
+
+ DMFTCHECKHR_GOTO( GenerateMFMediaTypeListFromDevice(streamId()),done );
+
+done:
+ if ( FAILED(hr) )
+ {
+ m_spSourceTransform = nullptr;
+
+ if ( m_waitInputMediaTypeWaiter )
+ {
+ CloseHandle( m_waitInputMediaTypeWaiter );
+ m_waitInputMediaTypeWaiter = NULL;
+ }
+
+ m_stStreamType = GUID_NULL;
+ }
+
+ return hr;
+}
+
+HRESULT CInPin::GenerateMFMediaTypeListFromDevice(
+ _In_ UINT uiStreamId
+ )
+{
+ HRESULT hr = S_OK;
+ GUID stSubType = { 0 };
+ //This is only called in the begining when the input pin is constructed
+ DMFTCHECKNULL_GOTO( m_spSourceTransform, done, MF_E_TRANSFORM_TYPE_NOT_SET );
+ for (UINT iMediaType = 0; SUCCEEDED(hr) ; iMediaType++)
+ {
+ ComPtr<IMFMediaType> spMediaType;
+ DWORD pos = 0;
+
+ hr = m_spSourceTransform->GetOutputAvailableType(uiStreamId, iMediaType, spMediaType.GetAddressOf());
+ if (hr != S_OK)
+ break;
+
+ DMFTCHECKHR_GOTO(AddMediaType(&pos, spMediaType.Get()), done);
+ }
+done:
+ if (hr == MF_E_NO_MORE_TYPES) {
+ hr = S_OK;
+ }
+ return hr;
+}
+
+IFACEMETHODIMP CInPin::SendSample(
+ _In_ IMFSample *pSample
+ )
+{
+ HRESULT hr = S_OK;
+ CAutoLock Lock(lock());
+ if (FAILED(Active()))
+ {
+ goto done;
+ }
+ COutPin *poPin = static_cast<COutPin*>(m_outpin.Get());
+ DMFTCHECKNULL_GOTO(pSample, done, S_OK);
+ DMFTCHECKHR_GOTO(poPin->AddSample(pSample, this), done);
+
+ done:
+ return hr;
+}
+
+IFACEMETHODIMP_(VOID) CInPin::ConnectPin( _In_ CBasePin * poPin )
+{
+ CAutoLock Lock(lock());
+ if (poPin!=nullptr)
+ {
+ m_outpin = poPin;
+ }
+}
+
+IFACEMETHODIMP CInPin::WaitForSetInputPinMediaChange()
+{
+ DWORD dwWait = 0;
+ HRESULT hr = S_OK;
+
+ dwWait = WaitForSingleObject( m_waitInputMediaTypeWaiter, INFINITE );
+
+ if ( dwWait != WAIT_OBJECT_0 )
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ goto done;
+ }
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+HRESULT CInPin::GetInputStreamPreferredState(
+ _Inout_ DeviceStreamState* value,
+ _Outptr_opt_result_maybenull_ IMFMediaType** ppMediaType
+ )
+{
+ HRESULT hr = S_OK;
+ CAutoLock Lock(lock());
+
+ if (value!=nullptr)
+ {
+ *value = m_preferredStreamState;
+ }
+
+ if (ppMediaType )
+ {
+ *ppMediaType = nullptr;
+ if (m_spPrefferedMediaType != nullptr )
+ {
+ m_spPrefferedMediaType.CopyTo(ppMediaType);
+ }
+ }
+
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+HRESULT CInPin::SetInputStreamState(
+ _In_ IMFMediaType* pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(dwFlags);
+
+ CAutoLock Lock(lock());
+ //
+ //Set the media type
+ //
+ setMediaType(pMediaType);
+ SetState(value);
+ //
+ //Set the event. This event is being waited by an output media/state change operation
+ //
+ m_spPrefferedMediaType = nullptr;
+ SetEvent(m_waitInputMediaTypeWaiter);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+IFACEMETHODIMP_(VOID) CInPin::ShutdownPin()
+{
+ m_spSourceTransform = nullptr;
+ m_outpin = nullptr;
+}
+//
+//Output Pin Implementation
+//
+COutPin::COutPin(
+ _In_ ULONG ulPinId,
+ _In_opt_ CMultipinMft *pparent,
+ _In_ IKsControl* pIksControl
+ )
+ : CBasePin(ulPinId, pparent)
+ , m_firstSample(false)
+ , m_queue(nullptr)
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFAttributes> spAttributes;
+
+ //
+ //Get the input pin IKS control.. the pin IKS control talks to sourcetransform's IKS control
+ //
+ m_spIkscontrol = pIksControl;
+
+ MFCreateAttributes( &spAttributes, 3 ); //Create the space for the attribute store!!
+ setAttributes( spAttributes.Get());
+ DMFTCHECKHR_GOTO( SetUINT32( MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE ), done );
+ DMFTCHECKHR_GOTO( SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"Sample_CameraExtensionMft" ),done );
+ DMFTCHECKHR_GOTO( SetUINT32( MF_TRANSFORM_ASYNC, TRUE ),done );
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+}
+
+COutPin::~COutPin()
+{
+ m_spAttributes = nullptr;
+ SAFE_DELETE(m_queue);
+}
+
+/*++
+COutPin::AddPin
+Description:
+Called from AddSample if the Output Pin is in open state. This function looks for the queue
+corresponding to the input pin and adds it in the queue.
+--*/
+IFACEMETHODIMP COutPin::AddPin(
+ _In_ DWORD inputPinId
+ )
+{
+ //
+ //Add a new queue corresponding to the input pin
+ //
+ HRESULT hr = S_OK;
+ CAutoLock Lock(lock());
+
+ m_queue = new (std::nothrow) CPinQueue(inputPinId,Parent());
+ DMFTCHECKNULL_GOTO(m_queue, done, E_OUTOFMEMORY );
+done:
+
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return S_OK;
+}
+/*++
+COutPin::AddSample
+Description:
+Called when ProcessInput is called on the Device Transform. The Input Pin puts the samples
+in the pins connected. If the Output pins are in open state the sample lands in the queues
+--*/
+
+IFACEMETHODIMP COutPin::AddSample(
+ _In_ IMFSample *pSample,
+ _In_ CBasePin *pPin)
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(pPin);
+
+ CAutoLock Lock(lock()); // Serialize
+
+ DMFTCHECKNULL_GOTO(pSample, done, E_INVALIDARG);
+ if (FAILED(Active()))
+ {
+ goto done;
+ }
+ DMFTCHECKHR_GOTO(m_queue->Insert(pSample), done);
+done:
+ if (FAILED(hr))
+ {
+ // Throw an Error to the pipeline
+ DMFTCHECKHR_GOTO(Parent()->QueueEvent(MEError, GUID_NULL, hr, NULL), done);
+ }
+ return hr;
+}
+
+/*++
+COutPin::SetState
+Description:
+State setter for the output pin
+--*/
+IFACEMETHODIMP_(VOID) COutPin::SetFirstSample(
+ _In_ BOOL fisrtSample )
+{
+ m_firstSample = fisrtSample;
+}
+
+/*++
+COutPin::FlushQueues
+Description:
+Called from the device Transform when the output queues have to be flushed
+
+--*/
+HRESULT COutPin::FlushQueues()
+{
+ HRESULT hr = S_OK;
+ CAutoLock Lock( lock() );
+ (VOID)m_queue->Clear();
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+/*++
+COutPin::ChangeMediaTypeFromInpin
+Description:
+called from the Device Transform when the input media type is changed. This will result in
+the xvp being possibly installed in the queue if the media types set on the input
+and the output dont match
+--*/
+HRESULT COutPin::ChangeMediaTypeFromInpin(
+ _In_ IMFMediaType* pOutMediaType,
+ _In_ DeviceStreamState state)
+{
+ HRESULT hr = S_OK;
+ CAutoLock Lock(lock());
+ //
+ //Set the state to disabled and while going out we will reset the state back to the requested state
+ //Flush so that we drop any samples we have in store!!
+ //
+ SetState(DeviceStreamState_Disabled);
+ DMFTCHECKHR_GOTO(FlushQueues(),done);
+ DMFTCHECKNULL_GOTO(m_queue,done, E_UNEXPECTED); // The queue should alwaye be set
+ if ( SUCCEEDED( hr ) )
+ {
+ (VOID)setMediaType( pOutMediaType );
+ (VOID)SetState( state );
+ }
+done:
+ return hr;
+}
+
+/*++
+Description:
+ called from the IMFdeviceTransform's
+--*/
+
+IFACEMETHODIMP COutPin::GetOutputStreamInfo(
+ _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo
+ )
+{
+ HRESULT hr = S_OK;
+ IMFMediaType* pMediatype = nullptr;
+ getMediaType( &pMediatype );
+
+ if (SUCCEEDED(hr) && !pMediatype) {
+ pMediatype->Release();
+ pStreamInfo->cbAlignment = 0;
+ pStreamInfo->cbSize = 0;
+ pStreamInfo->dwFlags = MFT_OUTPUT_STREAM_WHOLE_SAMPLES | MFT_OUTPUT_STREAM_SINGLE_SAMPLE_PER_BUFFER | MFT_OUTPUT_STREAM_FIXED_SAMPLE_SIZE;
+ pStreamInfo->dwFlags |= MFT_OUTPUT_STREAM_PROVIDES_SAMPLES;
+ //We provide our samples..
+ }
+ else {
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+ return hr;
+}
+
+
+/*++
+COutPin::ProcessOutput
+Description:
+ called from the Device Transform when the transform manager demands output samples..
+ If we have samples we forward it.
+ If we are a photo pin then we forward only if trigger is sent. We ask the devicetransform if we have received the transform or not.
+ If we have received the sample and we are passing out a sample we should reset the trigger set on the Device Transform
+--*/
+
+IFACEMETHODIMP COutPin::ProcessOutput(_In_ DWORD dwFlags,
+ _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample,
+ _Out_ DWORD *pdwStatus
+ )
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFSample> spSample;
+ UNREFERENCED_PARAMETER(pdwStatus);
+ UNREFERENCED_PARAMETER(dwFlags);
+ CAutoLock lock(lock());
+ MFTIME llTime = 0;
+ if (FAILED(Active()))
+ {
+ goto done;
+ }
+ DMFTCHECKNULL_GOTO(m_queue, done, MF_E_INVALID_STREAM_STATE);
+ pOutputSample->dwStatus = S_OK;
+
+ DMFTCHECKHR_GOTO(m_queue->Remove(spSample.GetAddressOf()), done);
+
+ if (FAILED(spSample->GetSampleTime(&llTime)))
+ {
+ spSample->SetSampleTime(MFGetSystemTime());
+ }
+ if (m_firstSample)
+ {
+ spSample->SetUINT32(MFSampleExtension_Discontinuity,TRUE);
+ SetFirstSample(FALSE);
+ }
+ //
+ // Any processing before we pass the sample to further in the pipeline should be done here
+ // PROCESSSAMPLE(pSample); There is a bug in the pipeline and to circumvent that we have to
+ // keep a reference on the sample. The pipeline is not releasing a reference when the sample
+ // is fed in ProcessInput. We are explicitly releasing it for the pipeline.
+ //
+ pOutputSample->pSample = spSample.Detach();
+ pOutputSample->dwStatus = S_OK;
+done:
+ return hr;
+}
+
+/*++
+ COutPin::KsProperty
+Description:
+The KsProperty for the Pin.. this is to reroute all pin kscontrols to the input pin
+--*/
+IFACEMETHODIMP COutPin::KsProperty(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned
+ )
+{
+ //
+ //Route it to input pin
+ //
+ return m_spIkscontrol->KsProperty(pProperty,
+ ulPropertyLength,
+ pPropertyData,
+ ulDataLength,
+ pBytesReturned);
+}
+
diff --git a/avstream/avscamera/DMFT/basepin.h b/avstream/avscamera/DMFT/basepin.h
new file mode 100644
index 00000000..8051188a
--- /dev/null
+++ b/avstream/avscamera/DMFT/basepin.h
@@ -0,0 +1,568 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+#pragma once
+#include "stdafx.h"
+
+extern DeviceStreamState pinStateTransition[][4];
+
+
+class CPinQueue;
+class CPinState;
+class CMultipinMft;
+
+class CBasePin:
+ public IMFAttributes,
+ public IKsControl
+{
+public:
+ CBasePin( _In_ ULONG _id=0, _In_ CMultipinMft *parent=NULL);
+
+ virtual ~CBasePin() = 0;
+ virtual IFACEMETHODIMP_(DeviceStreamState) GetState();
+ virtual IFACEMETHODIMP_(DeviceStreamState) SetState( _In_ DeviceStreamState State);
+
+
+ //
+ //IUnknown Interface functions
+ //
+
+ IFACEMETHODIMP_(ULONG) AddRef(
+ void
+ )
+ {
+ return InterlockedIncrement(&m_nRefCount);
+ }
+ IFACEMETHODIMP_(ULONG) Release(
+ void
+ )
+ {
+ ULONG uCount = InterlockedDecrement(&m_nRefCount);
+ if (uCount == 0)
+ {
+ delete this;
+ }
+ return uCount;
+ }
+
+ IFACEMETHODIMP_(HRESULT) QueryInterface(
+ _In_ REFIID riid,
+ _Outptr_result_maybenull_ void **ppvObject
+ );
+ //
+ // IKsControl Interface functions
+ //
+
+ IFACEMETHODIMP KsProperty(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned
+ )
+ {
+ if ( m_spIkscontrol!=nullptr )
+ {
+ return m_spIkscontrol->KsProperty(pProperty,
+ ulPropertyLength,
+ pPropertyData,
+ ulDataLength,
+ pBytesReturned);
+ }
+ else
+ {
+ return E_NOTIMPL;
+ }
+ }
+ virtual IFACEMETHODIMP FlushQueues(
+ )
+ {
+ return S_OK;
+ }
+ //
+ // NOOPs for this iteration..
+ //
+ IFACEMETHODIMP KsMethod(
+ _In_reads_bytes_(ulMethodLength) PKSMETHOD pMethod,
+ _In_ ULONG ulMethodLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pMethodData,
+ _In_ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned
+ )
+ {
+ UNREFERENCED_PARAMETER(pBytesReturned);
+ UNREFERENCED_PARAMETER(ulDataLength);
+ UNREFERENCED_PARAMETER(pMethodData);
+ UNREFERENCED_PARAMETER(pMethod);
+ UNREFERENCED_PARAMETER(ulMethodLength);
+ return S_OK;
+ }
+
+ IFACEMETHODIMP KsEvent(
+ _In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned
+ )
+ {
+ UNREFERENCED_PARAMETER(pBytesReturned);
+ UNREFERENCED_PARAMETER(ulDataLength);
+ UNREFERENCED_PARAMETER(pEventData);
+ UNREFERENCED_PARAMETER(pEvent);
+ UNREFERENCED_PARAMETER(ulEventLength);
+ return S_OK;
+ }
+
+ //
+ //IMFAttributes implementation
+ //
+ IFACEMETHODIMP GetItem(
+ _In_ REFGUID guidKey,
+ _Inout_opt_ PROPVARIANT* pValue
+ )
+ {
+ return m_spAttributes->GetItem(guidKey, pValue);
+ }
+
+ IFACEMETHODIMP GetItemType(
+ _In_ REFGUID guidKey,
+ _Out_ MF_ATTRIBUTE_TYPE* pType
+ )
+ {
+ return m_spAttributes->GetItemType(guidKey, pType);
+ }
+
+ IFACEMETHODIMP CompareItem(
+ _In_ REFGUID guidKey,
+ _In_ REFPROPVARIANT Value,
+ _Out_ BOOL* pbResult
+ )
+ {
+ return m_spAttributes->CompareItem(guidKey, Value, pbResult);
+ }
+
+ IFACEMETHODIMP Compare(
+ _In_ IMFAttributes* pTheirs,
+ _In_ MF_ATTRIBUTES_MATCH_TYPE MatchType,
+ _Out_ BOOL* pbResult
+ )
+ {
+ return m_spAttributes->Compare(pTheirs, MatchType, pbResult);
+ }
+
+ IFACEMETHODIMP GetUINT32(
+ _In_ REFGUID guidKey,
+ _Out_ UINT32* punValue
+ )
+ {
+ return m_spAttributes->GetUINT32(guidKey, punValue);
+ }
+
+ IFACEMETHODIMP GetUINT64(
+ _In_ REFGUID guidKey,
+ _Out_ UINT64* punValue
+ )
+ {
+ return m_spAttributes->GetUINT64(guidKey, punValue);
+ }
+
+ IFACEMETHODIMP GetDouble(
+ _In_ REFGUID guidKey,
+ _Out_ double* pfValue
+ )
+ {
+ return m_spAttributes->GetDouble(guidKey, pfValue);
+ }
+
+ IFACEMETHODIMP GetGUID(
+ _In_ REFGUID guidKey,
+ _Out_ GUID* pguidValue
+ )
+ {
+ return m_spAttributes->GetGUID(guidKey, pguidValue);
+ }
+
+ IFACEMETHODIMP GetStringLength(
+ _In_ REFGUID guidKey,
+ _Out_ UINT32* pcchLength
+ )
+ {
+ return m_spAttributes->GetStringLength(guidKey, pcchLength);
+ }
+
+ IFACEMETHODIMP GetString(
+ _In_ REFGUID guidKey,
+ _Out_writes_(cchBufSize) LPWSTR pwszValue,
+ _In_ UINT32 cchBufSize,
+ _Inout_opt_ UINT32* pcchLength
+ )
+ {
+ return m_spAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
+ }
+
+ IFACEMETHODIMP GetAllocatedString(
+ _In_ REFGUID guidKey,
+ _Out_writes_(*pcchLength + 1) LPWSTR* ppwszValue,
+ _Inout_ UINT32* pcchLength
+ )
+ {
+ return m_spAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
+ }
+
+ IFACEMETHODIMP GetBlobSize(
+ _In_ REFGUID guidKey,
+ _Out_ UINT32* pcbBlobSize
+ )
+ {
+ return m_spAttributes->GetBlobSize(guidKey, pcbBlobSize);
+ }
+
+ IFACEMETHODIMP GetBlob(
+ _In_ REFGUID guidKey,
+ _Out_writes_(cbBufSize) UINT8* pBuf,
+ UINT32 cbBufSize,
+ _Inout_ UINT32* pcbBlobSize
+ )
+ {
+ return m_spAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize);
+ }
+
+ IFACEMETHODIMP GetAllocatedBlob(
+ __RPC__in REFGUID guidKey,
+ __RPC__deref_out_ecount_full_opt(*pcbSize) UINT8** ppBuf,
+ __RPC__out UINT32* pcbSize
+ )
+ {
+ return m_spAttributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize);
+ }
+
+ IFACEMETHODIMP GetUnknown(
+ __RPC__in REFGUID guidKey,
+ __RPC__in REFIID riid,
+ __RPC__deref_out_opt LPVOID *ppv
+ )
+ {
+ return m_spAttributes->GetUnknown(guidKey, riid, ppv);
+ }
+
+ IFACEMETHODIMP SetItem(
+ _In_ REFGUID guidKey,
+ _In_ REFPROPVARIANT Value
+ )
+ {
+ return m_spAttributes->SetItem(guidKey, Value);
+ }
+
+ IFACEMETHODIMP DeleteItem(
+ _In_ REFGUID guidKey
+ )
+ {
+ return m_spAttributes->DeleteItem(guidKey);
+ }
+
+ IFACEMETHODIMP DeleteAllItems()
+ {
+ return m_spAttributes->DeleteAllItems();
+ }
+
+ IFACEMETHODIMP SetUINT32(
+ _In_ REFGUID guidKey,
+ _In_ UINT32 unValue
+ )
+ {
+ return m_spAttributes->SetUINT32(guidKey, unValue);
+ }
+
+ IFACEMETHODIMP SetUINT64(
+ _In_ REFGUID guidKey,
+ _In_ UINT64 unValue
+ )
+ {
+ return m_spAttributes->SetUINT64(guidKey, unValue);
+ }
+
+ IFACEMETHODIMP SetDouble(
+ _In_ REFGUID guidKey,
+ _In_ double fValue
+ )
+ {
+ return m_spAttributes->SetDouble(guidKey, fValue);
+ }
+
+ IFACEMETHODIMP SetGUID(
+ _In_ REFGUID guidKey,
+ _In_ REFGUID guidValue
+ )
+ {
+ return m_spAttributes->SetGUID(guidKey, guidValue);
+ }
+
+ IFACEMETHODIMP SetString(
+ _In_ REFGUID guidKey,
+ _In_ LPCWSTR wszValue
+ )
+ {
+ return m_spAttributes->SetString(guidKey, wszValue);
+ }
+
+ IFACEMETHODIMP SetBlob(
+ _In_ REFGUID guidKey,
+ _In_reads_(cbBufSize) const UINT8* pBuf,
+ UINT32 cbBufSize
+ )
+ {
+ return m_spAttributes->SetBlob(guidKey, pBuf, cbBufSize);
+ }
+
+ IFACEMETHODIMP SetUnknown(
+ _In_ REFGUID guidKey,
+ _In_ IUnknown* pUnknown
+ )
+ {
+ return m_spAttributes->SetUnknown(guidKey, pUnknown);
+ }
+
+ IFACEMETHODIMP LockStore()
+ {
+ return m_spAttributes->LockStore();
+ }
+
+ IFACEMETHODIMP UnlockStore()
+ {
+ return m_spAttributes->UnlockStore();
+ }
+
+ IFACEMETHODIMP GetCount(
+ _Out_ UINT32* pcItems
+ )
+ {
+ return m_spAttributes->GetCount(pcItems);
+ }
+
+ IFACEMETHODIMP GetItemByIndex(
+ UINT32 unIndex,
+ _Out_ GUID* pguidKey,
+ _Inout_ PROPVARIANT* pValue
+ )
+ {
+ return m_spAttributes->GetItemByIndex(unIndex, pguidKey, pValue);
+ }
+
+ IFACEMETHODIMP CopyAllItems(
+ _In_ IMFAttributes* pDest
+ )
+ {
+ return m_spAttributes->CopyAllItems(pDest);
+ }
+
+ //
+ //Helper Functions
+ //
+ __requires_lock_held(m_lock)
+ __inline HRESULT Active()
+ {
+ return (m_state == DeviceStreamState_Run)?S_OK:HRESULT_FROM_WIN32(ERROR_INVALID_STATE);
+ }
+ __inline DWORD streamId()
+ {
+ return m_StreamId;
+ }
+
+ __inline VOID setMediaType(_In_opt_ IMFMediaType *pMediaType)
+ {
+ m_setMediaType = pMediaType;
+ }
+
+ __inline HRESULT getMediaType(_Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType)
+ {
+ HRESULT hr = S_OK;
+ if (!ppMediaType)
+ return E_INVALIDARG;
+
+ if (m_setMediaType != nullptr)
+ {
+ hr = m_setMediaType.CopyTo(ppMediaType);
+ }
+ else
+ {
+ hr = MF_E_TRANSFORM_TYPE_NOT_SET;
+ }
+ return hr;
+ }
+
+ __inline IFACEMETHODIMP getPinAttributes (_In_ IMFAttributes **ppAttributes)
+ {
+ return QueryInterface( IID_PPV_ARGS(ppAttributes) );
+ }
+
+ IFACEMETHODIMP AddMediaType(
+ _Inout_ DWORD *pos,
+ _In_ IMFMediaType *pMediatype); /*Filling the media types data structure*/
+ IFACEMETHODIMP GetMediaTypeAt(
+ _In_ DWORD pos,
+ _Outptr_result_maybenull_ IMFMediaType **pMediaType); /* getting the data from the data structure*/
+ IFACEMETHODIMP_(BOOL) IsMediaTypeSupported(
+ _In_ IMFMediaType *pMediaType,
+ _When_(ppIMFMediaTypeFull != nullptr, _Outptr_result_maybenull_)
+ IMFMediaType **ppIMFMediaTypeFull);
+ IFACEMETHODIMP GetOutputAvailableType(
+ _In_ DWORD dwTypeIndex,
+ _Out_opt_ IMFMediaType **ppType);
+
+ VOID SetD3DManager(_In_opt_ IUnknown* pManager);
+ VOID SetWorkQueue(_In_ DWORD dwQueueId)
+ {
+ m_dwWorkQueueId = dwQueueId;
+ }
+protected:
+ //
+ //Inline helper functions
+ //
+ _inline CMultipinMft* Parent()
+ {
+ return m_Parent;
+ }
+ __inline HRESULT setAttributes(_In_ IMFAttributes* _pAttributes)
+ {
+ m_spAttributes = _pAttributes;
+ return S_OK;
+ }
+ __inline CCritSec& lock()
+ {
+ return m_lock;
+ }
+ IMFMediaTypeArray m_listOfMediaTypes;
+ ComPtr<IMFAttributes> m_spAttributes;
+ ComPtr<IKsControl> m_spIkscontrol;
+ DeviceStreamState m_state;
+ ComPtr<IUnknown> m_spDxgiManager;
+ DWORD m_dwWorkQueueId;
+private:
+ ULONG m_StreamId; /*Device Stream Id*/
+ CCritSec m_lock; /*This is only used to change the reference count i.e. active users of this stream*/
+ ComPtr<IMFMediaType> m_setMediaType;
+ CMultipinMft* m_Parent;
+ ULONG m_nRefCount;
+};
+
+
+
+class CInPin: public CBasePin{
+public:
+ CInPin( _In_opt_ IMFAttributes*, _In_ ULONG ulPinId = 0, _In_ CMultipinMft *pParent=NULL);
+ ~CInPin();
+
+ IFACEMETHODIMP Init(
+ _In_ IMFDeviceTransform *
+ );
+ IFACEMETHODIMP_(VOID) ConnectPin(
+ _In_ CBasePin *
+ );
+ IFACEMETHODIMP SendSample(
+ _In_ IMFSample *
+ );
+ HRESULT GenerateMFMediaTypeListFromDevice(
+ _In_ UINT uiStreamId
+ );
+ IFACEMETHODIMP WaitForSetInputPinMediaChange(
+ );
+ //
+ //Corresponding IMFDeviceTransform functions for the Pin
+ //
+ HRESULT GetInputStreamPreferredState(
+ _Inout_ DeviceStreamState *value,
+ _Outptr_opt_result_maybenull_ IMFMediaType** ppMediaType
+ );
+ HRESULT SetInputStreamState(
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags
+ );
+
+ virtual IFACEMETHODIMP FlushQueues()
+ {
+ return S_OK;
+ }
+ //
+ //Inline functions
+ //
+ __inline IMFMediaType* getPreferredMediaType()
+ {
+ return m_spPrefferedMediaType.Get();
+ }
+ __inline VOID setPreferredMediaType( _In_ IMFMediaType *pMediaType)
+ {
+ m_spPrefferedMediaType = pMediaType;
+ }
+ __inline DeviceStreamState setPreferredStreamState(_In_ DeviceStreamState streamState)
+ {
+ return (DeviceStreamState)InterlockedCompareExchange((LONG*)&m_preferredStreamState, (LONG)streamState, (LONG)m_preferredStreamState);
+ }
+ __inline DeviceStreamState getPreferredStreamState()
+ {
+ return m_preferredStreamState;
+ }
+
+ IFACEMETHODIMP_( VOID) ShutdownPin();
+
+protected:
+ ComPtr<IMFDeviceTransform> m_spSourceTransform; /*Source Transform i.e. DevProxy*/
+ GUID m_stStreamType; /*GUID representing the GUID*/
+ ComPtr<CBasePin> m_outpin; //Only one output pin connected per input pin. There can be multiple pins connected and this could be a list
+ DeviceStreamState m_preferredStreamState;
+ ComPtr<IMFMediaType> m_spPrefferedMediaType;
+ HANDLE m_waitInputMediaTypeWaiter; /*Set when the input media type is changed*/
+
+};
+
+
+
+class COutPin: public CBasePin{
+public:
+ COutPin(
+ _In_ ULONG id = 0,
+ _In_opt_ CMultipinMft *pparent = NULL,
+ _In_ IKsControl* iksControl=NULL
+ );
+ ~COutPin();
+ IFACEMETHODIMP FlushQueues();
+ IFACEMETHODIMP AddPin(
+ _In_ DWORD pinId
+ );
+ virtual IFACEMETHODIMP AddSample(
+ _In_ IMFSample *pSample,
+ _In_ CBasePin *inPin
+ );
+ IFACEMETHODIMP GetOutputStreamInfo(
+ _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo
+ );
+ virtual IFACEMETHODIMP ChangeMediaTypeFromInpin(
+ _In_ IMFMediaType* pOutMediaType,
+ _In_ DeviceStreamState state );
+ IFACEMETHODIMP ProcessOutput (
+ _In_ DWORD dwFlags,
+ _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample,
+ _Out_ DWORD *pdwStatus
+ );
+ IFACEMETHODIMP KsProperty(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned
+ );
+ IFACEMETHODIMP_(VOID) SetFirstSample(
+ _In_ BOOL
+ );
+
+ UINT32 GetMediatypeCount()
+ {
+ return (UINT32)m_listOfMediaTypes.size();
+ }
+
+protected:
+ CPinQueue * m_queue; /* Queue where the sample will be stored*/
+ BOOL m_firstSample;
+};
+
diff --git a/avstream/avscamera/DMFT/common.h b/avstream/avscamera/DMFT/common.h
new file mode 100644
index 00000000..b6e636a8
--- /dev/null
+++ b/avstream/avscamera/DMFT/common.h
@@ -0,0 +1,360 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#pragma once
+
+#ifndef MF_WPP
+#define DMFTRACE(...)
+#endif
+
+//
+// The below guid is used to register the GUID as the Device Transform. This should be adeed to the
+// HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\DeviceClasses\ and under the
+// GLOBAL#\Device Parameters key, add a CameraDeviceMFTCLSID value, and set its value to
+// {836E84ED-45E9-4160-A79D-771F1C718CD2} for the Pipeline to pick up the Transform.
+//
+
+DEFINE_GUID(CLSID_AvsCameraDMFT, 0x836e84ed, 0x45e9, 0x4160, 0xa7, 0x9d, 0x77, 0x1f, 0x1c, 0x71, 0x8c, 0xd2);
+
+#ifdef DBG
+#define mf_assert(a) if(!a) DebugBreak()
+#else
+#define mf_assert(a)
+#endif
+
+#define WPP_CONTROL_GUIDS \
+ WPP_DEFINE_CONTROL_GUID(CtlGUID_DMFTTrace, (CBCCA12E, 9472, 409D, A1B1, 753C98BF03C0), \
+ WPP_DEFINE_BIT(DMFT_INIT) \
+ WPP_DEFINE_BIT(DMFT_CONTROL) \
+ WPP_DEFINE_BIT(DMFT_GENERAL) \
+ )
+
+#define WPP_LEVEL_FLAG_LOGGER(lvl,flags) WPP_LEVEL_LOGGER(flags)
+#define WPP_LEVEL_FLAG_ENABLED(lvl, flags) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
+#define WPP_FLAG_LEVEL_LOGGER(flags,lvl) WPP_LEVEL_LOGGER(flags)
+#define WPP_FLAG_LEVEL_ENABLED(flags, lvl) (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl)
+
+#define WPP_CHECK_LEVEL_ENABLED(flags, level) 1
+
+//begin_wpp config
+//
+// USEPREFIX (DMFTCHECKNULL_GOTO,"%!STDPREFIX!");
+// FUNC DMFTCHECKNULL_GOTO(CHECKNULLGOTO_EXP,LABEL,HR,...);
+// USESUFFIX (DMFTCHECKNULL_GOTO," failed %!HRESULT!\n", hr);
+//
+//end_wpp
+
+//begin_wpp config
+//
+// USEPREFIX (DMFTCHECKHR_GOTO,"%!STDPREFIX!");
+// FUNC DMFTCHECKHR_GOTO(CHECKHRGOTO_EXP,LABEL,...);
+// USESUFFIX (DMFTCHECKHR_GOTO," failed %!HRESULT!\n", hr);
+//
+
+//end_wpp
+
+#define WPP_CHECKNULLGOTO_EXP_LABEL_HR_PRE(pointer,label,HR) if( pointer == NULL ) { hr = HR;
+#define WPP_CHECKNULLGOTO_EXP_LABEL_HR_POST(pointer,label,HR) ; goto label; }
+
+#define WPP_CHECKNULLGOTO_EXP_LABEL_HR_LOGGER(pointer,label,HR) WPP_LEVEL_LOGGER( DMFT_INIT )
+#define WPP_CHECKNULLGOTO_EXP_LABEL_HR_ENABLED(pointer,label,HR) WPP_CHECK_LEVEL_ENABLED( DMFT_INIT, TP_ERROR )
+
+#define WPP_CHECKHRGOTO_EXP_LABEL_PRE(HR,label) if( FAILED( hr = HR ) ) {
+#define WPP_CHECKHRGOTO_EXP_LABEL_POST(HR,label) ; goto label; }
+
+#define WPP_CHECKHRGOTO_EXP_LABEL_LOGGER(HR, label) WPP_LEVEL_LOGGER( DMFT_INIT )
+#define WPP_CHECKHRGOTO_EXP_LABEL_ENABLED(HR, label) WPP_CHECK_LEVEL_ENABLED( DMFT_INIT, TP_ERROR )
+
+
+// Give it checkhr and checknull definitions if some future generations of visual studio remove the wpp processor support
+
+//#if !defined DMFTCHECKHR_GOTO
+//#define DMFTCHECKHR_GOTO(a,b) {hr=(a); if(FAILED(hr)){goto b;}}
+//#endif
+//
+//#if !defined DMFTCHECKNULL_GOTO
+//#define DMFTCHECKNULL_GOTO(a,b,c) {if(!a) {hr = c; goto b;}}
+//#endif
+
+#define SAFE_ADDREF(p) if( NULL != p ) { ( p )->AddRef(); }
+#define SAFE_DELETE(p) delete p; p = NULL;
+#define SAFE_SHUTDELETE(p) if( NULL != p ) { ( p )->Shutdown(); delete p; p = NULL; }
+#define SAFE_RELEASE(p) if( NULL != p ) { ( p )->Release(); p = NULL; }
+#define SAFE_SHUTRELEASE(p) if( NULL != p ) { ( p )->Shutdown(); ( p )->Release(); p = NULL; }
+#define SAFE_CLOSERELEASE(p) if( NULL != p ) { ( p )->Close( TRUE ); ( p )->Release(); p = NULL; }
+#define SAFE_COTASKMEMFREE(p) CoTaskMemFree( p ); p = NULL;
+#define SAFE_SYSFREESTRING(p) SysFreeString( p ); p = NULL;
+#define SAFE_ARRAYDELETE(p) delete [] p; p = NULL;
+#define SAFE_BYTEARRAYDELETE(p) delete [] (BYTE*) p; p = NULL;
+#define SAFE_CLOSEHANDLE(h) { if(INVALID_HANDLE_VALUE != (h)) { ::CloseHandle(h); (h) = INVALID_HANDLE_VALUE; } }
+
+
+#define SAFERELEASE(x) \
+if (x) {\
+ x->Release(); \
+ x = NULL; \
+}
+
+#if !defined(_IKsControl_)
+#define _IKsControl_
+interface DECLSPEC_UUID("28F54685-06FD-11D2-B27A-00A0C9223196") IKsControl;
+#undef INTERFACE
+#define INTERFACE IKsControl
+DECLARE_INTERFACE_(IKsControl, IUnknown)
+{
+ STDMETHOD(KsProperty)(
+ THIS_
+ IN PKSPROPERTY Property,
+ IN ULONG PropertyLength,
+ IN OUT LPVOID PropertyData,
+ IN ULONG DataLength,
+ OUT ULONG* BytesReturned
+ ) PURE;
+ STDMETHOD(KsMethod)(
+ THIS_
+ IN PKSMETHOD Method,
+ IN ULONG MethodLength,
+ IN OUT LPVOID MethodData,
+ IN ULONG DataLength,
+ OUT ULONG* BytesReturned
+ ) PURE;
+ STDMETHOD(KsEvent)(
+ THIS_
+ IN PKSEVENT Event OPTIONAL,
+ IN ULONG EventLength,
+ IN OUT LPVOID EventData,
+ IN ULONG DataLength,
+ OUT ULONG* BytesReturned
+ ) PURE;
+};
+#endif //!defined(_IKsControl_)
+
+//Forward defintion
+class CBasePin;
+//////////////////////////////////////////////////////////////////////////
+// CCritSec
+// Description: Wraps a critical section.
+//////////////////////////////////////////////////////////////////////////
+
+class CCritSec
+{
+private:
+ CRITICAL_SECTION m_criticalSection;
+public:
+ CCritSec();
+ ~CCritSec();
+ _Requires_lock_not_held_(m_criticalSection) _Acquires_lock_(m_criticalSection)
+ void Lock();
+ _Requires_lock_held_(m_criticalSection) _Releases_lock_(m_criticalSection)
+ void Unlock();
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+// CAutoLock
+// Description: Provides automatic locking and unlocking of a
+// of a critical section.
+//////////////////////////////////////////////////////////////////////////
+
+class CAutoLock
+{
+protected:
+ CCritSec *m_pCriticalSection;
+public:
+ _Acquires_lock_(this->m_pCriticalSection->m_criticalSection)
+ CAutoLock(CCritSec& crit);
+ _Acquires_lock_(this->m_pCriticalSection->m_criticalSection)
+ CAutoLock(CCritSec* crit);
+ _Releases_lock_(this->m_pCriticalSection->m_criticalSection)
+ ~CAutoLock();
+};
+
+class MediaBufferLock
+{
+public:
+ MediaBufferLock(_In_ IMFMediaBuffer* pBuffer) :
+ m_bLocked(false)
+ {
+ m_spBuffer = pBuffer;
+ }
+
+ HRESULT LockBuffer(
+ _Outptr_result_bytebuffer_to_(*pcbMaxLength, *pcbCurrentLength) BYTE** ppbBuffer,
+ _Out_opt_ DWORD* pcbMaxLength,
+ _Out_opt_ DWORD* pcbCurrentLength)
+ {
+ if (!m_spBuffer)
+ {
+ return E_INVALIDARG;
+ }
+
+ HRESULT hr = m_spBuffer->Lock(ppbBuffer, pcbMaxLength, pcbCurrentLength);
+ if (FAILED(hr))
+ {
+ return hr;
+ }
+ m_bLocked = true;
+ return S_OK;
+ }
+
+ ~MediaBufferLock()
+ {
+ if (m_spBuffer && m_bLocked)
+ {
+ //Unlock fails only if we did not lock it first
+ (void)m_spBuffer->Unlock();
+ }
+ }
+
+private:
+ ComPtr<IMFMediaBuffer> m_spBuffer;
+ bool m_bLocked;
+};
+
+typedef std::vector<ComPtr<IMFMediaType>> IMFMediaTypeArray;
+typedef std::vector<ComPtr<CBasePin>> CBasePinArray;
+typedef std::vector<ComPtr<IMFSample>> IMFSampleList;
+typedef std::pair< std::multimap<int, int>::iterator, std::multimap<int, int>::iterator > MMFTMMAPITERATOR;
+
+STDMETHODIMP_(BOOL) IsPinStateInActive(
+ _In_ DeviceStreamState state
+ );
+
+
+template <typename Lambda>
+HRESULT ExceptionBoundary(Lambda&& lambda)
+{
+ try
+ {
+ lambda();
+ return S_OK;
+ }
+ catch (const _com_error& e)
+ {
+ return e.Error();
+ }
+ catch (const std::bad_alloc&)
+ {
+ return E_OUTOFMEMORY;
+ }
+ catch (const std::out_of_range&)
+ {
+ return MF_E_INVALIDINDEX;
+ }
+ catch (...)
+ {
+ return E_UNEXPECTED;
+ }
+}
+
+//
+// Object LifeTime manager. The Class has a global variable which
+// maintains a reference count of the number of objects in the
+// system managed by the DLL.
+//
+class CDMFTModuleLifeTimeManager{
+public:
+ CDMFTModuleLifeTimeManager()
+ {
+ InterlockedIncrement(&s_lObjectCount);
+ }
+ ~CDMFTModuleLifeTimeManager()
+ {
+ InterlockedDecrement(&s_lObjectCount);
+ }
+ static long GetDMFTObjCount()
+ {
+ return s_lObjectCount;
+ }
+private:
+ static volatile long s_lObjectCount;
+};
+
+class CPinQueue : public IUnknown
+{
+public:
+ CPinQueue(_In_ DWORD _inPinId, _In_ IMFDeviceTransform* pTransform = nullptr);
+ ~CPinQueue();
+
+ STDMETHODIMP Insert(_In_ IMFSample* pSample);
+ STDMETHODIMP Remove(_Outptr_result_maybenull_ IMFSample** pSample);
+ STDMETHODIMP_(VOID) Clear();
+
+ //
+ // Inline functions
+ //
+ __inline BOOL Empty()
+ {
+ return (!m_sampleList.size());
+ }
+ __inline DWORD pinStreamId()
+ {
+ return m_dwInPinId;
+ }
+ __inline GUID pinCategory()
+ {
+ if (IsEqualCLSID(m_streamCategory, GUID_NULL))
+ {
+ ComPtr<IMFAttributes> spAttributes;
+ if (SUCCEEDED(m_pTransform->GetOutputStreamAttributes(pinStreamId(), spAttributes.ReleaseAndGetAddressOf())))
+ {
+ (VOID) spAttributes->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &m_streamCategory);
+ }
+ }
+ return m_streamCategory;
+ }
+
+ STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
+ {
+ HRESULT hr = S_OK;
+ if (ppv != nullptr)
+ {
+ *ppv = nullptr;
+ if (riid == __uuidof(IUnknown))
+ {
+ AddRef();
+ *ppv = static_cast<IUnknown*>(this);
+ }
+ else
+ {
+ hr = E_NOINTERFACE;
+ }
+ }
+ else
+ {
+ hr = E_POINTER;
+ }
+ return hr;
+ }
+
+ STDMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+ STDMETHODIMP_(ULONG) Release()
+ {
+ long cRef = InterlockedDecrement(&m_cRef);
+ if (cRef == 0)
+ {
+ delete this;
+ }
+ return cRef;
+ }
+
+private:
+ DWORD m_dwInPinId; /* This is the input pin */
+ IMFSampleList m_sampleList; /* List storing the samples */
+ IMFDeviceTransform* m_pTransform; /* Weak reference to the the device MFT */
+ GUID m_streamCategory;
+ ULONG m_cRef;
+};
+
+
+HRESULT ProcessMetadata(_In_ IMFSample* pSample);
+// Metadata defintions
+
diff --git a/avstream/avscamera/DMFT/dllmain.cpp b/avstream/avscamera/DMFT/dllmain.cpp
new file mode 100644
index 00000000..5a988320
--- /dev/null
+++ b/avstream/avscamera/DMFT/dllmain.cpp
@@ -0,0 +1,354 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+//////////////////////////////////////////////////////////////////////////
+//
+// dllmain.cpp : Implements DLL exports and COM class factory
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+// PARTICULAR PURPOSE.
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// Note: This source file implements the class factory for the transform,
+// plus the following DLL functions:
+// - DllMain
+// - DllCanUnloadNow
+// - DllRegisterServer
+// - DllUnregisterServer
+// - DllGetClassObject
+//
+//////////////////////////////////////////////////////////////////////////
+#include "stdafx.h"
+
+#ifdef MF_WPP
+#include "dllmain.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+
+//
+// The static variable needed to check the object count of the deviceMFts loaded.
+//
+
+volatile long CDMFTModuleLifeTimeManager::s_lObjectCount = 0;
+
+
+
+HRESULT RegisterObject(HMODULE hModule, REFGUID guid, PCWSTR pszDescription, PCWSTR pszThreadingModel);
+
+HRESULT UnregisterObject(const GUID& guid);
+
+
+// Module Ref count
+long g_cRefModule = 0;
+
+// Handle to the DLL's module
+HMODULE g_hModule = NULL;
+
+void DllAddRef()
+{
+ InterlockedIncrement(&g_cRefModule);
+}
+
+void DllRelease()
+{
+ InterlockedDecrement(&g_cRefModule);
+}
+
+//
+// IClassFactory implementation
+//
+
+typedef HRESULT (*PFNCREATEINSTANCE)(REFIID riid, void **ppvObject);
+struct CLASS_OBJECT_INIT
+{
+ const CLSID *pClsid;
+ PFNCREATEINSTANCE pfnCreate;
+};
+
+// Classes supported by this module:
+const CLASS_OBJECT_INIT c_rgClassObjectInit[] =
+{
+ { &CLSID_AvsCameraDMFT, MFT_CreateInstance },
+};
+
+class CClassFactory : public IClassFactory
+{
+public:
+
+ static HRESULT CreateInstance(
+ REFCLSID clsid, // The CLSID of the object to create (from DllGetClassObject)
+ const CLASS_OBJECT_INIT *pClassObjectInits, // Array of class factory data.
+ size_t cClassObjectInits, // Number of elements in the array.
+ REFIID riid, // The IID of the interface to retrieve (from DllGetClassObject)
+ void **ppv // Receives a pointer to the interface.
+ )
+ {
+ *ppv = NULL;
+
+ HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
+
+ for (size_t i = 0; i < cClassObjectInits; i++)
+ {
+ if (clsid == *pClassObjectInits[i].pClsid)
+ {
+ IClassFactory *pClassFactory = new (std::nothrow) CClassFactory(pClassObjectInits[i].pfnCreate);
+
+ if (pClassFactory)
+ {
+ hr = pClassFactory->QueryInterface(riid, ppv);
+ pClassFactory->Release();
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+ break; // match found
+ }
+ }
+ return hr;
+ }
+
+ // IUnknown methods
+ IFACEMETHODIMP QueryInterface(REFIID riid, void ** ppv)
+ {
+#if 0
+ static const QITAB qit[] =
+ {
+ QITABENT(CClassFactory, IClassFactory),
+ { 0 }
+ };
+ return QISearch(this, qit, riid, ppv);
+
+#else
+ if (riid == __uuidof(IClassFactory))
+ {
+ *ppv = static_cast< IClassFactory* >(this);
+ AddRef();
+ }
+ return S_OK;
+#endif
+ }
+
+ IFACEMETHODIMP_(ULONG) AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ IFACEMETHODIMP_(ULONG) Release()
+ {
+ long cRef = InterlockedDecrement(&m_cRef);
+ if (cRef == 0)
+ {
+ delete this;
+ }
+ return cRef;
+ }
+
+ // IClassFactory methods
+
+ IFACEMETHODIMP CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
+ {
+ return punkOuter ? CLASS_E_NOAGGREGATION : m_pfnCreate(riid, ppv);
+ }
+
+ IFACEMETHODIMP LockServer(BOOL fLock)
+ {
+ if (fLock)
+ {
+ DllAddRef();
+ }
+ else
+ {
+ DllRelease();
+ }
+ return S_OK;
+ }
+
+private:
+
+ CClassFactory(PFNCREATEINSTANCE pfnCreate) : m_cRef(1), m_pfnCreate(pfnCreate)
+ {
+ DllAddRef();
+ }
+
+ ~CClassFactory()
+ {
+ DllRelease();
+ }
+
+ long m_cRef;
+ PFNCREATEINSTANCE m_pfnCreate;
+};
+
+
+
+//
+// Standard DLL functions
+//
+
+IFACEMETHODIMP_(BOOL) WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, void*)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ g_hModule = (HMODULE)hInstance;
+ DisableThreadLibraryCalls(hInstance);
+#ifdef MF_WPP
+ WPP_INIT_TRACING(L"MultiPinMft");
+#endif
+ }
+ else
+ if (dwReason == DLL_PROCESS_DETACH)
+ {
+#ifdef MF_WPP
+ WPP_CLEANUP();
+#endif
+ }
+ return TRUE;
+}
+
+IFACEMETHODIMP DllCanUnloadNow()
+{
+ HRESULT hr = ((g_cRefModule == 0) && (CDMFTModuleLifeTimeManager::GetDMFTObjCount() == 0)) ? S_OK : S_FALSE;
+ //
+ // Debug object lifetimes
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! returning %d %d %!HRESULT!",
+ g_cRefModule,
+ CDMFTModuleLifeTimeManager::GetDMFTObjCount(),
+ hr);
+
+ return hr;
+
+}
+
+_Check_return_
+STDAPI DllGetClassObject(_In_ REFCLSID clsid, _In_ REFIID riid, _Outptr_ LPVOID FAR* ppv)
+{
+ return CClassFactory::CreateInstance(clsid, c_rgClassObjectInit, ARRAYSIZE(c_rgClassObjectInit), riid, ppv);
+}
+
+IFACEMETHODIMP DllRegisterServer()
+{
+ assert(g_hModule != NULL);
+
+ // Register the CLSID for CoCreateInstance.
+ HRESULT hr = RegisterObject(g_hModule, CLSID_AvsCameraDMFT, TEXT("Multiple MFTs"), TEXT("Both"));
+
+ return hr;
+}
+
+IFACEMETHODIMP DllUnregisterServer()
+{
+ // Unregister the CLSID.
+ UnregisterObject(CLSID_AvsCameraDMFT);
+
+ return S_OK;
+}
+
+
+// Converts a CLSID into a string with the form "CLSID\{clsid}"
+IFACEMETHODIMP CreateObjectKeyName(REFGUID guid, _Out_writes_(cchMax) PWSTR pszName, DWORD cchMax)
+{
+ const DWORD chars_in_guid = 39;
+
+ // convert CLSID uuid to string
+ OLECHAR szCLSID[chars_in_guid];
+ HRESULT hr = StringFromGUID2(guid, szCLSID, chars_in_guid);
+ if (SUCCEEDED(hr))
+ {
+ // Create a string of the form "CLSID\{clsid}"
+ hr = StringCchPrintf((STRSAFE_LPWSTR)pszName, cchMax, TEXT("Software\\Classes\\CLSID\\%ls"), szCLSID);
+ }
+ return hr;
+}
+
+// Creates a registry key (if needed) and sets the default value of the key
+IFACEMETHODIMP CreateRegKeyAndValue(HKEY hKey, PCWSTR pszSubKeyName, PCWSTR pszValueName,
+ PCWSTR pszData, PHKEY phkResult)
+{
+ *phkResult = NULL;
+ LONG lRet = RegCreateKeyExW(
+ hKey, pszSubKeyName,
+ 0, NULL, REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS, NULL, phkResult, NULL);
+
+ if (lRet == ERROR_SUCCESS)
+ {
+ lRet = RegSetValueExW(
+ (*phkResult),
+ pszValueName, 0, REG_SZ,
+ (LPBYTE) pszData,
+ ((DWORD) wcslen(pszData) + 1) * sizeof(WCHAR)
+ );
+
+ if (lRet != ERROR_SUCCESS)
+ {
+ RegCloseKey(*phkResult);
+ }
+ }
+
+ return HRESULT_FROM_WIN32(lRet);
+}
+
+// Creates the registry entries for a COM object.
+
+HRESULT RegisterObject(HMODULE hModule, const GUID& guid, const TCHAR *pszDescription, const TCHAR *pszThreadingModel)
+{
+ HKEY hKey = NULL;
+ HKEY hSubkey = NULL;
+ TCHAR achTemp[MAX_PATH];
+
+ // Create the name of the key from the object's CLSID
+ HRESULT hr = CreateObjectKeyName(guid, achTemp, MAX_PATH);
+
+ // Create the new key.
+ if (SUCCEEDED(hr))
+ {
+ hr = CreateRegKeyAndValue(HKEY_LOCAL_MACHINE, achTemp, NULL, pszDescription,&hKey);
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ (void)GetModuleFileName(hModule, achTemp, MAX_PATH);
+
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ }
+
+ // Create the "InprocServer32" subkey
+ if (SUCCEEDED(hr))
+ {
+ hr = CreateRegKeyAndValue(hKey, L"InProcServer32", NULL, achTemp, &hSubkey);
+ RegCloseKey(hSubkey);
+ }
+
+ // Add a new value to the subkey, for "ThreadingModel" = <threading model>
+ if (SUCCEEDED(hr))
+ {
+ hr = CreateRegKeyAndValue(hKey, L"InProcServer32", L"ThreadingModel", pszThreadingModel, &hSubkey);
+ RegCloseKey(hSubkey);
+ }
+
+ // close hkeys
+ RegCloseKey(hKey);
+ return hr;
+}
+
+// Deletes the registry entries for a COM object.
+
+HRESULT UnregisterObject(const GUID& guid)
+{
+ WCHAR achTemp[MAX_PATH];
+
+ HRESULT hr = CreateObjectKeyName(guid, achTemp, MAX_PATH);
+ if (SUCCEEDED(hr))
+ {
+ // Delete the key recursively.
+ LONG lRes = RegDeleteTree(HKEY_LOCAL_MACHINE, achTemp);
+ hr = HRESULT_FROM_WIN32(lRes);
+ }
+ return hr;
+}
+
+
diff --git a/avstream/avscamera/DMFT/mftpeventgenerator.cpp b/avstream/avscamera/DMFT/mftpeventgenerator.cpp
new file mode 100644
index 00000000..1e510cfa
--- /dev/null
+++ b/avstream/avscamera/DMFT/mftpeventgenerator.cpp
@@ -0,0 +1,234 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#include "stdafx.h"
+#include "common.h"
+#include "mftpeventgenerator.h"
+
+
+
+#ifdef MF_WPP
+#include "mftpeventgenerator.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+
+CMediaEventGenerator::CMediaEventGenerator () :
+ m_nRefCount(0),
+ m_pQueue(NULL),
+ m_bShutdown(FALSE)
+{
+ //Call this explicit...
+ InitMediaEventGenerator();
+}
+
+STDMETHODIMP CMediaEventGenerator::InitMediaEventGenerator(
+ void
+ )
+{
+
+ return MFCreateEventQueue(&m_pQueue);
+
+}
+
+STDMETHODIMP_(ULONG) CMediaEventGenerator::AddRef(
+ void
+ )
+{
+ return InterlockedIncrement(&m_nRefCount);
+}
+
+STDMETHODIMP_(ULONG) CMediaEventGenerator::Release(
+ void
+ )
+{
+ ULONG uCount = InterlockedDecrement(&m_nRefCount);
+
+ if (uCount == 0)
+ {
+ delete this;
+ }
+ return uCount;
+}
+
+STDMETHODIMP CMediaEventGenerator::QueryInterface(
+ _In_ REFIID iid,
+ _COM_Outptr_ void** ppv)
+{
+ HRESULT hr = S_OK;
+
+ *ppv = NULL;
+
+ if (iid == __uuidof(IUnknown) || iid == __uuidof(IMFMediaEventGenerator))
+ {
+ *ppv = static_cast<IMFMediaEventGenerator*>(this);
+ AddRef();
+ }
+ else
+ {
+ hr = E_NOINTERFACE;
+ }
+
+ return hr;
+}
+
+//
+// IMediaEventGenerator methods
+//
+STDMETHODIMP CMediaEventGenerator::BeginGetEvent(
+ _In_ IMFAsyncCallback* pCallback,
+ _In_ IUnknown* pState
+ )
+{
+ HRESULT hr = S_OK;
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_pQueue->BeginGetEvent(pCallback, pState);
+ }
+
+ m_critSec.Unlock();
+
+ return hr;
+}
+
+STDMETHODIMP CMediaEventGenerator::EndGetEvent(
+ _In_ IMFAsyncResult* pResult,
+ _Outptr_result_maybenull_ IMFMediaEvent** ppEvent
+ )
+{
+ HRESULT hr = S_OK;
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+
+ if (SUCCEEDED(hr))
+ {
+ hr = m_pQueue->EndGetEvent(pResult, ppEvent);
+ }
+
+ m_critSec.Unlock();
+
+ return hr;
+}
+
+STDMETHODIMP CMediaEventGenerator::GetEvent(
+ _In_ DWORD dwFlags,
+ _Outptr_result_maybenull_ IMFMediaEvent** ppEvent
+ )
+{
+ //
+ // Because GetEvent can block indefinitely, it requires
+ // a slightly different locking strategy.
+ //
+ HRESULT hr = S_OK;
+ IMFMediaEventQueue *pQueue = NULL;
+
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+ //
+ // Store the pointer in a local variable, so that another thread
+ // does not release it after we leave the critical section.
+ //
+ if (SUCCEEDED(hr))
+ {
+ pQueue = m_pQueue;
+ }
+
+ m_critSec.Unlock();
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pQueue->GetEvent(dwFlags, ppEvent);
+ }
+
+ return hr;
+}
+
+STDMETHODIMP CMediaEventGenerator::QueueEvent(
+ _In_ MediaEventType met,
+ _In_ REFGUID extendedType,
+ _In_ HRESULT hrStatus,
+ _In_opt_ const PROPVARIANT* pvValue
+ )
+{
+ HRESULT hr = S_OK;
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+
+ if (SUCCEEDED(hr))
+ {
+
+ hr = m_pQueue->QueueEventParamVar(
+ met,
+ extendedType,
+ hrStatus,
+ pvValue
+ );
+ }
+
+ m_critSec.Unlock();
+
+ return hr;
+}
+
+STDMETHODIMP CMediaEventGenerator::ShutdownEventGenerator(
+ void
+ )
+{
+ HRESULT hr = S_OK;
+
+
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+
+ if (SUCCEEDED(hr))
+ {
+ if (m_pQueue)
+ {
+ hr = m_pQueue->Shutdown();
+ }
+ SAFE_RELEASE(m_pQueue);
+ m_bShutdown = TRUE;
+ }
+ m_critSec.Unlock();
+
+ return hr;
+}
+
+STDMETHODIMP CMediaEventGenerator::QueueEvent(
+ _In_ IMFMediaEvent* pEvent
+ )
+{
+ HRESULT hr = S_OK;
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+
+ if (SUCCEEDED(hr))
+ {
+ if (m_pQueue)
+ {
+ hr = m_pQueue->QueueEvent(pEvent);
+ }
+ }
+
+ m_critSec.Unlock();
+ return hr;
+}
+
+CMediaEventGenerator::~CMediaEventGenerator (
+ void
+ )
+{
+ ShutdownEventGenerator();
+}
diff --git a/avstream/avscamera/DMFT/mftpeventgenerator.h b/avstream/avscamera/DMFT/mftpeventgenerator.h
new file mode 100644
index 00000000..2ddae218
--- /dev/null
+++ b/avstream/avscamera/DMFT/mftpeventgenerator.h
@@ -0,0 +1,94 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+#pragma once
+
+class CMediaEventGenerator :
+ public IMFMediaEventGenerator
+{
+
+public:
+
+ //
+ // IUnknown
+ //
+ STDMETHOD_(ULONG, AddRef)(
+ void
+ );
+
+ STDMETHOD_(ULONG, Release)(
+ void
+ );
+
+ STDMETHOD(QueryInterface)(
+ _In_ REFIID iid,
+ _COM_Outptr_ void** ppv);
+
+
+ //
+ // IMFMediaEventGenerator
+ //
+ STDMETHOD(BeginGetEvent)(
+ _In_ IMFAsyncCallback* pCallback,
+ _In_ IUnknown* pState
+ );
+
+ STDMETHOD(EndGetEvent)(
+ _In_ IMFAsyncResult* pResult,
+ _Outptr_result_maybenull_ IMFMediaEvent** ppEvent
+ );
+
+ STDMETHOD(GetEvent)(
+ _In_ DWORD dwFlags,
+ _Outptr_result_maybenull_ IMFMediaEvent** ppEvent
+ );
+
+ STDMETHOD(QueueEvent)(
+ _In_ MediaEventType met,
+ _In_ REFGUID extendedType,
+ _In_ HRESULT hrStatus,
+ _In_opt_ const PROPVARIANT* pvValue
+ );
+
+ STDMETHOD(QueueEvent)(
+ _In_ IMFMediaEvent* pEvent
+ );
+
+protected:
+
+ CMediaEventGenerator(
+ void
+ );
+
+ virtual ~CMediaEventGenerator (
+ void
+ );
+ //
+ // Utility Methods
+ //
+ STDMETHOD(ShutdownEventGenerator)(
+ void
+ );
+
+ STDMETHOD (InitMediaEventGenerator)(
+ void
+ );
+
+ __inline HRESULT (CheckShutdown)(
+ void
+ ) const
+ {
+ return (m_bShutdown? MF_E_SHUTDOWN : S_OK);
+ }
+
+private:
+
+ long m_nRefCount;
+ CCritSec m_critSec;
+ IMFMediaEventQueue* m_pQueue;
+ BOOL m_bShutdown;
+};
diff --git a/avstream/avscamera/DMFT/packages.config b/avstream/avscamera/DMFT/packages.config
new file mode 100644
index 00000000..26065b14
--- /dev/null
+++ b/avstream/avscamera/DMFT/packages.config
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Microsoft.Windows.ImplementationLibrary" version="1.0.210204.1" targetFramework="native" />
+</packages> \ No newline at end of file
diff --git a/avstream/avscamera/DMFT/stdafx.h b/avstream/avscamera/DMFT/stdafx.h
new file mode 100644
index 00000000..d21def93
--- /dev/null
+++ b/avstream/avscamera/DMFT/stdafx.h
@@ -0,0 +1,47 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+#pragma once
+
+
+#include <SDKDDKVer.h>
+#include <windows.h>
+#include <winnt.h>
+#include <tchar.h>
+#include <comdef.h>
+#include <initguid.h>
+#include <ks.h>
+#include <ksmedia.h>
+#include <Strsafe.h>
+#include <wchar.h>
+#include <stdio.h>
+#include <assert.h>
+#include <mfidl.h>
+#include <wincodec.h>
+#include <mfapi.h>
+#include <mftransform.h>
+#include <mfidl.h>
+#include <mferror.h>
+#include <mftransform.h>
+#include <time.h>
+#include <initguid.h>
+#include <d3d9.h>
+#include <dxva2api.h>
+#include <d3d11.h>
+#include <mfcaptureengine.h>
+#include <algorithm>
+#include <new>
+#include <d3d11_4.h>
+#include <vector>
+#include <map>
+#include <stdexcept>
+using namespace std;
+#include <Windows.Foundation.h>
+#include <wrl\client.h>
+using namespace ABI::Windows::Foundation;
+using namespace Microsoft::WRL;
+
+#include "common.h"
+#include "AvsCameraDMFT.h"
+#include "basepin.h"
+#include "metadataInternal.h"
diff --git a/avstream/avscamera/DMFT/stdafxsrc.cpp b/avstream/avscamera/DMFT/stdafxsrc.cpp
new file mode 100644
index 00000000..a6f44b0e
--- /dev/null
+++ b/avstream/avscamera/DMFT/stdafxsrc.cpp
@@ -0,0 +1,4 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+#include "stdafx.h" \ No newline at end of file