summaryrefslogtreecommitdiff
path: root/AVStream/sampledevicemft
diff options
context:
space:
mode:
authorWei Mao <[email protected]>2017-03-17 19:47:04 -0700
committerWei Mao <[email protected]>2017-03-17 19:47:04 -0700
commit1a3e0d580380e58bf336a242d2affc8a1e2d1ddf (patch)
treebf5d9c5b0b4cba1b81726b9f78c4d5ff5c636fea /AVStream/sampledevicemft
parentda21c8784c83c5fd614f3030323e229d6a5fb10e (diff)
Fix cases
Diffstat (limited to 'AVStream/sampledevicemft')
-rw-r--r--AVStream/sampledevicemft/SampleDeviceMft.sln28
-rw-r--r--AVStream/sampledevicemft/Source.def5
-rw-r--r--AVStream/sampledevicemft/basepin.cpp847
-rw-r--r--AVStream/sampledevicemft/basepin.h596
-rw-r--r--AVStream/sampledevicemft/common.h717
-rw-r--r--AVStream/sampledevicemft/custompin.cpp98
-rw-r--r--AVStream/sampledevicemft/custompin.h30
-rw-r--r--AVStream/sampledevicemft/dllmain.cpp354
-rw-r--r--AVStream/sampledevicemft/mftpeventgenerator.cpp250
-rw-r--r--AVStream/sampledevicemft/mftpeventgenerator.h94
-rw-r--r--AVStream/sampledevicemft/multipinmft.cpp2453
-rw-r--r--AVStream/sampledevicemft/multipinmft.h477
-rw-r--r--AVStream/sampledevicemft/multipinmft.vcxproj263
-rw-r--r--AVStream/sampledevicemft/multipinmft.vcxproj.Filters46
-rw-r--r--AVStream/sampledevicemft/multipinmfthelpers.cpp988
-rw-r--r--AVStream/sampledevicemft/multipinmfthelpers.h291
-rw-r--r--AVStream/sampledevicemft/multipinmftutils.cpp877
-rw-r--r--AVStream/sampledevicemft/stdafx.h39
-rw-r--r--AVStream/sampledevicemft/stdafxsrc.cpp1
19 files changed, 8454 insertions, 0 deletions
diff --git a/AVStream/sampledevicemft/SampleDeviceMft.sln b/AVStream/sampledevicemft/SampleDeviceMft.sln
new file mode 100644
index 00000000..a6a00c4d
--- /dev/null
+++ b/AVStream/sampledevicemft/SampleDeviceMft.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0
+MinimumVisualStudioVersion = 12.0
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "multipinmft", "multipinmft.vcxproj", "{E77657CD-A270-49E1-823A-8A14FF8596C8}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|Win32.Build.0 = Debug|Win32
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|Win32.ActiveCfg = Release|Win32
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|Win32.Build.0 = Release|Win32
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|x64.ActiveCfg = Debug|x64
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Debug|x64.Build.0 = Debug|x64
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|x64.ActiveCfg = Release|x64
+ {E77657CD-A270-49E1-823A-8A14FF8596C8}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/AVStream/sampledevicemft/Source.def b/AVStream/sampledevicemft/Source.def
new file mode 100644
index 00000000..752ef2ea
--- /dev/null
+++ b/AVStream/sampledevicemft/Source.def
@@ -0,0 +1,5 @@
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
+ DllGetClassObject PRIVATE
diff --git a/AVStream/sampledevicemft/basepin.cpp b/AVStream/sampledevicemft/basepin.cpp
new file mode 100644
index 00000000..a1f71860
--- /dev/null
+++ b/AVStream/sampledevicemft/basepin.cpp
@@ -0,0 +1,847 @@
+#include "stdafx.h"
+#include "common.h"
+#include "multipinmft.h"
+#include "multipinmfthelpers.h"
+#include "basepin.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)
+{
+
+}
+
+CBasePin::~CBasePin()
+{
+ IMFMediaType *pMediaType = nullptr;
+ for ( ULONG ulIndex = 0, ulSize = (ULONG)m_listOfMediaTypes.size(); ulIndex < ulSize; ulIndex++ )
+ {
+ pMediaType = m_listOfMediaTypes[ulIndex];
+ SAFE_RELEASE(pMediaType);
+ }
+ m_listOfMediaTypes.clear();
+ m_spAttributes = nullptr;
+}
+
+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);
+ pMediaType->AddRef();
+
+ 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());
+ DMFTCHECKNULL_GOTO(ppMediaType,done,E_INVALIDARG);
+
+ if (pos >= m_listOfMediaTypes.size())
+ {
+ DMFTCHECKHR_GOTO(MF_E_NO_MORE_TYPES,done);
+ }
+ *ppMediaType = m_listOfMediaTypes[pos];
+ if (*ppMediaType)
+ {
+ (*ppMediaType)->AddRef();
+ }
+done:
+ return hr;
+}
+
+STDMETHODIMP_(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) {
+ *ppIMFMediaTypeFull = m_listOfMediaTypes[uIIndex];
+ (*ppIMFMediaTypeFull)->AddRef();
+ }
+ break;
+ }
+ else if (FAILED(hr))
+ {
+ DMFTCHECKHR_GOTO(hr,done);
+ }
+ }
+done:
+ return SUCCEEDED(hr) ? TRUE : FALSE;
+}
+
+
+STDMETHODIMP 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, out, E_POINTER);
+
+ *ppv = nullptr;
+
+ if ( iid == __uuidof( IUnknown ) )
+ {
+ *ppv = static_cast<VOID*>(this);
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IMFAttributes ) )
+ {
+ *ppv = static_cast< IMFAttributes* >( this );
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IKsControl ) )
+ {
+ *ppv = static_cast< IKsControl* >( this );
+ AddRef();
+ }
+ else
+ {
+ hr = E_NOINTERFACE;
+ }
+out:
+ return hr;
+}
+
+
+
+
+//
+//Input Pin implementation
+//
+CInPin::CInPin(
+ _In_opt_ IMFAttributes *pAttributes,
+ _In_ ULONG ulPinId,
+ _In_ CMultipinMft *pParent)
+ :
+ CBasePin(ulPinId, pParent),
+ m_stStreamType(GUID_NULL),
+ m_activeStreamCount(0),
+ m_state(DeviceStreamState_Stop),
+ m_prefferedMediaType(nullptr),
+ m_waitInputMediaTypeWaiter(NULL),
+ m_preferredStreamState(DeviceStreamState_Stop)
+{
+ setAttributes(pAttributes);
+}
+
+
+
+CInPin::~CInPin()
+{
+ setAttributes( nullptr );
+ m_spSourceTransform = nullptr;
+
+ for (ULONG ulIndex = 0, ulSize = (ULONG)m_outpins.size();
+ ulIndex < ulSize;
+ ulIndex++)
+ {
+ CBasePin *pPin = m_outpins[ulIndex];
+ SAFERELEASE(pPin);
+ }
+ if (m_waitInputMediaTypeWaiter)
+ {
+ CloseHandle(m_waitInputMediaTypeWaiter);
+ }
+
+}
+
+
+
+STDMETHODIMP CInPin::Init(
+ _In_ IMFTransform* 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,
+ TEXT("MediaTypeWaiter")
+ );
+ 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;
+}
+
+
+STDMETHODIMP 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->MFTGetOutputAvailableType(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;
+}
+
+STDMETHODIMP CInPin::SendSample(
+ _In_ IMFSample *pSample
+ )
+{
+ HRESULT hr = S_OK;
+ BOOL sentOne = TRUE;
+ DMFTCHECKNULL_GOTO(pSample, done, S_OK);
+
+ for ( ULONG ulIndex = 0, ulSize = (ULONG) m_outpins.size(); ulIndex < ulSize; ulIndex++ )
+ {
+ COutPin *poPin = (COutPin *)m_outpins[ ulIndex ];
+
+ pSample->AddRef();
+
+ if (FAILED(hr = poPin->AddSample(pSample, this)))
+ {
+ pSample->Release();
+ }
+ sentOne = (sentOne || SUCCEEDED(hr));
+ }
+done:
+ return sentOne ? S_OK : E_FAIL;
+}
+
+STDMETHODIMP_(VOID) CInPin::ConnectPin( _In_ CBasePin * poPin )
+{
+ CAutoLock Lock(lock());
+ if (poPin!=nullptr)
+ {
+ m_outpins.push_back(poPin);
+ poPin->AddRef();
+ }
+}
+
+STDMETHODIMP_(DeviceStreamState) CInPin::GetState()
+{
+ return m_state;
+}
+
+STDMETHODIMP_(DeviceStreamState) CInPin::SetState( _In_ DeviceStreamState state )
+{
+ return (DeviceStreamState)InterlockedExchange((LONG*)&m_state, state );
+}
+
+STDMETHODIMP CInPin::WaitForSetInputPinMediaChange()
+{
+ DWORD dwWait = 0;
+ HRESULT hr = S_OK;
+
+ dwWait = WaitForSingleObject( m_waitInputMediaTypeWaiter, INFINITE );
+
+ if ( dwWait != WAIT_OBJECT_0 )
+ {
+ hr = E_FAIL;
+ goto done;
+ }
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP 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_prefferedMediaType != nullptr )
+ {
+ m_prefferedMediaType.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_prefferedMediaType = nullptr;
+ SetEvent(m_waitInputMediaTypeWaiter);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+//
+//Output Pin Implementation
+//
+COutPin::COutPin(
+ _In_ ULONG ulPinId,
+ _In_opt_ CMultipinMft *pparent,
+ _In_ IKsControl* pIksControl
+ )
+ : CBasePin( ulPinId, pparent ),
+ m_firstSample( false )
+{
+ HRESULT hr = S_OK;
+ CPinState* pState = NULL;
+ ComPtr<IMFAttributes> spAttributes;
+
+ for ( ULONG ulIndex = 0; ulIndex <= DeviceStreamState_Disabled; ulIndex++ )
+ {
+ switch ( ulIndex )
+ {
+
+ case DeviceStreamState_Run:
+ pState = ( CPinState* )new CPinOpenState(this);
+ DMFTCHECKNULL_GOTO(pState, done, E_OUTOFMEMORY);
+ break;
+ case DeviceStreamState_Pause:
+ case DeviceStreamState_Stop:
+ case DeviceStreamState_Disabled:
+ //Currently both the closed and the drain state behave similarly
+ pState = ( CPinState* )new CPinClosedState();
+ DMFTCHECKNULL_GOTO(pState, done, E_OUTOFMEMORY);
+ break;
+ }
+
+ m_states.push_back( pState );
+
+ m_state = m_states[ DeviceStreamState_Stop ];
+ }
+ //
+ //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()
+{
+ CPinQueue *que = NULL;
+ m_spAttributes = nullptr;
+
+ for ( ULONG ulIndex = 0, ulSize = (ULONG)m_queues.size(); ulIndex < ulSize; ulIndex++ )
+ {
+ que = m_queues[ ulIndex ];
+ delete(que);
+ que = NULL;
+ }
+ CPinState *pinState = NULL;
+ for (ULONG ulIndex = 0, ulSize = (ULONG)m_states.size(); ulIndex < ulSize; ulIndex++)
+ {
+ pinState = m_states[ ulIndex ];
+ delete( pinState );
+ pinState = NULL;
+ }
+ m_states.clear();
+ m_queues.clear();
+}
+
+/*++
+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.
+--*/
+STDMETHODIMP COutPin::AddPin(
+ _In_ DWORD inputPinId
+ )
+{
+ //
+ //Add a new queue corresponding to the input pin
+ //
+ HRESULT hr = S_OK;
+ CAutoLock Lock(lock());
+
+ CPinQueue *que = new (std::nothrow) CPinQueue(inputPinId);
+ DMFTCHECKNULL_GOTO( que, done, E_OUTOFMEMORY );
+ hr = ExceptionBoundary([&]()
+ {
+ (void)m_queues.push_back(que);
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ //
+ //Just ramdonmize media types for odd numbered pins
+ //
+ if ( streamId() != 0 && streamId() % 2 != 0 )
+ {
+ RandomnizeMediaTypes(m_listOfMediaTypes);
+ }
+
+done:
+
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return S_OK;
+}
+
+/*++
+COutPin::AddSampleInternal
+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.
+--*/
+
+STDMETHODIMP COutPin::AddSampleInternal( _In_ IMFSample *pSample, _In_ CBasePin *pPin )
+{
+ BOOL res = true;
+ CAutoLock Lock( lock() );
+
+ for ( DWORD dwIndex = 0, dwSize = (DWORD)m_queues.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ //
+ //This output pin maybe connected to multiple input pins
+ //Only insert into the corresponding queue to the input pin on which the
+ //sample is received
+ //
+ if (m_queues[dwIndex]->pinStreamId() == pPin->streamId())
+ {
+ if (! m_queues[ dwIndex ]->Insert( pSample ) )
+ {
+ res |= false;
+ }
+
+ }
+ }
+ return res ? S_OK : E_FAIL;
+}
+
+/*++
+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
+--*/
+
+STDMETHODIMP COutPin::AddSample( _In_ IMFSample *pSample, _In_ CBasePin *pPin)
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock( lock() );
+
+ DMFTCHECKHR_GOTO( m_state->Open(), done );
+
+ DMFTCHECKHR_GOTO( AddSampleInternal( pSample, pPin ),done );
+
+done:
+ return hr;
+}
+
+/*++
+COutPin::SetState
+Description:
+State setter for the output pin
+--*/
+STDMETHODIMP_(VOID) COutPin::SetFirstSample(
+ _In_ BOOL fisrtSample )
+{
+ m_firstSample = fisrtSample;
+}
+
+/*++
+COutPin::GetState
+Description:
+State getter for the output pin
+--*/
+DeviceStreamState COutPin::GetState()
+{
+ return m_state->State();
+}
+
+/*++
+COutPin::SetState
+Description:
+State setter for the output pin
+--*/
+
+DeviceStreamState COutPin::SetState(DeviceStreamState state)
+{
+ CAutoLock Lock(lock());
+ DeviceStreamState oldState = m_state->State();
+ m_state = m_states[state];
+ return oldState;
+
+}
+
+/*++
+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() );
+
+ for ( DWORD dwIndex = 0, dwSize = (DWORD) m_queues.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ CPinQueue *que = m_queues[ dwIndex ];
+ que->Clear();
+ }
+
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+/*++
+COutPin::ChangeMediaTypeFromInpin
+Description:
+called from the Device Transfrom 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_ CInPin* inPin,
+ _In_ IMFMediaType *pInMediatype,
+ _In_ IMFMediaType* pOutMediaType,
+ _In_ DeviceStreamState state)
+{
+ HRESULT hr = S_OK;
+ CPinQueue *que = NULL;
+ 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);
+ FlushQueues();
+
+ for (DWORD dwIndex = 0, dwSize = (DWORD) m_queues.size(); dwIndex < dwSize; dwIndex++)
+ {
+ que = m_queues[ dwIndex ];
+ if (inPin->streamId() == que->pinStreamId())
+ {
+ break;
+ }
+ que = NULL;
+ }
+
+ if ( que )
+ {
+ //
+ //recreate the tee, pass the D3D Manager to the Tee which will use DX if D3D manager is present
+ //
+ IUnknown *pD3DManagerUnk = NULL;
+
+ (VOID)Parent()->GetD3DDeviceManager( &pD3DManagerUnk );
+ hr = que->RecreateTee( pInMediatype, pOutMediaType, pD3DManagerUnk );
+ if ( SUCCEEDED( hr ) )
+ {
+ (VOID)setMediaType( pOutMediaType );
+ (VOID)SetState( state );
+ }
+ SAFE_RELEASE(pD3DManagerUnk);
+ }
+ return hr;
+}
+
+/*++
+Description:
+ called from the IMFdeviceTransform's
+--*/
+
+STDMETHODIMP 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 Transfrom 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 recieved the transform or not.
+ If we have recieved the sample and we are passing out a sample we should reset the trigger set on the Device Transform
+--*/
+
+STDMETHODIMP COutPin::ProcessOutput(_In_ DWORD dwFlags,
+ _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample,
+ _Out_ DWORD *pdwStatus
+ )
+{
+ HRESULT hr = S_OK;
+ IMFSample* pSample = nullptr;
+ GUID pinClsid = GUID_NULL;
+ BOOL IsImagePin = FALSE;
+ BOOL IsSkipSample = FALSE;
+ UNREFERENCED_PARAMETER(pdwStatus);
+ UNREFERENCED_PARAMETER(dwFlags);
+ CAutoLock lock(lock());
+ DMFTCHECKHR_GOTO(m_state->Open(), done);
+
+ //
+ //Check if we are an image photo pin. The process output in that case should only proceed if trigger has been sent
+ //Candidate for subclass!
+ //
+
+ if (SUCCEEDED(GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &pinClsid))
+ && ((IsEqualCLSID(pinClsid, PINNAME_IMAGE)) || IsEqualCLSID(pinClsid, PINNAME_VIDEO_STILL)))
+ {
+ IsImagePin = TRUE;
+ }
+
+ if (IsImagePin && !Parent()->isPhotoTriggerSent())
+ {
+ IsSkipSample = TRUE;
+ }
+
+
+
+ for ( DWORD dwIndex = 0, dwSize = (DWORD) m_queues.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ CPinQueue *que = m_queues[dwIndex];
+
+ pOutputSample->dwStatus = S_OK;
+
+ if (!que->Remove(&pSample))
+ {
+ break;
+ }
+
+ MFTIME llTime = 0L;
+
+ if (FAILED(pSample->GetSampleTime(&llTime)))
+ {
+ llTime = MFGetSystemTime();
+ pSample->SetSampleTime(llTime);
+ }
+
+ if (!IsSkipSample)
+ {
+ if (m_firstSample)
+ {
+ pSample->SetUINT32(MFSampleExtension_Discontinuity,TRUE);
+ SetFirstSample(FALSE);
+ }
+
+ //
+ // Any processing before we pass the sample to further in the pipeline should be done here
+ // PROCESSSAMPLE(pSample);
+ //
+
+ pOutputSample->pSample = pSample;
+ pOutputSample->dwStatus = S_OK;
+ }
+ else
+ {
+ SAFERELEASE(pSample);
+ }
+ }
+ if (!IsSkipSample && IsImagePin && pSample)
+ {
+ //
+ //A sample has been sent over so image pin should exit
+ //
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ if (Parent()->IsPhotoConfirmationEnabled())
+ {
+ //
+ // Photo confirmation is enabled i.e. the pipeline has set up photo confirmation
+ // Service photo confirmation.
+ //
+ ComPtr<IMFMediaType> spMediaType = nullptr;
+
+ DMFTCHECKHR_GOTO(getMediaType(spMediaType.GetAddressOf()), done);
+
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Calling PhotoConfirmation %p, is passed", pSample);
+
+ DMFTCHECKHR_GOTO(Parent()->ProcessCapturePhotoConfirmationCallBack(spMediaType.Get(), pSample), done);
+ }
+#endif
+ if (!Parent()->isPhotoModePhotoSequence())
+ {
+ //
+ //A sample has been sent over so image pin should exit
+ //
+ Parent()->setPhotoTriggerSent(FALSE);
+ }
+ }
+done:
+ return hr;
+}
+
+/*++
+ COutPin::KsProperty
+Description:
+The KsProperty for the Pin.. this is to reroute all pin kscontrols to the input pin
+--*/
+STDMETHODIMP 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/sampledevicemft/basepin.h b/AVStream/sampledevicemft/basepin.h
new file mode 100644
index 00000000..9b254e2a
--- /dev/null
+++ b/AVStream/sampledevicemft/basepin.h
@@ -0,0 +1,596 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+#pragma once
+#include "stdafx.h"
+#include "common.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 STDMETHODIMP_(DeviceStreamState) GetState() = 0;
+ virtual STDMETHODIMP_(DeviceStreamState) SetState( _In_ DeviceStreamState State) = 0;
+
+
+ //
+ //IUnknown Interface functions
+ //
+
+ STDMETHODIMP_(ULONG) AddRef(
+ void
+ )
+ {
+ return InterlockedIncrement(&m_nRefCount);
+ }
+ STDMETHODIMP_(ULONG) Release(
+ void
+ )
+ {
+ ULONG uCount = InterlockedDecrement(&m_nRefCount);
+ if (uCount == 0)
+ {
+ delete this;
+ }
+ return uCount;
+ }
+
+ STDMETHODIMP_(HRESULT) QueryInterface(
+ _In_ REFIID riid,
+ _Outptr_result_maybenull_ void **ppvObject
+ );
+ //
+ // IKsControl Interface functions
+ //
+
+ STDMETHOD(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;
+ }
+ }
+ //
+ //NOOPs for this iteration..
+ //
+ STDMETHOD(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;
+ }
+
+ STDMETHOD(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
+ //
+ STDMETHOD(GetItem)(
+ _In_ REFGUID guidKey,
+ _Inout_opt_ PROPVARIANT* pValue
+ )
+ {
+ return m_spAttributes->GetItem(guidKey, pValue);
+ }
+
+ STDMETHOD(GetItemType)(
+ _In_ REFGUID guidKey,
+ _Out_ MF_ATTRIBUTE_TYPE* pType
+ )
+ {
+ return m_spAttributes->GetItemType(guidKey, pType);
+ }
+
+ STDMETHOD(CompareItem)(
+ _In_ REFGUID guidKey,
+ _In_ REFPROPVARIANT Value,
+ _Out_ BOOL* pbResult
+ )
+ {
+ return m_spAttributes->CompareItem(guidKey, Value, pbResult);
+ }
+
+ STDMETHOD(Compare)(
+ _In_ IMFAttributes* pTheirs,
+ _In_ MF_ATTRIBUTES_MATCH_TYPE MatchType,
+ _Out_ BOOL* pbResult
+ )
+ {
+ return m_spAttributes->Compare(pTheirs, MatchType, pbResult);
+ }
+
+ STDMETHOD(GetUINT32)(
+ _In_ REFGUID guidKey,
+ _Out_ UINT32* punValue
+ )
+ {
+ return m_spAttributes->GetUINT32(guidKey, punValue);
+ }
+
+ STDMETHOD(GetUINT64)(
+ _In_ REFGUID guidKey,
+ _Out_ UINT64* punValue
+ )
+ {
+ return m_spAttributes->GetUINT64(guidKey, punValue);
+ }
+
+ STDMETHOD(GetDouble)(
+ _In_ REFGUID guidKey,
+ _Out_ double* pfValue
+ )
+ {
+ return m_spAttributes->GetDouble(guidKey, pfValue);
+ }
+
+ STDMETHOD(GetGUID)(
+ _In_ REFGUID guidKey,
+ _Out_ GUID* pguidValue
+ )
+ {
+ return m_spAttributes->GetGUID(guidKey, pguidValue);
+ }
+
+ STDMETHOD(GetStringLength)(
+ _In_ REFGUID guidKey,
+ _Out_ UINT32* pcchLength
+ )
+ {
+ return m_spAttributes->GetStringLength(guidKey, pcchLength);
+ }
+
+ STDMETHOD(GetString)(
+ _In_ REFGUID guidKey,
+ _Out_writes_(cchBufSize) LPWSTR pwszValue,
+ _In_ UINT32 cchBufSize,
+ _Inout_opt_ UINT32* pcchLength
+ )
+ {
+ return m_spAttributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
+ }
+
+ STDMETHOD(GetAllocatedString)(
+ _In_ REFGUID guidKey,
+ _Out_writes_(*pcchLength + 1) LPWSTR* ppwszValue,
+ _Inout_ UINT32* pcchLength
+ )
+ {
+ return m_spAttributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
+ }
+
+ STDMETHOD(GetBlobSize)(
+ _In_ REFGUID guidKey,
+ _Out_ UINT32* pcbBlobSize
+ )
+ {
+ return m_spAttributes->GetBlobSize(guidKey, pcbBlobSize);
+ }
+
+ STDMETHOD(GetBlob)(
+ _In_ REFGUID guidKey,
+ _Out_writes_(cbBufSize) UINT8* pBuf,
+ UINT32 cbBufSize,
+ _Inout_ UINT32* pcbBlobSize
+ )
+ {
+ return m_spAttributes->GetBlob(guidKey, pBuf, cbBufSize, pcbBlobSize);
+ }
+
+ STDMETHOD(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);
+ }
+
+ STDMETHOD(GetUnknown)(
+ __RPC__in REFGUID guidKey,
+ __RPC__in REFIID riid,
+ __RPC__deref_out_opt LPVOID *ppv
+ )
+ {
+ return m_spAttributes->GetUnknown(guidKey, riid, ppv);
+ }
+
+ STDMETHOD(SetItem)(
+ _In_ REFGUID guidKey,
+ _In_ REFPROPVARIANT Value
+ )
+ {
+ return m_spAttributes->SetItem(guidKey, Value);
+ }
+
+ STDMETHOD(DeleteItem)(
+ _In_ REFGUID guidKey
+ )
+ {
+ return m_spAttributes->DeleteItem(guidKey);
+ }
+
+ STDMETHOD(DeleteAllItems)()
+ {
+ return m_spAttributes->DeleteAllItems();
+ }
+
+ STDMETHOD(SetUINT32)(
+ _In_ REFGUID guidKey,
+ _In_ UINT32 unValue
+ )
+ {
+ return m_spAttributes->SetUINT32(guidKey, unValue);
+ }
+
+ STDMETHOD(SetUINT64)(
+ _In_ REFGUID guidKey,
+ _In_ UINT64 unValue
+ )
+ {
+ return m_spAttributes->SetUINT64(guidKey, unValue);
+ }
+
+ STDMETHOD(SetDouble)(
+ _In_ REFGUID guidKey,
+ _In_ double fValue
+ )
+ {
+ return m_spAttributes->SetDouble(guidKey, fValue);
+ }
+
+ STDMETHOD(SetGUID)(
+ _In_ REFGUID guidKey,
+ _In_ REFGUID guidValue
+ )
+ {
+ return m_spAttributes->SetGUID(guidKey, guidValue);
+ }
+
+ STDMETHOD(SetString)(
+ _In_ REFGUID guidKey,
+ _In_ LPCWSTR wszValue
+ )
+ {
+ return m_spAttributes->SetString(guidKey, wszValue);
+ }
+
+ STDMETHOD(SetBlob)(
+ _In_ REFGUID guidKey,
+ _In_reads_(cbBufSize) const UINT8* pBuf,
+ UINT32 cbBufSize
+ )
+ {
+ return m_spAttributes->SetBlob(guidKey, pBuf, cbBufSize);
+ }
+
+ STDMETHOD(SetUnknown)(
+ _In_ REFGUID guidKey,
+ _In_ IUnknown* pUnknown
+ )
+ {
+ return m_spAttributes->SetUnknown(guidKey, pUnknown);
+ }
+
+ STDMETHOD(LockStore)()
+ {
+ return m_spAttributes->LockStore();
+ }
+
+ STDMETHOD(UnlockStore)()
+ {
+ return m_spAttributes->UnlockStore();
+ }
+
+ STDMETHOD(GetCount)(
+ _Out_ UINT32* pcItems
+ )
+ {
+ return m_spAttributes->GetCount(pcItems);
+ }
+
+ STDMETHOD(GetItemByIndex)(
+ UINT32 unIndex,
+ _Out_ GUID* pguidKey,
+ _Inout_ PROPVARIANT* pValue
+ )
+ {
+ return m_spAttributes->GetItemByIndex(unIndex, pguidKey, pValue);
+ }
+
+ STDMETHOD(CopyAllItems)(
+ _In_ IMFAttributes* pDest
+ )
+ {
+ return m_spAttributes->CopyAllItems(pDest);
+ }
+
+ //
+ //Helper Functions
+ //
+ __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 STDMETHOD (getPinAttributes) (_In_ IMFAttributes **ppAttributes)
+ {
+ HRESULT hr = S_OK;
+ DMFTCHECKNULL_GOTO( ppAttributes, done, E_INVALIDARG );
+ DMFTCHECKHR_GOTO ( QueryInterface( IID_PPV_ARGS(ppAttributes) ), done );
+ done:
+ return hr;
+ }
+
+ STDMETHODIMP AddMediaType(
+ _Inout_ DWORD *pos,
+ _In_ IMFMediaType *pMediatype); /*Filling the media types data structure*/
+ STDMETHODIMP GetMediaTypeAt(
+ _In_ DWORD pos,
+ _Outptr_result_maybenull_ IMFMediaType **pMediaType); /* getting the data from the data structure*/
+ STDMETHODIMP_(BOOL) IsMediaTypeSupported(
+ _In_ IMFMediaType *pMediaType,
+ _When_(ppIMFMediaTypeFull != nullptr, _Outptr_result_maybenull_)
+ IMFMediaType **ppIMFMediaTypeFull);
+ STDMETHODIMP GetOutputAvailableType(
+ _In_ DWORD dwTypeIndex,
+ _Out_opt_ IMFMediaType **ppType);
+
+protected:
+ //
+ //Inline helper functions
+ //
+ _inline CMultipinMft* Parent()
+ {
+ return m_Parent.Get();
+ }
+ __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;
+
+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;
+ ComPtr<CMultipinMft> m_Parent;
+ ULONG m_nRefCount;
+};
+
+
+
+class CInPin: public CBasePin{
+public:
+ CInPin( _In_opt_ IMFAttributes*, _In_ ULONG ulPinId = 0, _In_ CMultipinMft *pParent=NULL);
+ ~CInPin();
+
+ STDMETHOD ( Init )(
+ _In_ IMFTransform *
+ );
+ STDMETHOD_( VOID, ConnectPin)(
+ _In_ CBasePin *
+ );
+ STDMETHOD (SendSample)(
+ _In_ IMFSample *
+ );
+ STDMETHODIMP GenerateMFMediaTypeListFromDevice(
+ _In_ UINT uiStreamId
+ );
+ STDMETHODIMP WaitForSetInputPinMediaChange(
+ );
+ STDMETHOD_ (DeviceStreamState, SetState)(
+ _In_ DeviceStreamState
+ ); /*True for Active and False for Stop*/
+ STDMETHOD_(DeviceStreamState, GetState)(
+ VOID
+ );
+ //
+ //Corresponding IMFDeviceTransform functions for the Pin
+ //
+ STDMETHODIMP_(HRESULT) GetInputStreamPreferredState(
+ _Inout_ DeviceStreamState *value,
+ _Outptr_opt_result_maybenull_ IMFMediaType** ppMediaType
+ );
+ STDMETHODIMP_(HRESULT) SetInputStreamState(
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags
+ );
+
+ //
+ //Inline functions
+ //
+ __inline IMFMediaType* getPreferredMediaType()
+ {
+ return m_prefferedMediaType.Get();
+ }
+ __inline VOID setPreferredMediaType( _In_ IMFMediaType *pMediaType)
+ {
+ m_prefferedMediaType = pMediaType;
+ }
+ __inline DeviceStreamState setPreferredStreamState(_In_ DeviceStreamState streamState)
+ {
+ return (DeviceStreamState)InterlockedCompareExchange((LONG*)&m_preferredStreamState, (LONG)streamState, (LONG)m_preferredStreamState);
+ }
+ __inline DeviceStreamState getPreferredStreamState()
+ {
+ return m_preferredStreamState;
+ }
+
+protected:
+ ComPtr<IMFTransform> m_spSourceTransform; /*Source Transform*/
+private:
+ GUID m_stStreamType; /*GUID representing the GUID*/
+ ULONG m_activeStreamCount; /*Set when this stream is active*/
+ vector<CBasePin*> m_outpins;
+ DeviceStreamState m_state;
+ DeviceStreamState m_preferredStreamState;
+ ComPtr<IMFMediaType> m_prefferedMediaType;
+ 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();
+ STDMETHODIMP AddPin(
+ _In_ DWORD pinId
+ );
+ STDMETHODIMP AddSample(
+ _In_ IMFSample *pSample,
+ _In_ CBasePin *inPin
+ );
+ STDMETHODIMP AddSampleInternal(
+ _In_ IMFSample *pSample,
+ _In_ CBasePin *inPin
+ );
+ STDMETHODIMP RemoveSample(
+ _Out_ IMFSample **
+ );
+ STDMETHODIMP_(DeviceStreamState) SetState(
+ _In_ DeviceStreamState
+ ); /*True for Active and False for Stop*/
+ STDMETHODIMP_(DeviceStreamState) GetState(
+ );
+ STDMETHODIMP FlushQueues(
+ );
+ STDMETHODIMP GetOutputStreamInfo(
+ _Out_ MFT_OUTPUT_STREAM_INFO *pStreamInfo
+ );
+ STDMETHODIMP ChangeMediaTypeFromInpin(
+ _In_ CInPin* inPin,
+ _In_ IMFMediaType *pInMediatype,
+ _In_ IMFMediaType* pOutMediaType,
+ _In_ DeviceStreamState state );
+ STDMETHODIMP ProcessOutput (
+ _In_ DWORD dwFlags,
+ _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample,
+ _Out_ DWORD *pdwStatus
+ );
+ STDMETHODIMP KsProperty(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Out_opt_ ULONG* pBytesReturned
+ );
+ STDMETHODIMP_(VOID) SetD3Dmanager(
+ _In_opt_ IUnknown *
+ );
+ STDMETHODIMP_(VOID) SetFirstSample(
+ _In_ BOOL
+ );
+
+
+private:
+ vector< CPinState *> m_states; /*Array of possible states*/
+ CPinState* m_state; /*Current state*/
+ vector< CPinQueue *> m_queues; /*List of Queues corresponding to input pins*/
+ BOOL m_firstSample;
+ friend class CPinState;
+};
+
+//
+//Not Implemented!!!
+//
+
+class CImagePin : public COutPin{
+private:
+ BOOL isTriggerSent;
+public:
+ CImagePin();
+ ~CImagePin();
+ STDMETHODIMP ProcessOutput(
+ _In_ DWORD dwFlags,
+ _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample,
+ _Out_ DWORD *pdwStatus
+ );
+};
+
+
diff --git a/AVStream/sampledevicemft/common.h b/AVStream/sampledevicemft/common.h
new file mode 100644
index 00000000..238decfb
--- /dev/null
+++ b/AVStream/sampledevicemft/common.h
@@ -0,0 +1,717 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#pragma once
+
+#define GUID_STRING_LENGTH 36
+#define GUID_BUFFER_SIZE 37
+#define SLEEP_5MILLISEC 5
+#define SLEEP_ONE_SECOND 1000 // One second in milli seconds.
+
+#ifndef MF_WPP
+#define DMFTRACE(...)
+#endif
+
+//TP_NORMAL
+//TP_LOWEST
+//TP_LOW
+//TP_HIGH
+//TP_HIGHEST
+//TP_ERROR
+//TP_MUTED = 0x00070000
+
+
+
+#define mf_assert(a) if(!a) DebugBreak()
+
+#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 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 DMFTCHECKHR_GOTO(val,label) \
+ hr = (val); \
+if (FAILED(hr)) {\
+ /*DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr); */\
+ goto label; \
+}
+
+
+#define DMFTCHECKNULL_GOTO( val, label, err) \
+if( (val) == NULL ) { \
+ hr = (err); \
+ /*DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);*/\
+ goto label; \
+}
+
+#define TP_SCOPE_TRACE TP_NORMAL
+#define DH_THIS_FILE DH_DEVPROXY
+
+#define SAFERELEASE(x) \
+if (x) {\
+ x->Release(); \
+ x = NULL; \
+}
+
+#define CHK_LOG_BRK(exp) \
+if (FAILED(hr = (exp))) {\
+ wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \
+ /*MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MULTIPINERROR File: %s Ln:%d",__FILE__,__LINE__);*/\
+ break; \
+}
+
+
+#define CHK_NULL_BRK(exp) \
+if ((exp) == NULL) {\
+hr = E_OUTOFMEMORY; \
+wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \
+break; \
+}
+
+#define CHK_NULL_PTR_BRK(exp) \
+if ((exp) == NULL) {\
+hr = E_INVALIDARG; \
+wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \
+break; \
+}
+
+#define CHK_BOOL_BRK(exp) \
+if (!exp) {\
+ hr = E_FAIL; \
+ wprintf(L"HR=%08x File: %S Ln: %d\n", hr, __FILE__, __LINE__); \
+ break; \
+}
+
+
+//
+// The Below type definitions are added for this iteration. It will taken out in the
+// next one when we will have the windows headers modified to include the interfaces
+// externally.
+//
+
+
+#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_)
+
+
+
+#if !defined(__IMFDeviceTransform_INTERFACE_DEFINED__)
+//
+//These definitions will have to be taken out when the
+//internal defines are made public
+//
+
+EXTERN_GUID(MEDeviceStreamCreated, 0x0252a1cf, 0x3540, 0x43b4, 0x91, 0x64, 0xd7, 0x2e, 0xb4, 0x05, 0xfa, 0x40);
+
+typedef
+enum _DeviceStreamState
+{
+ DeviceStreamState_Stop = 0,
+ DeviceStreamState_Pause = (DeviceStreamState_Stop + 1),
+ DeviceStreamState_Run = (DeviceStreamState_Pause + 1),
+ DeviceStreamState_Disabled = (DeviceStreamState_Run + 1)
+} DeviceStreamState;
+
+/* size is 4, align is 4*/
+typedef enum _DeviceStreamState *PDeviceStreamState;
+
+EXTERN_C const IID IID_IMFDeviceTransform;
+MIDL_INTERFACE("D818FBD8-FC46-42F2-87AC-1EA2D1F9BF32")
+IMFDeviceTransform : public IUnknown
+{
+public:
+ virtual HRESULT STDMETHODCALLTYPE InitializeTransform(
+ /* [annotation][in] */
+ _In_ IMFAttributes *pAttributes) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInputAvailableType(
+ /* [annotation][in] */
+ _In_ DWORD dwInputStreamID,
+ /* [annotation][in] */
+ _In_ DWORD dwTypeIndex,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFMediaType **pMediaType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInputCurrentType(
+ /* [annotation][in] */
+ _In_ DWORD dwInputStreamID,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFMediaType **pMediaType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInputStreamAttributes(
+ /* [annotation][in] */
+ _In_ DWORD dwInputStreamID,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFAttributes **ppAttributes) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOutputAvailableType(
+ /* [annotation][in] */
+ _In_ DWORD dwOutputStreamID,
+ /* [annotation][in] */
+ _In_ DWORD dwTypeIndex,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFMediaType **pMediaType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOutputCurrentType(
+ /* [annotation][in] */
+ _In_ DWORD dwOutputStreamID,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFMediaType **pMediaType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOutputStreamAttributes(
+ /* [annotation][in] */
+ _In_ DWORD dwOutputStreamID,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFAttributes **ppAttributes) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStreamCount(
+ /* [annotation][out] */
+ _Out_ DWORD *pcInputStreams,
+ /* [annotation][out] */
+ _Out_ DWORD *pcOutputStreams) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStreamIDs(
+ /* [annotation][in] */
+ _In_ DWORD dwInputIDArraySize,
+ /* [annotation][out] */
+ _Out_ DWORD *pdwInputStreamIds,
+ /* [annotation][in] */
+ _In_ DWORD dwOutputIDArraySize,
+ /* [annotation][out] */
+ _Out_ DWORD *pdwOutputStreamIds) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProcessEvent(
+ /* [annotation][in] */
+ _In_ DWORD dwInputStreamID,
+ /* [annotation][in] */
+ _In_ IMFMediaEvent *pEvent) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProcessInput(
+ /* [annotation][in] */
+ _In_ DWORD dwInputStreamID,
+ /* [annotation][in] */
+ _In_ IMFSample *pSample,
+ /* [annotation][in] */
+ _In_ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProcessMessage(
+ /* [annotation][in] */
+ _In_ MFT_MESSAGE_TYPE eMessage,
+ /* [annotation][in] */
+ _In_ ULONG_PTR ulParam) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProcessOutput(
+ /* [annotation][in] */
+ _In_ DWORD dwFlags,
+ /* [annotation][in] */
+ _In_ DWORD cOutputBufferCount,
+ /* [size_is][annotation][out][in] */
+ _Inout_ MFT_OUTPUT_DATA_BUFFER *pOutputSample,
+ /* [annotation][out] */
+ _Out_ DWORD *pdwStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetInputStreamState(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamID,
+ /* [annotation][in] */
+ _In_ IMFMediaType *pMediaType,
+ /* [annotation][in] */
+ _In_ DeviceStreamState value,
+ /* [annotation][in] */
+ _In_ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInputStreamState(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamID,
+ /* [annotation][out] */
+ _Out_ DeviceStreamState *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetOutputStreamState(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamID,
+ /* [annotation][in] */
+ _In_ IMFMediaType *pMediaType,
+ /* [annotation][in] */
+ _In_ DeviceStreamState value,
+ /* [annotation][in] */
+ _In_ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOutputStreamState(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamID,
+ /* [annotation][out] */
+ _Out_ DeviceStreamState *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInputStreamPreferredState(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamID,
+ /* [annotation][out] */
+ _Out_ DeviceStreamState *value,
+ /* [annotation][out] */
+ _COM_Outptr_ IMFMediaType **ppMediaType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushInputStream(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamIndex,
+ /* [annotation][in] */
+ _In_ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FlushOutputStream(
+ /* [annotation][in] */
+ _In_ DWORD dwStreamIndex,
+ /* [annotation][in] */
+ _In_ DWORD dwFlags) = 0;
+
+};
+
+#endif
+
+
+interface IDirect3DDeviceManager9;
+//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();
+};
+
+//////////////////////////////////////////////////////////////////////////
+// CMediaTypePrinter
+// Description: Rudimentary class for printing media type!
+//////////////////////////////////////////////////////////////////////////
+
+#define MEDIAPRINTER_STARTLEN (512)
+
+class CMediaTypePrinter{
+private:
+ IMFMediaType *pMediaType;
+ PCHAR m_pBuffer;
+ ULONG buffLen;
+public:
+ CMediaTypePrinter( _In_ IMFMediaType *_pMediaType );
+ ~CMediaTypePrinter( );
+ STDMETHODIMP_(PCHAR) ToCompleteString( );
+ STDMETHODIMP_(PCHAR) ToString();
+};
+
+
+//
+//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
+// {0E313280-3169-4F41-A329-9E854169634F} for the Pipeline to pick up the Transform.
+//
+DEFINE_GUID(CLSID_MultiPinMFT,
+ 0xe313280, 0x3169, 0x4f41, 0xa3, 0x29, 0x9e, 0x85, 0x41, 0x69, 0x63, 0x4f);
+
+
+typedef enum _MF_TRANSFORM_XVP_OPERATION{
+ DeviceMftTransformXVPDisruptiveIn, //Break the XVP tranform and go to the new Media Type
+ DeviceMftTransformXVPDisruptiveOut, //Keep the old transform
+ DeviceMftTransformXVPCurrent, //Don't need an XVP
+ DeviceMftTransformXVPIllegal //Either of the media types NULL, Major types don't match
+}MF_TRANSFORM_XVP_OPERATION,*PMF_TRANSFORM_XVP_OPERATION;
+
+typedef std::vector< IMFMediaType *> IMFMediaTypeArray;
+typedef std::vector< CBasePin *> CBasePinArray;
+typedef std::vector< IMFSample *> IMFSampleList;
+typedef std::pair< std::multimap<int, int>::iterator, std::multimap<int, int>::iterator > MMFTMMAPITERATOR;
+
+
+HRESULT CreateCodec(
+ _In_opt_ IMFMediaType * inMediaType,
+ _In_opt_ IMFMediaType *outMediaType,
+ _In_ BOOL operation /*True = Encode, False = Decode*/,
+ _Out_ IMFTransform **pTransform
+ );
+
+STDMETHODIMP IsOptimizedPlanarVideoInputImageOutputPair(
+ _In_ IMFMediaType *inMediaType,
+ _In_ IMFMediaType *outMediaType,
+ _Out_ bool *optimized,
+ _Out_ bool *optimizedxvpneeded
+ );
+
+STDMETHODIMP CompareMediaTypesForXVP(_In_opt_ IMFMediaType *inMediaType,
+ _In_ IMFMediaType *newMediaType,
+ _Inout_ MF_TRANSFORM_XVP_OPERATION *operation
+ );
+
+STDMETHODIMP RandomnizeMediaTypes(
+ _In_ IMFMediaTypeArray &pMediaTypeArray
+ );
+
+STDMETHODIMP IsInputDxSample(
+ _In_ IMFSample* pSample,
+ _Inout_ BOOL *isDxSample
+ );
+
+STDMETHODIMP_(BOOL) IsPinStateInActive(
+ _In_ DeviceStreamState state
+ );
+
+STDMETHODIMP_(BOOL) IsKnownUncompressedVideoType(
+ _In_ GUID guidSubType
+ );
+LPSTR DumpGUIDA(
+ _In_ REFGUID guid
+ );
+
+
+void printMessageEvent(MFT_MESSAGE_TYPE msg);
+
+
+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_FAIL;
+ }
+}
+
+
+//
+// Custom Pin GUID. The avstream driver should define a PIN_DESCRIPTOR with this GUID
+// defined in cateogory. This will lead to devproxy creating this pin. This pin however
+// cannot be used by the pipeline as it may share a custom media type and pipeline could
+// fail. Moreover pipeline can currently (when this sample is written) only deal with
+// the known pins (PREVIEW/CAPTURE/IMAGE). This code snippet creates a custom pin
+// and
+//
+DEFINE_GUID(AVSTREAM_CUSTOM_PIN_IMAGE,
+ 0x888c4105, 0xb328, 0x4ed6, 0xa3, 0xca, 0x2f, 0xf4, 0xc0, 0x3a, 0x9f, 0x33);
+
+
+//
+// The Below redirections are to support MFT0. Implement this only if you need to load
+// MFT0 and DeviceMft simultaneously.
+//
+
+#define _DEFINE_DEVICEMFT_MFT0HELPER_IMPL__ \
+ STDMETHOD(MFTGetStreamLimits)( \
+ _Inout_ DWORD *pdwInputMinimum, \
+ _Inout_ DWORD *pdwInputMaximum, \
+ _Inout_ DWORD *pdwOutputMinimum, \
+ _Inout_ DWORD *pdwOutputMaximum \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(pdwInputMinimum); \
+ UNREFERENCED_PARAMETER(pdwInputMaximum); \
+ UNREFERENCED_PARAMETER(pdwOutputMinimum); \
+ UNREFERENCED_PARAMETER(pdwOutputMaximum); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTGetStreamCount)( \
+ _Inout_ DWORD* pdwInputStreams, \
+ _Inout_ DWORD* pdwOutputStreams \
+ ) \
+{ \
+ return GetStreamCount(pdwInputStreams, pdwOutputStreams); \
+} \
+ STDMETHOD(MFTGetStreamIDs)( \
+ _In_ DWORD dwInputIDArraySize, \
+ _Inout_updates_(dwInputIDArraySize) DWORD* pdwInputIDs, \
+ _In_ DWORD dwOutputIDArraySize, \
+ _Inout_updates_(dwOutputIDArraySize) DWORD* pdwOutputIDs \
+ ) \
+{ \
+ return GetStreamIDs(dwInputIDArraySize, \
+ pdwInputIDs, \
+ dwOutputIDArraySize, \
+ pdwOutputIDs); \
+} \
+ STDMETHOD(MFTGetInputStreamInfo)( \
+ _In_ DWORD dwInputStreamID, \
+ _Inout_ MFT_INPUT_STREAM_INFO* pStreamInfo \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(dwInputStreamID); \
+ UNREFERENCED_PARAMETER(pStreamInfo); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTGetOutputStreamInfo)( \
+ _In_ DWORD dwOutputStreamID, \
+ _Inout_ MFT_OUTPUT_STREAM_INFO* pStreamInfo \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(dwOutputStreamID); \
+ UNREFERENCED_PARAMETER(pStreamInfo); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTGetInputStreamAttributes)( \
+ _In_ DWORD dwInputStreamID, \
+ _Out_ IMFAttributes** ppAttributes \
+ ) \
+{ \
+ return GetInputStreamAttributes( \
+ dwInputStreamID, \
+ ppAttributes); \
+} \
+ STDMETHOD(MFTGetOutputStreamAttributes)( \
+ _In_ DWORD dwOutputStreamID, \
+ _Out_ IMFAttributes** ppAttributes \
+ ) \
+{ \
+ return GetOutputStreamAttributes( \
+ dwOutputStreamID, ppAttributes); \
+} \
+ STDMETHOD(MFTDeleteInputStream)( \
+ _In_ DWORD dwStreamID \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(dwStreamID); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTAddInputStreams)( \
+ _In_ DWORD cStreams, \
+ _In_ DWORD* adwStreamIDs \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(cStreams); \
+ UNREFERENCED_PARAMETER(adwStreamIDs); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTGetInputAvailableType)( \
+ _In_ DWORD dwInputStreamID, \
+ _In_ DWORD dwTypeIndex, \
+ _Out_ IMFMediaType** ppType \
+ ) \
+{ \
+ return GetInputAvailableType( \
+ dwInputStreamID, dwTypeIndex, ppType); \
+} \
+ STDMETHOD(MFTGetOutputAvailableType)( \
+ _In_ DWORD dwOutputStreamID, \
+ _In_ DWORD dwTypeIndex, \
+ _Out_ IMFMediaType** ppMediaType \
+ ) \
+{ \
+ return GetOutputAvailableType( \
+ dwOutputStreamID, dwTypeIndex, ppMediaType); \
+} \
+ STDMETHOD(MFTSetInputType)( \
+ _In_ DWORD dwInputStreamID, \
+ _In_ IMFMediaType* pMediaType, \
+ _In_ DWORD dwFlags \
+ ) \
+{\
+ UNREFERENCED_PARAMETER(dwInputStreamID); \
+ UNREFERENCED_PARAMETER(pMediaType); \
+ UNREFERENCED_PARAMETER(dwFlags); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTSetOutputType)( \
+ _In_ DWORD dwOutputStreamID, \
+ _In_ IMFMediaType* pMediaType, \
+ _In_ DWORD dwFlags \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(dwOutputStreamID); \
+ UNREFERENCED_PARAMETER(pMediaType); \
+ UNREFERENCED_PARAMETER(dwFlags); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTGetInputCurrentType)( \
+ _In_ DWORD dwInputStreamID, \
+ _Out_ IMFMediaType** ppMediaType \
+ ) \
+{\
+ UNREFERENCED_PARAMETER(dwInputStreamID); \
+ UNREFERENCED_PARAMETER(ppMediaType); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTGetOutputCurrentType)( \
+ _In_ DWORD dwOutputStreamID, \
+ _Out_ IMFMediaType** ppMediaType \
+ ) \
+{ \
+ return GetOutputCurrentType(dwOutputStreamID, ppMediaType); \
+} \
+ STDMETHOD(MFTGetInputStatus)( \
+ _In_ DWORD dwInputStreamID, \
+ _Inout_ DWORD* pdwFlags \
+ )\
+{\
+ UNREFERENCED_PARAMETER(dwInputStreamID); \
+ UNREFERENCED_PARAMETER(pdwFlags); \
+ return E_NOTIMPL; \
+}\
+ STDMETHOD(MFTGetOutputStatus)( \
+ _Inout_ DWORD *pdwFlags \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(pdwFlags); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTSetOutputBounds)( \
+ _In_ LONGLONG hnsLowerBound, \
+ _In_ LONGLONG hnsUpperBound \
+ ) \
+{\
+ UNREFERENCED_PARAMETER(hnsLowerBound); \
+ UNREFERENCED_PARAMETER(hnsUpperBound); \
+ return E_NOTIMPL; \
+}\
+ STDMETHOD(MFTProcessMessage)( \
+ _In_ MFT_MESSAGE_TYPE eMessage, \
+ _In_ ULONG_PTR ulParam \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(eMessage); \
+ UNREFERENCED_PARAMETER(ulParam); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTProcessInput)( \
+ _In_ DWORD dwInputStreamID, \
+ _In_ IMFSample* pSample, \
+ _In_ DWORD dwFlags \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(dwInputStreamID); \
+ UNREFERENCED_PARAMETER(pSample); \
+ UNREFERENCED_PARAMETER(dwFlags); \
+ return E_NOTIMPL; \
+} \
+ STDMETHOD(MFTProcessOutput)( \
+ _In_ DWORD dwFlags, \
+ _In_ DWORD cOutputBufferCount, \
+ _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples, \
+ _Inout_ DWORD *pdwStatus \
+ ) \
+{ \
+ UNREFERENCED_PARAMETER(dwFlags); \
+ UNREFERENCED_PARAMETER(cOutputBufferCount); \
+ UNREFERENCED_PARAMETER(pOutputSamples); \
+ UNREFERENCED_PARAMETER(pdwStatus); \
+ return E_NOTIMPL; \
+}
+
+//
+// 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;
+};
diff --git a/AVStream/sampledevicemft/custompin.cpp b/AVStream/sampledevicemft/custompin.cpp
new file mode 100644
index 00000000..00edb329
--- /dev/null
+++ b/AVStream/sampledevicemft/custompin.cpp
@@ -0,0 +1,98 @@
+#include "stdafx.h"
+#include "multipinmft.h"
+#include "basepin.h"
+#include "custompin.h"
+#ifdef MF_WPP
+#include "custompin.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+
+
+//
+// Implementation notes
+// Implement this file only if you have custom media pins streaming
+// This implementation just streams from the driver and sends it back
+// to the pipeline. This method can be used to stream 3A/Statistic Pins.
+//
+
+CCustomPin::CCustomPin(
+ _In_ IMFAttributes *pAttributes,
+ _In_ ULONG PinId,
+ _In_ CMultipinMft *pParent
+ )
+ :CInPin( pAttributes, PinId, pParent )
+{
+
+}
+//
+// Process input calls the pin here.. In this code sample we
+// don't send it anywhere. It is simply shortcircuited back to the pipeline
+//
+STDMETHODIMP CCustomPin::SendSample(
+ _In_ IMFSample *pSample
+ )
+{
+ //
+ // Log sample and exit.. The pipeline will just keep on churning more samples till
+ // We go into the stop state
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Custom Pin %d recieved Sample %p", streamId(), pSample);
+
+ return S_OK;
+}
+
+//
+// State change transitions on the custom pins are different than the other pins
+// The other known pins i.e. preview, record, image etc are exposed out to the pipeline
+// and the pipeline will set state on it, reset state, For the other pins we tell the
+// pipeline that we have samples and the pipeline picks it up.
+//
+// The CUSTOM pin differs in that it's state has to be managed to by the device MFT.
+// This code snippet just varies state transitions on the custom pin when the Device MFT
+// changes state to STREAMING/END_STREAMING on it's exposed pins.
+//
+// The below function tells the pipeline to change the state on the custom pin by sending
+// METransformInputStreamStateChanged event with the streamid attribute. The pipeline will
+// call back in the custom pin at getprefferedmediatype and finally setinputstreamstate
+// which will signal back here singnalling sucessful state transition.
+//
+
+STDMETHODIMP_(DeviceStreamState) CCustomPin::SetState(
+ _In_ DeviceStreamState State
+ )
+{
+ HRESULT hr = S_OK;
+
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Id:%d Transition into state: %d ", streamId(), State);
+
+ DeviceStreamState oldState = setPreferredStreamState( State );
+
+ if ( oldState != State )
+ {
+ ComPtr<IMFMediaType> preferredMediaType = nullptr;
+
+ if (State == DeviceStreamState_Run)
+ {
+ GetMediaTypeAt(0, preferredMediaType.ReleaseAndGetAddressOf());
+ }
+
+ setPreferredMediaType(preferredMediaType.Get());
+ setPreferredStreamState( State );
+
+ {
+ //
+ // Notify the device transform manager that we have changed state
+ //
+ ComPtr<IMFMediaEvent> pEvent = nullptr;
+ DMFTCHECKHR_GOTO( MFCreateMediaEvent(METransformInputStreamStateChanged, GUID_NULL, S_OK, NULL, pEvent.ReleaseAndGetAddressOf()), done );
+ DMFTCHECKHR_GOTO( pEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, streamId()), done );
+ DMFTCHECKHR_GOTO( Parent()->QueueEvent(pEvent.Get()), done );
+ }
+ //
+ // Wait to be notified back from the pipeline.
+ //
+ DMFTCHECKHR_GOTO( WaitForSetInputPinMediaChange(),done );
+ }
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return oldState;
+}
diff --git a/AVStream/sampledevicemft/custompin.h b/AVStream/sampledevicemft/custompin.h
new file mode 100644
index 00000000..c0c3c35f
--- /dev/null
+++ b/AVStream/sampledevicemft/custompin.h
@@ -0,0 +1,30 @@
+#pragma once
+#include "stdafx.h"
+#include "common.h"
+
+//
+// Custom Pin is only an input pin in this sample..It is short circuited back
+// to the pipeline. This can have uses in implementing depth pins etc.
+// It is not exposed to the down stream i.e. captureengine or the
+// WinRT code.
+//
+class CCustomPin : public CInPin{
+public:
+
+ CCustomPin(
+ _In_ IMFAttributes *pAttributes,
+ _In_ ULONG PinId,
+ _In_ CMultipinMft *pParent
+ );
+ STDMETHODIMP SendSample(
+ _In_ IMFSample *pSample
+ );
+ STDMETHODIMP_( DeviceStreamState )SetState(
+ _In_ DeviceStreamState
+ );
+};
+
+STDMETHODIMP CheckCustomPin(
+ _In_ CInPin * pin,
+ _Inout_ PBOOL isCustom
+ );
diff --git a/AVStream/sampledevicemft/dllmain.cpp b/AVStream/sampledevicemft/dllmain.cpp
new file mode 100644
index 00000000..6978a9d5
--- /dev/null
+++ b/AVStream/sampledevicemft/dllmain.cpp
@@ -0,0 +1,354 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// 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"
+#include "common.h"
+#include "multipinmft.h"
+#include <initguid.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_MultiPinMFT, 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
+//
+
+STDMETHODIMP_(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;
+}
+
+STDMETHODIMP 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);
+}
+
+STDMETHODIMP DllRegisterServer()
+{
+ assert(g_hModule != NULL);
+
+ // Register the CLSID for CoCreateInstance.
+ HRESULT hr = RegisterObject(g_hModule, CLSID_MultiPinMFT, TEXT("Multiple MFTs"), TEXT("Both"));
+
+ return hr;
+}
+
+STDMETHODIMP DllUnregisterServer()
+{
+ // Unregister the CLSID.
+ UnregisterObject(CLSID_MultiPinMFT);
+
+ return S_OK;
+}
+
+
+// Converts a CLSID into a string with the form "CLSID\{clsid}"
+STDMETHODIMP 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
+STDMETHODIMP 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/sampledevicemft/mftpeventgenerator.cpp b/AVStream/sampledevicemft/mftpeventgenerator.cpp
new file mode 100644
index 00000000..72b395ff
--- /dev/null
+++ b/AVStream/sampledevicemft/mftpeventgenerator.cpp
@@ -0,0 +1,250 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#include "stdafx.h"
+#include "common.h"
+#include "mftpeventgenerator.h"
+
+
+#define TP_SCOPE_TRACE TP_NORMAL
+#define DH_THIS_FILE DH_DEVPROXY
+
+#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;
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+
+done:
+
+ return hr;
+}
+
+//
+// IMediaEventGenerator methods
+//
+STDMETHODIMP CMediaEventGenerator::BeginGetEvent(
+ _In_ IMFAsyncCallback* pCallback,
+ _In_ IUnknown* pState
+ )
+{
+ HRESULT hr = S_OK;
+ //MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MultiPinMFT BeginGetEvent called");
+ 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;
+ //MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MultiPinMFT EndGetEvent called");
+ 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;
+ //MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MultiPinMFT GetEvent called");
+ 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;
+ //MFWMITRACE(DH_THIS_FILE, TP_NORMAL, __FUNCTION__ " : MultiPinMFT QueueEvent called");
+ 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;
+
+ // MFWMITRACE( DH_THIS_FILE, TP_LOWEST, __FUNCTION__ " : entering ...");
+
+ m_critSec.Lock();
+
+ hr = CheckShutdown();
+
+ if (SUCCEEDED(hr))
+ {
+ if (m_pQueue)
+ {
+ hr = m_pQueue->Shutdown();
+ //MFWMITRACE( DH_THIS_FILE, TP_NORMAL, __FUNCTION__ "Event Generator Queue shutdown hr = %x", hr);
+ }
+ SAFE_RELEASE(m_pQueue);
+ m_bShutdown = TRUE;
+ }
+ m_critSec.Unlock();
+
+ // MFWMITRACE( DH_THIS_FILE, TP_LOWEST, __FUNCTION__ " : exiting...");
+
+ return hr;
+}
+
+STDMETHODIMP CMediaEventGenerator::QueueEvent(
+ _In_ IMFMediaEvent* pEvent
+ )
+{
+ HRESULT hr = S_OK;
+ //MFWMITRACE(DH_THIS_FILE, TP_LOWEST, __FUNCTION__ " : QueueEvent 1 ...");
+ 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();
+ //MFASSERT(m_bShutdown);
+ //MFASSERT(m_nRefCount == 0);
+}
diff --git a/AVStream/sampledevicemft/mftpeventgenerator.h b/AVStream/sampledevicemft/mftpeventgenerator.h
new file mode 100644
index 00000000..2ddae218
--- /dev/null
+++ b/AVStream/sampledevicemft/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/sampledevicemft/multipinmft.cpp b/AVStream/sampledevicemft/multipinmft.cpp
new file mode 100644
index 00000000..ea7fd892
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmft.cpp
@@ -0,0 +1,2453 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#include "stdafx.h"
+#include "multipinmft.h"
+#ifdef MF_WPP
+#include "multipinmft.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+//
+//Note since MFT_UNIQUE_METHOD_NAMES is defined all the functions of IMFTransform have the Mft suffix..
+//
+extern const CLSID CLSID_HwMFTActivate;
+
+#if _NEED_MFTLOCKING_
+#define MFTLOCKED() {\
+ UINT32 punValue = FALSE; \
+ hr = GetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, &punValue);\
+if (FAILED(hr) || punValue == FALSE){\
+ return MF_E_TRANSFORM_ASYNC_LOCKED; \
+}\
+}
+#else
+
+#define MFTLOCKED()
+
+#endif
+
+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_PhotoTriggerSent(false),
+ m_filterHasIndependentPin( false ),
+ m_FilterInPhotoSequence( false ),
+ m_filterInWarmStart(false)
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ , m_spPhotoConfirmationCallback(nullptr)
+#endif
+{
+ ComPtr<IMFAttributes> pAttributes = nullptr;
+ MFCreateAttributes( &pAttributes, 0 );
+ pAttributes->SetUINT32( MF_TRANSFORM_ASYNC, TRUE );
+ pAttributes->SetUINT32( MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE );
+ pAttributes->SetUINT32( MF_SA_D3D_AWARE, TRUE );
+ pAttributes->SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"SampleMultiPinMft" );
+ m_spAttributes = pAttributes;
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ m_guidPhotoConfirmationSubtype = MFVideoFormat_NV12;
+#endif
+}
+
+CMultipinMft::~CMultipinMft( )
+{
+ CBasePin *pioPin = NULL;
+
+ for ( ULONG ulIndex = 0, ulSize = (ULONG) m_InPins.size(); ulIndex < ulSize; ulIndex++ )
+ {
+ pioPin = m_InPins[ ulIndex ];
+ SAFERELEASE( pioPin );
+ }
+ m_InPins.clear();
+
+ for (ULONG ulIndex = 0, ulSize = (ULONG) m_OutPins.size(); ulIndex < ulSize; ulIndex++)
+ {
+ pioPin = m_OutPins[ ulIndex ];
+ SAFERELEASE( pioPin );
+ }
+ m_OutPins.clear();
+ m_spSourceTransform = nullptr;
+
+}
+
+STDMETHODIMP_(ULONG) CMultipinMft::AddRef(
+ void
+ )
+{
+ return InterlockedIncrement(&m_nRefCount);
+}
+
+STDMETHODIMP_(ULONG) CMultipinMft::Release(
+ void
+ )
+{
+ ULONG uCount = InterlockedDecrement(&m_nRefCount);
+
+ if ( uCount == 0 )
+ {
+ delete this;
+ }
+ return uCount;
+}
+
+STDMETHODIMP 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);
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IMFMediaEventGenerator ) )
+ {
+ *ppv = static_cast< IMFMediaEventGenerator* >(this);
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IMFShutdown ) )
+ {
+ *ppv = static_cast< IMFShutdown* >( this );
+ AddRef();
+ }
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+ else
+ if (iid == __uuidof(IMFTransform))
+ {
+ *ppv = static_cast< IMFTransform* >(this);
+ AddRef();
+ }
+#endif
+ else
+ if ( iid == __uuidof( IKsControl ) )
+ {
+ *ppv = static_cast< IKsControl* >( this );
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IMFRealTimeClientEx ) )
+ {
+ *ppv = static_cast< IMFRealTimeClientEx* >( this );
+ AddRef();
+ }
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ else
+ if (iid == __uuidof(IMFCapturePhotoConfirmation))
+ {
+ *ppv = static_cast< IMFCapturePhotoConfirmation* >(this);
+ AddRef();
+ }
+ else
+ if (iid == __uuidof(IMFGetService))
+ {
+ *ppv = static_cast< IMFGetService* >(this);
+ AddRef();
+ }
+#endif
+ else
+ {
+ hr = E_NOINTERFACE;
+ }
+ 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
+
+--*/
+
+STDMETHODIMP 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;
+
+ 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 );
+
+ DMFTCHECKHR_GOTO( spFilterUnk.As( &m_spSourceTransform ), done );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform.As( &m_spIkscontrol ), done );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform->MFTGetStreamCount( &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 DWORD[ inputStreams ];
+ DMFTCHECKNULL_GOTO( pcInputStreams, done, E_OUTOFMEMORY);
+
+ pcOutputStreams = new DWORD[ outputStreams ];
+ DMFTCHECKNULL_GOTO( pcOutputStreams, done, E_OUTOFMEMORY );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform->MFTGetStreamIDs( inputStreams, pcInputStreams,
+ outputStreams,
+ pcOutputStreams ),done );
+
+ //
+ // Output pins from DevProxy = Input pins of device MFT.. We are the first transform in the pipeline before MFT0
+ //
+
+ for ( ULONG ulIndex = 0; ulIndex < outputStreams; ulIndex++ )
+ {
+ ComPtr<IMFAttributes> pInAttributes = nullptr;
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform->GetOutputStreamAttributes(pcOutputStreams[ulIndex], pInAttributes.GetAddressOf()), done);
+
+ DMFTCHECKHR_GOTO( pInAttributes->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &streamCategory), done);
+
+ if ( IsEqualCLSID( streamCategory, PINNAME_IMAGE ) )
+ {
+ //We have independent pins..
+ m_filterHasIndependentPin = true;
+ }
+ CInPin *pInPin = nullptr;
+ if (IsEqualCLSID(streamCategory, AVSTREAM_CUSTOM_PIN_IMAGE))
+ {
+ pInPin = new CCustomPin( pInAttributes.Get(), pcOutputStreams[ulIndex], this);
+ DMFTCHECKNULL_GOTO( pInPin, done, E_OUTOFMEMORY);
+ //
+ // Since the custom pin is an input pin too we will push it
+ // in the input pins list. This is however not being connected
+ // to the output in this sample.
+ m_CustomPinCount++;
+ }
+ else
+ {
+ pInPin = new CInPin( pInAttributes.Get(), pcOutputStreams[ulIndex], this);
+ DMFTCHECKNULL_GOTO(pInPin, done, E_OUTOFMEMORY);
+ }
+
+ hr = ExceptionBoundary([this,pInPin]()
+ {
+ m_InPins.push_back(pInPin);
+ });
+
+ DMFTCHECKHR_GOTO(hr, done);
+ DMFTCHECKHR_GOTO( pInPin->Init(m_spSourceTransform.Get() ), done);
+
+
+ pInPin->AddRef();
+
+ }
+ //
+ // If we have just one output stream exposed off the source transform create a one to three pin
+ //
+ if ( ( outputStreams == 1 ) && IsEqualGUID( streamCategory, PINNAME_VIDEO_CAPTURE ) )
+ {
+ outputStreams = 3;
+ outGuids = new GUID [ outputStreams ];
+ DMFTCHECKNULL_GOTO(outGuids, done, E_OUTOFMEMORY);
+
+ m_OutPins.resize(outputStreams, nullptr);
+
+ CInPin *piPin = (CInPin *)m_InPins[0];
+
+ *outGuids = PINNAME_VIDEO_CAPTURE;
+ *( outGuids + 1 ) = PINNAME_VIDEO_PREVIEW;
+ *(outGuids + 2) = PINNAME_IMAGE; //PINNAME_IMAGE for independent pin and PINNAME_VIDEO_STILL for dependent pin!!
+
+ for ( ULONG ulIndex = 0; ulIndex < outputStreams; ulIndex++ )
+ {
+ ComPtr<IKsControl> pKsControl = NULL;
+ COutPin *poPin = nullptr;
+
+ DMFTCHECKHR_GOTO( piPin->QueryInterface(IID_PPV_ARGS( &pKsControl ) ), done);
+
+ hr = ExceptionBoundary([&]()
+ {
+ poPin = new COutPin(ulIndex, this, pKsControl.Get());
+ });
+
+ DMFTCHECKHR_GOTO(hr, done);
+
+ DMFTCHECKNULL_GOTO( poPin,done, E_OUTOFMEMORY );
+
+ DMFTCHECKHR_GOTO( BridgeInputPinOutputPin( piPin, poPin ),done );
+
+ DMFTCHECKHR_GOTO( poPin->SetGUID( MF_DEVICESTREAM_STREAM_CATEGORY, outGuids[ ulIndex ] ),done );
+
+ DMFTCHECKHR_GOTO( poPin->SetUINT32( MF_DEVICESTREAM_STREAM_ID, ulIndex ),done );
+
+ m_OutPins[ ulIndex ] = poPin;
+ poPin->AddRef();
+
+ }
+ }
+ else
+ {
+ //
+ //Create one on one mapping
+ //
+
+ for (ULONG ulIndex = 0; ulIndex < m_InPins.size(); ulIndex++)
+ {
+ ULONG ulPinIndex = 0;
+ GUID pinGuid = GUID_NULL;
+ ComPtr< IKsControl > pKsControl = nullptr;
+
+ CInPin *piPin = ( CInPin * )m_InPins[ ulIndex ];
+
+ if (piPin)
+ {
+ BOOL isCustom = false;
+ if ( SUCCEEDED( CheckCustomPin( piPin, &isCustom )) && ( isCustom ) )
+ {
+ //
+ // In this sample we are not connecting the custom pin to the output
+ // This is because we really have no way of testing the custom pin with the
+ // pipeline.
+ // This however can be changed if the custom media type is converted here in
+ // the device MFT and later exposed to the pipeline..
+ //
+ continue;
+ }
+ ulPinIndex = piPin->streamId();
+
+ DMFTCHECKHR_GOTO(piPin->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &pinGuid), done);
+
+ DMFTCHECKHR_GOTO(piPin->QueryInterface(IID_PPV_ARGS(&pKsControl)), done);
+
+ COutPin *poPin = new COutPin(ulPinIndex, this, pKsControl.Get());
+
+ DMFTCHECKNULL_GOTO(poPin, done, E_OUTOFMEMORY);
+
+ DMFTCHECKHR_GOTO(poPin->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, pinGuid), done);
+
+ DMFTCHECKHR_GOTO(poPin->SetUINT32(MF_DEVICESTREAM_STREAM_ID, ulPinIndex), done);
+
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+ //
+ // If we wish to load MFT0 as well as Device MFT then we should be doing the following
+ // Copy over the GUID attribute MF_DEVICESTREAM_EXTENSION_PLUGIN_CLSID from the input
+ // pin to the output pin. This is because Device MFT is the new face of the filter now
+ // and MFT0 will now get loaded for the output pins exposed from Device MFT rather than
+ // DevProxy!
+ //
+
+ GUID guidMFT0 = GUID_NULL;
+
+ hr = piPin->GetGUID(MF_DEVICESTREAM_EXTENSION_PLUGIN_CLSID, &guidMFT0);
+
+ if (SUCCEEDED(hr))
+ {
+ //
+ // This stream has an MFT0 .. Attach the GUID to the Outpin pin attribute
+ // The downstream will query this attribute on the pins exposed from device MFT
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! setting Mft0 guid on pin %d", ulIndex);
+
+ DMFTCHECKHR_GOTO(poPin->SetGUID(MF_DEVICESTREAM_EXTENSION_PLUGIN_CLSID, guidMFT0), done);
+
+ DMFTCHECKHR_GOTO(poPin->SetUnknown(MF_DEVICESTREAM_EXTENSION_PLUGIN_CONNECTION_POINT,
+ static_cast< IUnknown* >(static_cast < IKsControl * >(this))), done);
+
+ }
+ else
+ {
+ // Reset Error.. MFT0 absence should not be an error
+ hr = S_OK;
+ }
+#endif
+ DMFTCHECKHR_GOTO(BridgeInputPinOutputPin(piPin, poPin), done);
+ hr = ExceptionBoundary([&]()
+ {
+ m_OutPins.push_back(poPin);
+ });
+ 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
+ while ( m_InPins.size() > 0 )
+ {
+ CInPin *pInPin = nullptr;
+ pInPin = ( CInPin* )m_InPins.back();
+ m_InPins.pop_back();
+ SAFERELEASE( pInPin );
+ }
+ while ( m_OutPins.size() > 0 )
+ {
+ COutPin *pin = nullptr;
+ pin = ( COutPin* )m_OutPins.back();
+ m_OutPins.pop_back();
+ SAFERELEASE( pin );
+ }
+ //
+ // Simply clear the custom pins since the input pins must have deleted the pin
+ //
+ m_spSourceTransform = nullptr;
+ }
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::SetWorkQueueEx(
+ _In_ DWORD dwWorkQueueId,
+ _In_ LONG lWorkItemBasePriority
+ )
+/*++
+ Description:
+
+ Implements IMFRealTimeClientEx::SetWorkQueueEx function
+
+--*/
+{
+ CAutoLock lock( m_critSec );
+ //
+ // Cache the WorkQueuId and WorkItemBasePriority
+ //
+ m_dwWorkQueueId = dwWorkQueueId;
+ m_lWorkQueuePriority = lWorkItemBasePriority;
+ return S_OK;
+
+}
+
+//
+// IMFDeviceTransform functions
+//
+STDMETHODIMP CMultipinMft::GetStreamCount(
+ _Inout_ DWORD *pdwInputStreams,
+ _Inout_ DWORD *pdwOutputStreams
+ )
+/*++
+ Description: Implements IMFTransform::GetStreamCount function
+--*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+
+
+ *pdwInputStreams = m_InputPinCount;
+ *pdwOutputStreams = m_OutputPinCount;
+
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+//
+//Doesn't striclt conform to GetStreamIDs on IMFTransform Interface!
+//
+STDMETHODIMP 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);
+
+ MFTLOCKED();
+
+ 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.
+--*/
+STDMETHODIMP CMultipinMft::GetInputAvailableType(
+ _In_ DWORD dwInputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppMediaType
+ )
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+
+
+ CInPin *piPin = ( CInPin* )GetInPin( dwInputStreamID );
+
+ DMFTCHECKNULL_GOTO( piPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ *ppMediaType = nullptr;
+
+ hr = piPin->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;
+}
+
+STDMETHODIMP 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;
+ MFTLOCKED();
+
+ DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG);
+
+ COutPin*poPin = ( COutPin* )GetOutPin( dwOutputStreamID );
+
+ DMFTCHECKNULL_GOTO( poPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ *ppMediaType = nullptr;
+
+ hr = poPin->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;
+}
+
+STDMETHODIMP 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;
+}
+
+STDMETHODIMP 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;
+ MFTLOCKED();
+ CAutoLock lock( m_critSec );
+
+ DMFTCHECKNULL_GOTO( ppMediaType, done, E_INVALIDARG );
+
+ *ppMediaType = nullptr;
+
+ COutPin *poPin = ( COutPin* )GetOutPin( dwOutputStreamID );
+
+ DMFTCHECKNULL_GOTO( poPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ DMFTCHECKHR_GOTO( poPin->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;
+}
+
+
+STDMETHODIMP 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;
+}
+
+
+
+STDMETHODIMP 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;
+ MFTLOCKED();
+
+ UNREFERENCED_PARAMETER(ulParam);
+
+ CAutoLock _lock( m_critSec );
+
+ printMessageEvent( eMessage );
+
+ 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");
+ }
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ {
+ SetStreamingState( DeviceStreamState_Run );
+ //
+ // Start Streaming custom pins if the device transfrom has any
+ //
+ SetStreamingStateCustomPins( DeviceStreamState_Run );
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_END_STREAMING:
+ {
+ SetStreamingState(DeviceStreamState_Stop);
+ //
+ // Stop streaming custom pins if the device transform has any
+ //
+ SetStreamingStateCustomPins( 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;
+}
+
+STDMETHODIMP 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 );
+
+ MFTLOCKED();
+
+ CInPin *inPin = ( CInPin* )GetInPin( dwInputStreamID );
+ DMFTCHECKNULL_GOTO( inPin, done, E_INVALIDARG );
+
+ if ( !IsStreaming() )
+ {
+ goto done;
+ }
+
+ DMFTCHECKHR_GOTO( inPin->SendSample( pSample ), done );
+
+ QueueEvent( METransformHaveOutput, GUID_NULL, S_OK, NULL );
+
+done:
+ SAFERELEASE( pSample );
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+
+}
+
+STDMETHODIMP 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;
+ MFTLOCKED();
+ 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;
+
+ COutPin *poPin = ( COutPin * )GetOutPin( dwStreamID );
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+
+ if ( SUCCEEDED( poPin->ProcessOutput( dwFlags, &pOutputSamples[i],
+ pdwStatus ) ) )
+ {
+ gotOne = true;
+ }
+ }
+ if (gotOne)
+ {
+ hr = S_OK;
+ }
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP 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;
+ MFTLOCKED();
+
+ DMFTCHECKNULL_GOTO( ppAttributes, done, E_INVALIDARG );
+ *ppAttributes = nullptr;
+
+ CInPin *piPin = static_cast<CInPin*>(GetInPin( dwInputStreamID ));
+
+ DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG );
+
+ hr = piPin->getPinAttributes(ppAttributes);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP 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;
+ MFTLOCKED();
+
+ DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG);
+ *ppAttributes = nullptr;
+
+ COutPin *poPin = (COutPin *)GetOutPin(dwOutputStreamID);
+
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+
+ DMFTCHECKHR_GOTO( poPin->getPinAttributes(ppAttributes), done );
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+_Requires_no_locks_held_
+STDMETHODIMP 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;
+ CInPin *piPin = (CInPin*)GetInPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ DMFTCHECKHR_GOTO(piPin->SetInputStreamState(pMediaType, value, dwFlags),done);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value
+ )
+{
+ HRESULT hr = S_OK;
+ CInPin *piPin = (CInPin*)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;
+}
+
+
+STDMETHODIMP 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;
+}
+
+STDMETHODIMP CMultipinMft::GetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value
+ )
+ /*++
+ 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);
+
+ COutPin *poPin = (COutPin *)GetOutPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(poPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ *value = poPin->GetState();
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP 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;
+ CInPin *piPin = (CInPin*)GetInPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ piPin->GetInputStreamPreferredState(value, ppMediaType);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP 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;
+}
+
+STDMETHODIMP 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);
+
+ COutPin *poPin = (COutPin*)GetOutPin(dwStreamIndex);
+ DMFTCHECKNULL_GOTO(poPin, done, E_INVALIDARG);
+
+ DeviceStreamState oldState = poPin->SetState(DeviceStreamState_Disabled);
+
+ hr = poPin->FlushQueues();
+
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! failed %x = %!HRESULT!", hr, hr);
+ }
+ //
+ //Restore state
+ //
+ poPin->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.
+ --*/
+STDMETHODIMP_(VOID) CMultipinMft::FlushAllStreams(
+ VOID
+ )
+{
+ DeviceStreamState oldState;
+ for ( DWORD dwIndex = 0, dwSize = (DWORD)m_OutPins.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ COutPin *poPin = (COutPin *)m_OutPins[dwIndex];
+ oldState = poPin->SetState(DeviceStreamState_Disabled);
+ poPin->FlushQueues();
+ //
+ //Restore state
+ //
+ poPin->SetState(oldState);
+ }
+}
+
+
+//
+// IKsControl interface functions
+//
+STDMETHODIMP 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;
+ UNREFERENCED_PARAMETER(pulBytesReturned);
+ DMFTCHECKNULL_GOTO(pProperty, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(pulBytesReturned, done, E_INVALIDARG);
+
+ //
+ // Enable Warm Start on All filters for the sample. Please comment out this
+ // section if this is not needed
+ //
+ if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl)
+ && (pProperty->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART))
+ {
+ DMFTCHECKHR_GOTO(WarmStartHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned),done);
+ goto done;
+ }
+
+ if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl)
+ && (pProperty->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTHUMBNAIL))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Thumbnail sent %d",pProperty->Flags);
+ }
+ if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl)
+ &&(!filterHasIndependentPin()))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Extended Control %d Passed ",pProperty->Id);
+ switch (pProperty->Id)
+ {
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE:
+ hr = ExtendedPhotoModeHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE:
+ hr = ExtendedPhotoMaxFrameRate(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES:
+ hr = MaxVidFPS_PhotoResHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME:
+ hr = QPCTimeHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOFRAMERATE:
+ hr = PhotoFrameRateHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+
+ }
+ }
+ else
+ if ((IsEqualCLSID(pProperty->Set, PROPSETID_VIDCAP_VIDEOCONTROL)) &&
+ (pProperty->Id == KSPROPERTY_VIDEOCONTROL_MODE))
+ {
+ //
+ //A photo trigger was sent!!!
+ //We need to set the event haveoutput
+ //
+ PKSPROPERTY_VIDEOCONTROL_MODE_S VideoControl = NULL;
+ if (sizeof(KSPROPERTY_VIDEOCONTROL_MODE_S) == ulDataLength)
+ {
+ VideoControl = (PKSPROPERTY_VIDEOCONTROL_MODE_S)pvPropertyData;
+ m_PhotoModeIsPhotoSequence = false;
+
+ if (VideoControl->Mode == KS_VideoControlFlag_StartPhotoSequenceCapture)
+ {
+ //
+ //Signalling start of photo sequence
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Starting PhotoSequence Trigger");
+ m_PhotoModeIsPhotoSequence = true;
+ setPhotoTriggerSent(true);
+ }
+ else
+ if (VideoControl->Mode == KS_VideoControlFlag_StopPhotoSequenceCapture)
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Stopping PhotoSequence Trigger");
+ m_PhotoModeIsPhotoSequence = false;
+ setPhotoTriggerSent(false);
+ }
+ else
+ {
+ //
+ //Normal trigger sent for single photo acquisition!
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Take Single Photo Trigger");
+ setPhotoTriggerSent(true);
+ }
+
+ }
+
+ if (!filterHasIndependentPin())
+ {
+ goto done;
+ }
+ }
+ hr = m_spIkscontrol->KsProperty(pProperty,
+ ulPropertyLength,
+ pvPropertyData,
+ ulDataLength,
+ pulBytesReturned);
+
+
+done:
+ LPSTR guidStr = DumpGUIDA(pProperty->Set);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! g:%s p:%d exiting %x = %!HRESULT!", guidStr, pProperty->Id, hr, hr);
+ delete(guidStr);
+ return hr;
+}
+
+STDMETHODIMP 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.
+ --*/
+{
+ return m_spIkscontrol->KsMethod(
+ pMethod,
+ ulPropertyLength,
+ pvPropertyData,
+ ulDataLength,
+ pulBytesReturned
+ );
+}
+
+STDMETHODIMP 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;
+ if (pEvent && (pEvent->Set == KSEVENTSETID_ExtendedCameraControl) &&
+ (pEvent->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Acquiring Event for Async Extended Control");
+ //
+ // For the Sample the warmstate handlers are supported by Device MFT and not passed to driver
+ //
+ hr = m_eventHandler.KSEvent(pEvent,
+ ulEventLength,
+ pEventData,
+ ulDataLength,
+ pBytesReturned
+ );
+ goto done;
+ }
+
+ if ((pEvent && (pEvent->Set == KSEVENTSETID_ExtendedCameraControl))
+ && (!filterHasIndependentPin()))
+ {
+ //
+ // Important: Extended controls will send events which are strictly
+ // One shot. The event comes first where it should be duped and stored,
+ // the control comes next. The event should be set after control completes
+ // and it should be then closed.
+ // The below code handles only certain events needed for
+ // implementing photo sequence. For a complete exhaustive
+ // list refer documentation.
+ //
+ switch (pEvent->Id)
+ {
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOFRAMERATE:
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Acquiring Event for Async Extended Control");
+ //
+ // Let the event handler handle the event
+ //
+ DMFTCHECKHR_GOTO(m_eventHandler.KSEvent(pEvent,
+ ulEventLength,
+ pEventData,
+ ulDataLength,
+ pBytesReturned
+ ),done);
+ goto done;
+ }
+ }
+ }
+ //
+ // All the Events we don't handle should be sent to the driver!
+ //
+ hr = m_spIkscontrol->KsEvent(pEvent,
+ ulEventLength,
+ pEventData,
+ ulDataLength,
+ pBytesReturned);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+//
+//IMFGetService functions
+//
+
+STDMETHODIMP CMultipinMft::GetService(
+ __in REFGUID guidService,
+ __in REFIID riid,
+ __deref_out LPVOID* ppvObject
+ )
+{
+ //
+ //This doesn't necessarily need to be a GetService function, but this is just so that the
+ //pipeline implementation and the Device transform implementation is consistent.
+ //In this sample the photoconfirmation interface is implementated by the same class
+ //we can delegate it later to any of the pins if needed
+ //
+ UNREFERENCED_PARAMETER(guidService);
+ if (riid == __uuidof(IMFCapturePhotoConfirmation))
+ {
+ return QueryInterface(riid, ppvObject);
+ }
+ else
+ return MF_E_UNSUPPORTED_SERVICE;
+
+
+}
+
+//
+//IMFCapturePhotoConfirmation functions implemented
+//
+
+STDMETHODIMP CMultipinMft::SetPhotoConfirmationCallback(
+ _In_ IMFAsyncCallback* pNotificationCallback
+ )
+{
+ CAutoLock Lock(m_critSec);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting PhotoConfirmation %p, is passed", pNotificationCallback);
+
+ m_spPhotoConfirmationCallback = pNotificationCallback;
+ return S_OK;
+}
+STDMETHODIMP CMultipinMft::SetPixelFormat(
+ _In_ GUID subtype
+ )
+{
+ m_guidPhotoConfirmationSubtype = subtype;
+ return S_OK;
+}
+STDMETHODIMP CMultipinMft::GetPixelFormat(
+ _Out_ GUID* subtype
+ )
+{
+ *subtype = m_guidPhotoConfirmationSubtype;
+ return S_OK;
+}
+
+#endif
+
+
+
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+
+//
+// IMFTransform function(s).
+//
+
+//
+// Note: This is the only IMFTransform function which is not a redirector to the
+// DeviceTransform functions. The rest of IMFTransform functions are in the file common.h
+// This function returns the IMFAttribute created for Device MFT. If DMFT is
+// not loaded (usually )MFT0's call to GetAttributes will get the Attribute store of DevProxy.
+// A device MFT loaded will not pass through the devproxy attribute store, but it will pass
+// the device MFT attributes. This should be similar to the singular DevProxy attribute
+// which the MFT0 providers can use to synchronize across various MFT0's
+//
+
+STDMETHODIMP CMultipinMft::GetAttributes(
+ _COM_Outptr_opt_result_maybenull_ IMFAttributes** ppAttributes
+ )
+{
+ HRESULT hr = S_OK;
+
+ DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG);
+
+ *ppAttributes = nullptr;
+
+ if (m_spAttributes != nullptr)
+ {
+ m_spAttributes.CopyTo(ppAttributes);
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+
+done:
+ return hr;
+}
+#endif
+
+
+
+
+//
+//HELPER FUNCTIONS
+//
+
+STDMETHODIMP_(CBasePin*) 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];
+ if (dwStreamId == inPin->streamId())
+ {
+ break;
+ }
+ inPin = NULL;
+ }
+ return inPin;
+}
+
+STDMETHODIMP_(CBasePin*) 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 ];
+
+ if ( dwStreamId == outPin->streamId() )
+ {
+ break;
+ }
+
+ outPin = NULL;
+ }
+
+ return outPin;
+}
+
+/*++
+Description:
+This is a critical function which changes the state on an output pin
+This should be called under the control lock of the DT.
+Here the
+--*/
+STDMETHODIMP CMultipinMft::ChangeMediaTypeEx(
+ _In_ ULONG pinId,
+ _In_opt_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState reqState
+ )
+{
+ HRESULT hr = S_OK;
+ DeviceStreamState oldOutPinState;
+ DeviceStreamState newOutStreamState;
+ ComPtr<IMFMediaType> pFullType = nullptr;
+
+ COutPin *poPin = static_cast<COutPin*>( GetOutPin(pinId) );
+
+ MMFTMMAPITERATOR inputPinPos;
+
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+ //
+ //Check if the media type requested is a supported type
+ //
+ if ( pMediaType )
+ {
+ if ( !poPin->IsMediaTypeSupported( pMediaType, &pFullType ) )
+ {
+ DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done);
+ }
+ }
+ //
+ //First step disable the output pin. store the old state
+ //
+ oldOutPinState = poPin->SetState( DeviceStreamState_Disabled );
+
+ (void)poPin->FlushQueues();
+
+ newOutStreamState = pinStateTransition[oldOutPinState][reqState]; //New state needed
+
+ //
+ //Go through the output pins' maps that has the conencted input pin to the output pin
+ //
+ inputPinPos = m_outputPinMap.equal_range( pinId );
+
+ for (std::multimap<int, int>::iterator piterator = inputPinPos.first; piterator != inputPinPos.second;piterator++)
+ {
+ //
+ //Get the output pins connected to the input pin. The input pin map consists of the output pins connected
+ //
+ ULONG connectedInputPin = (*piterator).second;
+ BOOL isAnyConnectedOutPinActive = false;
+ BOOL isAnyConnectedOutPinPaused = false;
+ BOOL isAnyConnectedOutPinRunning = false;
+ BOOL doWeWaitForSetInput = false;
+ DeviceStreamState oldInputStreamState;
+ MF_TRANSFORM_XVP_OPERATION operation = DeviceMftTransformXVPIllegal;
+ ComPtr<IMFMediaType> pInputMediaType = nullptr;
+ CInPin *pconnectedInPin = (CInPin*)GetInPin( connectedInputPin );
+ oldInputStreamState = pconnectedInPin->SetState( DeviceStreamState_Disabled );
+ DeviceStreamState newRequestedInPinState = pinStateTransition[oldInputStreamState][newOutStreamState];
+
+ if (pFullType)
+ {
+ pconnectedInPin->getMediaType( &pInputMediaType );
+ }
+
+ //
+ // Check if we need an XVP to be inserted between this input and output pins.
+ //
+ CompareMediaTypesForXVP( pInputMediaType.Get(), pFullType.Get(), &operation );
+ DMFTCHECKHR_GOTO( GetConnectOutPinStatus( connectedInputPin,
+ pinId, // pinId = stream which should be excluded from the search. This function searches if
+ &isAnyConnectedOutPinPaused, // there are any other output pins connected other than the ouput pin (on which the change media type is requested)
+ &isAnyConnectedOutPinRunning, //, which is streaming, paused. This way if the output pin is requested to go to Pause, Stop and if any of the
+ &isAnyConnectedOutPinActive ),done ); //other connected output pins are active, then input it not deactivated
+
+ //
+ //Check if we are asked to go to an active state
+ //Check for the new media type. if
+ //
+ if ( !IsPinStateInActive( newRequestedInPinState ) )
+ {
+ //
+ //We are being told to go active
+ //We will request a change in input stream state.
+ //
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! %p Going active IN: %d OUT: %d ", this, connectedInputPin, pinId );
+ doWeWaitForSetInput = true;
+ if ( !pFullType )
+ {
+ DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done);
+ }
+ if ( (! pInputMediaType ) || ( operation == DeviceMftTransformXVPDisruptiveIn ) )
+ {
+ pInputMediaType = pFullType;
+ }
+ if ( newRequestedInPinState == DeviceStreamState_Pause && isAnyConnectedOutPinRunning )
+ {
+ newRequestedInPinState = DeviceStreamState_Run;
+ }
+ }
+ else
+ {
+ //
+ //We have been requested to go inactive
+ //
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! %p Going Inactive IN: %d OUT: %d ", this, connectedInputPin, pinId );
+
+ if ( operation == DeviceMftTransformXVPDisruptiveIn )
+ {
+ //
+ //Only where we recieve a disruptive media type change and a media type along with it, which is unlikely!!
+ //
+ pInputMediaType = pFullType;
+ doWeWaitForSetInput = true;
+ }
+ if ( isAnyConnectedOutPinActive )
+ {
+ newRequestedInPinState = ( isAnyConnectedOutPinRunning ) ? DeviceStreamState_Run : DeviceStreamState_Pause;
+ }
+ else
+ {
+ //Switch over to the new media type..
+ pInputMediaType = pFullType;
+ if ( !IsPinStateInActive( oldInputStreamState ) )
+ {
+ //It was originall active.. now going down
+ doWeWaitForSetInput = true;
+ }
+ }
+ }
+
+ //
+ // This will happen if we need a change in Input media type, We will send an event
+ // METransformInputStreamStateChanged to the Device transform manager. This will result
+ // in the Device Transform manager calling us back in getprefferedinputstate where
+ // we will give it back the state of the input and the media type to be set.
+ // All this happens when we are holding a lock here in Change output media type. Hence during the
+ // input media type change we don't hold a lock. THE DTM takes care not to send you any more media
+ // type change operations that can cause a deadlock.
+ //
+
+ if ( doWeWaitForSetInput )
+ {
+ pconnectedInPin->setPreferredMediaType( pInputMediaType.Get() );
+ pconnectedInPin->setPreferredStreamState( newRequestedInPinState );
+ SendEventToManager( METransformInputStreamStateChanged, GUID_NULL, pconnectedInPin->streamId() );
+ //
+ //The media type will be set on the input pin by the time we return from the wait
+ //
+ DMFTCHECKHR_GOTO( pconnectedInPin->WaitForSetInputPinMediaChange(), done );
+ }
+ else
+ {
+ pconnectedInPin->SetState( oldInputStreamState );
+ pconnectedInPin->setMediaType( pInputMediaType.Get() );
+ }
+
+ //Now the input type is all set..
+ pInputMediaType = nullptr;
+ (VOID)pconnectedInPin->getMediaType( &pInputMediaType );
+ //
+ //Now propogate the media type change to the output pins
+ //
+ MMFTMMAPITERATOR outputPinPos = m_inputPinMap.equal_range(pconnectedInPin->streamId());
+ for ( std::multimap<int, int>::iterator poutPinsIterator = outputPinPos.first;
+ poutPinsIterator != outputPinPos.second;
+ poutPinsIterator++ )
+ {
+ ComPtr<IMFMediaType> pOutMediatype = nullptr;
+ DeviceStreamState outPinState;
+ ULONG connectedoutPin = (*poutPinsIterator).second;
+ COutPin* pIoPin = static_cast<COutPin*>( GetOutPin ( connectedoutPin ) );
+
+ (VOID)pIoPin->getMediaType( &pOutMediatype );
+ outPinState = pIoPin->GetState();
+
+ if ( pIoPin->streamId() != pinId)
+ {
+ //
+ //This is the pin other than the output pin where the original change media type was recieved.
+ //
+
+ if ( pInputMediaType != nullptr && pOutMediatype != nullptr )
+ {
+ DMFTCHECKHR_GOTO( pIoPin->ChangeMediaTypeFromInpin(pconnectedInPin, pInputMediaType.Get(),
+ pOutMediatype.Get(),
+ outPinState ),done);
+ }
+ }
+ else
+ {
+ //
+ //Change the media type of the requested output pin
+ //
+ DMFTCHECKHR_GOTO( pIoPin->ChangeMediaTypeFromInpin(pconnectedInPin, pInputMediaType.Get(), pFullType.Get(), newOutStreamState), done);
+ //Also signal to the manager that a stream state change has happened
+ SendEventToManager( MEUnknown, MEDeviceStreamCreated, pIoPin->streamId());
+ //
+ //Set the First Sample Flag. this will get reset when the first sample comes in. We will signal the discontinuity
+ //when we get a Processoutput from the Device Transform Manager
+ //
+ pIoPin->SetFirstSample(TRUE);
+
+ }
+ pOutMediatype = nullptr;
+ }
+
+ }
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP 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;
+ }
+
+
+STDMETHODIMP CMultipinMft::GetConnectOutPinStatus(
+ _In_ ULONG ulPinId,
+ _In_ ULONG ulOutPinId,
+ _Inout_ PBOOL pAnyInPauseState,
+ _Inout_ PBOOL pAnyInRunState,
+ _Inout_ PBOOL pAnyActive
+ )
+ /*++
+ Description:
+
+ This function gets the statuses of the output pins other than the one specified
+ The arguments are as follows
+ ulPinId: The input pins which are connected to the ouput pin ulOutPinId
+ ulOutPinId: The pin to be excluded from the check i.e. the input pin from which the request is usually sent.
+ --*/
+{
+ HRESULT hr = S_OK;
+ MMFTMMAPITERATOR outputPinPos;
+ CInPin *pconnectedInPin = (CInPin*)GetInPin(ulPinId);
+ DMFTCHECKNULL_GOTO( pconnectedInPin, done, E_INVALIDARG );
+
+ outputPinPos = m_inputPinMap.equal_range( pconnectedInPin->streamId() );
+ DMFTCHECKNULL_GOTO( pconnectedInPin, done, E_FAIL );
+
+ *pAnyActive = *pAnyInPauseState = *pAnyInRunState = false;
+
+ for ( std::multimap<int, int>::iterator poutPosIterator = outputPinPos.first;
+ poutPosIterator != outputPinPos.second;
+ poutPosIterator++ )
+ {
+ ULONG connectedoutPin = (*poutPosIterator).second;
+ COutPin* pconnectedOutPin = ( COutPin * )GetOutPin( connectedoutPin );
+
+ if (pconnectedOutPin->streamId() != ulOutPinId)
+ {
+ //This is excluding the outpin which requested pin state change
+ *pAnyActive |= !IsPinStateInActive( pconnectedOutPin->GetState() );
+ *pAnyInPauseState |= ( pconnectedOutPin->GetState() == DeviceStreamState_Pause );
+ *pAnyInRunState |= ( pconnectedOutPin->GetState() == DeviceStreamState_Run );
+ }
+
+ }
+ done:
+ return S_OK;
+}
+
+
+/*++
+Description:
+This function connects the input and output pins.
+Any media type filtering can happen here
+--*/
+STDMETHODIMP CMultipinMft::BridgeInputPinOutputPin(
+ _In_ CInPin* piPin,
+ _In_ COutPin* poPin
+ )
+{
+ HRESULT hr = S_OK;
+ ULONG ulIndex = 0;
+ ComPtr<IMFMediaType> pMediaType = nullptr;
+
+ DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG );
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+ //
+ // Copy over the media types from input pin to output pin. Since there is no
+ // decoder support, only the uncompressed media types are inserted. Please make
+ // sure any pin advertised supports at least one media type. The pipeline doesn't
+ // like pins with no media types
+ //
+ while ( SUCCEEDED( hr = piPin->GetMediaTypeAt( ulIndex++, &pMediaType )))
+ {
+ GUID subType = GUID_NULL;
+ DMFTCHECKHR_GOTO( pMediaType->GetGUID(MF_MT_SUBTYPE,&subType), done );
+
+ if ( IsKnownUncompressedVideoType( subType ) )
+ {
+ DMFTCHECKHR_GOTO( poPin->AddMediaType(NULL, pMediaType.Get() ), done );
+ }
+
+ pMediaType = nullptr;
+ }
+ //
+ //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.
+ //
+ piPin->ConnectPin(poPin);
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ //
+ //Create the map. This will be useful when we have to decide the state transitions of the pins
+ //
+ m_inputPinMap.insert ( std::pair< int,int >( piPin->streamId(), poPin->streamId()) );
+ 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;
+}
+
+
+//
+//The below routines are used to implement the extended controls needed to implement the photo sequence
+//The photo sequence is enabled for cameras with no independent image pins
+//The extended controls needed to enable photo sequence are discussed in detail in the photo sequence document
+//
+
+/*++
+Extended Photo Mode handler is the extended property handler dealing with the photosequence and single mode capabilities of the camera
+--*/
+STDMETHODIMP CMultipinMft::ExtendedPhotoModeHandler(
+_In_ PKSPROPERTY Property,
+_In_ ULONG ulPropertyLength,
+_In_ LPVOID pData,
+_In_ ULONG ulOutputBufferLength,
+_Inout_ PULONG pulBytesReturned
+)
+
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE );
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ) )
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ) )
+ {
+ PBYTE pPayload = ( PBYTE )pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ //
+ //Use the below structure to make changes to the Property and thus affect the configuration
+ //PKSCAMERA_EXTENDEDPROP_PHOTOMODE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_PHOTOMODE)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ m_FilterInPhotoSequence = pExtendedHeader->Flags & KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE;
+ DMFTCHECKHR_GOTO(m_eventHandler.SetOneShot(KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE), done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+ }
+ else if ( Property->Flags & KSPROPERTY_TYPE_GET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE );
+ hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ) )
+ {
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ PKSCAMERA_EXTENDEDPROP_PHOTOMODE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_PHOTOMODE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) );
+
+ pExtendedHeader->Capability = ( KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE );
+ pExtendedHeader->Flags = ( m_FilterInPhotoSequence ) ? KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE : KSCAMERA_EXTENDEDPROP_PHOTOMODE_NORMAL;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE );
+ pExtendedHeader->Version = 1;
+
+ pExtendedValue->MaxHistoryFrames = 10;
+ pExtendedValue->RequestedHistoryFrames = 0 ;
+ pExtendedValue->SubMode = 0 ;
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE );
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO( E_INVALIDARG, done );
+ }
+ }
+
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+
+ return hr;
+}
+
+/*++
+The Extended Max Frame rate is self explanatory
+--*/
+STDMETHODIMP CMultipinMft::ExtendedPhotoMaxFrameRate(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (ulOutputBufferLength < sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE))
+ {
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (pData && ulOutputBufferLength >= sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE))
+ {
+ //
+ //This is for setting the Max frame rate..
+ //
+ //PBYTE pPayload = (PBYTE)pData;
+ //PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = (PKSCAMERA_EXTENDEDPROP_HEADER)(pPayload);
+ //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ DMFTCHECKHR_GOTO(m_eventHandler.SetOneShot(KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE), done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+ }
+ else if ( Property->Flags & KSPROPERTY_TYPE_GET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ hr = HRESULT_FROM_WIN32( ERROR_MORE_DATA );
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ PBYTE pPayload = ( PBYTE )pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_VALUE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) );
+ pExtendedHeader->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL;
+ pExtendedHeader->Flags = 0;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE);
+ pExtendedHeader->Version = 1;
+ pExtendedValue->Value.ratio.HighPart = 30;
+ pExtendedValue->Value.ratio.LowPart = 1;
+ *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+ }
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::MaxVidFPS_PhotoResHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+ sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES );
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+ sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES ) )
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if (pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES ))
+ {
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ //
+ //Use the extended value to make changes to the property.. refer documentation
+ //PKSCAMERA_MAXVIDEOFPS_FORPHOTORES pExtendedValue = (PKSCAMERA_MAXVIDEOFPS_FORPHOTORES)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ pExtendedHeader->Capability = 0;
+ pExtendedHeader->Flags = 0;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ pExtendedHeader->Version = 1;
+
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES );
+ }
+
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+ else if (Property->Flags & KSPROPERTY_TYPE_GET)
+ {
+ if (ulOutputBufferLength == 0)
+ {
+ *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES);
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (ulOutputBufferLength < sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES))
+ {
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (pData && ulOutputBufferLength >= sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES))
+ {
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )(pPayload );
+ PKSCAMERA_MAXVIDEOFPS_FORPHOTORES pExtendedValue = (PKSCAMERA_MAXVIDEOFPS_FORPHOTORES)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ pExtendedHeader->Capability = 0;
+ pExtendedHeader->Flags = 0;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(PKSCAMERA_MAXVIDEOFPS_FORPHOTORES);
+ pExtendedHeader->Version = 1;
+
+ pExtendedValue->PreviewFPSNum = 30;
+ pExtendedValue->PreviewFPSDenom = 1;
+ pExtendedValue->CaptureFPSNum = 30;
+ pExtendedValue->CaptureFPSDenom = 1;
+ pExtendedValue->PhotoResHeight = 240;
+ pExtendedValue->PhotoResWidth = 320;
+
+ *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES);
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::QPCTimeHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) )
+ {
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) )
+ {
+ //PBYTE pPayload = (PBYTE)pData;
+ //
+ //If the payload is to be used.. use the below structures
+ //
+ //PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = (PKSCAMERA_EXTENDEDPROP_HEADER)(pPayload);
+ //Use the extended value to make changes to the property.. refer documentation
+ //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload +sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ *pulBytesReturned = sizeof( PKSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+ else if ( Property->Flags & KSPROPERTY_TYPE_GET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) + sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) )
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) + sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) )
+ {
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_VALUE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) );
+ pExtendedHeader->Capability = 0;
+ pExtendedHeader->Flags = KSPROPERTY_CAMERA_PHOTOTRIGGERTIME_SET;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) + sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ pExtendedHeader->Version = 1;
+ pExtendedValue->Value.ull = 0;
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+ sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::PhotoFrameRateHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+{
+ HRESULT hr = S_OK;
+
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ //
+ //This is a read only property!!!
+ //
+ hr = E_INVALIDARG;
+ }
+ else if ( Property->Flags & KSPROPERTY_TYPE_GET )
+ {
+ if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_VALUE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) );
+ pExtendedHeader->Capability = 0;
+ pExtendedHeader->Flags = 0;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ pExtendedHeader->Version = 1;
+ pExtendedValue->Value.ratio.HighPart = 30;
+ pExtendedValue->Value.ratio.LowPart = 1;
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+
+ }
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::WarmStartHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+{
+
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+ *pulBytesReturned = 0;
+
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done);
+ }
+ else if (ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done);
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ PBYTE pPayload = ( PBYTE )pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )pPayload;
+ //
+ //Use the extended value to make changes to the property.. refer documentation
+ //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ if ( pExtendedHeader->Flags & KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED )
+ {
+ m_filterInWarmStart = true;
+ }
+ else
+ {
+ m_filterInWarmStart = false;
+ }
+
+ *pulBytesReturned = sizeof( PKSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ m_eventHandler.SetOneShot(KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART);
+ }
+ else
+ {
+ hr = S_OK;
+ }
+ }
+ else if (Property->Flags & KSPROPERTY_TYPE_GET)
+ {
+ if (ulOutputBufferLength == 0)
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if (pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ PBYTE pPayload = ( PBYTE )pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ //
+ //Use the extended value to make changes to the property.. refer documentation
+ //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload +sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ pExtendedHeader->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED;
+ pExtendedHeader->Flags = 0;
+
+ if (m_filterInWarmStart)
+ {
+ pExtendedHeader->Flags |= KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED;
+ }
+
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ pExtendedHeader->Version = 1;
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ hr = S_OK;
+ }
+ else
+ {
+ hr = S_OK;
+ }
+ }
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+
+//
+// IMFShutdown interface functions
+//
+
+/*++
+Description:
+Implements the Shutdown from IMFShutdown
+--*/
+STDMETHODIMP CMultipinMft::Shutdown(
+ void
+ )
+{
+ CAutoLock Lock(m_critSec);
+ (VOID) m_eventHandler.Clear();
+ return ShutdownEventGenerator();
+}
+
+//
+// Static method to create an instance of the MFT.
+//
+HRESULT CMultipinMft::CreateInstance(REFIID iid, void **ppMFT)
+{
+ HRESULT hr = S_OK;
+ CMultipinMft *pMFT = NULL;
+ DMFTCHECKNULL_GOTO(ppMFT, done, E_POINTER);
+ pMFT = new (std::nothrow) CMultipinMft();
+ DMFTCHECKNULL_GOTO(pMFT, done, E_OUTOFMEMORY);
+
+ DMFTCHECKHR_GOTO(pMFT->QueryInterface(iid, ppMFT), done);
+
+done:
+ if (FAILED(hr))
+ {
+ SAFERELEASE(pMFT);
+ }
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+
+
+
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+/*
+Desciption:
+This function will be called by the preview pin to execute the photo confirmation stored with the
+MFT.
+*/
+
+STDMETHODIMP CMultipinMft::ProcessCapturePhotoConfirmationCallBack(
+ _In_ IMFMediaType* pMediaType,
+ _In_ IMFSample* pSample
+ )
+{
+ //
+ //PhotoConfirmation Implementation
+ //Note this function doesn't scan the metadata as the pipeline does to find out which buffer is the photoconfirmation buffer
+ //The pipeline treats the preview buffer as the photo confirmation buffer and the driver marks the metadata on the buffer as being so.
+ //This example treats every buffer coming on the pin as the confirmation buffer.
+ //
+
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaType> spMediaType = nullptr;
+ LONGLONG timeStamp = 0;
+
+ DMFTCHECKHR_GOTO(MFCreateMediaType(&spMediaType), done);
+ DMFTCHECKHR_GOTO(pMediaType->CopyAllItems(spMediaType.Get()), done);
+
+ DMFTCHECKHR_GOTO(pSample->SetUnknown(MFSourceReader_SampleAttribute_MediaType_priv, spMediaType.Get()), done);
+
+ DMFTCHECKHR_GOTO(pSample->GetSampleTime(&timeStamp), done);
+ DMFTCHECKHR_GOTO(pSample->SetUINT64(MFSampleExtension_DeviceReferenceSystemTime, timeStamp), done);
+
+ if (m_spPhotoConfirmationCallback)
+ {
+
+ //
+ //We are directly sending the photo sample over to the consumers of the photoconfirmation interface.
+ //
+ ComPtr<IMFAsyncResult> spResult;
+ DMFTCHECKHR_GOTO(MFCreateAsyncResult(pSample, m_spPhotoConfirmationCallback.Get(), NULL, &spResult), done);
+ DMFTCHECKHR_GOTO(MFInvokeCallback(spResult.Get()), done);
+ }
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+#endif
+
+//
+// Only worry about this if you have customs pins defined in the driver
+//
+
+STDMETHODIMP CMultipinMft::SetStreamingStateCustomPins(
+ DeviceStreamState State
+ )
+{
+ HRESULT hr = S_OK;
+
+ if ( m_CustomPinCount > 0 )
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Custom Pin State changing to %d", State);
+
+ for (ULONG ulIndex = 0; ulIndex < m_InPins.size(); ulIndex++)
+ {
+ BOOL isCustom = false;
+ CInPin* pInPin = static_cast<CInPin*>(m_InPins[ulIndex]);
+
+ if ( SUCCEEDED( CheckCustomPin(pInPin, &isCustom) )
+ && ( isCustom ) )
+ {
+ pInPin->SetState(State);
+ }
+ }
+ }
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
diff --git a/AVStream/sampledevicemft/multipinmft.h b/AVStream/sampledevicemft/multipinmft.h
new file mode 100644
index 00000000..244a47be
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmft.h
@@ -0,0 +1,477 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#pragma once
+
+#include "common.h"
+#include "mftpeventgenerator.h"
+#include "basepin.h"
+#include "custompin.h"
+#include "multipinmfthelpers.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;
+
+//
+// CMultipinMft class:
+// Implements a device proxy MFT.
+//
+class CMultipinMft :
+ public IMFDeviceTransform
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+ , public IMFTransform
+#endif
+ , public IMFShutdown
+ , public CMediaEventGenerator
+ , public IMFRealTimeClientEx
+ , public IKsControl
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ , public IMFCapturePhotoConfirmation
+ , public IMFGetService
+#endif
+{
+public:
+ CMultipinMft(
+ void );
+
+ virtual ~CMultipinMft();
+
+ //
+ // IUnknown
+ //
+ STDMETHOD_(ULONG, AddRef)(
+ void );
+
+ STDMETHOD_(ULONG, Release)(
+ void );
+
+ STDMETHOD(QueryInterface)(
+ _In_ REFIID iid,
+ _COM_Outptr_ void** ppv);
+
+
+ //
+ // IMFDeviceTransform functions
+ //
+ STDMETHOD(GetStreamCount)(
+ _Inout_ DWORD *pdwInputStreams,
+ _Inout_ DWORD *pdwOutputStreams);
+
+
+ STDMETHOD(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
+ );
+
+ STDMETHOD(GetInputStreamAttributes)(
+ _In_ DWORD dwInputStreamID,
+ _COM_Outptr_result_maybenull_ IMFAttributes** ppAttributes);
+
+ STDMETHOD(GetOutputStreamAttributes)(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ IMFAttributes** ppAttributes);
+
+ STDMETHOD(GetInputAvailableType)(
+ _In_ DWORD dwInputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppType);
+
+ STDMETHOD(GetOutputAvailableType)(
+ _In_ DWORD dwOutputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppMediaType);
+
+ STDMETHOD(GetInputCurrentType)(
+ _In_ DWORD dwInputStreamID,
+ _COM_Outptr_result_maybenull_ IMFMediaType** ppMediaType);
+
+ STDMETHOD(GetOutputCurrentType)(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ IMFMediaType** ppMediaType);
+
+ STDMETHOD(ProcessMessage)(
+ _In_ MFT_MESSAGE_TYPE eMessage,
+ _In_ ULONG_PTR ulParam );
+
+ STDMETHOD(ProcessEvent)(
+ _In_ DWORD dwInputStreamID,
+ _In_ IMFMediaEvent *pEvent);
+
+
+ STDMETHOD(ProcessInput)(
+ _In_ DWORD dwInputStreamID,
+ _In_ IMFSample* pSample,
+ _In_ DWORD dwFlags );
+
+ STDMETHOD(ProcessOutput)(
+ _In_ DWORD dwFlags,
+ _In_ DWORD cOutputBufferCount,
+ _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples,
+ _Out_ DWORD *pdwStatus );
+
+ //
+ // IMFRealTimeClientEx
+ //
+ STDMETHOD(RegisterThreadsEx)(
+ _Inout_ DWORD* pdwTaskIndex,
+ _In_ LPCWSTR wszClassName,
+ _In_ LONG lBasePriority )
+ {
+ UNREFERENCED_PARAMETER(pdwTaskIndex);
+ UNREFERENCED_PARAMETER(wszClassName);
+ UNREFERENCED_PARAMETER(lBasePriority);
+ return S_OK;
+ }
+
+ STDMETHOD(UnregisterThreads)()
+ {
+ return S_OK;
+ }
+
+ STDMETHOD(SetWorkQueueEx)(
+ _In_ DWORD dwWorkQueueId,
+ _In_ LONG lWorkItemBasePriority );
+
+ //
+ // IMFShutdown
+ //
+ STDMETHOD(Shutdown)(
+ void );
+
+ STDMETHOD(GetShutdownStatus)(
+ MFSHUTDOWN_STATUS *pStatus)
+ {
+ UNREFERENCED_PARAMETER(pStatus);
+ return(m_eShutdownStatus);
+ };
+
+ //
+ // IMFDeviceTransform function declarations
+ //
+ STDMETHODIMP InitializeTransform(
+ _In_ IMFAttributes *pAttributes );
+
+ _Requires_no_locks_held_
+ STDMETHODIMP SetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags );
+
+ STDMETHODIMP GetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value );
+
+ STDMETHODIMP SetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags );
+
+ STDMETHODIMP GetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value );
+
+ STDMETHODIMP GetInputStreamPreferredState(
+ _In_ DWORD dwStreamID,
+ _Inout_ DeviceStreamState *value,
+ _Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType );
+
+ STDMETHODIMP FlushInputStream(
+ _In_ DWORD dwStreamIndex,
+ _In_ DWORD dwFlags );
+
+ STDMETHODIMP FlushOutputStream(
+ _In_ DWORD dwStreamIndex,
+ _In_ DWORD dwFlags );
+
+ STDMETHODIMP_(VOID) FlushAllStreams(
+ VOID
+ );
+
+ //
+ //IKSControl Inferface function declarations
+ //
+ STDMETHOD(KsEvent)(
+ _In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ );
+ STDMETHOD(KsProperty)(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ );
+ STDMETHOD(KsMethod)(
+ _In_reads_bytes_(ulPropertyLength) PKSMETHOD pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ );
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ //
+ // The Below functions are needed for photoconfirmation
+ //
+ //
+ STDMETHOD(GetService)(
+ __in REFGUID guidService,
+ __in REFIID riid,
+ __deref_out LPVOID* ppvObject
+ );
+ //
+ //IMFCapturePhotoConfirmation Inferface function declarations
+ //
+ STDMETHOD(SetPhotoConfirmationCallback)(
+ _In_ IMFAsyncCallback* pNotificationCallback
+ );
+ STDMETHOD(SetPixelFormat)(
+ _In_ GUID subtype
+ );
+ STDMETHOD(GetPixelFormat)(
+ _Out_ GUID* subtype
+ );
+
+ __inline BOOL IsPhotoConfirmationEnabled()
+ {
+ return (m_spPhotoConfirmationCallback != nullptr);
+ }
+
+ STDMETHODIMP ProcessCapturePhotoConfirmationCallBack(
+ _In_ IMFMediaType* pMediaType,
+ _In_ IMFSample* pSample
+ );
+
+ __inline VOID SetPhotoConfirmationCallBack(_In_ IMFAsyncCallback *Callback)
+ {
+ m_spPhotoConfirmationCallback = Callback;
+ }
+
+#endif
+
+ static STDMETHODIMP CreateInstance(
+ REFIID iid, void **ppMFT);
+
+ //
+ //Below functions are used by the pins to enquire the state of the Filter for Photo sequence.
+ //A Trigger is a ksproperty sent to the filter.
+ //
+
+ __inline VOID setPhotoTriggerSent(_In_ BOOL Set)
+ {
+ m_PhotoTriggerSent = Set;
+ }
+ __inline BOOL isPhotoTriggerSent()
+ {
+ return m_PhotoTriggerSent;
+ }
+
+ __inline BOOL isPhotoModePhotoSequence()
+ {
+ return m_PhotoModeIsPhotoSequence;
+ }
+ __inline BOOL filterHasIndependentPin()
+ {
+ return m_filterHasIndependentPin;
+ }
+
+ //
+ //Will be used from Pins to get the D3D manager once set!!!
+ //
+ __inline STDMETHODIMP_(VOID) GetD3DDeviceManager(
+ IUnknown** ppDeviceManagerUnk
+ )
+ {
+ m_spDeviceManagerUnk.CopyTo( ppDeviceManagerUnk );
+ }
+
+ STDMETHODIMP SendEventToManager(
+ _In_ MediaEventType,
+ _In_ REFGUID,
+ _In_ UINT32
+ );
+
+protected:
+
+ //
+ //Helper functions
+ //
+
+ STDMETHODIMP SetStreamingStateCustomPins(
+ _In_ DeviceStreamState
+ );
+
+ STDMETHODIMP_(CBasePin*) GetInPin(
+ _In_ DWORD dwStreamID
+ );
+
+ STDMETHODIMP_(CBasePin*) GetOutPin(
+ _In_ DWORD dwStreamID
+ );
+
+ STDMETHODIMP ChangeMediaTypeEx(
+ _In_ ULONG pinId,
+ _In_opt_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState newState
+ );
+
+ STDMETHODIMP GetConnectOutPinStatus(
+ _In_ ULONG ulPinId,
+ _In_ ULONG ulOutPin,
+ _Inout_ PBOOL pAnyInPauseState,
+ _Inout_ PBOOL pAnyInRunState,
+ _Inout_ PBOOL pAnyActive
+ );
+ STDMETHODIMP BridgeInputPinOutputPin(
+ _In_ CInPin* pInPin,
+ _In_ COutPin* pOutPin);
+
+ //
+ //Implementing the below to simulate a photosequence
+ //This is just to show that photosequence can be achieved purely in
+ //the user mode with the device MFT..
+ //
+ STDMETHODIMP ExtendedPhotoModeHandler(
+ _In_ PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pvPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ PULONG pulBytesReturned
+ );
+
+ STDMETHODIMP ExtendedPhotoMaxFrameRate(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ );
+ STDMETHODIMP MaxVidFPS_PhotoResHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ );
+ STDMETHODIMP QPCTimeHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ );
+ STDMETHODIMP PhotoFrameRateHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ );
+ STDMETHODIMP CMultipinMft::WarmStartHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ );
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+ STDMETHODIMP CMultipinMft::GetAttributes(
+ _COM_Outptr_opt_result_maybenull_ IMFAttributes** ppAttributes
+ );
+#endif
+
+#if (defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES))
+ _DEFINE_DEVICEMFT_MFT0HELPER_IMPL__
+#endif
+
+
+ //
+ //Inline functions
+ //
+
+ __inline IMFTransform* Parent()
+ {
+ return m_spSourceTransform.Get();
+ }
+
+ __inline VOID SetStreamingState(DeviceStreamState state)
+ {
+ InterlockedExchange((LONG*)&m_StreamingState, state);
+ }
+ __inline DeviceStreamState GetStreamingState()
+ {
+ return (DeviceStreamState)InterlockedCompareExchange((LONG*)&m_StreamingState, m_StreamingState, m_StreamingState);
+ }
+ __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_PhotoTriggerSent;
+ BOOL m_PhotoModeIsPhotoSequence; // used to store if the filter is in photo sequence or not
+ BOOL m_FilterInPhotoSequence; // This applies for the filter, which is in a photo sequence or not. This is set by the Extended property handler
+ BOOL m_filterHasIndependentPin; // If any of the input pins from the source transform expose an independent photo pin then we will not simluate photoseqeunce
+ BOOL m_filterInWarmStart; // Used to store if the filter is in warm start 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<IMFTransform> m_spSourceTransform; // The sources transform
+ MFSHUTDOWN_STATUS m_eShutdownStatus;
+ DWORD m_dwWorkQueueId;
+ LONG m_lWorkQueuePriority;
+ UINT32 m_punValue;
+ ComPtr<IKsControl> m_spIkscontrol;
+ ComPtr<IMFAttributes> m_spAttributes;
+
+ multimap<int, int> m_inputPinMap; // How input pins are connected to output pins o-><0..inpins>
+ multimap<int, int> m_outputPinMap; // How output pins are connected to input pins i-><0..outpins>
+ CDMFTEventHandler m_eventHandler;
+
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ ComPtr<IMFAsyncCallback> m_spPhotoConfirmationCallback; //Photo Confirmation related definitions
+ GUID m_guidPhotoConfirmationSubtype;
+#endif
+
+};
+
+
+
+inline HRESULT MFT_CreateInstance(REFIID riid, void **ppv)
+{
+ return CMultipinMft::CreateInstance(riid, ppv);
+}
+
+
diff --git a/AVStream/sampledevicemft/multipinmft.vcxproj b/AVStream/sampledevicemft/multipinmft.vcxproj
new file mode 100644
index 00000000..31107772
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmft.vcxproj
@@ -0,0 +1,263 @@
+<?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|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</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>
+ </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 Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <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|Win32'">
+ <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 Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <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>
+ </ClCompile>
+ <ClCompile Include="multipinmft.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>
+ </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>
+ </ClCompile>
+ <ClCompile Include="multipinmfthelpers.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>
+ </ClCompile>
+ <ClCompile Include="multipinmftutils.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>
+ </ClCompile>
+ <ClCompile Include="custompin.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>
+ </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>
+ </ClCompile>
+ </ItemGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <TargetName>multipinmft</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <TargetName>multipinmft</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <TargetName>multipinmft</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <TargetName>multipinmft</TargetName>
+ </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|Win32'">
+ <ClCompile>
+ <ExceptionHandling>Sync</ExceptionHandling>
+ </ClCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <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>
+ </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>
+ </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|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </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|Win32'">
+ <ClCompile>
+ <PreprocessorDefinitions>%(PreprocessorDefinitions);UNICODE;MF_WPP;SECURITY_WIN32;MFT_UNIQUE_METHOD_NAMES;MF_DEVICEMFT_ALLOW_MFT0_LOAD</PreprocessorDefinitions>
+ </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 Exclude="@(None)" Include="*.def;*.bat;*.hpj;*.asmx" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Exclude="@(ClInclude)" Include="*.h;*.hpp;*.hxx;*.hm;*.inl;*.xsd" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project> \ No newline at end of file
diff --git a/AVStream/sampledevicemft/multipinmft.vcxproj.Filters b/AVStream/sampledevicemft/multipinmft.vcxproj.Filters
new file mode 100644
index 00000000..e06f675d
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmft.vcxproj.Filters
@@ -0,0 +1,46 @@
+<?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="custompin.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="multipinmft.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="multipinmfthelpers.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="multipinmftutils.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>
+</Project> \ No newline at end of file
diff --git a/AVStream/sampledevicemft/multipinmfthelpers.cpp b/AVStream/sampledevicemft/multipinmfthelpers.cpp
new file mode 100644
index 00000000..078ca337
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmfthelpers.cpp
@@ -0,0 +1,988 @@
+#include "stdafx.h"
+#include "common.h"
+#include "multipinmfthelpers.h"
+#include "multipinmft.h"
+#include "basepin.h"
+#include <wincodec.h>
+
+#ifdef MF_WPP
+#include "multipinmfthelpers.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+class CMediaTypePrinter;
+//
+//Queue implementation
+//
+
+CPinQueue::CPinQueue( _In_ DWORD _InpinId )
+: m_teer(0),
+ m_discotinuity(0),
+ m_sampleCount(0),
+ m_dwInPinId(_InpinId)
+ /*
+ Description
+ _InpinId is the input pin Id to which this queue corresponds
+ */
+{
+}
+CPinQueue::~CPinQueue( )
+{
+}
+
+/*++
+Description:
+ Insert sample into the list once we reach the open queue
+--*/
+STDMETHODIMP_(VOID) CPinQueue::InsertInternal( _In_ IMFSample *pSample )
+{
+ pSample->AddRef();
+ HRESULT hr = ExceptionBoundary([&]()
+ {
+ m_sampleList.push_back(pSample);
+ });
+
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ SAFE_RELEASE(pSample);
+ }
+}
+
+STDMETHODIMP_(BOOL) CPinQueue::Insert( _In_ IMFSample *pSample )
+//
+//m_teer is the wraptee.. this could be a null tee which is a passthrough, an xvp tee, which inserts an xvp into the queue
+//
+{
+ return SUCCEEDED( m_teer->PassThrough( pSample, this ) );
+}
+
+
+/*++
+Description:
+ This extracts the first sample from the queue. called from Pin's ProcessOutput
+--*/
+
+STDMETHODIMP_(BOOL) 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();
+ }
+
+ DMFTCHECKNULL_GOTO( *ppSample, done, MF_E_TRANSFORM_NEED_MORE_INPUT );
+
+ (*ppSample)->Release( );
+
+ m_sampleList.erase( m_sampleList.begin() );
+done:
+ return SUCCEEDED( hr ) ? TRUE : FALSE;
+}
+
+/*++
+Description:
+ Empties the Queue. used by the flush
+--*/
+VOID CPinQueue::Clear( )
+{
+ IMFSample* pSample = nullptr;
+ while ( !Empty() )
+ {
+ Remove( &pSample );
+ SAFE_RELEASE( pSample );
+ }
+}
+
+/*++
+Description:
+ RecreateTee creates the underlying Tees in the queue. It accepts the input media type
+ which is the media type set on the input pin and the output mediatype, which (duh) is the
+ media type on the output pin
+ It also takes an IUnknown which is the D3D Manager. if it is valid we might use it if we
+ have an xvp in the path i.e. inputMediatype =! outputMediatype
+--*/
+
+STDMETHODIMP CPinQueue::RecreateTee( _In_ IMFMediaType *inMediatype,
+ _In_ IMFMediaType *outMediatype,
+ _In_opt_ IUnknown* punkManager )
+{
+ HRESULT hr = S_OK;
+ MF_TRANSFORM_XVP_OPERATION operation = DeviceMftTransformXVPIllegal;
+
+ DMFTCHECKNULL_GOTO(inMediatype, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(outMediatype, done, E_INVALIDARG);
+
+ SAFE_DELETE(m_teer);
+
+ CNullTee *nulltee = new (std::nothrow) CNullTee();
+ DMFTCHECKNULL_GOTO( nulltee, done, E_OUTOFMEMORY);
+
+ DMFTCHECKHR_GOTO( CompareMediaTypesForXVP(inMediatype, outMediatype, &operation), done);
+
+ if ( (operation != DeviceMftTransformXVPCurrent) && (operation!= DeviceMftTransformXVPIllegal) )
+ {
+ CXvptee* pXvptee = new (std::nothrow) CXvptee(nulltee);
+ DMFTCHECKNULL_GOTO(pXvptee, done, E_OUTOFMEMORY);
+ (void)pXvptee->SetD3DManager( punkManager );
+ (void)pXvptee->SetMediaTypes( inMediatype, outMediatype );
+ m_teer = dynamic_cast< Ctee* >( pXvptee );
+ }
+ else
+ {
+ m_teer = nulltee; /*A simple passthrough*/
+ }
+
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+
+ if (FAILED(hr))
+ {
+ if (m_teer){
+ delete(m_teer);
+ m_teer = NULL;
+ }
+
+ }
+ return hr;
+}
+
+//
+//State implementation
+//
+CPinOpenState::CPinOpenState(CBasePin *_pin)
+:CPinState(DeviceStreamState_Run), m_pin(_pin)
+{
+
+}
+
+
+
+/*++
+Description:
+ This is the passthrough Tee in the literal sense i.e. It just dumps the sample
+ into the queue qupplied as an argument
+--*/
+STDMETHODIMP CNullTee::PassThrough( _In_ IMFSample *pSample, _In_ CPinQueue *que )
+{
+ HRESULT hr = S_OK;
+
+ DMFTCHECKNULL_GOTO(pSample, done, S_OK); //No OP for a NULL Sample!!!
+ (VOID)que->InsertInternal(pSample);
+
+ done:
+ return hr;
+}
+
+/*++
+Description:
+ This function sets the Media types on the XVP or the decoder transform. Here is where we configure the XVP
+ or the Decoder or the Encoder tee if present. The first iteration only has the XVP added
+--*/
+STDMETHODIMP CWrapTee::SetMediaTypes( _In_ IMFMediaType* pInMediaType, _In_ IMFMediaType* pOutMediaType )
+{
+ HRESULT hr = S_OK;
+ IMFTransform *pTransform = nullptr;
+
+ DMFTCHECKHR_GOTO(Configure( pInMediaType, pOutMediaType, &pTransform ),done);
+ m_videoProcessor = pTransform;
+ m_pInputMediaType = pInMediaType;
+ m_pOutputMediaType = pOutMediaType;
+
+done:
+ SAFE_RELEASE(pTransform);
+ return hr;
+}
+
+/*++
+Description:
+This is used when an XVP is present in the Pin. If the path is a passthrough i.e.
+the media type on the input and the output pins are the same then we will not see
+this path traversed. This function feeds the sample to the XVP or the decoding Tee
+--*/
+STDMETHODIMP CWrapTee::PassThrough(_In_ IMFSample* pInSample, _In_ CPinQueue *pQue)
+{
+ HRESULT hr = S_OK;
+ IMFSample* pOutSample = nullptr;
+
+ DMFTCHECKHR_GOTO(Do(pInSample, &pOutSample),done);
+
+ if (m_objectWrapped)
+ {
+ hr = m_objectWrapped->PassThrough(pOutSample, pQue);
+ }
+
+done:
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ }
+
+ return hr;
+}
+
+
+/*++
+CXvptee::Do
+Description:
+Called to do what an XVP is supposed to do i.e. scaling, resize etc.
+This function is called when the samples are desposited from the input pin to the
+output pin queue during a ProcessInput call on the device transform. Of course the
+outpin should be in Open state for the sample to reach the XVP and consequetively the
+Output Pin.
+
+If the DX manager is set on the Transform and we receieve a DX sample then we will
+undertake the DX transform in the XVP else we will skip it and go the software way
+--*/
+STDMETHODIMP CXvptee::Do(_In_ IMFSample *pSample, _Outptr_ IMFSample** pOutSample)
+{
+ //
+ //Since we are streaming in the software mode we will create a new sample
+ //
+ HRESULT hr = S_OK,pohr = S_OK;
+ MFT_OUTPUT_DATA_BUFFER outputSample;
+ MFT_OUTPUT_STREAM_INFO StreamInfo;
+ IMFSample* spXVPOutputSample = nullptr;
+ IMFMediaType* pOutMediaType = nullptr;
+ ComPtr <IMFMediaBuffer> spIMFMediaBuffer = nullptr;
+ GUID guidOutputSubType = GUID_NULL;
+ pOutMediaType = getOutMediaType();
+
+ DMFTCHECKNULL_GOTO(pOutSample, done, E_INVALIDARG);
+
+ DMFTCHECKHR_GOTO(pOutMediaType->GetGUID(MF_MT_SUBTYPE, &guidOutputSubType), done);
+
+ BOOL isDx = false;
+
+ if (SUCCEEDED(IsInputDxSample(pSample, &isDx)) && isDx)
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! DX Sample sent to XVP %p", pSample);
+ }
+
+ outputSample.dwStreamID = 0;
+ outputSample.pSample = NULL;
+
+ if (!(isDx && m_spDeviceManagerUnk!=nullptr))
+ {
+ //
+ //Create a new sample for software encoding
+ //
+ DMFTCHECKHR_GOTO(MFCreateSample(&spXVPOutputSample), done);
+
+ DMFTCHECKHR_GOTO(pSample->CopyAllItems(spXVPOutputSample), done);
+
+ outputSample.pSample = spXVPOutputSample;
+
+
+ DMFTCHECKHR_GOTO(Transform()->MFTGetOutputStreamInfo(0, &StreamInfo), done);
+
+ if (!m_isOutPutImage)
+ {
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(pOutMediaType, MF_MT_FRAME_SIZE, &m_uWidth, &m_uHeight), done);
+ hr = MFCreate2DMediaBuffer(
+ m_uWidth,
+ m_uHeight,
+ guidOutputSubType.Data1,
+ FALSE, // top-down buffer (DX compatible)
+ &spIMFMediaBuffer);
+ if (FAILED(hr))
+ {
+ spIMFMediaBuffer = nullptr;
+ spXVPOutputSample->Release();
+
+ DMFTCHECKHR_GOTO(MFCreateAlignedMemoryBuffer(
+ StreamInfo.cbSize,
+ StreamInfo.cbAlignment,
+ &spIMFMediaBuffer), done);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP Configured without DX, Created a 1D buffer");
+
+ }
+ else
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP Configured with DX, Created a 2D buffer");
+ }
+ DMFTCHECKHR_GOTO(spXVPOutputSample->AddBuffer(spIMFMediaBuffer.Get()), done);
+ }
+ }
+
+
+ //
+ //Start streaming the xvp transform..
+ //
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_BEGIN_STREAMING, 0), done); // ulParam set to zero
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_START_OF_STREAM, 0), done); // ulParam set to zero
+
+
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessInput(0, pSample, 0),done);
+
+ DWORD dwStatus = 0;
+
+ pohr = Transform()->MFTProcessOutput(0, 1, &outputSample, &dwStatus);
+
+ if (FAILED(pohr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! XVP ProcessOutput,failure %x sample =%p", pohr, &outputSample);
+ SAFERELEASE(spXVPOutputSample);
+ }
+
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0), done); // Flush the stream
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0), done); // Notify end of stream
+ DMFTCHECKHR_GOTO(Transform()->MFTProcessMessage(MFT_MESSAGE_NOTIFY_END_STREAMING, 0), done); // Notify end of streaming
+
+ spXVPOutputSample = outputSample.pSample;
+
+ if ( SUCCEEDED(pohr) )
+ {
+ //Let us copy the timestamps
+ LONGLONG hnsSampleDuration = 0;
+ LONGLONG hnsSampleTime = 0;
+
+ pSample->GetSampleDuration(&hnsSampleDuration);
+ pSample->GetSampleTime(&hnsSampleTime);
+ spXVPOutputSample->SetSampleDuration(hnsSampleDuration);
+ spXVPOutputSample->SetSampleTime(hnsSampleTime);
+ }
+
+ *pOutSample = spXVPOutputSample;
+ //
+ //Release the Sample back to the pipeline
+ //
+ pSample->Release();
+
+done:
+ hr = FAILED(pohr) ? pohr : hr;
+ return hr;
+}
+
+/*++
+Description:
+ Set the D3D Manager on the XVP
+--*/
+STDMETHODIMP_(VOID) CXvptee::SetD3DManager(IUnknown* pUnk)
+{
+ m_spDeviceManagerUnk = pUnk;
+}
+/*++
+Descrtiption:
+ Create the XVP Transform with the media types supplied.
+ This is invoked when an XVP is added to the Queue in the Output pins
+ and the input pins media type and the output pins media type don't match.
+
+--*/
+STDMETHODIMP CXvptee::Configure(
+ _In_opt_ IMFMediaType* inMediaType,
+ _In_opt_ IMFMediaType* outMediaType,
+ _Outptr_ IMFTransform **ppTransform
+ )
+{
+ HRESULT hr = S_OK;
+ GUID inMajorType = GUID_NULL;
+ GUID outMajorType = GUID_NULL;
+ bool imageType = false;
+ bool optimized = false;
+ bool optimizedxvpneeded = false;
+ IMFMediaType *pXvpOutputMediaType = nullptr;
+ ComPtr<IMFAttributes> pXvpTransformAttributes = nullptr;
+ UINT32 width = 0, height = 0;
+
+ DMFTCHECKNULL_GOTO(ppTransform, done, E_INVALIDARG);
+
+ m_isOutPutImage = false;
+ m_isoptimizedPlanarInputOutput = false;
+
+ //
+ //Print out the Media type set on the XVP
+ //
+ {
+ CMediaTypePrinter inType(inMediaType);
+ CMediaTypePrinter outType(outMediaType);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Input MediaType %s", inType.ToString());
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Output MediaType %s", outType.ToString());
+ }
+
+ DMFTCHECKHR_GOTO( CoCreateInstance(
+ CLSID_VideoProcessorMFT,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_PPV_ARGS(ppTransform)), done);
+
+
+
+ DMFTCHECKHR_GOTO( inMediaType->GetMajorType( &inMajorType ),done );
+ DMFTCHECKHR_GOTO( outMediaType->GetMajorType( &outMajorType ), done );
+ //
+ //Configuring DX Manager in SW mode. We will look to make it DX complaint in the next phase
+ //
+ if ( !IsEqualGUID(MFMediaType_Video, outMajorType ) )
+ {
+ imageType = true;
+ m_isOutPutImage = true;
+ IsOptimizedPlanarVideoInputImageOutputPair(
+ inMediaType,
+ outMediaType,
+ &optimized,
+ &optimizedxvpneeded );
+ }
+
+ //
+ //Disable frame rate conversion
+ //
+ DMFTCHECKHR_GOTO((*ppTransform)->GetAttributes(&pXvpTransformAttributes),done);
+ pXvpTransformAttributes->SetUINT32(MF_XVP_DISABLE_FRC, TRUE);
+ DMFTCHECKHR_GOTO( (*ppTransform)->MFTProcessMessage( MFT_MESSAGE_SET_D3D_MANAGER, NULL ), done );
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTSetInputType(0, inMediaType, 0), done);
+
+
+ DMFTCHECKHR_GOTO(MFCreateMediaType(&pXvpOutputMediaType), done);
+ DMFTCHECKHR_GOTO(outMediaType->CopyAllItems(pXvpOutputMediaType), done);
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_MAJOR_TYPE, MFMediaType_Video), done); //Video propcessor doesn't understand image types
+
+
+ if ( imageType )
+ {
+ GUID guidSub;
+
+ if ( !optimized )
+ {
+ DMFTCHECKHR_GOTO( inMediaType->GetGUID(MF_MT_SUBTYPE, &guidSub ), done );
+ if ( IsEqualGUID( guidSub, MFVideoFormat_ARGB32 ) )
+ {
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_ARGB32), done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32), done);
+ }
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(pXvpOutputMediaType, MF_MT_FRAME_SIZE, &width, &height), done);
+
+ m_uWidth = width;
+ m_uHeight = height;
+
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetUINT32(MF_MT_DEFAULT_STRIDE, width * 4), done); //So we always get a top down buffer
+
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTSetOutputType(0, pXvpOutputMediaType, 0), done);
+ }
+ else
+ {
+ //*** If we come here we know that the XVP is needed
+ //This case should be for non planar and xvp needed cases which we will always assume
+ LONG cStride = 0;
+ //For now we will just assume that we need the xvp in all cases
+ DMFTCHECKHR_GOTO( inMediaType->GetGUID(MF_MT_SUBTYPE, &guidSub ), done );
+
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetGUID(MF_MT_SUBTYPE, guidSub), done);
+
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(pXvpOutputMediaType, MF_MT_FRAME_SIZE, &width, &height), done);
+
+ DMFTCHECKHR_GOTO( MFGetStrideForBitmapInfoHeader( guidSub.Data1, width, &cStride ), done );
+
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetUINT32(MF_MT_DEFAULT_STRIDE, cStride), done); //So we always get a top down buffer for Nv12/Yv12
+
+ DMFTCHECKHR_GOTO(pXvpOutputMediaType->SetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, MFNominalRange_0_255), done); //Always set nominal range to 0-255 to feed into a WIC encoder
+
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTSetOutputType(0, pXvpOutputMediaType, 0), done);
+ }
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTSetOutputType(0, outMediaType, 0), done);
+ }
+ if ((m_spDeviceManagerUnk != nullptr))
+ {
+ //
+ //Set the D3D Manager on the XVP if present
+ //
+ DMFTCHECKHR_GOTO((*ppTransform)->MFTProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER,
+ reinterpret_cast<ULONG_PTR>(m_spDeviceManagerUnk.Get())), done);
+ }
+done:
+ SAFE_RELEASE(pXvpOutputMediaType);
+ return hr;
+
+}
+
+
+CXvptee::CXvptee( _In_ Ctee *tee) :
+CWrapTee(tee),
+ m_isOutPutImage(false),
+ m_isoptimizedPlanarInputOutput(true),
+ m_spDeviceManagerUnk(nullptr),
+ m_uHeight(0),
+ m_uWidth(0)
+
+{
+
+}
+
+
+CXvptee::~CXvptee()
+{
+ m_spDeviceManagerUnk = nullptr;
+}
+
+//To be implemented..Not needed for the sample!!
+/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+
+STDMETHODIMP CDecoderTee::Do(_In_ IMFSample* pSample, _Out_ IMFSample **pOutSample )
+{
+ UNREFERENCED_PARAMETER(pSample);
+ UNREFERENCED_PARAMETER(pOutSample);
+ return S_OK;
+}
+STDMETHODIMP CDecoderTee::Configure( _In_opt_ IMFMediaType *inMediaType, _In_opt_ IMFMediaType *outMediaType, _Outptr_ IMFTransform** ppTransform)
+{
+ HRESULT hr = S_OK;
+ GUID guidcategory = GUID_NULL;
+ BOOL IsDecoder = true;
+ UINT32 unFlags = 0;
+ MFT_REGISTER_TYPE_INFO in;
+ MFT_REGISTER_TYPE_INFO out;
+ UINT32 cActivates = 0;
+ UINT32 unMFTFlags = 0;
+ ComPtr<IMFMediaType> pInputMediaType = nullptr;
+ ComPtr<IMFMediaType> pOutputMediaType = nullptr;
+ IMFActivate **ppActivates = nullptr;
+ DWORD dwInputStreams;
+ DWORD dwOutputStreams;
+ UNREFERENCED_PARAMETER(outMediaType);
+ UNREFERENCED_PARAMETER(inMediaType);
+ UNREFERENCED_PARAMETER(ppTransform);
+
+ guidcategory = (IsDecoder)?MFT_CATEGORY_VIDEO_DECODER : MFT_CATEGORY_VIDEO_ENCODER;
+
+ if (IsDecoder)
+ {
+ DMFTCHECKHR_GOTO(pInputMediaType->GetGUID(MF_MT_MAJOR_TYPE, &in.guidMajorType), done);
+ DMFTCHECKHR_GOTO(pInputMediaType->GetGUID(MF_MT_SUBTYPE, &in.guidSubtype), done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(pOutputMediaType->GetGUID(MF_MT_MAJOR_TYPE, &out.guidMajorType), done);
+ DMFTCHECKHR_GOTO(pOutputMediaType->GetGUID(MF_MT_SUBTYPE, &out.guidSubtype), done);
+ }
+
+ //
+ //Use all possible plugins
+ //
+
+ unFlags = MFT_ENUM_FLAG_ASYNCMFT | MFT_ENUM_FLAG_SYNCMFT | MFT_ENUM_FLAG_SORTANDFILTER | MFT_ENUM_FLAG_SORTANDFILTER_WEB_ONLY;
+ DMFTCHECKHR_GOTO(MFTEnumEx(guidcategory,
+ unFlags,
+ IsDecoder ? &in : NULL,
+ IsDecoder ? NULL : &out,
+ &ppActivates,
+ &cActivates
+ ),done);
+ if (cActivates!=0)
+ {
+ DMFTCHECKHR_GOTO(MF_E_TOPO_CODEC_NOT_FOUND, done);
+ }
+ for (DWORD dwIndex = 0; dwIndex < cActivates; dwIndex++)
+ {
+ //
+ //Check if this MFT requires an unlocking.. skip if it does
+ //
+ unMFTFlags = MFGetAttributeUINT32(ppActivates[dwIndex], MF_TRANSFORM_FLAGS_Attribute, 0);
+ if (unMFTFlags & MFT_ENUM_FLAG_FIELDOFUSE)
+ {
+ //
+ //If you have the unlocking key set MFT_FIELDOFUSE_UNLOCK_Attribute on the activate
+ //
+ continue;
+ }
+
+ hr = ppActivates[dwIndex]->ActivateObject(IID_PPV_ARGS(ppTransform));
+ if (FAILED(hr))
+ continue; //hope the next activate is activable
+ ppActivates[dwIndex]->DetachObject();
+
+ hr = (*ppTransform)->MFTGetStreamCount(&dwInputStreams, &dwOutputStreams);
+
+ if (FAILED(hr) || dwInputStreams != 1 || dwOutputStreams > 127)//remove the hardcoding
+ {
+ //
+ //Exception.. we can't use a stream that doesn't give us an idea about it's streams
+ //
+ continue;
+ }
+ if (IsDecoder)
+ {
+ hr = ConfigureDecoder(*ppTransform);
+ }
+ else
+ {
+ hr = ConfigureEncoder(*ppTransform);
+ }
+ if (FAILED(hr))
+ {
+ SAFE_RELEASE(*ppTransform);
+ }
+ }
+
+done:
+ return hr;
+}
+
+/*++
+
+--*/
+
+STDMETHODIMP CDecoderTee::ConfigureEncoder( _In_ IMFTransform *pTransform )
+{
+ HRESULT hr = S_OK;
+ //
+ //Set the input media type and the output media type and that should be pretty much it
+ //
+ ComPtr<IMFMediaType> pInputType = nullptr;
+ ComPtr<IMFMediaType> pOutputType = nullptr;
+
+ pInputType = getInMediaType();
+ pOutputType = getOutMediaType();
+
+ if (pInputType && pOutputType)
+ {
+ //We should be good by now
+ DMFTCHECKHR_GOTO( pTransform->MFTSetInputType( 0,pInputType.Get(), 0), done);
+ //If we have D3D enabled then try again with D3D disabled and see the result
+ //
+ DMFTCHECKHR_GOTO(pTransform->MFTSetOutputType(0,pOutputType.Get(), 0), done);
+ //
+ //If the above operation fails and we are allowing partial media types then
+ //we have to find the full media type and then check again
+ }
+ else
+ {
+ hr = E_FAIL;
+ }
+done:
+ return hr;
+}
+
+STDMETHODIMP CDecoderTee::ConfigureDecoder( _In_ IMFTransform *pTransform)
+{
+ UNREFERENCED_PARAMETER( pTransform );
+ return S_OK;
+}
+
+/*++
+Descrtiption:
+ Handles events sent by the pipeline
+ --*/
+STDMETHODIMP CDMFTEventHandler::KSEvent(
+ _In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned)
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(ulDataLength);
+ UNREFERENCED_PARAMETER(pBytesReturned);
+
+ if (pEvent == nullptr)
+ {
+ //
+ // We can have an Event Reset here
+ //
+ if (pEventData == nullptr)
+ {
+ //
+ // Invalid input. KSEVENT and KSEVENTDATA cannot both be null
+ //
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+ //
+ // The way KSevents work are, KSEVENT and KSEVENTDATA both have to be non null for events to be Set
+ // on the driver. If the pipeline wishes to reset the event we pass the KSEVENT structure as NULL and
+ // the KSEVENTDATA to be nonnull.
+ // ********** EVENT RESET here since KSEVENT is null and KSEVENTDATA is not**********
+ // We will never get Event Reset for One shot events
+ // Search the list of regular events to find the KSEVENTDATA pointer and then free the entry
+ //
+ for ( vector<PDMFTEventEntry>::iterator it = m_RegularEventList.begin(); it != m_RegularEventList.end(); ++it )
+ {
+ PDMFTEventEntry pEntry = nullptr;
+ pEntry = *it;
+ DMFTCHECKNULL_GOTO(pEntry, done, E_UNEXPECTED); // We should never see a null data structure entry
+ if (pEntry->m_pEventData == pEventData)
+ {
+ it = m_RegularEventList.erase(it);
+ delete(pEntry); // Delete the entry!
+ goto done;
+ }
+ }
+
+ DMFTCHECKHR_GOTO(E_NOT_SET, done);
+ }
+ else
+ {
+ //
+ // If we are here the pipeline wants to do the following things
+ // 1) Store a regular event
+ // 2) Store a oneshot event
+ //
+ HANDLE evtHandle = nullptr;
+ PKSEVENT pEvt = pEvent;
+ PKSEVENTDATA pEvtdata = reinterpret_cast<PKSEVENTDATA>(pEventData);
+
+ if (ulEventLength < sizeof(KSEVENT))
+ {
+ DMFTCHECKNULL_GOTO(pBytesReturned, done, E_INVALIDARG);
+ *pBytesReturned = sizeof(KSEVENT);
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+
+ if (!pEvtdata)
+ {
+ //
+ // Need the event data to be present to service the call properly!
+ //
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+
+ if (pEvt->Flags & KSEVENT_TYPE_ENABLE) // Regular/ Manual Reset Event
+ {
+ vector<PDMFTEventEntry>::iterator it = m_RegularEventList.begin();
+ for (; it != m_RegularEventList.end(); it++)
+ {
+ PDMFTEventEntry pEntry = *it;
+ DMFTCHECKNULL_GOTO(pEntry, done, E_FAIL);
+ if (pEntry->m_pEventData == pEventData)
+ {
+ break;
+ }
+ }
+ if (it != m_RegularEventList.end())
+ {
+ //
+ // Duplicate entry found.
+ //
+ DMFTCHECKHR_GOTO(E_NOT_VALID_STATE, done);
+ }
+ }
+ else if (pEvt->Flags & KSEVENT_TYPE_ONESHOT)
+ {
+ ULONG ulEventCommand = pEvt->Id;
+ hr = ExceptionBoundary([&]()
+ {
+ map<ULONG, HANDLE>::iterator it = m_OneShotEventMap.find(ulEventCommand);
+ if (it != m_OneShotEventMap.end())
+ {
+ //
+ // Duplicate entry found.
+ //
+ hr = E_NOT_VALID_STATE;
+ }
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(E_NOTIMPL, done);
+ }
+
+ //
+ // Duplicate the handle
+ //
+ DMFTCHECKHR_GOTO(Dupe(pEvtdata->EventHandle.Event, &evtHandle),done);
+ ULONG ulEventCommand = pEvt->Id;
+
+ if (pEvt->Flags & KSEVENT_TYPE_ENABLE)
+ {
+ // ************** REGULAR EVENT ****************************
+ // Regualar event. When this needs to be cleqared we will geta call with KSEVENT = null
+ // and KSEVENTDATA with the same address as this call(pEvtdata). Hence store it
+ // To set the event all we need is the EVENT id.
+ //
+ PDMFTEventEntry pEntry = new DMFTEventEntry(ulEventCommand, pEvtdata, evtHandle);
+ DMFTCHECKNULL_GOTO(pEntry, done, E_OUTOFMEMORY);
+ hr = ExceptionBoundary([&]()
+ {
+ (VOID)m_RegularEventList.push_back(pEntry);
+ });
+ }
+ else if(pEvt->Flags & KSEVENT_TYPE_ONESHOT)
+ {
+ // *************** SINGLE SHOT EVENT ************************
+ // Single Shot event store. Store the event Id and the Handle.
+ //
+ hr = ExceptionBoundary([&]()
+ {
+ (VOID)m_OneShotEventMap.insert(std::pair<ULONG, HANDLE>(ulEventCommand, evtHandle));
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+ }
+
+done:
+ return hr;
+}
+
+/*++
+Descrtiption:
+ Used to set the One shot events sent by the pipeline.
+ One shot events should be closed by the component after firing. The Pipeline
+ will not send a reset or a clear for one shot events
+--*/
+
+STDMETHODIMP CDMFTEventHandler::SetOneShot( ULONG ulEventId )
+{
+ HRESULT hr = S_OK;
+ hr = ExceptionBoundary([&]()
+ {
+ map<ULONG, HANDLE>::iterator it = m_OneShotEventMap.find(ulEventId);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! trying to Set OneShot %d ", ulEventId);
+
+ if (it != m_OneShotEventMap.end())
+ {
+ // Found the event
+ HANDLE hOneShot = it->second;
+ if (SetEvent(hOneShot))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting OneShot %d Succeeded",
+ ulEventId);
+ CloseHandle(hOneShot);
+ m_OneShotEventMap.erase(it);
+ }
+ else
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting OneShot %d failed %x",
+ ulEventId,
+ HRESULT_FROM_WIN32(GetLastError()));
+ }
+ }
+ else
+ {
+ hr = E_NOT_SET;
+ }
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting OneShot %d failed %x",
+ ulEventId,
+ HRESULT_FROM_WIN32(GetLastError()));
+ return hr;
+}
+
+/*++
+Descrtiption:
+ Used to set the Regular events sent by the pipeline.
+ Regular events unlike the one shot events must be persisted
+ until the pipeline explicitly needs the event to be unset.
+--*/
+
+STDMETHODIMP CDMFTEventHandler::SetRegularEvent(ULONG ulEventId)
+{
+ BOOL bEvtFound = FALSE;
+ HRESULT hr = ExceptionBoundary([&]()
+ {
+
+ for (vector<PDMFTEventEntry>::iterator it = m_RegularEventList.begin(); it != m_RegularEventList.end(); ++it)
+ {
+ PDMFTEventEntry pEntry = *it;
+ if (ulEventId == pEntry->m_ulEventId)
+ {
+ // Found the event
+ bEvtFound = TRUE;
+ if (!::SetEvent(pEntry->m_hHandle))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting Event %d Failed 0x%x",
+ ulEventId, hr);
+ }
+ else
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting Event %d s",
+ ulEventId);
+ }
+ }
+ }
+ });
+ if (!bEvtFound)
+ {
+ DMFTCHECKHR_GOTO(E_NOT_SET, done);
+ }
+done:
+ return hr;
+}
+
+/*++
+Descrtiption:
+ Duplicates the handle passed.
+--*/
+
+STDMETHODIMP CDMFTEventHandler::Dupe(_In_ HANDLE hEventHandle, _Outptr_ LPHANDLE lpTargetHandle)
+{
+ HRESULT hr = S_OK;
+ DMFTCHECKNULL_GOTO(hEventHandle, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(lpTargetHandle, done, E_INVALIDARG);
+ //
+ // Duplicate handle and store it for when it needs to be fired
+ //
+ if (!DuplicateHandle(GetCurrentProcess(), hEventHandle,
+ GetCurrentProcess(), lpTargetHandle,
+ 0,
+ false,
+ DUPLICATE_SAME_ACCESS
+ ))
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Duplicating Event Handle failed %x",
+ hr);
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+done:
+ return hr;
+}
+
+/*++
+
+Descrtiption:
+ Cleans the event lists, both the Single shot and the Regular ones
+
+--*/
+STDMETHODIMP CDMFTEventHandler::Clear()
+{
+ HRESULT hr = S_OK;
+ hr = ExceptionBoundary([&]()
+ {
+ map<ULONG, HANDLE>::iterator it = m_OneShotEventMap.begin();
+ for (; it != m_OneShotEventMap.end(); ++it)
+ {
+ //
+ // Delete the one shot entries. We should not see this path usually
+ // as the pipeline will send a one shot event and set it soon. We
+ // should remore the entry then.
+ //
+ CloseHandle(it->second);
+ it = m_OneShotEventMap.erase(it);
+ if (it == m_OneShotEventMap.end())
+ {
+ // We've reached the end break
+ break;
+ }
+ }
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ hr = ExceptionBoundary([=]()
+ {
+ vector<PDMFTEventEntry>::iterator it2 = m_RegularEventList.begin();
+ for (; it2 != m_RegularEventList.end(); ++it2)
+ {
+ //
+ // Delete the entries. This will be traversed
+ //
+ PDMFTEventEntry pEntry = *it2;
+ it2 = m_RegularEventList.erase(it2);
+ SAFE_DELETE(pEntry);
+ if (it2 == m_RegularEventList.end())
+ {
+ break;
+ }
+ }
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+done:
+ return hr;
+}
diff --git a/AVStream/sampledevicemft/multipinmfthelpers.h b/AVStream/sampledevicemft/multipinmfthelpers.h
new file mode 100644
index 00000000..25d87eb8
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmfthelpers.h
@@ -0,0 +1,291 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+#pragma once
+#include "stdafx.h"
+#include "common.h"
+
+
+
+//
+//Queue class!!!
+//
+class Ctee;
+//typedef CMFAttributesTrace CMediaTypeTrace; /* Only used for debug. take this out*/
+
+
+class CPinQueue{
+public:
+ CPinQueue(_In_ DWORD _inPinId);
+ ~CPinQueue();
+
+ STDMETHODIMP_(BOOL) SetState ( _In_ BOOL state );
+ STDMETHODIMP_(VOID) InsertInternal ( _In_ IMFSample *pSample = nullptr );
+ STDMETHODIMP_(BOOL) Insert ( _In_ IMFSample *pSample );
+ STDMETHODIMP_(BOOL) Remove (_Outptr_result_maybenull_ IMFSample **pSample);
+ STDMETHODIMP RecreateTee ( _In_ IMFMediaType *inMediatype, _In_ IMFMediaType *outMediatype, _In_opt_ IUnknown* punkManager );
+ STDMETHODIMP_(VOID) Clear();
+
+ //
+ //Inline functions
+ //
+ __inline BOOL Empty()
+ {
+ return (!m_sampleList.size());
+ }
+
+ __inline DWORD pinStreamId()
+ {
+ return m_dwInPinId;
+ }
+
+private:
+ DWORD m_dwInPinId; /*This is the input pin */
+ IMFSampleList m_sampleList; /*List storing the samples */
+ ULONG m_sampleCount; /*Numebr of sampels */
+ Ctee* m_teer; /*Tee that acts as a passthrough or an XVP */
+ BOOL m_discotinuity; /*Set after the queue is emptied or flushed */
+
+};
+
+class CPinState{
+public:
+ virtual STDMETHODIMP Open() = 0;
+ CPinState( _In_ DeviceStreamState _state = DeviceStreamState_Disabled) :m_State( _state )
+ {
+
+ }
+ STDMETHODIMP_(DeviceStreamState) SetState( _In_ DeviceStreamState ); /*True for Active and False for Stop*/
+ STDMETHODIMP_(DeviceStreamState) GetState();
+
+ __inline STDMETHODIMP_(DeviceStreamState) State()
+ {
+ return m_State;
+ }
+ virtual ~CPinState() = 0
+ {
+ }
+protected:
+ DeviceStreamState m_State;
+};
+
+class CPinOpenState :public CPinState{
+public:
+ CPinOpenState( _In_ CBasePin *p = NULL );
+ //
+ //Inline
+ //
+ __inline STDMETHODIMP Open()
+ {
+ return S_OK;
+ }
+
+private:
+ CBasePin *m_pin;
+};
+class CPinClosedState : public CPinState{
+public:
+ CPinClosedState(DeviceStreamState _state = DeviceStreamState_Stop)
+ :CPinState(_state)
+ {
+
+ }
+ //
+ //Inline
+ //
+ __inline STDMETHODIMP Open()
+ {
+ return MF_INVALID_STATE_ERR;
+ }
+};
+
+
+
+//
+// Define these in different components
+// The below classes are used to add the
+// XVP and the Decoder components
+//
+class Ctee{
+public:
+ virtual STDMETHODIMP PassThrough( _In_ IMFSample *, _In_ CPinQueue * ) = 0;
+};
+
+
+class CNullTee:public Ctee{
+public:
+ STDMETHODIMP PassThrough( _In_ IMFSample*, _In_ CPinQueue * );
+};
+
+
+class CWrapTee : public Ctee{
+public:
+ CWrapTee(_In_ Ctee *tee=nullptr)
+: m_objectWrapped(tee)
+ , m_pInputMediaType(nullptr)
+ , m_pOutputMediaType(nullptr)
+ {
+
+ }
+ virtual ~CWrapTee()=0
+ {
+ m_videoProcessor = nullptr;
+ if (m_objectWrapped)
+ {
+ delete(m_objectWrapped);
+ }
+ }
+
+ STDMETHODIMP PassThrough ( _In_ IMFSample*, _In_ CPinQueue * );
+ virtual STDMETHODIMP Configure ( _In_ IMFMediaType *, _In_ IMFMediaType *, _Inout_ IMFTransform** ) = 0;
+ virtual STDMETHODIMP Do ( _In_ IMFSample* pSample, _Out_ IMFSample ** ) = 0;
+ STDMETHODIMP SetMediaTypes ( _In_ IMFMediaType* pInMediaType, _In_ IMFMediaType* pOutMediaType );
+
+ //
+ //Inline functions
+ //
+protected:
+ __inline IMFTransform* Transform()
+ {
+ return m_videoProcessor.Get();
+ }
+ __inline IMFMediaType* getInMediaType()
+ {
+ IMFMediaType* pmediaType = nullptr;
+ m_pInputMediaType.CopyTo(&pmediaType);
+ return pmediaType;
+ }
+ __inline IMFMediaType* getOutMediaType()
+ {
+ IMFMediaType* pmediaType = nullptr;
+ m_pOutputMediaType.CopyTo(&pmediaType);
+ return pmediaType;
+ }
+
+private:
+ ComPtr< IMFTransform > m_videoProcessor;
+ ComPtr< IMFMediaType > m_pInputMediaType;
+ ComPtr< IMFMediaType > m_pOutputMediaType;
+ Ctee *m_objectWrapped;
+};
+
+
+class CXvptee :public CWrapTee{
+public:
+ CXvptee( _In_ Ctee * );
+ ~CXvptee();
+ STDMETHODIMP Do ( _In_ IMFSample* pSample, _Outptr_ IMFSample ** );
+ STDMETHODIMP Configure ( _In_opt_ IMFMediaType *, _In_opt_ IMFMediaType *, _Outptr_ IMFTransform** );
+ STDMETHODIMP_(VOID) SetD3DManager( IUnknown* punk );
+
+private:
+ BOOL m_isoptimizedPlanarInputOutput;
+ BOOL m_isOutPutImage;
+ UINT32 m_uWidth;
+ UINT32 m_uHeight;
+ ComPtr<IUnknown> m_spDeviceManagerUnk;
+};
+
+class CDecoderTee : public CWrapTee{
+public:
+ CDecoderTee(Ctee* *);
+ ~CDecoderTee();
+
+ STDMETHODIMP Do( _In_ IMFSample* pSample, _Out_ IMFSample ** );
+ STDMETHODIMP Configure( _In_opt_ IMFMediaType *, _In_opt_ IMFMediaType *, _Outptr_ IMFTransform** );
+ STDMETHODIMP ConfigureEncoder( _In_ IMFTransform *pTransform );
+ STDMETHODIMP ConfigureDecoder( _In_ IMFTransform *pTransform );
+private:
+ ComPtr<IUnknown> m_spDeviceManagerUnk;
+};
+
+
+/*
+################## EVENT HANDLING #############################################
+Events are usually divided into two categories by the Capture Pipeline
+1) Regular Event / Manual Reset Event
+2) One Shot Event
+
+Regular events are set and cleared by the pipeline
+One shot Events will only be set by the pipeline and it should be cleared
+by the Component managing the Event Store i.e. KS or DMFT. For Redstone
+The pipeline should not send any Non One shot events.This sample however
+does show the handling of Regular/ Manual Reset events
+
+This clearing of One shot events is done when the event is fired..
+E.g before sending the warm start command The pipeline will send a one shot event
+KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART and when the operation completes the
+event should be fired.
+The Device MFT should usually keep a watch for one shot events sent by the Pipeline
+for Async Extended controls..The list of Asynchronous controls are as follows..
+
+KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE
+KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE
+KSPROPERTY_CAMERACONTROL_EXTENDED_FOCUSMODE
+KSPROPERTY_CAMERACONTROL_REGION_OF_INTEREST_PROPERTY_ID
+KSPROPERTY_CAMERACONTROL_EXTENDED_ISO
+KSPROPERTY_CAMERACONTROL_EXTENDED_ISO_ADVANCED
+KSPROPERTY_CAMERACONTROL_EXTENDED_EVCOMPENSATION
+KSPROPERTY_CAMERACONTROL_EXTENDED_WHITEBALANCEMODE
+KSPROPERTY_CAMERACONTROL_EXTENDED_EXPOSUREMODE
+KSPROPERTY_CAMERACONTROL_EXTENDED_SCENEMODE
+KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTHUMBNAIL
+KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART
+KSPROPERTY_CAMERACONTROL_EXTENDED_ROI_ISPCONTROL
+KSPROPERTY_CAMERACONTROL_EXTENDED_PROFILE
+The complete list can be found from the Camera DDI spec
+###############################################################################
+*/
+
+typedef struct _DMFTEventEntry{
+ ULONG m_ulEventId; // KSEVENT->Id
+ PVOID m_pEventData; // Lookup for events in the data structure
+ HANDLE m_hHandle; // The duplicate handle stored from the event
+ //
+ // Constructor. We simply cache the handles, the property id and the KSEVENTDATA buffer sent from the user mode
+ //
+ _DMFTEventEntry( _In_ ULONG ulEventId, _In_ PVOID pEventData, _In_ HANDLE pHandle):m_pEventData(pEventData)
+ , m_ulEventId(ulEventId)
+ , m_hHandle(pHandle)
+ {
+ }
+ ~_DMFTEventEntry()
+ {
+ if ( m_hHandle != nullptr )
+ {
+ CloseHandle(m_hHandle);
+ m_hHandle = nullptr;
+ }
+ }
+
+}DMFTEventEntry, *PDMFTEventEntry;
+
+//
+// Handler for one shot events and Normal events
+//
+class CDMFTEventHandler{
+public:
+ //
+ // Handle the events here
+ //
+ STDMETHOD(KSEvent)(_In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned);
+ STDMETHOD(SetOneShot)(ULONG);
+ STDMETHOD(SetRegularEvent)(ULONG);
+ STDMETHOD(Clear)();
+protected:
+ STDMETHOD(Dupe)(_In_ HANDLE hEventHandle, _Outptr_ LPHANDLE lpTargetHandle);
+private:
+ map< ULONG, HANDLE > m_OneShotEventMap;
+ vector< PDMFTEventEntry > m_RegularEventList;
+};
+
+
+
diff --git a/AVStream/sampledevicemft/multipinmftutils.cpp b/AVStream/sampledevicemft/multipinmftutils.cpp
new file mode 100644
index 00000000..6f5735b5
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmftutils.cpp
@@ -0,0 +1,877 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#include "stdafx.h"
+#include "common.h"
+#include "multipinmft.h"
+#include "basepin.h"
+
+#pragma comment(lib, "d2d1")
+#ifdef MF_WPP
+#include "multipinmftutils.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:
+ Used to check if the input and the output Image types are optinmized or not
+--*/
+
+STDMETHODIMP IsOptimizedPlanarVideoInputImageOutputPair(
+ _In_ IMFMediaType *inMediaType,
+ _In_ IMFMediaType *outMediaType,
+ _Out_ bool *optimized,
+ _Out_ bool *optimizedxvpneeded )
+{
+ HRESULT hr = S_OK;
+ GUID guidInputSubType = GUID_NULL;
+ GUID guidOutputSubType = GUID_NULL;
+ UINT32 uWidthIn = 0, uHeightIn = 0, uWidthOut = 0, uHeightOut = 0;
+
+
+ DMFTCHECKHR_GOTO(inMediaType->GetGUID(MF_MT_SUBTYPE, &guidInputSubType), done);
+
+ DMFTCHECKHR_GOTO(outMediaType->GetGUID(MF_MT_SUBTYPE, &guidOutputSubType), done);
+
+ *optimized = false; //Assume we aren't optimized . Optimized = (ip = YU12|NV12 and op = JPEG)
+ *optimizedxvpneeded = true; //Assume we need xvps
+
+ if (IsEqualGUID(guidInputSubType, MFVideoFormat_YV12) || IsEqualGUID(guidInputSubType, MFVideoFormat_NV12))
+ {
+ if (IsEqualGUID(guidOutputSubType, GUID_ContainerFormatJpeg))
+ {
+ *optimized = true;
+ }
+ }
+
+ if (!*optimized)
+ {
+ goto done;
+ }
+
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(inMediaType, MF_MT_FRAME_SIZE, &uWidthIn, &uHeightIn), done);
+ DMFTCHECKHR_GOTO(MFGetAttributeSize(outMediaType, MF_MT_FRAME_SIZE, &uWidthOut, &uHeightOut), done);
+
+ if ((uWidthIn == uWidthOut) && (uHeightIn == uHeightOut))
+ {
+ *optimizedxvpneeded = false;
+ }
+ if (!*optimizedxvpneeded)
+ {
+ UINT32 nominalRange;
+ hr = inMediaType->GetUINT32(MF_MT_VIDEO_NOMINAL_RANGE, &nominalRange);
+
+ if (FAILED(hr) || nominalRange != MFNominalRange_0_255)
+ {
+ //XVP needed since nominal range is not 0-255 for YV12 or NV12 fed into WIC
+ *optimizedxvpneeded = true;
+ }
+ hr = S_OK;
+ }
+
+done:
+ return hr;
+}
+
+
+/*
+Description:
+
+ This is used whenever there is a media type change on an output pin and the
+ Output queue is being reconfigured.
+ The possible return values for the function are as follows
+
+ DeviceMftTransformXVPIllegal -> If either of the mediatypes or both are NULL
+ DeviceMftTransformXVPDisruptiveIn -> If the mediatype at the output pin is greater than the input pin. This will result in change of the media type on the input
+ DeviceMftTransformXVPDisruptiveOut -> This is a reconfiguration or addition of the XVP in the Output pin queue
+ DeviceMftTransformXVPCurrent -> No XVP needed at all
+ Note: This iteration doesn't support decoder. The next one will and this function will accordingly change
+*/
+STDMETHODIMP CompareMediaTypesForXVP(
+ _In_opt_ IMFMediaType *inMediaType,
+ _In_ IMFMediaType *newMediaType,
+ _Inout_ MF_TRANSFORM_XVP_OPERATION *operation
+ )
+{
+ UINT32 unWidthin, unHeightin, unWidthNew, unHeightNew = 0;
+ HRESULT hr = S_OK;
+ GUID guidTypeA = GUID_NULL;
+ GUID guidTypeB = GUID_NULL;
+
+ *operation = DeviceMftTransformXVPIllegal;
+ if ((!inMediaType) || (!newMediaType))
+ {
+ goto done;
+ }
+
+ DMFTCHECKHR_GOTO( MFGetAttributeSize( inMediaType, MF_MT_FRAME_SIZE, &unWidthin, &unHeightin ), done );
+ DMFTCHECKHR_GOTO( MFGetAttributeSize( newMediaType, MF_MT_FRAME_SIZE, &unWidthNew, &unHeightNew ), done );
+
+
+ if ( SUCCEEDED( inMediaType->GetGUID( MF_MT_MAJOR_TYPE, &guidTypeA ) ) &&
+ SUCCEEDED( newMediaType->GetGUID( MF_MT_MAJOR_TYPE, &guidTypeB ) ) &&
+ IsEqualGUID( guidTypeA, guidTypeB ) )
+ {
+ if ( SUCCEEDED( inMediaType->GetGUID ( MF_MT_SUBTYPE, &guidTypeA ) ) &&
+ SUCCEEDED( newMediaType->GetGUID( MF_MT_SUBTYPE, &guidTypeB ) ) &&
+ IsEqualGUID( guidTypeA, guidTypeB ) )
+ {
+ //Comparing the MF_MT_AM_FORMAT_TYPE for the directshow format guid
+#if 0
+ if (SUCCEEDED(inMediaType->GetGUID(MF_MT_AM_FORMAT_TYPE, &guidTypeA)) &&
+ SUCCEEDED(newMediaType->GetGUID(MF_MT_AM_FORMAT_TYPE, &guidTypeB)) &&
+ IsEqualGUID(guidTypeA, guidTypeB))
+#endif
+ {
+
+ if (!(( unWidthin == unWidthNew ) &&
+ ( unHeightin == unHeightNew ) ) )
+ {
+ if ( ( unWidthNew > unWidthin ) || ( unHeightNew > unHeightin ) )
+ {
+ *operation = DeviceMftTransformXVPDisruptiveIn; //Media type needs to change at input
+ }
+ else
+ {
+ *operation = DeviceMftTransformXVPDisruptiveOut; //Media type needs to change at output
+ }
+ goto done;
+ }
+
+ if ( MFGetAttributeUINT32( inMediaType, MF_MT_SAMPLE_SIZE, 0 ) !=
+ MFGetAttributeUINT32( newMediaType, MF_MT_SAMPLE_SIZE, 0 ) )
+ {
+ hr = S_FALSE; //Sample sizes differ.
+ goto done;
+ }
+ else
+ {
+ //Same media type.. No XVP needed or the current XVP is fine!
+ *operation = DeviceMftTransformXVPCurrent;
+ }
+ }
+ }
+ else
+ {
+ //This is a disruptive operation. Actually a decoder operation!
+ *operation = DeviceMftTransformXVPDisruptiveIn;
+ }
+ }
+ done:
+ return hr;
+}
+
+/*++
+Description:
+ A Simple function to randomnize the media types supplied in an array
+--*/
+STDMETHODIMP RandomnizeMediaTypes(_In_ IMFMediaTypeArray &pMediaTypeArray)
+{
+ HRESULT hr = S_OK;
+ IMFMediaType *pTempMediaType = nullptr;
+ UNREFERENCED_PARAMETER(pTempMediaType);
+ if (pMediaTypeArray.empty())
+ {
+ goto done;
+ }
+
+ srand(static_cast<unsigned long>(GetTickCount64()));
+
+ for (DWORD dwIndex = (DWORD)pMediaTypeArray.size() - 1; dwIndex > 0; dwIndex--)
+ {
+ DWORD fromIndex = rand() % ( dwIndex + 1 );
+ pTempMediaType = pMediaTypeArray[dwIndex];
+ pMediaTypeArray [ dwIndex ] = pMediaTypeArray[fromIndex] ;
+ pMediaTypeArray [ fromIndex ] = pTempMediaType;
+ }
+ //
+ //Just reverse the array
+ //
+ for (DWORD dwIndex = (DWORD)pMediaTypeArray.size() - 1, fromIndex = 0; dwIndex > 0; dwIndex--, fromIndex++)
+ {
+
+ pTempMediaType = pMediaTypeArray[dwIndex];
+ pMediaTypeArray [ dwIndex ] = pMediaTypeArray[fromIndex];
+ pMediaTypeArray [ fromIndex ] = pTempMediaType;
+ }
+ done:
+ return hr;
+
+}
+
+/*++
+Description: Used to test if the sample passed is a DX sample or not?
+--*/
+STDMETHODIMP IsInputDxSample(
+ _In_ IMFSample* pSample,
+ _Inout_ BOOL *isDxSample
+ )
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaBuffer> spBuffer = nullptr;
+ DMFTCHECKNULL_GOTO( pSample, done, E_INVALIDARG );
+
+ *isDxSample = false;
+ if ( SUCCEEDED( pSample->GetBufferByIndex( 0, &spBuffer ) ) )
+ {
+ ComPtr<IMFDXGIBuffer> spDXGIBuffer;
+ ComPtr<ID3D11Texture2D> spResourceTexture;
+ if ( SUCCEEDED( spBuffer.As(&spDXGIBuffer ) ) &&
+ SUCCEEDED( spDXGIBuffer-> GetResource( IID_PPV_ARGS( &spResourceTexture ) ) ) )
+ {
+ *isDxSample = true;
+ }
+ }
+done:
+ return hr;
+}
+
+
+/*++
+ 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;
+}
+
+/*
+Description:
+ A Helper function to return if the Mediatype is a compressed video type or not!
+*/
+STDMETHODIMP_(BOOL) IsKnownUncompressedVideoType(_In_ GUID guidSubType)
+{
+ if (guidSubType == MFVideoFormat_ARGB32 ||
+ guidSubType == MFVideoFormat_RGB24 ||
+ guidSubType == MFVideoFormat_RGB555 ||
+ guidSubType == MFVideoFormat_RGB565 ||
+ guidSubType == MFVideoFormat_RGB32 ||
+ guidSubType == MFVideoFormat_RGB8 ||
+ guidSubType == MFVideoFormat_AI44 ||
+ guidSubType == MFVideoFormat_AYUV ||
+ guidSubType == MFVideoFormat_YUY2 ||
+ guidSubType == MFVideoFormat_YVYU ||
+ guidSubType == MFVideoFormat_YVU9 ||
+ guidSubType == MFVideoFormat_UYVY ||
+ guidSubType == MFVideoFormat_NV11 ||
+ guidSubType == MFVideoFormat_NV12 ||
+ guidSubType == MFVideoFormat_YV12 ||
+ guidSubType == MFVideoFormat_I420 ||
+ guidSubType == MFVideoFormat_IYUV ||
+ guidSubType == MFVideoFormat_Y210 ||
+ guidSubType == MFVideoFormat_Y216 ||
+ guidSubType == MFVideoFormat_Y410 ||
+ guidSubType == MFVideoFormat_Y416 ||
+ guidSubType == MFVideoFormat_Y41P ||
+ guidSubType == MFVideoFormat_Y41T ||
+ guidSubType == MFVideoFormat_Y42T ||
+ guidSubType == MFVideoFormat_P210 ||
+ guidSubType == MFVideoFormat_P216 ||
+ guidSubType == MFVideoFormat_P010 ||
+ guidSubType == MFVideoFormat_P016 ||
+ guidSubType == MFVideoFormat_v210 ||
+ guidSubType == MFVideoFormat_v216 ||
+ guidSubType == MFVideoFormat_v410 ||
+ guidSubType == MFVideoFormat_L8 ||
+ guidSubType == MFVideoFormat_L16 ||
+ guidSubType == MFVideoFormat_D16)
+ {
+ return( TRUE );
+ }
+
+ return( FALSE );
+}
+
+/*++
+Description:
+ Function used to lock the MFT.
+--*/
+
+STDMETHODIMP UnLockAsynMFT(IMFTransform* pTransform)
+{
+ HRESULT hr = S_OK;
+ IMFAttributes *pAttributes;
+ UINT32 unValue;
+
+ DMFTCHECKNULL_GOTO(pTransform,done, E_INVALIDARG);
+ DMFTCHECKHR_GOTO(pTransform->GetAttributes(&pAttributes),done);
+ DMFTCHECKHR_GOTO(pAttributes->GetUINT32(MF_TRANSFORM_ASYNC, &unValue), done);
+
+ if (unValue)
+ {
+ DMFTCHECKHR_GOTO(pAttributes->SetUINT32(MF_TRANSFORM_ASYNC, true), done);
+ }
+
+done:
+ return hr;
+}
+
+
+#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 char[len]; \
+if (!a){\
+goto done;}\
+ a[0] = 0; \
+ strcat_s(a, len, tStore); \
+ delete(tStore); }\
+}
+
+
+/*++
+Description:
+ returns an ascii buffer for the GUID passed. The Caller should release the memory allocated
+--*/
+LPSTR DumpGUIDA(_In_ REFGUID guid)
+{
+ LPOLESTR lpszGuidString = NULL;
+ char *ansiguidStr = NULL;
+ if (SUCCEEDED(StringFromCLSID(guid, &lpszGuidString)))
+ {
+ int mbGuidLen = 0;
+ mbGuidLen = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, lpszGuidString, -1, NULL, 0, NULL, NULL);
+ if (mbGuidLen > 0)
+ {
+ mf_assert(mbGuidLen == (int)wcslen(lpszGuidString));
+ ansiguidStr = new char[mbGuidLen];
+ WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, lpszGuidString, -1, ansiguidStr, mbGuidLen, NULL, NULL);
+ CoTaskMemFree(lpszGuidString);
+ ansiguidStr[mbGuidLen - 1] = 0;
+ }
+ }
+ return ansiguidStr;
+}
+
+//
+//Borrrowed from MDSN sample
+//
+LPCSTR GetGUIDNameConst(const GUID& guid)
+{
+ IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE);
+ IF_EQUAL_RETURN(guid, MF_MT_MAJOR_TYPE);
+ IF_EQUAL_RETURN(guid, MF_MT_SUBTYPE);
+ IF_EQUAL_RETURN(guid, MF_MT_ALL_SAMPLES_INDEPENDENT);
+ IF_EQUAL_RETURN(guid, MF_MT_FIXED_SIZE_SAMPLES);
+ IF_EQUAL_RETURN(guid, MF_MT_COMPRESSED);
+ IF_EQUAL_RETURN(guid, MF_MT_SAMPLE_SIZE);
+ IF_EQUAL_RETURN(guid, MF_MT_WRAPPED_TYPE);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_NUM_CHANNELS);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_SECOND);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FLOAT_SAMPLES_PER_SECOND);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_AVG_BYTES_PER_SECOND);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BLOCK_ALIGNMENT);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_BITS_PER_SAMPLE);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_VALID_BITS_PER_SAMPLE);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_SAMPLES_PER_BLOCK);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_CHANNEL_MASK);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_FOLDDOWN_MATRIX);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKREF);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_PEAKTARGET);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGREF);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_WMADRC_AVGTARGET);
+ IF_EQUAL_RETURN(guid, MF_MT_AUDIO_PREFER_WAVEFORMATEX);
+ IF_EQUAL_RETURN(guid, MF_MT_AAC_PAYLOAD_TYPE);
+ IF_EQUAL_RETURN(guid, MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION);
+ IF_EQUAL_RETURN(guid, MF_MT_FRAME_SIZE);
+ IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE);
+ IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MAX);
+ IF_EQUAL_RETURN(guid, MF_MT_FRAME_RATE_RANGE_MIN);
+ IF_EQUAL_RETURN(guid, MF_MT_PIXEL_ASPECT_RATIO);
+ IF_EQUAL_RETURN(guid, MF_MT_DRM_FLAGS);
+ IF_EQUAL_RETURN(guid, MF_MT_PAD_CONTROL_FLAGS);
+ IF_EQUAL_RETURN(guid, MF_MT_SOURCE_CONTENT_HINT);
+ IF_EQUAL_RETURN(guid, MF_MT_VIDEO_CHROMA_SITING);
+ IF_EQUAL_RETURN(guid, MF_MT_INTERLACE_MODE);
+ IF_EQUAL_RETURN(guid, MF_MT_TRANSFER_FUNCTION);
+ IF_EQUAL_RETURN(guid, MF_MT_VIDEO_PRIMARIES);
+ IF_EQUAL_RETURN(guid, MF_MT_CUSTOM_VIDEO_PRIMARIES);
+ IF_EQUAL_RETURN(guid, MF_MT_YUV_MATRIX);
+ IF_EQUAL_RETURN(guid, MF_MT_VIDEO_LIGHTING);
+ IF_EQUAL_RETURN(guid, MF_MT_VIDEO_NOMINAL_RANGE);
+ IF_EQUAL_RETURN(guid, MF_MT_GEOMETRIC_APERTURE);
+ IF_EQUAL_RETURN(guid, MF_MT_MINIMUM_DISPLAY_APERTURE);
+ IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_APERTURE);
+ IF_EQUAL_RETURN(guid, MF_MT_PAN_SCAN_ENABLED);
+ IF_EQUAL_RETURN(guid, MF_MT_AVG_BITRATE);
+ IF_EQUAL_RETURN(guid, MF_MT_AVG_BIT_ERROR_RATE);
+ IF_EQUAL_RETURN(guid, MF_MT_MAX_KEYFRAME_SPACING);
+ IF_EQUAL_RETURN(guid, MF_MT_DEFAULT_STRIDE);
+ IF_EQUAL_RETURN(guid, MF_MT_PALETTE);
+ IF_EQUAL_RETURN(guid, MF_MT_USER_DATA);
+ IF_EQUAL_RETURN(guid, MF_MT_AM_FORMAT_TYPE);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG_START_TIME_CODE);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG2_PROFILE);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG2_LEVEL);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG2_FLAGS);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG_SEQUENCE_HEADER);
+ IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_0);
+ IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_0);
+ IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_SRC_PACK_1);
+ IF_EQUAL_RETURN(guid, MF_MT_DV_AAUX_CTRL_PACK_1);
+ IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_SRC_PACK);
+ IF_EQUAL_RETURN(guid, MF_MT_DV_VAUX_CTRL_PACK);
+ IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_HEADER);
+ IF_EQUAL_RETURN(guid, MF_MT_ARBITRARY_FORMAT);
+ IF_EQUAL_RETURN(guid, MF_MT_IMAGE_LOSS_TOLERANT);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG4_SAMPLE_DESCRIPTION);
+ IF_EQUAL_RETURN(guid, MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY);
+ IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_4CC);
+ IF_EQUAL_RETURN(guid, MF_MT_ORIGINAL_WAVE_FORMAT_TAG);
+
+ // Media types
+
+ IF_EQUAL_RETURN(guid, MFMediaType_Audio);
+ IF_EQUAL_RETURN(guid, MFMediaType_Video);
+ IF_EQUAL_RETURN(guid, MFMediaType_Protected);
+ IF_EQUAL_RETURN(guid, MFMediaType_SAMI);
+ IF_EQUAL_RETURN(guid, MFMediaType_Script);
+ IF_EQUAL_RETURN(guid, MFMediaType_Image);
+ IF_EQUAL_RETURN(guid, MFMediaType_HTML);
+ IF_EQUAL_RETURN(guid, MFMediaType_Binary);
+ IF_EQUAL_RETURN(guid, MFMediaType_FileTransfer);
+
+ IF_EQUAL_RETURN(guid, MFVideoFormat_AI44); // FCC('AI44')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_ARGB32); // D3DFMT_A8R8G8B8
+ IF_EQUAL_RETURN(guid, MFVideoFormat_AYUV); // FCC('AYUV')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_DV25); // FCC('dv25')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_DV50); // FCC('dv50')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_DVH1); // FCC('dvh1')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_DVSD); // FCC('dvsd')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_DVSL); // FCC('dvsl')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_H264); // FCC('H264')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_I420); // FCC('I420')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_IYUV); // FCC('IYUV')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_M4S2); // FCC('M4S2')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MJPG);
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MP43); // FCC('MP43')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MP4S); // FCC('MP4S')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MP4V); // FCC('MP4V')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MPG1); // FCC('MPG1')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MSS1); // FCC('MSS1')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_MSS2); // FCC('MSS2')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_NV11); // FCC('NV11')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_NV12); // FCC('NV12')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_P010); // FCC('P010')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_P016); // FCC('P016')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_P210); // FCC('P210')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_P216); // FCC('P216')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_RGB24); // D3DFMT_R8G8B8
+ IF_EQUAL_RETURN(guid, MFVideoFormat_RGB32); // D3DFMT_X8R8G8B8
+ IF_EQUAL_RETURN(guid, MFVideoFormat_RGB555); // D3DFMT_X1R5G5B5
+ IF_EQUAL_RETURN(guid, MFVideoFormat_RGB565); // D3DFMT_R5G6B5
+ IF_EQUAL_RETURN(guid, MFVideoFormat_RGB8);
+ IF_EQUAL_RETURN(guid, MFVideoFormat_UYVY); // FCC('UYVY')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_v210); // FCC('v210')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_v410); // FCC('v410')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_WMV1); // FCC('WMV1')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_WMV2); // FCC('WMV2')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_WMV3); // FCC('WMV3')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_WVC1); // FCC('WVC1')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_Y210); // FCC('Y210')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_Y216); // FCC('Y216')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_Y410); // FCC('Y410')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_Y416); // FCC('Y416')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_Y41P);
+ IF_EQUAL_RETURN(guid, MFVideoFormat_Y41T);
+ IF_EQUAL_RETURN(guid, MFVideoFormat_YUY2); // FCC('YUY2')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_YV12); // FCC('YV12')
+ IF_EQUAL_RETURN(guid, MFVideoFormat_YVYU);
+
+ IF_EQUAL_RETURN(guid, MFAudioFormat_PCM); // WAVE_FORMAT_PCM
+ IF_EQUAL_RETURN(guid, MFAudioFormat_Float); // WAVE_FORMAT_IEEE_FLOAT
+ IF_EQUAL_RETURN(guid, MFAudioFormat_DTS); // WAVE_FORMAT_DTS
+ IF_EQUAL_RETURN(guid, MFAudioFormat_Dolby_AC3_SPDIF); // WAVE_FORMAT_DOLBY_AC3_SPDIF
+ IF_EQUAL_RETURN(guid, MFAudioFormat_DRM); // WAVE_FORMAT_DRM
+ IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV8); // WAVE_FORMAT_WMAUDIO2
+ IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudioV9); // WAVE_FORMAT_WMAUDIO3
+ IF_EQUAL_RETURN(guid, MFAudioFormat_WMAudio_Lossless); // WAVE_FORMAT_WMAUDIO_LOSSLESS
+ IF_EQUAL_RETURN(guid, MFAudioFormat_WMASPDIF); // WAVE_FORMAT_WMASPDIF
+ IF_EQUAL_RETURN(guid, MFAudioFormat_MSP1); // WAVE_FORMAT_WMAVOICE9
+ IF_EQUAL_RETURN(guid, MFAudioFormat_MP3); // WAVE_FORMAT_MPEGLAYER3
+ IF_EQUAL_RETURN(guid, MFAudioFormat_MPEG); // WAVE_FORMAT_MPEG
+ IF_EQUAL_RETURN(guid, MFAudioFormat_AAC); // WAVE_FORMAT_MPEG_HEAAC
+ IF_EQUAL_RETURN(guid, MFAudioFormat_ADTS); // WAVE_FORMAT_MPEG_ADTS_AAC
+
+ return NULL;
+}
+
+
+LPSTR DumpAttribute( _In_ const MF_ATTRIBUTE_TYPE& type,
+ _In_ REFPROPVARIANT var)
+{
+ CHAR *tempStr = NULL;
+ tempStr = new CHAR[256];
+ switch (type)
+ {
+ case MF_ATTRIBUTE_UINT32:
+ if (var.vt == VT_UI4)
+ {
+ sprintf_s(tempStr, 256, "%u", var.ulVal);
+ }
+ break;
+ case MF_ATTRIBUTE_UINT64:
+ if (var.vt == VT_UI8)
+ {
+ sprintf_s(tempStr, 256, "%I64d (high: %d low: %d)", var.uhVal.QuadPart, var.uhVal.HighPart, var.uhVal.LowPart);
+ }
+ break;
+ case MF_ATTRIBUTE_DOUBLE:
+ if (var.vt == VT_R8)
+ {
+ sprintf_s(tempStr, 256, "%.4f", var.dblVal);
+ }
+ break;
+ case MF_ATTRIBUTE_GUID:
+ if (var.vt == VT_CLSID)
+ {
+ return DumpGUIDA(*var.puuid);
+ }
+ break;
+ case MF_ATTRIBUTE_STRING:
+ if (var.vt == VT_LPWSTR)
+ {
+ sprintf_s(tempStr, 256, "%S", var.pwszVal);
+ }
+ break;
+ case MF_ATTRIBUTE_IUNKNOWN:
+ break;
+ default:
+ printf("(Unknown Attribute Type = %d) ", type);
+ break;
+ }
+ return tempStr;
+}
+
+CMediaTypePrinter::CMediaTypePrinter(
+ _In_ IMFMediaType *_pMediaType )
+ : pMediaType(_pMediaType),
+ m_pBuffer(NULL)
+{
+}
+
+CMediaTypePrinter::~CMediaTypePrinter()
+{
+ if (m_pBuffer)
+ {
+ delete(m_pBuffer);
+ }
+}
+
+/*++
+Description:
+Rudimentary function to print the complete Media type
+--*/
+PCHAR CMediaTypePrinter::ToCompleteString( )
+{
+ HRESULT hr = S_OK;
+ UINT32 attrCount = 0;
+ GUID attrGuid = { 0 };
+ char *tempStore = nullptr;
+ PROPVARIANT var;
+ LPSTR pTempBaseStr;
+ MF_ATTRIBUTE_TYPE pType;
+
+ if ( pMediaType && !m_pBuffer )
+ {
+ DMFTCHECKHR_GOTO(pMediaType->GetCount(&attrCount), done);
+ buffLen = MEDIAPRINTER_STARTLEN;
+ m_pBuffer = new char[buffLen];
+ m_pBuffer[0] = 0;
+ for ( UINT32 ulIndex = 0; ulIndex < attrCount; ulIndex++ )
+ {
+ PropVariantInit( &var );
+ checkAdjustBufferCap( m_pBuffer, buffLen );
+ DMFTCHECKHR_GOTO( pMediaType->GetItemByIndex( ulIndex, &attrGuid, &var ), done );
+ DMFTCHECKHR_GOTO( pMediaType->GetItemType( attrGuid, &pType ), done );
+ if ( ulIndex > 0 )
+ strcat_s(m_pBuffer, MEDIAPRINTER_STARTLEN, " : ");
+ strcat_s( m_pBuffer, buffLen, GetGUIDNameConst( attrGuid ) );
+ strcat_s( m_pBuffer, buffLen, "=" );
+ pTempBaseStr = DumpAttribute( pType, var );
+ strcat_s( m_pBuffer, buffLen, pTempBaseStr );
+ delete( pTempBaseStr );
+ PropVariantClear( &var );
+ }
+ done:
+ if ( tempStore )
+ {
+ delete( tempStore );
+ }
+ }
+ return m_pBuffer;
+}
+
+/*++
+Description:
+Rudimentary function to print the Media type
+--*/
+
+PCHAR CMediaTypePrinter::ToString()
+{
+ //
+ //Following are the important ones of Mediatype attributes
+ //
+
+ HRESULT hr = S_OK;
+ PROPVARIANT var;
+ LPSTR pTempBaseStr;
+ MF_ATTRIBUTE_TYPE pType;
+ GUID attrGuid;
+ GUID impGuids[] = {
+ MF_MT_SUBTYPE,
+ MF_MT_FRAME_SIZE,
+ MF_MT_SAMPLE_SIZE,
+ MF_MT_FRAME_RATE,
+ MF_MT_DEFAULT_STRIDE,
+ MF_XVP_DISABLE_FRC
+ };
+
+ if (pMediaType && !m_pBuffer)
+ {
+ buffLen = MEDIAPRINTER_STARTLEN;
+ m_pBuffer = new char[buffLen];
+ m_pBuffer[0] = 0;
+ for (UINT32 ulIndex = 0; ulIndex < ARRAYSIZE(impGuids); ulIndex++)
+ {
+ PropVariantInit(&var);
+ checkAdjustBufferCap(m_pBuffer, buffLen);
+ attrGuid = impGuids[ulIndex];
+ DMFTCHECKHR_GOTO(pMediaType->GetItemType(attrGuid, &pType), done);
+ DMFTCHECKHR_GOTO(pMediaType->GetItem(attrGuid, &var), done);
+ if (ulIndex > 0)
+ strcat_s(m_pBuffer, MEDIAPRINTER_STARTLEN, " : ");
+ strcat_s(m_pBuffer, buffLen, GetGUIDNameConst(attrGuid));
+ strcat_s(m_pBuffer, buffLen, "=");
+ pTempBaseStr = DumpAttribute(pType, var);
+ strcat_s(m_pBuffer, buffLen, pTempBaseStr);
+ delete(pTempBaseStr);
+ PropVariantClear(&var);
+ }
+ }
+done:
+ return m_pBuffer;
+}
+/*++
+Description:
+ Debug message printer to print the message passed through WPP
+--*/
+void printMessageEvent(MFT_MESSAGE_TYPE msg)
+{
+ switch (msg)
+ {
+ case MFT_MESSAGE_COMMAND_FLUSH:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_FLUSH");
+ break;
+ case MFT_MESSAGE_COMMAND_DRAIN:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_DRAIN");
+ break;
+ case MFT_MESSAGE_COMMAND_MARKER:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_MARKER");
+ break;
+ case MFT_MESSAGE_COMMAND_TICK:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_COMMAND_TICK");
+ break;
+ case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_END_OF_STREAM");
+ break;
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_BEGIN_STREAMING");
+ break;
+ case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_NOTIFY_START_OF_STREAM");
+ break;
+ case MFT_MESSAGE_DROP_SAMPLES:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_DROP_SAMPLES");
+ break;
+ case MFT_MESSAGE_SET_D3D_MANAGER:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! :PROCESSMESSAGE: MFT_MESSAGE_SET_D3D_MANAGER");
+ break;
+
+ }
+}
+
+/*++
+Below functions not used in the current iteration..
+--*/
+HRESULT CreateCodec(
+ _In_opt_ IMFMediaType* inMediaType,
+ _In_opt_ IMFMediaType *outMediaType,
+ _In_ BOOL operation /*True = Encode, False = Decode*/,
+ _Out_ IMFTransform **pTransform)
+{
+ UNREFERENCED_PARAMETER(inMediaType);
+ UNREFERENCED_PARAMETER(outMediaType);
+ UNREFERENCED_PARAMETER(operation);
+ UNREFERENCED_PARAMETER(pTransform);
+ HRESULT hr = S_OK;
+ *pTransform = nullptr;
+ return hr;
+}
+
+
+HRESULT CheckDX9RotationSupport(_In_ ID3D11VideoDevice* pVideoDevice)
+{
+ HRESULT hr = S_OK;
+ //
+ // check if the DX9 device is ok
+ // New drivers should have an DXVA-HD rotation cap set
+ //
+ D3D11_VIDEO_PROCESSOR_CONTENT_DESC desc = {};
+ D3D11_VIDEO_PROCESSOR_CAPS caps;
+ ComPtr<ID3D11VideoProcessorEnumerator> spVideoProcEnum = nullptr;
+
+ DMFTCHECKNULL_GOTO(pVideoDevice, done, E_NOTIMPL);
+ desc.InputWidth = 640;
+ desc.InputHeight = 480;
+ desc.OutputWidth = 640;
+ desc.OutputHeight = 480;
+
+ DMFTCHECKHR_GOTO(pVideoDevice->CreateVideoProcessorEnumerator(&desc, &spVideoProcEnum), done);
+ DMFTCHECKHR_GOTO(spVideoProcEnum->GetVideoProcessorCaps(&caps), done);
+
+ if (!(caps.FeatureCaps & D3D11_VIDEO_PROCESSOR_FEATURE_CAPS_ROTATION))
+ {
+ hr = E_NOTIMPL;
+ }
+done:
+ return hr;
+}
+
+
+
+HRESULT IsDXOptimal(_In_ IUnknown *pDeviceManager, _Out_ BOOL *pIsOptimal)
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFDXGIDeviceManager> spDXGIDeviceManager = nullptr;
+ ComPtr<ID3D11Device> spD3D11 = nullptr;
+ ComPtr<ID3D11VideoDevice> spVideoDevice = nullptr;
+ HANDLE hDevice = NULL;
+ BOOL locked = FALSE;
+
+ *pIsOptimal = false;
+ DMFTCHECKNULL_GOTO( pDeviceManager, done, E_INVALIDARG );
+ DMFTCHECKHR_GOTO( pDeviceManager->QueryInterface(IID_PPV_ARGS( &spDXGIDeviceManager )), done );
+ DMFTCHECKHR_GOTO( spDXGIDeviceManager->OpenDeviceHandle( &hDevice ), done );
+ DMFTCHECKHR_GOTO( spDXGIDeviceManager->LockDevice( hDevice, IID_PPV_ARGS( &spD3D11 ), TRUE), done );
+ locked = TRUE;
+ DMFTCHECKHR_GOTO( spD3D11.As(&spVideoDevice), done );
+
+ if (spD3D11->GetFeatureLevel() <= D3D_FEATURE_LEVEL_9_3)
+ {
+ if (FAILED(CheckDX9RotationSupport(spVideoDevice.Get())))
+ {
+ goto done;
+ }
+ }
+ *pIsOptimal = TRUE;
+done:
+ if (hDevice)
+ {
+ if (locked)
+ {
+ spDXGIDeviceManager->UnlockDevice(hDevice, false);
+ }
+ spDXGIDeviceManager->CloseDeviceHandle(hDevice);
+ }
+ return hr;
+}
+
+
+//
+// Used to check if the pin is a custom pin or not!!
+//
+
+STDMETHODIMP CheckCustomPin(
+ _In_ CInPin * pPin,
+ _Inout_ PBOOL pIsCustom
+ )
+{
+ HRESULT hr = S_OK;
+ DMFTCHECKNULL_GOTO( pPin, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO( pIsCustom, done, E_INVALIDARG);
+
+ *pIsCustom = false;
+
+#if defined _CPPRTTI
+ if (dynamic_cast<CCustomPin*>(pPin) != nullptr)
+ {
+ *pIsCustom = true;
+ }
+ else
+#endif
+ {
+ GUID categoryGUID = GUID_NULL;
+ if (SUCCEEDED(pPin->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &categoryGUID))
+ && IsEqualCLSID(categoryGUID, AVSTREAM_CUSTOM_PIN_IMAGE))
+ {
+ *pIsCustom = true;
+ }
+ }
+done:
+ return hr;
+}
+
diff --git a/AVStream/sampledevicemft/stdafx.h b/AVStream/sampledevicemft/stdafx.h
new file mode 100644
index 00000000..9f4bab9f
--- /dev/null
+++ b/AVStream/sampledevicemft/stdafx.h
@@ -0,0 +1,39 @@
+//
+// 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 <new>
+#include <vector>
+#include <map>
+using namespace std;
+#include <Windows.Foundation.h>
+#include <wrl\client.h>
+using namespace ABI::Windows::Foundation;
+using namespace Microsoft::WRL;
diff --git a/AVStream/sampledevicemft/stdafxsrc.cpp b/AVStream/sampledevicemft/stdafxsrc.cpp
new file mode 100644
index 00000000..1577c4e3
--- /dev/null
+++ b/AVStream/sampledevicemft/stdafxsrc.cpp
@@ -0,0 +1 @@
+#include "stdafx.h" \ No newline at end of file