summaryrefslogtreecommitdiff
path: root/avstream/sampledevicemft/SampleSocDeviceMFT.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'avstream/sampledevicemft/SampleSocDeviceMFT.cpp')
-rw-r--r--avstream/sampledevicemft/SampleSocDeviceMFT.cpp1533
1 files changed, 1533 insertions, 0 deletions
diff --git a/avstream/sampledevicemft/SampleSocDeviceMFT.cpp b/avstream/sampledevicemft/SampleSocDeviceMFT.cpp
new file mode 100644
index 00000000..2a91906f
--- /dev/null
+++ b/avstream/sampledevicemft/SampleSocDeviceMFT.cpp
@@ -0,0 +1,1533 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#include "stdafx.h"
+#include "multipinmft.h"
+#ifdef MF_WPP
+#include "multipinmft.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+//
+// Note since MFT_UNIQUE_METHOD_NAMES is defined all the functions of IMFTransform have the Mft suffix..
+//
+extern const CLSID CLSID_HwMFTActivate;
+
+CMultipinMft::CMultipinMft()
+: m_nRefCount( 0 ),
+ m_InputPinCount( 0 ),
+ m_OutputPinCount( 0 ),
+ m_dwWorkQueueId ( MFASYNC_CALLBACK_QUEUE_MULTITHREADED ),
+ m_lWorkQueuePriority ( 0 ),
+ m_spAttributes( nullptr ),
+ m_spSourceTransform( nullptr ),
+ m_SymbolicLink(nullptr)
+{
+ HRESULT hr = S_OK;
+ ComPtr<IMFAttributes> pAttributes = nullptr;
+ MFCreateAttributes( &pAttributes, 0 );
+ DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MF_TRANSFORM_ASYNC, TRUE ),done);
+ DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE ),done);
+ DMFTCHECKHR_GOTO(pAttributes->SetUINT32( MF_SA_D3D_AWARE, TRUE ), done);
+ DMFTCHECKHR_GOTO(pAttributes->SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"SampleMultiPinMft" ),done);
+ m_spAttributes = pAttributes;
+done:
+ if (FAILED(hr))
+ {
+
+ }
+}
+
+CMultipinMft::~CMultipinMft( )
+{
+
+
+ for ( ULONG ulIndex = 0, ulSize = (ULONG) m_InPins.size(); ulIndex < ulSize; ulIndex++ )
+ {
+ SAFERELEASE(m_InPins[ ulIndex ]);
+ }
+ m_InPins.clear();
+ for (ULONG ulIndex = 0, ulSize = (ULONG) m_OutPins.size(); ulIndex < ulSize; ulIndex++)
+ {
+ SAFERELEASE(m_OutPins[ ulIndex ]);
+ }
+ m_OutPins.clear();
+ SAFE_ARRAYDELETE(m_SymbolicLink);
+ m_spSourceTransform = nullptr;
+
+}
+
+STDMETHODIMP_(ULONG) CMultipinMft::AddRef(
+ void
+ )
+{
+ return InterlockedIncrement(&m_nRefCount);
+}
+
+STDMETHODIMP_(ULONG) CMultipinMft::Release(
+ void
+ )
+{
+ ULONG uCount = InterlockedDecrement(&m_nRefCount);
+
+ if ( uCount == 0 )
+ {
+ delete this;
+ }
+ return uCount;
+}
+
+STDMETHODIMP CMultipinMft::QueryInterface(
+ _In_ REFIID iid,
+ _COM_Outptr_ void** ppv
+ )
+{
+
+ HRESULT hr = S_OK;
+ *ppv = NULL;
+
+ if ((iid == __uuidof(IMFDeviceTransform)) || (iid == __uuidof(IUnknown)))
+ {
+ *ppv = static_cast< IMFDeviceTransform* >(this);
+ }
+ else if ( iid == __uuidof( IMFMediaEventGenerator ) )
+ {
+ *ppv = static_cast< IMFMediaEventGenerator* >(this);
+ }
+ else if ( iid == __uuidof( IMFShutdown ) )
+ {
+ *ppv = static_cast< IMFShutdown* >( this );
+ }
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+ else if (iid == __uuidof(IMFTransform))
+ {
+ *ppv = static_cast< IMFTransform* >(this);
+ }
+#endif
+ else if ( iid == __uuidof( IKsControl ) )
+ {
+ *ppv = static_cast< IKsControl* >( this );
+ }
+ else if ( iid == __uuidof( IMFRealTimeClientEx ) )
+ {
+ *ppv = static_cast< IMFRealTimeClientEx* >( this );
+ }
+
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+ else if (iid == __uuidof(IMFSampleAllocatorControl))
+ {
+ *ppv = static_cast<IMFSampleAllocatorControl*>(this);
+ }
+#endif
+ else
+ {
+ hr = E_NOINTERFACE;
+ goto done;
+ }
+ AddRef();
+done:
+ return hr;
+}
+
+/*++
+ Description:
+ This function is the entry point of the transform
+ The following things may be initialized here
+ 1) Query for MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL on the attributes supplied
+ 2) From the IUnknown acquired get the IMFTransform interface.
+ 3) Get the stream count.. The output streams are of consequence to the tranform.
+ The input streams should correspond to the output streams exposed by the source transform
+ acquired from the Attributes supplied.
+ 4) Get the IKSControl which is used to send KSPROPERTIES, KSEVENTS and KSMETHODS to the driver for the filer level. Store it in your filter class
+ 5) Get the OutPutStreamAttributes for the output pins of the source transform. This can further be used to QI and acquire
+ the IKSControl related to the specific pin. This can be used to send PIN level KSPROPERTIES, EVENTS and METHODS to the pins
+ 6) Create the output pins
+
+--*/
+
+// This sample will create a grayscale for known media types. Please remove MF_DEVICEMFT_ADD_GRAYSCALER_ to remove the grayscaler
+// This sample also has photo confirmation enabled remove DMF_DEVICEMFT_PHTOTOCONFIRMATION to remove photo confirmation
+// Please search for the @@@@ README tag for critical sections in code and it's documentation
+//
+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;
+ ULONG ulOutPinIndex = 0;
+ UINT32 uiSymLinkLen = 0;
+ CPinCreationFactory* pPinFactory = new (std::nothrow) CPinCreationFactory(this);
+ DMFTCHECKNULL_GOTO( pAttributes, done, E_INVALIDARG );
+ //
+ // The attribute passed with MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL is the source transform. This generally represents a filter
+ // This needs to be stored so that we know the device properties. We cache it. We query for the IKSControl which is used to send
+ // controls to the driver.
+ //
+ DMFTCHECKHR_GOTO( pAttributes->GetUnknown( MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL,IID_PPV_ARGS( &spFilterUnk ) ),done );
+
+ if (SUCCEEDED(pAttributes->GetStringLength(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &uiSymLinkLen))) // Not available prior to RS5
+ {
+ m_SymbolicLink = new (std::nothrow) WCHAR[++uiSymLinkLen];
+ DMFTCHECKNULL_GOTO(m_SymbolicLink, done, E_OUTOFMEMORY);
+ DMFTCHECKHR_GOTO(pAttributes->GetString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, m_SymbolicLink, uiSymLinkLen, &uiSymLinkLen), done);
+ }
+
+ DMFTCHECKHR_GOTO( spFilterUnk.As( &m_spSourceTransform ), done );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform.As( &m_spIkscontrol ), done );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform->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 (std::nothrow) DWORD[ inputStreams ];
+ DMFTCHECKNULL_GOTO( pcInputStreams, done, E_OUTOFMEMORY);
+
+ pcOutputStreams = new (std::nothrow) DWORD[ outputStreams ];
+ DMFTCHECKNULL_GOTO( pcOutputStreams, done, E_OUTOFMEMORY );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform->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;
+ BOOL bCustom = FALSE;
+ ComPtr<CInPin> spInPin;
+
+ DMFTCHECKHR_GOTO(pPinFactory->CreatePin(
+ pcOutputStreams[ulIndex], /*Input Pin ID as advertised by the pipeline*/
+ 0, /*This is not needed for Input Pin*/
+ CPinCreationFactory::DMFT_PIN_INPUT, /*Input Pin*/
+ (CBasePin**)spInPin.GetAddressOf(),
+ bCustom), done);
+ if (bCustom)
+ {
+ m_CustomPinCount++;
+ }
+ hr = ExceptionBoundary([&]()
+ {
+ m_InPins.push_back(spInPin.Get());
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ DMFTCHECKHR_GOTO( spInPin->Init(m_spSourceTransform.Get() ), done);
+ spInPin.Detach();
+ }
+
+ //
+ // Create one on one mapping
+ //
+ for (ULONG ulIndex = 0; ulIndex < m_InPins.size(); ulIndex++)
+ {
+
+ ComPtr<COutPin> spoPin;
+ BOOL bCustom = FALSE;
+ ComPtr<CInPin> spiPin = ( CInPin * )m_InPins[ ulIndex ];
+
+ if (spiPin.Get())
+ {
+ BOOL isCustom = false;
+ if (SUCCEEDED(CheckCustomPin(spiPin.Get(), &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;
+ }
+
+ DMFTCHECKHR_GOTO(pPinFactory->CreatePin(spiPin->streamId(), /*Input Pin connected to the Output Pin*/
+ ulOutPinIndex, /*Output pin Id*/
+ CPinCreationFactory::DMFT_PIN_OUTPUT, /*Output pin */
+ (CBasePin**)spoPin.ReleaseAndGetAddressOf(),
+ bCustom), done);
+ hr = BridgeInputPinOutputPin(spiPin.Get(), spoPin.Get());
+ if (SUCCEEDED(hr))
+ {
+ DMFTCHECKHR_GOTO(ExceptionBoundary([&]()
+ {
+ m_OutPins.push_back(spoPin.Get());
+ }), done);
+ spoPin.Detach();
+ ulOutPinIndex++;
+ hr = S_OK;
+ }
+ if (hr == MF_E_INVALID_STREAM_DATA)
+ {
+ // Skip the pin which doesn't have any mediatypes exposed
+ hr = S_OK;
+ }
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+ }
+
+ }
+
+ m_InputPinCount = ULONG ( m_InPins.size() );
+ m_OutputPinCount = ULONG ( m_OutPins.size() );
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!",hr,hr);
+
+ if ( pcInputStreams )
+ {
+ delete[ ] ( pcInputStreams );
+ }
+ if ( pcOutputStreams )
+ {
+ delete[ ] ( pcOutputStreams );
+ }
+ if ( outGuids )
+ {
+ delete [] ( outGuids );
+ }
+ SAFE_DELETE(pPinFactory);
+ if ( FAILED( hr ) )
+ {
+ //Release the pins and the resources acquired
+ for (ULONG ulIndex = 0, ulSize = (ULONG)m_InPins.size(); ulIndex < ulSize; ulIndex++)
+ {
+ SAFERELEASE(m_InPins[ulIndex]);
+ }
+ m_InPins.clear();
+ for (ULONG ulIndex = 0, ulSize = (ULONG)m_OutPins.size(); ulIndex < ulSize; ulIndex++)
+ {
+ SAFERELEASE(m_OutPins[ulIndex]);
+ }
+ m_OutPins.clear();
+ //
+ // Simply clear the custom pins since the input pins must have deleted the pin
+ //
+ m_spSourceTransform = nullptr;
+ m_spIkscontrol = nullptr;
+ }
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::SetWorkQueueEx(
+ _In_ DWORD dwWorkQueueId,
+ _In_ LONG lWorkItemBasePriority
+ )
+/*++
+ Description:
+
+ Implements IMFRealTimeClientEx::SetWorkQueueEx function
+
+--*/
+{
+ CAutoLock lock( m_critSec );
+ //
+ // Cache the WorkQueuId and WorkItemBasePriority. This is called once soon after the device MFT is initialized
+ //
+ m_dwWorkQueueId = dwWorkQueueId;
+ m_lWorkQueuePriority = lWorkItemBasePriority;
+ // Set it on the pins
+ for (DWORD dwIndex = 0; dwIndex < (DWORD)m_InPins.size(); dwIndex++)
+ {
+ m_InPins[dwIndex]->SetWorkQueue(dwWorkQueueId);
+ }
+ for (DWORD dwIndex = 0; dwIndex < (DWORD)m_OutPins.size(); dwIndex++)
+ {
+ m_OutPins[dwIndex]->SetWorkQueue(dwWorkQueueId);
+ }
+ return S_OK;
+
+}
+
+//
+// IMFDeviceTransform functions
+//
+STDMETHODIMP CMultipinMft::GetStreamCount(
+ _Inout_ DWORD *pdwInputStreams,
+ _Inout_ DWORD *pdwOutputStreams
+ )
+/*++
+ Description: Implements IMFTransform::GetStreamCount function
+--*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+ DMFTCHECKNULL_GOTO(pdwInputStreams, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(pdwOutputStreams, done, E_INVALIDARG);
+ *pdwInputStreams = m_InputPinCount;
+ *pdwOutputStreams = m_OutputPinCount;
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+done:
+ return hr;
+}
+
+//
+//Doesn't strictly conform to the GetStreamIDs on IMFTransform Interface!
+//
+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);
+ 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;
+
+ ComPtr<CInPin> spiPin = GetInPin( dwInputStreamID );
+ DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO( spiPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ *ppMediaType = nullptr;
+
+ hr = spiPin->GetOutputAvailableType( dwTypeIndex,ppMediaType );
+
+ if (FAILED(hr))
+ {
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!",
+ dwInputStreamID,
+ dwTypeIndex,
+ hr);
+ }
+
+done:
+ return hr;
+}
+
+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;
+ CAutoLock Lock(m_critSec);
+
+ ComPtr<COutPin> spoPin = GetOutPin( dwOutputStreamID );
+
+ DMFTCHECKNULL_GOTO( spoPin.Get(), done, MF_E_INVALIDSTREAMNUMBER );
+ DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG);
+
+ *ppMediaType = nullptr;
+
+ hr = spoPin->GetOutputAvailableType( dwTypeIndex, ppMediaType );
+
+ if ( FAILED( hr ) )
+ {
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!",
+ dwOutputStreamID,
+ dwTypeIndex,
+ hr );
+ }
+
+done:
+ return hr;
+}
+
+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;
+ ComPtr<COutPin> spoPin;
+ CAutoLock lock( m_critSec );
+
+ DMFTCHECKNULL_GOTO( ppMediaType, done, E_INVALIDARG );
+
+ *ppMediaType = nullptr;
+
+ spoPin = GetOutPin( dwOutputStreamID );
+
+ DMFTCHECKNULL_GOTO(spoPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ DMFTCHECKHR_GOTO(spoPin->getMediaType( ppMediaType ),done );
+
+ DMFTCHECKNULL_GOTO( *ppMediaType, done, MF_E_TRANSFORM_TYPE_NOT_SET );
+
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+
+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;
+
+ 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");
+ }
+ //
+ // set it on the pins. Can happen anytime
+ //
+ for (DWORD dwIndex = 0; dwIndex < (DWORD)m_InPins.size(); dwIndex++)
+ {
+ m_InPins[dwIndex]->SetD3DManager(m_spDeviceManagerUnk.Get());
+ }
+ for (DWORD dwIndex = 0; dwIndex < (DWORD)m_OutPins.size(); dwIndex++)
+ {
+ m_OutPins[dwIndex]->SetD3DManager(m_spDeviceManagerUnk.Get());
+ }
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ {
+ SetStreamingState( DeviceStreamState_Run );
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_END_STREAMING:
+ {
+ SetStreamingState(DeviceStreamState_Stop);
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
+ {
+ SetStreamingState(DeviceStreamState_Stop);
+ }
+ break;
+ default:
+ ;
+ }
+
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+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 );
+
+ ComPtr<CInPin> spInPin = GetInPin( dwInputStreamID );
+ DMFTCHECKNULL_GOTO(spInPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ if ( !IsStreaming() )
+ {
+ goto done;
+ }
+
+ DMFTCHECKHR_GOTO(spInPin->SendSample( pSample ), done );
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ //
+ //@@@@ README : There is a bug in the sample that the device transform manager which manages the
+ // device MFT does not release the sample after passing it to Device MFT in processInput like it should. The
+ // Device MFT therefore unfortunately has to make sure that the sample that leaves processoutput has a reference count of 1
+ //
+ SAFE_RELEASE(pSample);
+ return hr;
+
+}
+
+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;
+ ComPtr<COutPin> spOpin;
+ UNREFERENCED_PARAMETER( dwFlags );
+
+ if (cOutputBufferCount > m_OutputPinCount )
+ {
+ DMFTCHECKHR_GOTO( E_INVALIDARG, done );
+ }
+ *pdwStatus = 0;
+
+ for ( DWORD i = 0; i < cOutputBufferCount; i++ )
+ {
+ DWORD dwStreamID = pOutputSamples[i].dwStreamID;
+ {
+ CAutoLock _lock(m_critSec);
+ spOpin = nullptr;
+ spOpin = GetOutPin(dwStreamID);
+ GUID pinGuid = GUID_NULL;
+ DMFTCHECKNULL_GOTO(spOpin.Get(), done, E_INVALIDARG);
+ }
+ if ( SUCCEEDED(spOpin->ProcessOutput( dwFlags, &pOutputSamples[i],
+ pdwStatus ) ) )
+ {
+ 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;
+ ComPtr<CInPin> spIPin;
+
+ DMFTCHECKNULL_GOTO( ppAttributes, done, E_INVALIDARG );
+ *ppAttributes = nullptr;
+
+ spIPin = GetInPin( dwInputStreamID );
+
+ DMFTCHECKNULL_GOTO(spIPin, done, E_INVALIDARG );
+
+ hr = spIPin->getPinAttributes(ppAttributes);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+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;
+ ComPtr<COutPin> spoPin;
+
+ DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG);
+
+ *ppAttributes = nullptr;
+
+ spoPin = GetOutPin(dwOutputStreamID);
+
+ DMFTCHECKNULL_GOTO(spoPin, done, E_INVALIDARG );
+
+ DMFTCHECKHR_GOTO(spoPin->getPinAttributes(ppAttributes), done );
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+_Requires_no_locks_held_
+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;
+ CAutoLock Lock(m_critSec);
+ ComPtr<CInPin> spiPin = GetInPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(spiPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ DMFTCHECKHR_GOTO(spiPin->SetInputStreamState(pMediaType, value, dwFlags),done);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value
+ )
+{
+ HRESULT hr = S_OK;
+ ComPtr<CInPin> piPin = GetInPin(dwStreamID);
+
+ DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ *value = piPin->GetState();
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+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 *pState
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::GetOutputStreamState function.
+ Gets the output stream state.
+ Called by the DTM to checks states. Atomic operation. needs a lock
+ --*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+
+ ComPtr<COutPin> spoPin = GetOutPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(pState, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(spoPin, done, MF_E_INVALIDSTREAMNUMBER);
+ *pState = spoPin->GetState();
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+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;
+ ComPtr<CInPin> spiPin = GetInPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(spiPin, done, MF_E_INVALIDSTREAMNUMBER);
+ hr = spiPin->GetInputStreamPreferredState(value, ppMediaType);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+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);
+
+ ComPtr<COutPin> spoPin = GetOutPin(dwStreamIndex);
+ DMFTCHECKNULL_GOTO(spoPin, done, E_INVALIDARG);
+ DeviceStreamState oldState = spoPin->SetState(DeviceStreamState_Disabled);
+ DMFTCHECKHR_GOTO(spoPin->FlushQueues(),done);
+ spoPin->SetState(oldState);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+/*++
+ Description:
+
+ Called when the Device Transform gets a MFT_MESSAGE_COMMAND_FLUSH. We drain all the queues.
+ This is called in device source when the source gets end of streaming.
+ --*/
+STDMETHODIMP_(VOID) CMultipinMft::FlushAllStreams(
+ VOID
+ )
+{
+ DeviceStreamState oldState;
+ CAutoLock Lock(m_critSec);
+ for ( DWORD dwIndex = 0, dwSize = (DWORD)m_OutPins.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ ComPtr<COutPin> spoPin = (COutPin *)m_OutPins[dwIndex];
+ oldState = spoPin->SetState(DeviceStreamState_Disabled);
+ spoPin->FlushQueues();
+ //
+ //Restore state
+ //
+ spoPin->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))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Extended Control %d Passed ",pProperty->Id);
+ }
+ else if ((IsEqualCLSID(pProperty->Set, PROPSETID_VIDCAP_VIDEOCONTROL)) && (pProperty->Id == KSPROPERTY_VIDEOCONTROL_MODE))
+ {
+ // A function illustrating how we can capture and service photos from the device MFT. This block shows how we can
+ // intercept Photo triggers going down to the pipeline
+
+ if (sizeof(KSPROPERTY_VIDEOCONTROL_MODE_S) == ulDataLength)
+ {
+ PKSPROPERTY_VIDEOCONTROL_MODE_S VideoControl = (PKSPROPERTY_VIDEOCONTROL_MODE_S)pvPropertyData;
+ m_PhotoModeIsPhotoSequence = false;
+ if (VideoControl->Mode == KS_VideoControlFlag_StartPhotoSequenceCapture)
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Starting PhotoSequence Trigger");
+ m_PhotoModeIsPhotoSequence = true;
+ }
+ else if (VideoControl->Mode == KS_VideoControlFlag_StopPhotoSequenceCapture)
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Stopping PhotoSequence Trigger");
+ m_PhotoModeIsPhotoSequence = false;
+ }
+ else
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Take Single Photo Trigger");
+ }
+ }
+ }
+ DMFTCHECKHR_GOTO(m_spIkscontrol->KsProperty(pProperty,
+ ulPropertyLength,
+ pvPropertyData,
+ ulDataLength,
+ pulBytesReturned),done);
+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. We can trap ksmethod calls here.
+ --*/
+{
+ return m_spIkscontrol->KsMethod(
+ pMethod,
+ ulPropertyLength,
+ pvPropertyData,
+ ulDataLength,
+ pulBytesReturned
+ );
+}
+
+STDMETHODIMP CMultipinMft::KsEvent(
+ _In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ )
+ /*++
+ Description:
+
+ Implements IKSProperty::KsEvent function.
+ --*/
+{
+
+ HRESULT hr = S_OK;
+ {
+
+ //
+ // All the Events we don't handle should be sent to the driver!
+ //
+ hr = m_spIkscontrol->KsEvent(pEvent,
+ ulEventLength,
+ pEventData,
+ ulDataLength,
+ pBytesReturned);
+ }
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+#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;
+ CAutoLock Lock(m_critSec);
+ DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG);
+
+ *ppAttributes = nullptr;
+
+ if (m_spAttributes != nullptr)
+ {
+ m_spAttributes.CopyTo(ppAttributes);
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+
+done:
+ return hr;
+}
+#endif
+
+#if ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+//
+// IMFSampleAllocatorControl Inferface function declarations
+//
+
+STDMETHODIMP CMultipinMft::SetDefaultAllocator(
+ _In_ DWORD dwOutputStreamID,
+ _In_ IUnknown *pAllocator
+)
+{
+ CAutoLock Lock(m_critSec);
+
+ // SetAllocator will be called on the streamId that returns MFSampleAllocatorMode_Default
+ wil::com_ptr_nothrow<COutPin> outPin = GetOutPin(dwOutputStreamID);
+ RETURN_HR_IF_NULL(E_INVALIDARG, outPin);
+ RETURN_HR_IF_NULL(E_INVALIDARG, pAllocator);
+
+ wil::com_ptr_nothrow<IMFVideoSampleAllocator> defaultAllocator;
+ RETURN_IF_FAILED(pAllocator->QueryInterface(&defaultAllocator));
+ outPin->SetAllocator(defaultAllocator.get());
+
+ return S_OK;
+}
+
+STDMETHODIMP CMultipinMft::GetAllocatorUsage(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ DWORD* pdwInputStreamID,
+ _Out_ MFSampleAllocatorUsage* peUsage
+)
+{
+ CAutoLock Lock(m_critSec);
+
+ RETURN_HR_IF_NULL(E_INVALIDARG, peUsage);
+
+ wil::com_ptr_nothrow<COutPin> outPin = GetOutPin(dwOutputStreamID);
+ RETURN_HR_IF_NULL(MF_E_INVALIDSTREAMNUMBER, outPin);
+ *peUsage = outPin->GetSampleAllocatorUsage();
+
+ if (*peUsage == MFSampleAllocatorUsage_DoesNotAllocate)
+ {
+ RETURN_HR_IF_NULL(E_INVALIDARG, pdwInputStreamID);
+ RETURN_IF_FAILED(GetConnectedInpin((ULONG)dwOutputStreamID, *(ULONG*)pdwInputStreamID));
+ }
+
+ return S_OK;
+}
+#endif // ((defined NTDDI_WIN10_VB) && (NTDDI_VERSION >= NTDDI_WIN10_VB))
+
+//
+// HELPER FUNCTIONS
+//
+
+//
+// A lock here could mean a deadlock because this will be called when the lock is already held
+// in another thread.
+//
+CInPin* CMultipinMft::GetInPin(
+ _In_ DWORD dwStreamId
+)
+{
+ CInPin *inPin = NULL;
+ for (DWORD dwIndex = 0, dwSize = (DWORD)m_InPins.size(); dwIndex < dwSize; dwIndex++)
+ {
+ inPin = (CInPin *)m_InPins[dwIndex];
+ if (dwStreamId == inPin->streamId())
+ {
+ break;
+ }
+ inPin = NULL;
+ }
+ return inPin;
+}
+
+COutPin* CMultipinMft::GetOutPin(
+ _In_ DWORD dwStreamId
+ )
+{
+ COutPin *outPin = NULL;
+ for ( DWORD dwIndex = 0, dwSize = (DWORD) m_OutPins.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ outPin = ( COutPin * )m_OutPins[ dwIndex ];
+
+ if ( dwStreamId == outPin->streamId() )
+ {
+ break;
+ }
+
+ outPin = NULL;
+ }
+
+ return outPin;
+}
+_Requires_lock_held_(m_Critsec)
+HRESULT CMultipinMft::GetConnectedInpin(_In_ ULONG ulOutpin, _Out_ ULONG &ulInPin)
+{
+ HRESULT hr = S_OK;
+ map<int, int>::iterator it = m_outputPinMap.find(ulOutpin);
+ if (it != m_outputPinMap.end())
+ {
+ ulInPin = it->second;
+ }
+ else
+ {
+ hr = MF_E_INVALIDSTREAMNUMBER;
+ }
+ return hr;
+}
+
+//
+// The Below function changes media type on the pins exposed by device MFT
+//
+__requires_lock_held(m_critSec)
+HRESULT CMultipinMft::ChangeMediaTypeEx(
+ _In_ ULONG pinId,
+ _In_opt_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState reqState
+)
+{
+ HRESULT hr = S_OK;
+ ComPtr<COutPin> spoPin = GetOutPin(pinId);
+ ComPtr<CInPin> spinPin;
+ DeviceStreamState oldOutPinState, oldInputStreamState, newOutStreamState, newRequestedInPinState;
+ ComPtr<IMFMediaType> pFullType, pInputMediaType;
+ ULONG ulInPinId = 0;
+ DWORD dwFlags = 0;
+
+
+ DMFTCHECKNULL_GOTO(spoPin, done, E_INVALIDARG);
+ {
+ //
+ // dump the media types to the logs
+ //
+ ComPtr<IMFMediaType> spOldMediaType;
+ (VOID)spoPin->getMediaType(spOldMediaType.GetAddressOf());
+ CMediaTypePrinter newType(pMediaType);
+ CMediaTypePrinter oldType(spOldMediaType.Get());
+ if (WPP_LEVEL_ENABLED(DMFT_GENERAL))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, " Pin:%d old MT:[%s] St:%d", pinId, oldType.ToString(), reqState);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, " Pin:%d new MT:[%s] St:%d", pinId, newType.ToString(), reqState);
+ }
+ }
+
+ if (pMediaType)
+ {
+ if (!spoPin->IsMediaTypeSupported(pMediaType, &pFullType))
+ {
+ DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done);
+ }
+ }
+
+ DMFTCHECKHR_GOTO(GetConnectedInpin(pinId, ulInPinId), done);
+ spinPin = GetInPin(ulInPinId); // Get the input pin
+
+ (VOID)spinPin->getMediaType(&pInputMediaType);
+ oldInputStreamState = spinPin->SetState(DeviceStreamState_Disabled); // Disable input pin
+ oldOutPinState = spoPin->SetState(DeviceStreamState_Disabled); // Disable output pin
+ (void)spoPin->FlushQueues(); // Flush the output queues
+ (void)spinPin->FlushQueues(); // Flush the input queues
+ newOutStreamState = pinStateTransition[oldOutPinState][reqState]; // New state needed
+
+ // The Old input and the output pin states should be the same
+ newRequestedInPinState = newOutStreamState;
+
+ if ((newOutStreamState != oldOutPinState) /*State change*/
+ ||((pFullType.Get() != nullptr) && (pInputMediaType.Get()!=nullptr) && (S_OK != (pFullType->IsEqual(pInputMediaType.Get(), &dwFlags)))) /*Media Types dont match*/
+ ||((pFullType == nullptr)||(pInputMediaType == nullptr))/*Either one of the mediatypes is null*/
+ )
+ {
+ //
+ // State has change or media type has changed so we need to change the media type on the
+ // underlying kernel pin
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "Changing Mediatype on the input ");
+ spinPin->setPreferredMediaType(pFullType.Get());
+ spinPin->setPreferredStreamState(newRequestedInPinState);
+ // Let the pipline know that the input needs to be changed.
+ SendEventToManager(METransformInputStreamStateChanged, GUID_NULL, spinPin->streamId());
+ //
+ // The media type will be set on the input pin by the time we return from the wait
+ //
+ m_critSec.Unlock();
+ hr = spinPin->WaitForSetInputPinMediaChange();
+ m_critSec.Lock();
+ // Change the media type on the output..
+ DMFTCHECKHR_GOTO(spoPin->ChangeMediaTypeFromInpin(pFullType.Get(), pMediaType , reqState), done);
+ //
+ // Notify the pipeline that the output stream media type has changed
+ //
+ DMFTCHECKHR_GOTO(SendEventToManager(MEUnknown, MEDeviceStreamCreated, spoPin->streamId()), done);
+ spoPin->SetFirstSample(TRUE);
+ }
+ else
+ {
+ // Restore back old states as we have nothing to do
+ spinPin->SetState(oldInputStreamState);
+ spoPin->SetState(oldOutPinState);
+ }
+
+
+done:
+ return hr;
+}
+
+//
+// The below function sends events to the pipeline.
+//
+
+HRESULT CMultipinMft::SendEventToManager(
+ _In_ MediaEventType eventType,
+ _In_ REFGUID pGuid,
+ _In_ UINT32 context
+ )
+ /*++
+ Description:
+ Used to send the event to DTM.
+ --*/
+ {
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaEvent> pEvent = nullptr;
+
+ DMFTCHECKHR_GOTO(MFCreateMediaEvent(eventType, pGuid, S_OK, NULL, &pEvent ),done);
+ DMFTCHECKHR_GOTO(pEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, (ULONG)context),done);
+ DMFTCHECKHR_GOTO(QueueEvent(pEvent.Get()),done);
+ done:
+
+ return hr;
+ }
+/*++
+Description:
+This function connects the input and output pins.
+Any media type filtering can happen here
+--*/
+HRESULT CMultipinMft::BridgeInputPinOutputPin(
+ _In_ CInPin* piPin,
+ _In_ COutPin* poPin
+ )
+{
+ HRESULT hr = S_OK;
+ ULONG ulIndex = 0;
+ ULONG ulAddedMediaTypeCount = 0;
+ ComPtr<IMFMediaType> spMediaType;
+
+ DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG );
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+ //
+ // Copy over the media types from input pin to output pin. Since there is no
+ // decoder support, only the uncompressed media types are inserted. Please make
+ // sure any pin advertised supports at least one media type. The pipeline doesn't
+ // like pins with no media types
+ //
+ while ( SUCCEEDED( hr = piPin->GetMediaTypeAt( ulIndex++, spMediaType.ReleaseAndGetAddressOf() )))
+ {
+ GUID subType = GUID_NULL;
+ DMFTCHECKHR_GOTO( spMediaType->GetGUID(MF_MT_SUBTYPE,&subType), done );
+ {
+ DMFTCHECKHR_GOTO(hr = poPin->AddMediaType(NULL, spMediaType.Get() ), done );
+ if (hr == S_OK)
+ {
+ ulAddedMediaTypeCount++;
+ }
+ }
+ }
+ if (ulAddedMediaTypeCount == 0)
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Make Sure Pin %d has one media type exposed ", piPin->streamId());
+ DMFTCHECKHR_GOTO( MF_E_INVALID_STREAM_DATA, done );
+ }
+ //
+ //Add the Input Pin to the output Pin
+ //
+ DMFTCHECKHR_GOTO(poPin->AddPin(piPin->streamId()), done);
+ hr = ExceptionBoundary([&](){
+ //
+ // Add the output pin to the input pin.
+ // Create the pin map. So that we know which pin input pin is connected to which output pin
+ //
+ piPin->ConnectPin(poPin);
+ m_outputPinMap.insert(std::pair< int, int >(poPin->streamId(), piPin->streamId()));
+ });
+
+
+
+done:
+ //
+ //Failed adding media types
+ //
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ }
+ return hr;
+}
+
+//
+// IMFShutdown interface functions
+//
+
+/*++
+Description:
+Implements the Shutdown from IMFShutdown
+--*/
+STDMETHODIMP CMultipinMft::Shutdown(
+ void
+ )
+{
+ CAutoLock Lock(m_critSec);
+ (VOID) m_eventHandler.Clear();
+
+ for (ULONG ulIndex = 0, ulSize = (ULONG)m_InPins.size(); ulIndex < ulSize; ulIndex++ )
+ {
+ CInPin *pInPin = static_cast<CInPin *>(m_InPins[ulIndex]);
+
+ // Deref on the connected outpins to break reference loop
+ (VOID)pInPin->ShutdownPin();
+ }
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+ for (ULONG ulIndex = 0, ulSize = (ULONG)m_OutPins.size(); ulIndex < ulSize; ulIndex++)
+ {
+ (VOID) m_OutPins[ulIndex]->DeleteItem(MF_DEVICESTREAM_EXTENSION_PLUGIN_CONNECTION_POINT);
+ }
+#endif
+ 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;
+}