summaryrefslogtreecommitdiff
path: root/avstream/sampledevicemft
diff options
context:
space:
mode:
authorJ M Rossy <[email protected]>2015-07-29 15:40:09 -0700
committerJ M Rossy <[email protected]>2015-07-29 16:34:40 -0700
commit5d61a4a79a1e96dc5d9af1e5e712c84507307544 (patch)
tree49ed270893578cd18758b74ffcca16dc7ab948d6 /avstream/sampledevicemft
parent5d41613e26e147d2300c786bb2b34cb4b4067a25 (diff)
Samples update for public Windows 10 release
Fix #2 Enabling WPP Recorder in Sensors Samples causes errors Fix #4 Add back fixed KMDOD sample Add new BarcodeScanner sample in pos folder Add new MagneticStripeReader sample in pos folder Add new SynpaticsTouch sample in input folder Add new Power Engine Plugin sample in pofx folder Add new DeviceMft sample in avstream folder Add new AvsCamera sample in root Add new SimBatt sample in root Add other pre-existing samples not yet released for Win10
Diffstat (limited to 'avstream/sampledevicemft')
-rw-r--r--avstream/sampledevicemft/README.md31
-rw-r--r--avstream/sampledevicemft/SampleDeviceMft.sln28
-rw-r--r--avstream/sampledevicemft/Source.def5
-rw-r--r--avstream/sampledevicemft/basepin.cpp861
-rw-r--r--avstream/sampledevicemft/basepin.h596
-rw-r--r--avstream/sampledevicemft/common.h697
-rw-r--r--avstream/sampledevicemft/custompin.cpp98
-rw-r--r--avstream/sampledevicemft/custompin.h30
-rw-r--r--avstream/sampledevicemft/dllmain.cpp337
-rw-r--r--avstream/sampledevicemft/mftpeventgenerator.cpp250
-rw-r--r--avstream/sampledevicemft/mftpeventgenerator.h94
-rw-r--r--avstream/sampledevicemft/multipinmft.cpp2376
-rw-r--r--avstream/sampledevicemft/multipinmft.h468
-rw-r--r--avstream/sampledevicemft/multipinmft.vcxproj263
-rw-r--r--avstream/sampledevicemft/multipinmft.vcxproj.Filters46
-rw-r--r--avstream/sampledevicemft/multipinmfthelpers.cpp661
-rw-r--r--avstream/sampledevicemft/multipinmfthelpers.h206
-rw-r--r--avstream/sampledevicemft/multipinmftutils.cpp874
-rw-r--r--avstream/sampledevicemft/stdafx.h38
-rw-r--r--avstream/sampledevicemft/stdafxsrc.cpp1
20 files changed, 7960 insertions, 0 deletions
diff --git a/avstream/sampledevicemft/README.md b/avstream/sampledevicemft/README.md
new file mode 100644
index 00000000..3d5e3914
--- /dev/null
+++ b/avstream/sampledevicemft/README.md
@@ -0,0 +1,31 @@
+Driver Device Transform Sample
+==============================
+Illustrative example for a *Driver Device Transform* which loads in a process streaming an Avstream based camera device using Media Foundation.
+
+A *Driver Device Transform* is a new kind of a transform that's used with a specific camera when capturing video. The *Driver Device Transform* is also known as DeviceMFT because it is the first Device Transform applied to the video source. This *Driver Device Transform* is an alternative to the Driver MFT i.e. MFT0 in that, it caters to the source rather than the streams . An N stream source supporting DeviceMFT will have a single instance of the *Device Driver Transform* loaded, while MFT0 will have *N* instances for each pipeline process. The DeviceMFT can advertise multiple streams at the output, which can differ from the number of streams advertised by the source. This is analogous to having a user mode driver in the MF pipeline which intercepts and processes commands before they enter/ leave the Kernel mode driver loaded for the streaming source.
+
+In this sample, the Device Transform , when enabled, will replicate a photo sequence in the user mode from a one pin device . It acts as a passthrough for sources exposing more than one pins.
+
+This sample is designed to be used with a specific camera. To run the sample, you need the your camera's device ID and device metadata package.
+
+
+Related topics
+--------------
+
+**Concepts**
+
+[Windows Store device apps for cameras](http://go.microsoft.com/fwlink/p/?LinkId=306683)
+
+[Windows 8 device experience](http://go.microsoft.com/fwlink/p/?linkid=241442)
+
+[Media Foundation Transforms](http://msdn.microsoft.com/en-us/library/windows/hardware/ms703138)
+
+[Roadmap for Developing Streaming Media Drivers](http://msdn.microsoft.com/en-us/library/windows/hardware/ff568130)
+
+[Universal camera driver design guide for Windows 10](https://msdn.microsoft.com/en-us/Library/Windows/Hardware/dn937080)
+
+**Samples**
+
+[Windows Store device app for camera sample](http://go.microsoft.com/fwlink/p/?linkid=249442)
+
+[Camera Capture UI sample](http://go.microsoft.com/fwlink/p/?linkid=249441%20) \ No newline at end of file
diff --git a/avstream/sampledevicemft/SampleDeviceMft.sln b/avstream/sampledevicemft/SampleDeviceMft.sln
new file mode 100644
index 00000000..874e9b3c
--- /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", "{FBAACBDA-D207-4158-8497-37F54DD12701}"
+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
+ {FBAACBDA-D207-4158-8497-37F54DD12701}.Debug|Win32.ActiveCfg = Debug|Win32
+ {FBAACBDA-D207-4158-8497-37F54DD12701}.Debug|Win32.Build.0 = Debug|Win32
+ {FBAACBDA-D207-4158-8497-37F54DD12701}.Release|Win32.ActiveCfg = Release|Win32
+ {FBAACBDA-D207-4158-8497-37F54DD12701}.Release|Win32.Build.0 = Release|Win32
+ {FBAACBDA-D207-4158-8497-37F54DD12701}.Debug|x64.ActiveCfg = Debug|x64
+ {FBAACBDA-D207-4158-8497-37F54DD12701}.Debug|x64.Build.0 = Debug|x64
+ {FBAACBDA-D207-4158-8497-37F54DD12701}.Release|x64.ActiveCfg = Release|x64
+ {FBAACBDA-D207-4158-8497-37F54DD12701}.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..30bfcc20
--- /dev/null
+++ b/avstream/sampledevicemft/basepin.cpp
@@ -0,0 +1,861 @@
+#include "stdafx.h"
+#include "common.h"
+#include "multipinmft.h"
+#include "multipinmfthelpers.h"
+#include "basepin.h"
+
+#ifdef MF_WPP
+#include "basepin.tmh"
+#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_Stop, DeviceStreamState_Run, DeviceStreamState_Disabled },
+ { DeviceStreamState_Stop, DeviceStreamState_Pause, DeviceStreamState_Run, DeviceStreamState_Disabled },
+ { DeviceStreamState_Stop, DeviceStreamState_Pause, DeviceStreamState_Run, DeviceStreamState_Disabled },
+ { DeviceStreamState_Disabled, DeviceStreamState_Disabled, DeviceStreamState_Disabled, DeviceStreamState_Disabled }
+};
+
+CBasePin::CBasePin( _In_ ULONG id, _In_ CMultipinMft *parent) :
+ m_StreamId(id)
+ , m_Parent(parent)
+ , m_setMediaType(nullptr)
+ , m_Attributes(nullptr)
+ , m_Ikscontrol(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_Attributes = nullptr;
+}
+
+HRESULT CBasePin::AddMediaType( _Inout_ DWORD *pos, _In_ IMFMediaType *pMediaType)
+{
+ HRESULT hr = S_OK;
+
+ DMFTCHECKNULL_GOTO(pMediaType, done, E_INVALIDARG);
+
+ m_listOfMediaTypes.push_back( pMediaType );
+ 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;
+
+ 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;
+
+ 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_pSourceTransform(nullptr),
+ 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_pSourceTransform = 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_pSourceTransform = 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_pSourceTransform.As( &m_Ikscontrol ), 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_pSourceTransform = 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_pSourceTransform, done, MF_E_TRANSFORM_TYPE_NOT_SET );
+ for (UINT iMediaType = 0; SUCCEEDED(hr) ; iMediaType++)
+ {
+ ComPtr<IMFMediaType> pMediaType = nullptr;
+ hr = m_pSourceTransform->MFTGetOutputAvailableType( uiStreamId, iMediaType, pMediaType.GetAddressOf() );
+ if (hr != S_OK)
+ break;
+ DMFTCHECKHR_GOTO(pMediaType->GetGUID(MF_MT_SUBTYPE, &stSubType),done);
+
+ if (((stSubType == MFVideoFormat_RGB8) || (stSubType == MFVideoFormat_RGB555) ||
+ (stSubType == MFVideoFormat_RGB565) || (stSubType == MFVideoFormat_RGB24) ||
+ (stSubType == MFVideoFormat_RGB32) || (stSubType == MFVideoFormat_ARGB32) ||
+ (stSubType == MFVideoFormat_AI44) || (stSubType == MFVideoFormat_AYUV) ||
+ (stSubType == MFVideoFormat_I420) || (stSubType == MFVideoFormat_IYUV) ||
+ (stSubType == MFVideoFormat_NV11) || (stSubType == MFVideoFormat_NV12) ||
+ (stSubType == MFVideoFormat_UYVY) || (stSubType == MFVideoFormat_Y41P) ||
+ (stSubType == MFVideoFormat_Y41T) || (stSubType == MFVideoFormat_Y42T) ||
+ (stSubType == MFVideoFormat_YUY2) || (stSubType == MFVideoFormat_YV12) ||
+ (stSubType == MFVideoFormat_P010) || (stSubType == MFVideoFormat_P016) ||
+ (stSubType == MFVideoFormat_P210) || (stSubType == MFVideoFormat_P216) ||
+ (stSubType == MFVideoFormat_v210) || (stSubType == MFVideoFormat_v216) ||
+ (stSubType == MFVideoFormat_v410) || (stSubType == MFVideoFormat_Y210) ||
+ (stSubType == MFVideoFormat_Y216) || (stSubType == MFVideoFormat_Y410) ||
+ (stSubType == MFVideoFormat_Y416)) )
+ {
+ DWORD pos = 0;
+ AddMediaType(&pos, pMediaType.Get());
+ }
+ pMediaType = nullptr;
+ }
+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 )
+{
+ 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;
+ IMFAttributes *pAttributes = nullptr;
+
+ 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_Ikscontrol = pIksControl;
+
+ MFCreateAttributes( &pAttributes, 3 ); //Create the space for the attribute store!!
+ setAttributes( pAttributes );
+ 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 );
+ //Set the pin attribute
+
+ SAFE_RELEASE( pAttributes );
+done:
+ ;
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+}
+
+COutPin::~COutPin()
+{
+ CPinQueue *que = NULL;
+ m_Attributes = 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;
+
+ CPinQueue *que = new (std::nothrow) CPinQueue(inputPinId);
+ DMFTCHECKNULL_GOTO( que, done, E_OUTOFMEMORY );
+
+ (void)m_queues.push_back( que );
+ //
+ //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_Ikscontrol->KsProperty(pProperty,
+ ulPropertyLength,
+ pPropertyData,
+ ulDataLength,
+ pBytesReturned);
+}
+
+
+
diff --git a/avstream/sampledevicemft/basepin.h b/avstream/sampledevicemft/basepin.h
new file mode 100644
index 00000000..63b94c2b
--- /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_Ikscontrol!=nullptr )
+ {
+ return m_Ikscontrol->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_Attributes->GetItem(guidKey, pValue);
+ }
+
+ STDMETHOD(GetItemType)(
+ _In_ REFGUID guidKey,
+ _Out_ MF_ATTRIBUTE_TYPE* pType
+ )
+ {
+ return m_Attributes->GetItemType(guidKey, pType);
+ }
+
+ STDMETHOD(CompareItem)(
+ _In_ REFGUID guidKey,
+ _In_ REFPROPVARIANT Value,
+ _Out_ BOOL* pbResult
+ )
+ {
+ return m_Attributes->CompareItem(guidKey, Value, pbResult);
+ }
+
+ STDMETHOD(Compare)(
+ _In_ IMFAttributes* pTheirs,
+ _In_ MF_ATTRIBUTES_MATCH_TYPE MatchType,
+ _Out_ BOOL* pbResult
+ )
+ {
+ return m_Attributes->Compare(pTheirs, MatchType, pbResult);
+ }
+
+ STDMETHOD(GetUINT32)(
+ _In_ REFGUID guidKey,
+ _Out_ UINT32* punValue
+ )
+ {
+ return m_Attributes->GetUINT32(guidKey, punValue);
+ }
+
+ STDMETHOD(GetUINT64)(
+ _In_ REFGUID guidKey,
+ _Out_ UINT64* punValue
+ )
+ {
+ return m_Attributes->GetUINT64(guidKey, punValue);
+ }
+
+ STDMETHOD(GetDouble)(
+ _In_ REFGUID guidKey,
+ _Out_ double* pfValue
+ )
+ {
+ return m_Attributes->GetDouble(guidKey, pfValue);
+ }
+
+ STDMETHOD(GetGUID)(
+ _In_ REFGUID guidKey,
+ _Out_ GUID* pguidValue
+ )
+ {
+ return m_Attributes->GetGUID(guidKey, pguidValue);
+ }
+
+ STDMETHOD(GetStringLength)(
+ _In_ REFGUID guidKey,
+ _Out_ UINT32* pcchLength
+ )
+ {
+ return m_Attributes->GetStringLength(guidKey, pcchLength);
+ }
+
+ STDMETHOD(GetString)(
+ _In_ REFGUID guidKey,
+ _Out_writes_(cchBufSize) LPWSTR pwszValue,
+ _In_ UINT32 cchBufSize,
+ _Inout_opt_ UINT32* pcchLength
+ )
+ {
+ return m_Attributes->GetString(guidKey, pwszValue, cchBufSize, pcchLength);
+ }
+
+ STDMETHOD(GetAllocatedString)(
+ _In_ REFGUID guidKey,
+ _Out_writes_(*pcchLength + 1) LPWSTR* ppwszValue,
+ _Inout_ UINT32* pcchLength
+ )
+ {
+ return m_Attributes->GetAllocatedString(guidKey, ppwszValue, pcchLength);
+ }
+
+ STDMETHOD(GetBlobSize)(
+ _In_ REFGUID guidKey,
+ _Out_ UINT32* pcbBlobSize
+ )
+ {
+ return m_Attributes->GetBlobSize(guidKey, pcbBlobSize);
+ }
+
+ STDMETHOD(GetBlob)(
+ _In_ REFGUID guidKey,
+ _Out_writes_(cbBufSize) UINT8* pBuf,
+ UINT32 cbBufSize,
+ _Inout_ UINT32* pcbBlobSize
+ )
+ {
+ return m_Attributes->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_Attributes->GetAllocatedBlob(guidKey, ppBuf, pcbSize);
+ }
+
+ STDMETHOD(GetUnknown)(
+ __RPC__in REFGUID guidKey,
+ __RPC__in REFIID riid,
+ __RPC__deref_out_opt LPVOID *ppv
+ )
+ {
+ return m_Attributes->GetUnknown(guidKey, riid, ppv);
+ }
+
+ STDMETHOD(SetItem)(
+ _In_ REFGUID guidKey,
+ _In_ REFPROPVARIANT Value
+ )
+ {
+ return m_Attributes->SetItem(guidKey, Value);
+ }
+
+ STDMETHOD(DeleteItem)(
+ _In_ REFGUID guidKey
+ )
+ {
+ return m_Attributes->DeleteItem(guidKey);
+ }
+
+ STDMETHOD(DeleteAllItems)()
+ {
+ return m_Attributes->DeleteAllItems();
+ }
+
+ STDMETHOD(SetUINT32)(
+ _In_ REFGUID guidKey,
+ _In_ UINT32 unValue
+ )
+ {
+ return m_Attributes->SetUINT32(guidKey, unValue);
+ }
+
+ STDMETHOD(SetUINT64)(
+ _In_ REFGUID guidKey,
+ _In_ UINT64 unValue
+ )
+ {
+ return m_Attributes->SetUINT64(guidKey, unValue);
+ }
+
+ STDMETHOD(SetDouble)(
+ _In_ REFGUID guidKey,
+ _In_ double fValue
+ )
+ {
+ return m_Attributes->SetDouble(guidKey, fValue);
+ }
+
+ STDMETHOD(SetGUID)(
+ _In_ REFGUID guidKey,
+ _In_ REFGUID guidValue
+ )
+ {
+ return m_Attributes->SetGUID(guidKey, guidValue);
+ }
+
+ STDMETHOD(SetString)(
+ _In_ REFGUID guidKey,
+ _In_ LPCWSTR wszValue
+ )
+ {
+ return m_Attributes->SetString(guidKey, wszValue);
+ }
+
+ STDMETHOD(SetBlob)(
+ _In_ REFGUID guidKey,
+ _In_reads_(cbBufSize) const UINT8* pBuf,
+ UINT32 cbBufSize
+ )
+ {
+ return m_Attributes->SetBlob(guidKey, pBuf, cbBufSize);
+ }
+
+ STDMETHOD(SetUnknown)(
+ _In_ REFGUID guidKey,
+ _In_ IUnknown* pUnknown
+ )
+ {
+ return m_Attributes->SetUnknown(guidKey, pUnknown);
+ }
+
+ STDMETHOD(LockStore)()
+ {
+ return m_Attributes->LockStore();
+ }
+
+ STDMETHOD(UnlockStore)()
+ {
+ return m_Attributes->UnlockStore();
+ }
+
+ STDMETHOD(GetCount)(
+ _Out_ UINT32* pcItems
+ )
+ {
+ return m_Attributes->GetCount(pcItems);
+ }
+
+ STDMETHOD(GetItemByIndex)(
+ UINT32 unIndex,
+ _Out_ GUID* pguidKey,
+ _Inout_ PROPVARIANT* pValue
+ )
+ {
+ return m_Attributes->GetItemByIndex(unIndex, pguidKey, pValue);
+ }
+
+ STDMETHOD(CopyAllItems)(
+ _In_ IMFAttributes* pDest
+ )
+ {
+ return m_Attributes->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_Attributes = _pAttributes;
+ return S_OK;
+ }
+ __inline CCritSec& lock()
+ {
+ return m_lock;
+ }
+ IMFMediaTypeArray m_listOfMediaTypes;
+ ComPtr<IMFAttributes> m_Attributes;
+ ComPtr<IKsControl> m_Ikscontrol;
+
+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_pSourceTransform; /*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..3959f96b
--- /dev/null
+++ b/avstream/sampledevicemft/common.h
@@ -0,0 +1,697 @@
+//*@@@+++@@@@******************************************************************
+//
+// 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 CameraPostProcessingPluginCLSID value, and set its value to
+// {0E313280-3169-4F41-A329-9E854169634F} for the Pipeline to pick up the Transform. MFT0 and Device
+// Transforms are exclusive and the presence of this key will lead the MFT0 to not load.
+//
+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; \
+}
+
+
diff --git a/avstream/sampledevicemft/custompin.cpp b/avstream/sampledevicemft/custompin.cpp
new file mode 100644
index 00000000..5c983b54
--- /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"
+#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..7445bfbd
--- /dev/null
+++ b/avstream/sampledevicemft/dllmain.cpp
@@ -0,0 +1,337 @@
+//////////////////////////////////////////////////////////////////////////
+//
+// 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"
+#endif
+
+
+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()
+{
+ return (g_cRefModule == 0) ? S_OK : S_FALSE;
+}
+
+_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..b3814260
--- /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"
+#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..31001858
--- /dev/null
+++ b/avstream/sampledevicemft/multipinmft.cpp
@@ -0,0 +1,2376 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#include "stdafx.h"
+#include "multipinmft.h"
+#ifdef MF_WPP
+#include "multipinmft.tmh"
+#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_attributes( nullptr ),
+ m_pSourceTransform( nullptr ),
+ m_PhotoTriggerSent(false),
+ m_filterHasIndependentPin( false ),
+ m_FilterInPhotoSequence( false ),
+ m_AsyncPropEvent( nullptr ),
+ 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_attributes = pAttributes;
+}
+
+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_pSourceTransform = 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();
+ }
+#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_pSourceTransform ), done );
+
+ DMFTCHECKHR_GOTO( m_pSourceTransform.As( &m_ikscontrol ), done );
+
+ DMFTCHECKHR_GOTO( m_pSourceTransform->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_pSourceTransform->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_pSourceTransform->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);
+ }
+ m_InPins.push_back( pInPin );
+
+ DMFTCHECKHR_GOTO( pInPin->Init(m_pSourceTransform.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;
+
+ DMFTCHECKHR_GOTO( piPin->QueryInterface(IID_PPV_ARGS( &pKsControl ) ), done);
+
+ COutPin *poPin = new COutPin( ulIndex, this, pKsControl.Get() );
+ 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);
+
+ m_OutPins.push_back(poPin);
+ }
+ }
+ }
+ }
+
+ 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_pSourceTransform = 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);
+ 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;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART:
+ hr = WarmStartHandler(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_ikscontrol->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_ikscontrol->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.
+ --*/
+{
+ if ((pEvent && (pEvent->Set == KSEVENTSETID_ExtendedCameraControl))
+ && (!filterHasIndependentPin()))
+ {
+ //
+ //Store only for emualted controls..To do!!!
+ //
+ 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:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART:
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Acquiring Event for Async Extended Control");
+ KSEVENTDATA* ksEventData = (KSEVENTDATA*)pEventData;
+ m_AsyncPropEvent = ksEventData->EventHandle.Event;
+ }
+ return S_OK;
+ }
+ }
+ return m_ikscontrol->KsEvent(pEvent,
+ ulEventLength,
+ pEventData,
+ ulDataLength,
+ pBytesReturned);
+}
+
+
+#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_attributes != nullptr)
+ {
+ m_attributes.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
+ //
+ 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 );
+ //
+ //Add the output pin to the input pin.
+ //
+ piPin->ConnectPin( poPin );
+
+ //
+ //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
+ //
+ 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;
+ SetEvent( m_AsyncPropEvent );
+ }
+ 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));
+ //
+ SetEvent(m_AsyncPropEvent);
+ }
+ 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 );
+
+ SetEvent( m_AsyncPropEvent );
+ }
+ 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
+ )
+{
+ 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, 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..b67c4179
--- /dev/null
+++ b/avstream/sampledevicemft/multipinmft.h
@@ -0,0 +1,468 @@
+//*@@@+++@@@@******************************************************************
+//
+// 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"
+
+
+
+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_pSourceTransform.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_pSourceTransform; // The sources transform
+ MFSHUTDOWN_STATUS m_eShutdownStatus;
+ DWORD m_dwWorkQueueId;
+ LONG m_lWorkQueuePriority;
+ UINT32 m_punValue;
+ ComPtr<IKsControl> m_ikscontrol;
+ ComPtr<IMFAttributes> m_attributes;
+
+ 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>
+ HANDLE m_AsyncPropEvent;
+
+#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..2493f021
--- /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>{CD76DACF-18E8-4625-9A09-19B020579A56}</ProjectGuid>
+ <RootNamespace>$(MSBuildProjectName)</RootNamespace>
+ <SupportsPackaging>false</SupportsPackaging>
+ <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <SampleGuid>{6DBDE413-6AD0-40FA-ABE2-273BA6176E9E}</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..4cf74a60
--- /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>{94BAD99E-E9EC-451B-A064-3C99833E8EE5}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files">
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ <UniqueIdentifier>{1308E3EE-C5B2-4417-BD87-A7116D7DD60D}</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>{2DCD9326-19A0-46C1-B32D-00012EB223F3}</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..f2f8fc8a
--- /dev/null
+++ b/avstream/sampledevicemft/multipinmfthelpers.cpp
@@ -0,0 +1,661 @@
+#include "stdafx.h"
+#include "common.h"
+#include "multipinmfthelpers.h"
+#include "multipinmft.h"
+#include "basepin.h"
+#include <wincodec.h>
+
+#ifdef MF_WPP
+#include "multipinmfthelpers.tmh"
+#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();
+ m_sampleList.push_back( 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;
+}
+
+
+
+
diff --git a/avstream/sampledevicemft/multipinmfthelpers.h b/avstream/sampledevicemft/multipinmfthelpers.h
new file mode 100644
index 00000000..a998f483
--- /dev/null
+++ b/avstream/sampledevicemft/multipinmfthelpers.h
@@ -0,0 +1,206 @@
+//*@@@+++@@@@******************************************************************
+//
+// 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;
+};
+
+
diff --git a/avstream/sampledevicemft/multipinmftutils.cpp b/avstream/sampledevicemft/multipinmftutils.cpp
new file mode 100644
index 00000000..d36baa13
--- /dev/null
+++ b/avstream/sampledevicemft/multipinmftutils.cpp
@@ -0,0 +1,874 @@
+//*@@@+++@@@@******************************************************************
+//
+// 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"
+#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 )
+ {
+ 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..58cd95dc
--- /dev/null
+++ b/avstream/sampledevicemft/stdafx.h
@@ -0,0 +1,38 @@
+//
+// Copyright (C) Microsoft. All rights reserved.
+//
+#pragma once
+
+
+#include <SDKDDKVer.h>
+#include <windows.h>
+#include <winnt.h>
+#include <tchar.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