summaryrefslogtreecommitdiff
path: root/AVStream/sampledevicemft/multipinmft.cpp
diff options
context:
space:
mode:
authorWei Mao <[email protected]>2017-03-17 19:47:04 -0700
committerWei Mao <[email protected]>2017-03-17 19:47:04 -0700
commit1a3e0d580380e58bf336a242d2affc8a1e2d1ddf (patch)
treebf5d9c5b0b4cba1b81726b9f78c4d5ff5c636fea /AVStream/sampledevicemft/multipinmft.cpp
parentda21c8784c83c5fd614f3030323e229d6a5fb10e (diff)
Fix cases
Diffstat (limited to 'AVStream/sampledevicemft/multipinmft.cpp')
-rw-r--r--AVStream/sampledevicemft/multipinmft.cpp2453
1 files changed, 2453 insertions, 0 deletions
diff --git a/AVStream/sampledevicemft/multipinmft.cpp b/AVStream/sampledevicemft/multipinmft.cpp
new file mode 100644
index 00000000..ea7fd892
--- /dev/null
+++ b/AVStream/sampledevicemft/multipinmft.cpp
@@ -0,0 +1,2453 @@
+//*@@@+++@@@@******************************************************************
+//
+// Microsoft Windows Media Foundation
+// Copyright (C) Microsoft Corporation. All rights reserved.
+//
+//*@@@---@@@@******************************************************************
+//
+
+#include "stdafx.h"
+#include "multipinmft.h"
+#ifdef MF_WPP
+#include "multipinmft.tmh" //--REF_ANALYZER_DONT_REMOVE--
+#endif
+//
+//Note since MFT_UNIQUE_METHOD_NAMES is defined all the functions of IMFTransform have the Mft suffix..
+//
+extern const CLSID CLSID_HwMFTActivate;
+
+#if _NEED_MFTLOCKING_
+#define MFTLOCKED() {\
+ UINT32 punValue = FALSE; \
+ hr = GetUINT32(MF_TRANSFORM_ASYNC_UNLOCK, &punValue);\
+if (FAILED(hr) || punValue == FALSE){\
+ return MF_E_TRANSFORM_ASYNC_LOCKED; \
+}\
+}
+#else
+
+#define MFTLOCKED()
+
+#endif
+
+CMultipinMft::CMultipinMft()
+: m_nRefCount( 0 ),
+ m_InputPinCount( 0 ),
+ m_OutputPinCount( 0 ),
+ m_dwWorkQueueId ( MFASYNC_CALLBACK_QUEUE_MULTITHREADED ),
+ m_lWorkQueuePriority ( 0 ),
+ m_spAttributes( nullptr ),
+ m_spSourceTransform( nullptr ),
+ m_PhotoTriggerSent(false),
+ m_filterHasIndependentPin( false ),
+ m_FilterInPhotoSequence( false ),
+ m_filterInWarmStart(false)
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ , m_spPhotoConfirmationCallback(nullptr)
+#endif
+{
+ ComPtr<IMFAttributes> pAttributes = nullptr;
+ MFCreateAttributes( &pAttributes, 0 );
+ pAttributes->SetUINT32( MF_TRANSFORM_ASYNC, TRUE );
+ pAttributes->SetUINT32( MFT_SUPPORT_DYNAMIC_FORMAT_CHANGE, TRUE );
+ pAttributes->SetUINT32( MF_SA_D3D_AWARE, TRUE );
+ pAttributes->SetString( MFT_ENUM_HARDWARE_URL_Attribute, L"SampleMultiPinMft" );
+ m_spAttributes = pAttributes;
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ m_guidPhotoConfirmationSubtype = MFVideoFormat_NV12;
+#endif
+}
+
+CMultipinMft::~CMultipinMft( )
+{
+ CBasePin *pioPin = NULL;
+
+ for ( ULONG ulIndex = 0, ulSize = (ULONG) m_InPins.size(); ulIndex < ulSize; ulIndex++ )
+ {
+ pioPin = m_InPins[ ulIndex ];
+ SAFERELEASE( pioPin );
+ }
+ m_InPins.clear();
+
+ for (ULONG ulIndex = 0, ulSize = (ULONG) m_OutPins.size(); ulIndex < ulSize; ulIndex++)
+ {
+ pioPin = m_OutPins[ ulIndex ];
+ SAFERELEASE( pioPin );
+ }
+ m_OutPins.clear();
+ m_spSourceTransform = nullptr;
+
+}
+
+STDMETHODIMP_(ULONG) CMultipinMft::AddRef(
+ void
+ )
+{
+ return InterlockedIncrement(&m_nRefCount);
+}
+
+STDMETHODIMP_(ULONG) CMultipinMft::Release(
+ void
+ )
+{
+ ULONG uCount = InterlockedDecrement(&m_nRefCount);
+
+ if ( uCount == 0 )
+ {
+ delete this;
+ }
+ return uCount;
+}
+
+STDMETHODIMP CMultipinMft::QueryInterface(
+ _In_ REFIID iid,
+ _COM_Outptr_ void** ppv
+ )
+{
+
+ HRESULT hr = S_OK;
+ *ppv = NULL;
+
+ if ((iid == __uuidof(IMFDeviceTransform)) || (iid == __uuidof(IUnknown)))
+ {
+ *ppv = static_cast< IMFDeviceTransform* >(this);
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IMFMediaEventGenerator ) )
+ {
+ *ppv = static_cast< IMFMediaEventGenerator* >(this);
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IMFShutdown ) )
+ {
+ *ppv = static_cast< IMFShutdown* >( this );
+ AddRef();
+ }
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+ else
+ if (iid == __uuidof(IMFTransform))
+ {
+ *ppv = static_cast< IMFTransform* >(this);
+ AddRef();
+ }
+#endif
+ else
+ if ( iid == __uuidof( IKsControl ) )
+ {
+ *ppv = static_cast< IKsControl* >( this );
+ AddRef();
+ }
+ else
+ if ( iid == __uuidof( IMFRealTimeClientEx ) )
+ {
+ *ppv = static_cast< IMFRealTimeClientEx* >( this );
+ AddRef();
+ }
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+ else
+ if (iid == __uuidof(IMFCapturePhotoConfirmation))
+ {
+ *ppv = static_cast< IMFCapturePhotoConfirmation* >(this);
+ AddRef();
+ }
+ else
+ if (iid == __uuidof(IMFGetService))
+ {
+ *ppv = static_cast< IMFGetService* >(this);
+ AddRef();
+ }
+#endif
+ else
+ {
+ hr = E_NOINTERFACE;
+ }
+ return hr;
+}
+
+/*++
+ Description:
+ This function is the entry point of the transform
+ The following things may be initialized here
+ 1) Query for MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL on the attributes supplied
+ 2) From the IUnknown acquired get the IMFTransform interface.
+ 3) Get the stream count.. The output streams are of consequence to the tranform.
+ The input streams should correspond to the output streams exposed by the source transform
+ acquired from the Attributes supplied.
+ 4) Get the IKSControl which is used to send KSPROPERTIES, KSEVENTS and KSMETHODS to the driver for the filer level. Store it in your filter class
+ 5) Get the OutPutStreamAttributes for the output pins of the source transform. This can further be used to QI and acquire
+ the IKSControl related to the specific pin. This can be used to send PIN level KSPROPERTIES, EVENTS and METHODS to the pins
+ 6) Create the output pins
+
+--*/
+
+STDMETHODIMP CMultipinMft::InitializeTransform (
+ _In_ IMFAttributes *pAttributes
+ )
+{
+ HRESULT hr = S_OK;
+ ComPtr<IUnknown> spFilterUnk = nullptr;
+ DWORD *pcInputStreams = NULL, *pcOutputStreams = NULL;
+ DWORD inputStreams = 0;
+ DWORD outputStreams = 0;
+ GUID* outGuids = NULL;
+ GUID streamCategory = GUID_NULL;
+
+ DMFTCHECKNULL_GOTO( pAttributes, done, E_INVALIDARG );
+ //
+ //The attribute passed with MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL is the source transform. This generally represents a filter
+ //This needs to be stored so that we know the device properties. We cache it. We query for the IKSControl which is used to send
+ //controls to the driver.
+ //
+ DMFTCHECKHR_GOTO( pAttributes->GetUnknown( MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL,IID_PPV_ARGS( &spFilterUnk ) ),done );
+
+ DMFTCHECKHR_GOTO( spFilterUnk.As( &m_spSourceTransform ), done );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform.As( &m_spIkscontrol ), done );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform->MFTGetStreamCount( &inputStreams, &outputStreams ), done );
+
+ spFilterUnk = nullptr;
+
+ //
+ //The number of input pins created by the device transform should match the pins exposed by
+ //the source transform i.e. outputStreams from SourceTransform or DevProxy = Input pins of the Device MFT
+ //
+
+ if ( inputStreams > 0 || outputStreams > 0 )
+ {
+ pcInputStreams = new DWORD[ inputStreams ];
+ DMFTCHECKNULL_GOTO( pcInputStreams, done, E_OUTOFMEMORY);
+
+ pcOutputStreams = new DWORD[ outputStreams ];
+ DMFTCHECKNULL_GOTO( pcOutputStreams, done, E_OUTOFMEMORY );
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform->MFTGetStreamIDs( inputStreams, pcInputStreams,
+ outputStreams,
+ pcOutputStreams ),done );
+
+ //
+ // Output pins from DevProxy = Input pins of device MFT.. We are the first transform in the pipeline before MFT0
+ //
+
+ for ( ULONG ulIndex = 0; ulIndex < outputStreams; ulIndex++ )
+ {
+ ComPtr<IMFAttributes> pInAttributes = nullptr;
+
+ DMFTCHECKHR_GOTO( m_spSourceTransform->GetOutputStreamAttributes(pcOutputStreams[ulIndex], pInAttributes.GetAddressOf()), done);
+
+ DMFTCHECKHR_GOTO( pInAttributes->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &streamCategory), done);
+
+ if ( IsEqualCLSID( streamCategory, PINNAME_IMAGE ) )
+ {
+ //We have independent pins..
+ m_filterHasIndependentPin = true;
+ }
+ CInPin *pInPin = nullptr;
+ if (IsEqualCLSID(streamCategory, AVSTREAM_CUSTOM_PIN_IMAGE))
+ {
+ pInPin = new CCustomPin( pInAttributes.Get(), pcOutputStreams[ulIndex], this);
+ DMFTCHECKNULL_GOTO( pInPin, done, E_OUTOFMEMORY);
+ //
+ // Since the custom pin is an input pin too we will push it
+ // in the input pins list. This is however not being connected
+ // to the output in this sample.
+ m_CustomPinCount++;
+ }
+ else
+ {
+ pInPin = new CInPin( pInAttributes.Get(), pcOutputStreams[ulIndex], this);
+ DMFTCHECKNULL_GOTO(pInPin, done, E_OUTOFMEMORY);
+ }
+
+ hr = ExceptionBoundary([this,pInPin]()
+ {
+ m_InPins.push_back(pInPin);
+ });
+
+ DMFTCHECKHR_GOTO(hr, done);
+ DMFTCHECKHR_GOTO( pInPin->Init(m_spSourceTransform.Get() ), done);
+
+
+ pInPin->AddRef();
+
+ }
+ //
+ // If we have just one output stream exposed off the source transform create a one to three pin
+ //
+ if ( ( outputStreams == 1 ) && IsEqualGUID( streamCategory, PINNAME_VIDEO_CAPTURE ) )
+ {
+ outputStreams = 3;
+ outGuids = new GUID [ outputStreams ];
+ DMFTCHECKNULL_GOTO(outGuids, done, E_OUTOFMEMORY);
+
+ m_OutPins.resize(outputStreams, nullptr);
+
+ CInPin *piPin = (CInPin *)m_InPins[0];
+
+ *outGuids = PINNAME_VIDEO_CAPTURE;
+ *( outGuids + 1 ) = PINNAME_VIDEO_PREVIEW;
+ *(outGuids + 2) = PINNAME_IMAGE; //PINNAME_IMAGE for independent pin and PINNAME_VIDEO_STILL for dependent pin!!
+
+ for ( ULONG ulIndex = 0; ulIndex < outputStreams; ulIndex++ )
+ {
+ ComPtr<IKsControl> pKsControl = NULL;
+ COutPin *poPin = nullptr;
+
+ DMFTCHECKHR_GOTO( piPin->QueryInterface(IID_PPV_ARGS( &pKsControl ) ), done);
+
+ hr = ExceptionBoundary([&]()
+ {
+ poPin = new COutPin(ulIndex, this, pKsControl.Get());
+ });
+
+ DMFTCHECKHR_GOTO(hr, done);
+
+ DMFTCHECKNULL_GOTO( poPin,done, E_OUTOFMEMORY );
+
+ DMFTCHECKHR_GOTO( BridgeInputPinOutputPin( piPin, poPin ),done );
+
+ DMFTCHECKHR_GOTO( poPin->SetGUID( MF_DEVICESTREAM_STREAM_CATEGORY, outGuids[ ulIndex ] ),done );
+
+ DMFTCHECKHR_GOTO( poPin->SetUINT32( MF_DEVICESTREAM_STREAM_ID, ulIndex ),done );
+
+ m_OutPins[ ulIndex ] = poPin;
+ poPin->AddRef();
+
+ }
+ }
+ else
+ {
+ //
+ //Create one on one mapping
+ //
+
+ for (ULONG ulIndex = 0; ulIndex < m_InPins.size(); ulIndex++)
+ {
+ ULONG ulPinIndex = 0;
+ GUID pinGuid = GUID_NULL;
+ ComPtr< IKsControl > pKsControl = nullptr;
+
+ CInPin *piPin = ( CInPin * )m_InPins[ ulIndex ];
+
+ if (piPin)
+ {
+ BOOL isCustom = false;
+ if ( SUCCEEDED( CheckCustomPin( piPin, &isCustom )) && ( isCustom ) )
+ {
+ //
+ // In this sample we are not connecting the custom pin to the output
+ // This is because we really have no way of testing the custom pin with the
+ // pipeline.
+ // This however can be changed if the custom media type is converted here in
+ // the device MFT and later exposed to the pipeline..
+ //
+ continue;
+ }
+ ulPinIndex = piPin->streamId();
+
+ DMFTCHECKHR_GOTO(piPin->GetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, &pinGuid), done);
+
+ DMFTCHECKHR_GOTO(piPin->QueryInterface(IID_PPV_ARGS(&pKsControl)), done);
+
+ COutPin *poPin = new COutPin(ulPinIndex, this, pKsControl.Get());
+
+ DMFTCHECKNULL_GOTO(poPin, done, E_OUTOFMEMORY);
+
+ DMFTCHECKHR_GOTO(poPin->SetGUID(MF_DEVICESTREAM_STREAM_CATEGORY, pinGuid), done);
+
+ DMFTCHECKHR_GOTO(poPin->SetUINT32(MF_DEVICESTREAM_STREAM_ID, ulPinIndex), done);
+
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+ //
+ // If we wish to load MFT0 as well as Device MFT then we should be doing the following
+ // Copy over the GUID attribute MF_DEVICESTREAM_EXTENSION_PLUGIN_CLSID from the input
+ // pin to the output pin. This is because Device MFT is the new face of the filter now
+ // and MFT0 will now get loaded for the output pins exposed from Device MFT rather than
+ // DevProxy!
+ //
+
+ GUID guidMFT0 = GUID_NULL;
+
+ hr = piPin->GetGUID(MF_DEVICESTREAM_EXTENSION_PLUGIN_CLSID, &guidMFT0);
+
+ if (SUCCEEDED(hr))
+ {
+ //
+ // This stream has an MFT0 .. Attach the GUID to the Outpin pin attribute
+ // The downstream will query this attribute on the pins exposed from device MFT
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! setting Mft0 guid on pin %d", ulIndex);
+
+ DMFTCHECKHR_GOTO(poPin->SetGUID(MF_DEVICESTREAM_EXTENSION_PLUGIN_CLSID, guidMFT0), done);
+
+ DMFTCHECKHR_GOTO(poPin->SetUnknown(MF_DEVICESTREAM_EXTENSION_PLUGIN_CONNECTION_POINT,
+ static_cast< IUnknown* >(static_cast < IKsControl * >(this))), done);
+
+ }
+ else
+ {
+ // Reset Error.. MFT0 absence should not be an error
+ hr = S_OK;
+ }
+#endif
+ DMFTCHECKHR_GOTO(BridgeInputPinOutputPin(piPin, poPin), done);
+ hr = ExceptionBoundary([&]()
+ {
+ m_OutPins.push_back(poPin);
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ }
+ }
+ }
+ }
+
+ m_InputPinCount = ULONG ( m_InPins.size() );
+ m_OutputPinCount = ULONG ( m_OutPins.size() );
+
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!",hr,hr);
+
+ if ( pcInputStreams )
+ {
+ delete[ ] ( pcInputStreams );
+ }
+ if ( pcOutputStreams )
+ {
+ delete[ ] ( pcOutputStreams );
+ }
+ if ( outGuids )
+ {
+ delete [] ( outGuids );
+ }
+ if ( FAILED( hr ) )
+ {
+ //Release the pins and the resources acquired
+ while ( m_InPins.size() > 0 )
+ {
+ CInPin *pInPin = nullptr;
+ pInPin = ( CInPin* )m_InPins.back();
+ m_InPins.pop_back();
+ SAFERELEASE( pInPin );
+ }
+ while ( m_OutPins.size() > 0 )
+ {
+ COutPin *pin = nullptr;
+ pin = ( COutPin* )m_OutPins.back();
+ m_OutPins.pop_back();
+ SAFERELEASE( pin );
+ }
+ //
+ // Simply clear the custom pins since the input pins must have deleted the pin
+ //
+ m_spSourceTransform = nullptr;
+ }
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::SetWorkQueueEx(
+ _In_ DWORD dwWorkQueueId,
+ _In_ LONG lWorkItemBasePriority
+ )
+/*++
+ Description:
+
+ Implements IMFRealTimeClientEx::SetWorkQueueEx function
+
+--*/
+{
+ CAutoLock lock( m_critSec );
+ //
+ // Cache the WorkQueuId and WorkItemBasePriority
+ //
+ m_dwWorkQueueId = dwWorkQueueId;
+ m_lWorkQueuePriority = lWorkItemBasePriority;
+ return S_OK;
+
+}
+
+//
+// IMFDeviceTransform functions
+//
+STDMETHODIMP CMultipinMft::GetStreamCount(
+ _Inout_ DWORD *pdwInputStreams,
+ _Inout_ DWORD *pdwOutputStreams
+ )
+/*++
+ Description: Implements IMFTransform::GetStreamCount function
+--*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+
+
+ *pdwInputStreams = m_InputPinCount;
+ *pdwOutputStreams = m_OutputPinCount;
+
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+//
+//Doesn't striclt conform to GetStreamIDs on IMFTransform Interface!
+//
+STDMETHODIMP CMultipinMft::GetStreamIDs(
+ _In_ DWORD dwInputIDArraySize,
+ _When_(dwInputIDArraySize >= m_InputPinCount, _Out_writes_(dwInputIDArraySize)) DWORD* pdwInputIDs,
+ _In_ DWORD dwOutputIDArraySize,
+ _When_(dwOutputIDArraySize >= m_OutputPinCount && (pdwInputIDs && (dwInputIDArraySize > 0)),
+ _Out_writes_(dwOutputIDArraySize)) _On_failure_(_Valid_) DWORD* pdwOutputIDs
+ )
+/*++
+ Description:
+ Implements IMFTransform::GetStreamIDs function
+--*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+
+ MFTLOCKED();
+
+ if ( ( dwInputIDArraySize < m_InputPinCount ) && ( dwOutputIDArraySize < m_OutputPinCount ) )
+ {
+ hr = MF_E_BUFFERTOOSMALL;
+ goto done;
+ }
+
+ if ( dwInputIDArraySize )
+ {
+ DMFTCHECKNULL_GOTO( pdwInputIDs, done, E_POINTER );
+ for ( DWORD dwIndex = 0; dwIndex < ((dwInputIDArraySize > m_InputPinCount) ? m_InputPinCount:
+ dwInputIDArraySize); dwIndex++ )
+ {
+ pdwInputIDs[ dwIndex ] = ( m_InPins[dwIndex] )->streamId();
+ }
+ }
+
+ if ( dwOutputIDArraySize )
+ {
+ DMFTCHECKNULL_GOTO( pdwOutputIDs, done, E_POINTER );
+ for ( DWORD dwIndex = 0; dwIndex < ((dwOutputIDArraySize > m_OutputPinCount)? m_OutputPinCount:
+ dwOutputIDArraySize); dwIndex++ )
+ {
+ pdwOutputIDs[ dwIndex ] = (m_OutPins[ dwIndex ])->streamId();
+ }
+ }
+done:
+ return hr;
+}
+
+/*++
+Name: CMultipinMft::GetInputAvailableType
+Description:
+Implements IMFTransform::GetInputAvailableType function. This function
+gets the media type supported by the specified stream based on the
+index dwTypeIndex.
+--*/
+STDMETHODIMP CMultipinMft::GetInputAvailableType(
+ _In_ DWORD dwInputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppMediaType
+ )
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+
+
+ CInPin *piPin = ( CInPin* )GetInPin( dwInputStreamID );
+
+ DMFTCHECKNULL_GOTO( piPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ *ppMediaType = nullptr;
+
+ hr = piPin->GetOutputAvailableType( dwTypeIndex,ppMediaType );
+
+ if (FAILED(hr))
+ {
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!",
+ dwInputStreamID,
+ dwTypeIndex,
+ hr);
+
+ }
+
+done:
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetOutputAvailableType(
+ _In_ DWORD dwOutputStreamID,
+ _In_ DWORD dwTypeIndex,
+ _Out_ IMFMediaType** ppMediaType
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::GetOutputAvailableType function. This function
+ gets the media type supported by the specified stream based on the
+ index dwTypeIndex.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+
+ DMFTCHECKNULL_GOTO(ppMediaType, done, E_INVALIDARG);
+
+ COutPin*poPin = ( COutPin* )GetOutPin( dwOutputStreamID );
+
+ DMFTCHECKNULL_GOTO( poPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ *ppMediaType = nullptr;
+
+ hr = poPin->GetOutputAvailableType( dwTypeIndex, ppMediaType );
+
+ if ( FAILED( hr ) )
+ {
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Pin: %d Index: %d exiting %!HRESULT!",
+ dwOutputStreamID,
+ dwTypeIndex,
+ hr );
+ }
+
+done:
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetInputCurrentType(
+ _In_ DWORD dwInputStreamID,
+ _COM_Outptr_result_maybenull_ IMFMediaType** ppMediaType
+ )
+/*++
+ Description:
+ Implements IMFTransform::GetInputCurrentType function. This function
+ returns the current media type set on the specified stream.
+--*/
+{
+ //
+ //The input current types will not come to this transform.
+ //The outputs of this transform matter. The DTM manages the
+ //output of this transform and the inptuts of the source transform
+ //
+ UNREFERENCED_PARAMETER(dwInputStreamID);
+ UNREFERENCED_PARAMETER(ppMediaType);
+ return S_OK;
+}
+
+STDMETHODIMP CMultipinMft::GetOutputCurrentType(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ IMFMediaType** ppMediaType
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::GetOutputCurrentType function. This function
+ returns the current media type set on the specified stream.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+ CAutoLock lock( m_critSec );
+
+ DMFTCHECKNULL_GOTO( ppMediaType, done, E_INVALIDARG );
+
+ *ppMediaType = nullptr;
+
+ COutPin *poPin = ( COutPin* )GetOutPin( dwOutputStreamID );
+
+ DMFTCHECKNULL_GOTO( poPin, done, MF_E_INVALIDSTREAMNUMBER );
+
+ DMFTCHECKHR_GOTO( poPin->getMediaType( ppMediaType ),done );
+
+ DMFTCHECKNULL_GOTO( *ppMediaType, done, MF_E_TRANSFORM_TYPE_NOT_SET );
+
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::ProcessEvent(
+ _In_ DWORD dwInputStreamID,
+ _In_ IMFMediaEvent* pEvent
+ )
+ /*++
+ Description:
+
+ Implements IMFTransform::ProcessEvent function. This function
+ processes events that come to the MFT.
+
+ --*/
+{
+ UNREFERENCED_PARAMETER(dwInputStreamID);
+ UNREFERENCED_PARAMETER(pEvent);
+ return S_OK;
+}
+
+
+
+STDMETHODIMP CMultipinMft::ProcessMessage(
+ _In_ MFT_MESSAGE_TYPE eMessage,
+ _In_ ULONG_PTR ulParam
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::ProcessMessage function. This function
+ processes messages coming to the MFT.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+
+ UNREFERENCED_PARAMETER(ulParam);
+
+ CAutoLock _lock( m_critSec );
+
+ printMessageEvent( eMessage );
+
+ switch ( eMessage )
+ {
+ case MFT_MESSAGE_COMMAND_FLUSH:
+ //
+ //This is MFT wide flush.. Flush all output pins
+ //
+ (VOID)FlushAllStreams();
+ break;
+ case MFT_MESSAGE_COMMAND_DRAIN:
+ //
+ //There is no draining for Device MFT. Just kept here for reference
+ //
+ break;
+ case MFT_MESSAGE_NOTIFY_START_OF_STREAM:
+ //
+ //No op for device MFTs
+ //
+ break;
+ case MFT_MESSAGE_SET_D3D_MANAGER:
+ {
+ if ( ulParam )
+ {
+ ComPtr< IDirect3DDeviceManager9 > spD3D9Manager;
+ ComPtr< IMFDXGIDeviceManager > spDXGIManager;
+
+ hr = ( ( IUnknown* ) ulParam )->QueryInterface( IID_PPV_ARGS( &spD3D9Manager ) );
+ if ( SUCCEEDED( hr ) )
+ {
+ m_spDeviceManagerUnk = ( IUnknown* )ulParam;
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! IDirect3DDeviceManager9 %p, is passed", spD3D9Manager.Get() );
+ }
+ else
+ {
+ hr = ( ( IUnknown* ) ulParam )->QueryInterface( IID_PPV_ARGS( &spDXGIManager ) );
+ if ( SUCCEEDED(hr) )
+ {
+ m_spDeviceManagerUnk = (IUnknown*)ulParam;
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! IMFDXGIDeviceManager %p, is passed", spDXGIManager.Get());
+ }
+ }
+ }
+ else
+ {
+ m_spDeviceManagerUnk = nullptr;
+ hr = S_OK;
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC!IDirect3DDeviceManager9 was not passed in");
+ }
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_BEGIN_STREAMING:
+ {
+ SetStreamingState( DeviceStreamState_Run );
+ //
+ // Start Streaming custom pins if the device transfrom has any
+ //
+ SetStreamingStateCustomPins( DeviceStreamState_Run );
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_END_STREAMING:
+ {
+ SetStreamingState(DeviceStreamState_Stop);
+ //
+ // Stop streaming custom pins if the device transform has any
+ //
+ SetStreamingStateCustomPins( DeviceStreamState_Stop );
+ }
+ break;
+ case MFT_MESSAGE_NOTIFY_END_OF_STREAM:
+ {
+ SetStreamingState(DeviceStreamState_Stop);
+ }
+ break;
+ default:
+ ;
+ }
+
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::ProcessInput(
+ _In_ DWORD dwInputStreamID,
+ _In_ IMFSample* pSample,
+ _In_ DWORD dwFlags
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::ProcessInput function.This function is called
+ when the sourcetransform has input to feed. the pins will try to deliver the
+ samples to the active output pins conencted. if none are connected then just
+ returns the sample back to the source transform
+
+--*/
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( dwFlags );
+
+ MFTLOCKED();
+
+ CInPin *inPin = ( CInPin* )GetInPin( dwInputStreamID );
+ DMFTCHECKNULL_GOTO( inPin, done, E_INVALIDARG );
+
+ if ( !IsStreaming() )
+ {
+ goto done;
+ }
+
+ DMFTCHECKHR_GOTO( inPin->SendSample( pSample ), done );
+
+ QueueEvent( METransformHaveOutput, GUID_NULL, S_OK, NULL );
+
+done:
+ SAFERELEASE( pSample );
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+
+}
+
+STDMETHODIMP CMultipinMft::ProcessOutput(
+ _In_ DWORD dwFlags,
+ _In_ DWORD cOutputBufferCount,
+ _Inout_updates_(cOutputBufferCount) MFT_OUTPUT_DATA_BUFFER *pOutputSamples,
+ _Out_ DWORD *pdwStatus
+)
+/*++
+Description:
+
+Implements IMFTransform::ProcessOutput function. This is called by the DTM when
+the DT indicates it has samples to give. The DTM will send enough MFT_OUTPUT_DATA_BUFFER
+pointers to be filled up as is the number of output pins available. The DT should traverse its
+output pins and populate the corresponding MFT_OUTPUT_DATA_BUFFER with the samples available
+
+--*/
+{
+ HRESULT hr = S_OK;
+ BOOL gotOne = false;
+ MFTLOCKED();
+ UNREFERENCED_PARAMETER( dwFlags );
+
+ if (cOutputBufferCount > m_OutputPinCount )
+ {
+ DMFTCHECKHR_GOTO( E_INVALIDARG, done );
+ }
+ *pdwStatus = 0;
+
+ for ( DWORD i = 0; i < cOutputBufferCount; i++ )
+ {
+ DWORD dwStreamID = pOutputSamples[i].dwStreamID;
+
+ COutPin *poPin = ( COutPin * )GetOutPin( dwStreamID );
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+
+ if ( SUCCEEDED( poPin->ProcessOutput( dwFlags, &pOutputSamples[i],
+ pdwStatus ) ) )
+ {
+ gotOne = true;
+ }
+ }
+ if (gotOne)
+ {
+ hr = S_OK;
+ }
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetInputStreamAttributes(
+ _In_ DWORD dwInputStreamID,
+ _COM_Outptr_result_maybenull_ IMFAttributes** ppAttributes
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::GetInputStreamAttributes function. This function
+ gets the specified input stream's attributes.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+
+ DMFTCHECKNULL_GOTO( ppAttributes, done, E_INVALIDARG );
+ *ppAttributes = nullptr;
+
+ CInPin *piPin = static_cast<CInPin*>(GetInPin( dwInputStreamID ));
+
+ DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG );
+
+ hr = piPin->getPinAttributes(ppAttributes);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetOutputStreamAttributes(
+ _In_ DWORD dwOutputStreamID,
+ _Out_ IMFAttributes** ppAttributes
+ )
+/*++
+ Description:
+
+ Implements IMFTransform::GetOutputStreamAttributes function. This function
+ gets the specified output stream's attributes.
+
+--*/
+{
+ HRESULT hr = S_OK;
+ MFTLOCKED();
+
+ DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG);
+ *ppAttributes = nullptr;
+
+ COutPin *poPin = (COutPin *)GetOutPin(dwOutputStreamID);
+
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+
+ DMFTCHECKHR_GOTO( poPin->getPinAttributes(ppAttributes), done );
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+_Requires_no_locks_held_
+STDMETHODIMP CMultipinMft::SetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState value,
+ _In_ DWORD dwFlags
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::SetInputStreamState function.
+ Sets the input stream state.
+
+ The control lock is not taken here. The lock is taken for operations on
+ output pins. This operation is a result of the DT notifying the DTM that
+ output pin change has resulted in the need for the input to be changed. In
+ this case the DTM sends a getpreferredinputstate and then this call
+
+ --*/
+{
+ HRESULT hr = S_OK;
+ CInPin *piPin = (CInPin*)GetInPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ DMFTCHECKHR_GOTO(piPin->SetInputStreamState(pMediaType, value, dwFlags),done);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetInputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value
+ )
+{
+ HRESULT hr = S_OK;
+ CInPin *piPin = (CInPin*)GetInPin(dwStreamID);
+
+ DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ *value = piPin->GetState();
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::SetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _In_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState state,
+ _In_ DWORD dwFlags
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::SetOutputStreamState function.
+ Sets the output stream state. This is called whenever the stream
+ is selected or deslected i.e. started or stopped.
+
+ The control lock taken here and this operation should be atomic.
+ This function should check the input pins connected to the output pin
+ switch off the state of the input pin. Check if any other Pin connected
+ to the input pin is in a conflicting state with the state requested on this
+ output pin. Accordinly it calculates the media type to be set on the input pin
+ and the state to transition into. It then might recreate the other output pins
+ connected to it
+ --*/
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(dwFlags);
+ CAutoLock Lock(m_critSec);
+
+ DMFTCHECKHR_GOTO(ChangeMediaTypeEx(dwStreamID, pMediaType, state),done);
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetOutputStreamState(
+ _In_ DWORD dwStreamID,
+ _Out_ DeviceStreamState *value
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::GetOutputStreamState function.
+ Gets the output stream state.
+ Called by the DTM to checks states. Atomic operation. needs a lock
+ --*/
+{
+ HRESULT hr = S_OK;
+ CAutoLock lock(m_critSec);
+
+ COutPin *poPin = (COutPin *)GetOutPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(poPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ *value = poPin->GetState();
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::GetInputStreamPreferredState(
+ _In_ DWORD dwStreamID,
+ _Inout_ DeviceStreamState *value,
+ _Outptr_opt_result_maybenull_ IMFMediaType **ppMediaType
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::GetInputStreamPreferredState function.
+ Gets the preferred state and the media type to be set on the input pin.
+ The lock is not held as this will always be called only when we notify
+ DTM to call us. We notify DTM only from the context on operations
+ happening on the output pin
+ --*/
+{
+ HRESULT hr = S_OK;
+ CInPin *piPin = (CInPin*)GetInPin(dwStreamID);
+ DMFTCHECKNULL_GOTO(piPin, done, MF_E_INVALIDSTREAMNUMBER);
+
+ piPin->GetInputStreamPreferredState(value, ppMediaType);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::FlushInputStream(
+ _In_ DWORD dwStreamIndex,
+ _In_ DWORD dwFlags
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::FlushInputStream function.
+ --*/
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(dwStreamIndex);
+ UNREFERENCED_PARAMETER(dwFlags);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::FlushOutputStream(
+ _In_ DWORD dwStreamIndex,
+ _In_ DWORD dwFlags
+ )
+ /*++
+ Description:
+
+ Implements IMFdeviceTransform::FlushOutputStream function.
+ Called by the DTM to flush streams
+ --*/
+{
+
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(dwFlags);
+ CAutoLock Lock(m_critSec);
+
+ COutPin *poPin = (COutPin*)GetOutPin(dwStreamIndex);
+ DMFTCHECKNULL_GOTO(poPin, done, E_INVALIDARG);
+
+ DeviceStreamState oldState = poPin->SetState(DeviceStreamState_Disabled);
+
+ hr = poPin->FlushQueues();
+
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! failed %x = %!HRESULT!", hr, hr);
+ }
+ //
+ //Restore state
+ //
+ poPin->SetState(oldState);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+/*++
+ Description:
+
+ Called when the Device Transform gets a MFT_MESSAGE_COMMAND_FLUSH. We drain all the queues.
+ This is called in device source when the source gets end of streaming.
+ --*/
+STDMETHODIMP_(VOID) CMultipinMft::FlushAllStreams(
+ VOID
+ )
+{
+ DeviceStreamState oldState;
+ for ( DWORD dwIndex = 0, dwSize = (DWORD)m_OutPins.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ COutPin *poPin = (COutPin *)m_OutPins[dwIndex];
+ oldState = poPin->SetState(DeviceStreamState_Disabled);
+ poPin->FlushQueues();
+ //
+ //Restore state
+ //
+ poPin->SetState(oldState);
+ }
+}
+
+
+//
+// IKsControl interface functions
+//
+STDMETHODIMP CMultipinMft::KsProperty(
+ _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pvPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pulBytesReturned
+ )
+ /*++
+ Description:
+
+ Implements IKSProperty::KsProperty function.
+ used to pass control commands to the driver (generally)
+ This can be used to intercepted the control to figure out
+ if it needs to be propogated to the driver or not
+ --*/
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER(pulBytesReturned);
+ DMFTCHECKNULL_GOTO(pProperty, done, E_INVALIDARG);
+ DMFTCHECKNULL_GOTO(pulBytesReturned, done, E_INVALIDARG);
+
+ //
+ // Enable Warm Start on All filters for the sample. Please comment out this
+ // section if this is not needed
+ //
+ if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl)
+ && (pProperty->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART))
+ {
+ DMFTCHECKHR_GOTO(WarmStartHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned),done);
+ goto done;
+ }
+
+ if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl)
+ && (pProperty->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTHUMBNAIL))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Thumbnail sent %d",pProperty->Flags);
+ }
+ if (IsEqualCLSID(pProperty->Set, KSPROPERTYSETID_ExtendedCameraControl)
+ &&(!filterHasIndependentPin()))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Extended Control %d Passed ",pProperty->Id);
+ switch (pProperty->Id)
+ {
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE:
+ hr = ExtendedPhotoModeHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE:
+ hr = ExtendedPhotoMaxFrameRate(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES:
+ hr = MaxVidFPS_PhotoResHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME:
+ hr = QPCTimeHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOFRAMERATE:
+ hr = PhotoFrameRateHandler(pProperty,
+ ulPropertyLength, pvPropertyData, ulDataLength, pulBytesReturned);
+ goto done;
+ break;
+
+ }
+ }
+ else
+ if ((IsEqualCLSID(pProperty->Set, PROPSETID_VIDCAP_VIDEOCONTROL)) &&
+ (pProperty->Id == KSPROPERTY_VIDEOCONTROL_MODE))
+ {
+ //
+ //A photo trigger was sent!!!
+ //We need to set the event haveoutput
+ //
+ PKSPROPERTY_VIDEOCONTROL_MODE_S VideoControl = NULL;
+ if (sizeof(KSPROPERTY_VIDEOCONTROL_MODE_S) == ulDataLength)
+ {
+ VideoControl = (PKSPROPERTY_VIDEOCONTROL_MODE_S)pvPropertyData;
+ m_PhotoModeIsPhotoSequence = false;
+
+ if (VideoControl->Mode == KS_VideoControlFlag_StartPhotoSequenceCapture)
+ {
+ //
+ //Signalling start of photo sequence
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Starting PhotoSequence Trigger");
+ m_PhotoModeIsPhotoSequence = true;
+ setPhotoTriggerSent(true);
+ }
+ else
+ if (VideoControl->Mode == KS_VideoControlFlag_StopPhotoSequenceCapture)
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Stopping PhotoSequence Trigger");
+ m_PhotoModeIsPhotoSequence = false;
+ setPhotoTriggerSent(false);
+ }
+ else
+ {
+ //
+ //Normal trigger sent for single photo acquisition!
+ //
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Take Single Photo Trigger");
+ setPhotoTriggerSent(true);
+ }
+
+ }
+
+ if (!filterHasIndependentPin())
+ {
+ goto done;
+ }
+ }
+ hr = m_spIkscontrol->KsProperty(pProperty,
+ ulPropertyLength,
+ pvPropertyData,
+ ulDataLength,
+ pulBytesReturned);
+
+
+done:
+ LPSTR guidStr = DumpGUIDA(pProperty->Set);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! g:%s p:%d exiting %x = %!HRESULT!", guidStr, pProperty->Id, hr, hr);
+ delete(guidStr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::KsMethod(
+ _In_reads_bytes_(ulPropertyLength) PKSMETHOD pMethod,
+ _In_ ULONG ulPropertyLength,
+ _Inout_updates_bytes_(ulDataLength) LPVOID pvPropertyData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pulBytesReturned
+ )
+ /*++
+ Description:
+
+ Implements IKSProperty::KsMethod function.
+ --*/
+{
+ return m_spIkscontrol->KsMethod(
+ pMethod,
+ ulPropertyLength,
+ pvPropertyData,
+ ulDataLength,
+ pulBytesReturned
+ );
+}
+
+STDMETHODIMP CMultipinMft::KsEvent(
+ _In_reads_bytes_(ulEventLength) PKSEVENT pEvent,
+ _In_ ULONG ulEventLength,
+ _Inout_updates_bytes_opt_(ulDataLength) LPVOID pEventData,
+ _In_ ULONG ulDataLength,
+ _Inout_ ULONG* pBytesReturned
+ )
+ /*++
+ Description:
+
+ Implements IKSProperty::KsEvent function.
+ --*/
+{
+
+ HRESULT hr = S_OK;
+ if (pEvent && (pEvent->Set == KSEVENTSETID_ExtendedCameraControl) &&
+ (pEvent->Id == KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Acquiring Event for Async Extended Control");
+ //
+ // For the Sample the warmstate handlers are supported by Device MFT and not passed to driver
+ //
+ hr = m_eventHandler.KSEvent(pEvent,
+ ulEventLength,
+ pEventData,
+ ulDataLength,
+ pBytesReturned
+ );
+ goto done;
+ }
+
+ if ((pEvent && (pEvent->Set == KSEVENTSETID_ExtendedCameraControl))
+ && (!filterHasIndependentPin()))
+ {
+ //
+ // Important: Extended controls will send events which are strictly
+ // One shot. The event comes first where it should be duped and stored,
+ // the control comes next. The event should be set after control completes
+ // and it should be then closed.
+ // The below code handles only certain events needed for
+ // implementing photo sequence. For a complete exhaustive
+ // list refer documentation.
+ //
+ switch (pEvent->Id)
+ {
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_MAXVIDFPS_PHOTORES:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOTRIGGERTIME:
+ case KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOFRAMERATE:
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Acquiring Event for Async Extended Control");
+ //
+ // Let the event handler handle the event
+ //
+ DMFTCHECKHR_GOTO(m_eventHandler.KSEvent(pEvent,
+ ulEventLength,
+ pEventData,
+ ulDataLength,
+ pBytesReturned
+ ),done);
+ goto done;
+ }
+ }
+ }
+ //
+ // All the Events we don't handle should be sent to the driver!
+ //
+ hr = m_spIkscontrol->KsEvent(pEvent,
+ ulEventLength,
+ pEventData,
+ ulDataLength,
+ pBytesReturned);
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+//
+//IMFGetService functions
+//
+
+STDMETHODIMP CMultipinMft::GetService(
+ __in REFGUID guidService,
+ __in REFIID riid,
+ __deref_out LPVOID* ppvObject
+ )
+{
+ //
+ //This doesn't necessarily need to be a GetService function, but this is just so that the
+ //pipeline implementation and the Device transform implementation is consistent.
+ //In this sample the photoconfirmation interface is implementated by the same class
+ //we can delegate it later to any of the pins if needed
+ //
+ UNREFERENCED_PARAMETER(guidService);
+ if (riid == __uuidof(IMFCapturePhotoConfirmation))
+ {
+ return QueryInterface(riid, ppvObject);
+ }
+ else
+ return MF_E_UNSUPPORTED_SERVICE;
+
+
+}
+
+//
+//IMFCapturePhotoConfirmation functions implemented
+//
+
+STDMETHODIMP CMultipinMft::SetPhotoConfirmationCallback(
+ _In_ IMFAsyncCallback* pNotificationCallback
+ )
+{
+ CAutoLock Lock(m_critSec);
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Setting PhotoConfirmation %p, is passed", pNotificationCallback);
+
+ m_spPhotoConfirmationCallback = pNotificationCallback;
+ return S_OK;
+}
+STDMETHODIMP CMultipinMft::SetPixelFormat(
+ _In_ GUID subtype
+ )
+{
+ m_guidPhotoConfirmationSubtype = subtype;
+ return S_OK;
+}
+STDMETHODIMP CMultipinMft::GetPixelFormat(
+ _Out_ GUID* subtype
+ )
+{
+ *subtype = m_guidPhotoConfirmationSubtype;
+ return S_OK;
+}
+
+#endif
+
+
+
+#if defined (MF_DEVICEMFT_ALLOW_MFT0_LOAD) && defined (MFT_UNIQUE_METHOD_NAMES)
+
+//
+// IMFTransform function(s).
+//
+
+//
+// Note: This is the only IMFTransform function which is not a redirector to the
+// DeviceTransform functions. The rest of IMFTransform functions are in the file common.h
+// This function returns the IMFAttribute created for Device MFT. If DMFT is
+// not loaded (usually )MFT0's call to GetAttributes will get the Attribute store of DevProxy.
+// A device MFT loaded will not pass through the devproxy attribute store, but it will pass
+// the device MFT attributes. This should be similar to the singular DevProxy attribute
+// which the MFT0 providers can use to synchronize across various MFT0's
+//
+
+STDMETHODIMP CMultipinMft::GetAttributes(
+ _COM_Outptr_opt_result_maybenull_ IMFAttributes** ppAttributes
+ )
+{
+ HRESULT hr = S_OK;
+
+ DMFTCHECKNULL_GOTO(ppAttributes, done, E_INVALIDARG);
+
+ *ppAttributes = nullptr;
+
+ if (m_spAttributes != nullptr)
+ {
+ m_spAttributes.CopyTo(ppAttributes);
+ }
+ else
+ {
+ hr = E_OUTOFMEMORY;
+ }
+
+done:
+ return hr;
+}
+#endif
+
+
+
+
+//
+//HELPER FUNCTIONS
+//
+
+STDMETHODIMP_(CBasePin*) CMultipinMft::GetInPin(
+ _In_ DWORD dwStreamId
+ )
+{
+ CInPin *inPin = NULL;
+ for (DWORD dwIndex = 0, dwSize = (DWORD)m_InPins.size(); dwIndex < dwSize; dwIndex++)
+ {
+ inPin = (CInPin *)m_InPins[dwIndex];
+ if (dwStreamId == inPin->streamId())
+ {
+ break;
+ }
+ inPin = NULL;
+ }
+ return inPin;
+}
+
+STDMETHODIMP_(CBasePin*) CMultipinMft::GetOutPin(
+ _In_ DWORD dwStreamId
+ )
+{
+ COutPin *outPin = NULL;
+
+ for ( DWORD dwIndex = 0, dwSize = (DWORD) m_OutPins.size(); dwIndex < dwSize; dwIndex++ )
+ {
+ outPin = ( COutPin * )m_OutPins[ dwIndex ];
+
+ if ( dwStreamId == outPin->streamId() )
+ {
+ break;
+ }
+
+ outPin = NULL;
+ }
+
+ return outPin;
+}
+
+/*++
+Description:
+This is a critical function which changes the state on an output pin
+This should be called under the control lock of the DT.
+Here the
+--*/
+STDMETHODIMP CMultipinMft::ChangeMediaTypeEx(
+ _In_ ULONG pinId,
+ _In_opt_ IMFMediaType *pMediaType,
+ _In_ DeviceStreamState reqState
+ )
+{
+ HRESULT hr = S_OK;
+ DeviceStreamState oldOutPinState;
+ DeviceStreamState newOutStreamState;
+ ComPtr<IMFMediaType> pFullType = nullptr;
+
+ COutPin *poPin = static_cast<COutPin*>( GetOutPin(pinId) );
+
+ MMFTMMAPITERATOR inputPinPos;
+
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+ //
+ //Check if the media type requested is a supported type
+ //
+ if ( pMediaType )
+ {
+ if ( !poPin->IsMediaTypeSupported( pMediaType, &pFullType ) )
+ {
+ DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done);
+ }
+ }
+ //
+ //First step disable the output pin. store the old state
+ //
+ oldOutPinState = poPin->SetState( DeviceStreamState_Disabled );
+
+ (void)poPin->FlushQueues();
+
+ newOutStreamState = pinStateTransition[oldOutPinState][reqState]; //New state needed
+
+ //
+ //Go through the output pins' maps that has the conencted input pin to the output pin
+ //
+ inputPinPos = m_outputPinMap.equal_range( pinId );
+
+ for (std::multimap<int, int>::iterator piterator = inputPinPos.first; piterator != inputPinPos.second;piterator++)
+ {
+ //
+ //Get the output pins connected to the input pin. The input pin map consists of the output pins connected
+ //
+ ULONG connectedInputPin = (*piterator).second;
+ BOOL isAnyConnectedOutPinActive = false;
+ BOOL isAnyConnectedOutPinPaused = false;
+ BOOL isAnyConnectedOutPinRunning = false;
+ BOOL doWeWaitForSetInput = false;
+ DeviceStreamState oldInputStreamState;
+ MF_TRANSFORM_XVP_OPERATION operation = DeviceMftTransformXVPIllegal;
+ ComPtr<IMFMediaType> pInputMediaType = nullptr;
+ CInPin *pconnectedInPin = (CInPin*)GetInPin( connectedInputPin );
+ oldInputStreamState = pconnectedInPin->SetState( DeviceStreamState_Disabled );
+ DeviceStreamState newRequestedInPinState = pinStateTransition[oldInputStreamState][newOutStreamState];
+
+ if (pFullType)
+ {
+ pconnectedInPin->getMediaType( &pInputMediaType );
+ }
+
+ //
+ // Check if we need an XVP to be inserted between this input and output pins.
+ //
+ CompareMediaTypesForXVP( pInputMediaType.Get(), pFullType.Get(), &operation );
+ DMFTCHECKHR_GOTO( GetConnectOutPinStatus( connectedInputPin,
+ pinId, // pinId = stream which should be excluded from the search. This function searches if
+ &isAnyConnectedOutPinPaused, // there are any other output pins connected other than the ouput pin (on which the change media type is requested)
+ &isAnyConnectedOutPinRunning, //, which is streaming, paused. This way if the output pin is requested to go to Pause, Stop and if any of the
+ &isAnyConnectedOutPinActive ),done ); //other connected output pins are active, then input it not deactivated
+
+ //
+ //Check if we are asked to go to an active state
+ //Check for the new media type. if
+ //
+ if ( !IsPinStateInActive( newRequestedInPinState ) )
+ {
+ //
+ //We are being told to go active
+ //We will request a change in input stream state.
+ //
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! %p Going active IN: %d OUT: %d ", this, connectedInputPin, pinId );
+ doWeWaitForSetInput = true;
+ if ( !pFullType )
+ {
+ DMFTCHECKHR_GOTO(MF_E_INVALIDMEDIATYPE, done);
+ }
+ if ( (! pInputMediaType ) || ( operation == DeviceMftTransformXVPDisruptiveIn ) )
+ {
+ pInputMediaType = pFullType;
+ }
+ if ( newRequestedInPinState == DeviceStreamState_Pause && isAnyConnectedOutPinRunning )
+ {
+ newRequestedInPinState = DeviceStreamState_Run;
+ }
+ }
+ else
+ {
+ //
+ //We have been requested to go inactive
+ //
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! %p Going Inactive IN: %d OUT: %d ", this, connectedInputPin, pinId );
+
+ if ( operation == DeviceMftTransformXVPDisruptiveIn )
+ {
+ //
+ //Only where we recieve a disruptive media type change and a media type along with it, which is unlikely!!
+ //
+ pInputMediaType = pFullType;
+ doWeWaitForSetInput = true;
+ }
+ if ( isAnyConnectedOutPinActive )
+ {
+ newRequestedInPinState = ( isAnyConnectedOutPinRunning ) ? DeviceStreamState_Run : DeviceStreamState_Pause;
+ }
+ else
+ {
+ //Switch over to the new media type..
+ pInputMediaType = pFullType;
+ if ( !IsPinStateInActive( oldInputStreamState ) )
+ {
+ //It was originall active.. now going down
+ doWeWaitForSetInput = true;
+ }
+ }
+ }
+
+ //
+ // This will happen if we need a change in Input media type, We will send an event
+ // METransformInputStreamStateChanged to the Device transform manager. This will result
+ // in the Device Transform manager calling us back in getprefferedinputstate where
+ // we will give it back the state of the input and the media type to be set.
+ // All this happens when we are holding a lock here in Change output media type. Hence during the
+ // input media type change we don't hold a lock. THE DTM takes care not to send you any more media
+ // type change operations that can cause a deadlock.
+ //
+
+ if ( doWeWaitForSetInput )
+ {
+ pconnectedInPin->setPreferredMediaType( pInputMediaType.Get() );
+ pconnectedInPin->setPreferredStreamState( newRequestedInPinState );
+ SendEventToManager( METransformInputStreamStateChanged, GUID_NULL, pconnectedInPin->streamId() );
+ //
+ //The media type will be set on the input pin by the time we return from the wait
+ //
+ DMFTCHECKHR_GOTO( pconnectedInPin->WaitForSetInputPinMediaChange(), done );
+ }
+ else
+ {
+ pconnectedInPin->SetState( oldInputStreamState );
+ pconnectedInPin->setMediaType( pInputMediaType.Get() );
+ }
+
+ //Now the input type is all set..
+ pInputMediaType = nullptr;
+ (VOID)pconnectedInPin->getMediaType( &pInputMediaType );
+ //
+ //Now propogate the media type change to the output pins
+ //
+ MMFTMMAPITERATOR outputPinPos = m_inputPinMap.equal_range(pconnectedInPin->streamId());
+ for ( std::multimap<int, int>::iterator poutPinsIterator = outputPinPos.first;
+ poutPinsIterator != outputPinPos.second;
+ poutPinsIterator++ )
+ {
+ ComPtr<IMFMediaType> pOutMediatype = nullptr;
+ DeviceStreamState outPinState;
+ ULONG connectedoutPin = (*poutPinsIterator).second;
+ COutPin* pIoPin = static_cast<COutPin*>( GetOutPin ( connectedoutPin ) );
+
+ (VOID)pIoPin->getMediaType( &pOutMediatype );
+ outPinState = pIoPin->GetState();
+
+ if ( pIoPin->streamId() != pinId)
+ {
+ //
+ //This is the pin other than the output pin where the original change media type was recieved.
+ //
+
+ if ( pInputMediaType != nullptr && pOutMediatype != nullptr )
+ {
+ DMFTCHECKHR_GOTO( pIoPin->ChangeMediaTypeFromInpin(pconnectedInPin, pInputMediaType.Get(),
+ pOutMediatype.Get(),
+ outPinState ),done);
+ }
+ }
+ else
+ {
+ //
+ //Change the media type of the requested output pin
+ //
+ DMFTCHECKHR_GOTO( pIoPin->ChangeMediaTypeFromInpin(pconnectedInPin, pInputMediaType.Get(), pFullType.Get(), newOutStreamState), done);
+ //Also signal to the manager that a stream state change has happened
+ SendEventToManager( MEUnknown, MEDeviceStreamCreated, pIoPin->streamId());
+ //
+ //Set the First Sample Flag. this will get reset when the first sample comes in. We will signal the discontinuity
+ //when we get a Processoutput from the Device Transform Manager
+ //
+ pIoPin->SetFirstSample(TRUE);
+
+ }
+ pOutMediatype = nullptr;
+ }
+
+ }
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::SendEventToManager(
+ _In_ MediaEventType eventType,
+ _In_ REFGUID pGuid,
+ _In_ UINT32 context
+ )
+ /*++
+ Description:
+ Used to send the event to DTM.
+ --*/
+ {
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaEvent> pEvent = nullptr;
+
+ DMFTCHECKHR_GOTO(MFCreateMediaEvent(eventType, pGuid, S_OK, NULL, &pEvent ),done);
+ DMFTCHECKHR_GOTO(pEvent->SetUINT32(MF_EVENT_MFT_INPUT_STREAM_ID, (ULONG)context),done);
+ DMFTCHECKHR_GOTO(QueueEvent(pEvent.Get()),done);
+ done:
+
+ return hr;
+ }
+
+
+STDMETHODIMP CMultipinMft::GetConnectOutPinStatus(
+ _In_ ULONG ulPinId,
+ _In_ ULONG ulOutPinId,
+ _Inout_ PBOOL pAnyInPauseState,
+ _Inout_ PBOOL pAnyInRunState,
+ _Inout_ PBOOL pAnyActive
+ )
+ /*++
+ Description:
+
+ This function gets the statuses of the output pins other than the one specified
+ The arguments are as follows
+ ulPinId: The input pins which are connected to the ouput pin ulOutPinId
+ ulOutPinId: The pin to be excluded from the check i.e. the input pin from which the request is usually sent.
+ --*/
+{
+ HRESULT hr = S_OK;
+ MMFTMMAPITERATOR outputPinPos;
+ CInPin *pconnectedInPin = (CInPin*)GetInPin(ulPinId);
+ DMFTCHECKNULL_GOTO( pconnectedInPin, done, E_INVALIDARG );
+
+ outputPinPos = m_inputPinMap.equal_range( pconnectedInPin->streamId() );
+ DMFTCHECKNULL_GOTO( pconnectedInPin, done, E_FAIL );
+
+ *pAnyActive = *pAnyInPauseState = *pAnyInRunState = false;
+
+ for ( std::multimap<int, int>::iterator poutPosIterator = outputPinPos.first;
+ poutPosIterator != outputPinPos.second;
+ poutPosIterator++ )
+ {
+ ULONG connectedoutPin = (*poutPosIterator).second;
+ COutPin* pconnectedOutPin = ( COutPin * )GetOutPin( connectedoutPin );
+
+ if (pconnectedOutPin->streamId() != ulOutPinId)
+ {
+ //This is excluding the outpin which requested pin state change
+ *pAnyActive |= !IsPinStateInActive( pconnectedOutPin->GetState() );
+ *pAnyInPauseState |= ( pconnectedOutPin->GetState() == DeviceStreamState_Pause );
+ *pAnyInRunState |= ( pconnectedOutPin->GetState() == DeviceStreamState_Run );
+ }
+
+ }
+ done:
+ return S_OK;
+}
+
+
+/*++
+Description:
+This function connects the input and output pins.
+Any media type filtering can happen here
+--*/
+STDMETHODIMP CMultipinMft::BridgeInputPinOutputPin(
+ _In_ CInPin* piPin,
+ _In_ COutPin* poPin
+ )
+{
+ HRESULT hr = S_OK;
+ ULONG ulIndex = 0;
+ ComPtr<IMFMediaType> pMediaType = nullptr;
+
+ DMFTCHECKNULL_GOTO( piPin, done, E_INVALIDARG );
+ DMFTCHECKNULL_GOTO( poPin, done, E_INVALIDARG );
+ //
+ // Copy over the media types from input pin to output pin. Since there is no
+ // decoder support, only the uncompressed media types are inserted. Please make
+ // sure any pin advertised supports at least one media type. The pipeline doesn't
+ // like pins with no media types
+ //
+ while ( SUCCEEDED( hr = piPin->GetMediaTypeAt( ulIndex++, &pMediaType )))
+ {
+ GUID subType = GUID_NULL;
+ DMFTCHECKHR_GOTO( pMediaType->GetGUID(MF_MT_SUBTYPE,&subType), done );
+
+ if ( IsKnownUncompressedVideoType( subType ) )
+ {
+ DMFTCHECKHR_GOTO( poPin->AddMediaType(NULL, pMediaType.Get() ), done );
+ }
+
+ pMediaType = nullptr;
+ }
+ //
+ //Add the Input Pin to the output Pin
+ //
+ DMFTCHECKHR_GOTO(poPin->AddPin(piPin->streamId()), done);
+ hr = ExceptionBoundary([&](){
+ //
+ //Add the output pin to the input pin.
+ //
+ piPin->ConnectPin(poPin);
+ });
+ DMFTCHECKHR_GOTO(hr, done);
+ //
+ //Create the map. This will be useful when we have to decide the state transitions of the pins
+ //
+ m_inputPinMap.insert ( std::pair< int,int >( piPin->streamId(), poPin->streamId()) );
+ m_outputPinMap.insert ( std::pair< int, int >( poPin->streamId(), piPin->streamId()) );
+done:
+ //
+ //Failed adding media types
+ //
+ if (FAILED(hr))
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_ERROR, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ }
+ return hr;
+}
+
+
+//
+//The below routines are used to implement the extended controls needed to implement the photo sequence
+//The photo sequence is enabled for cameras with no independent image pins
+//The extended controls needed to enable photo sequence are discussed in detail in the photo sequence document
+//
+
+/*++
+Extended Photo Mode handler is the extended property handler dealing with the photosequence and single mode capabilities of the camera
+--*/
+STDMETHODIMP CMultipinMft::ExtendedPhotoModeHandler(
+_In_ PKSPROPERTY Property,
+_In_ ULONG ulPropertyLength,
+_In_ LPVOID pData,
+_In_ ULONG ulOutputBufferLength,
+_Inout_ PULONG pulBytesReturned
+)
+
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE );
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ) )
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ) )
+ {
+ PBYTE pPayload = ( PBYTE )pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ //
+ //Use the below structure to make changes to the Property and thus affect the configuration
+ //PKSCAMERA_EXTENDEDPROP_PHOTOMODE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_PHOTOMODE)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ m_FilterInPhotoSequence = pExtendedHeader->Flags & KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE;
+ DMFTCHECKHR_GOTO(m_eventHandler.SetOneShot(KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMODE), done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+ }
+ else if ( Property->Flags & KSPROPERTY_TYPE_GET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE );
+ hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE ) )
+ {
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ PKSCAMERA_EXTENDEDPROP_PHOTOMODE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_PHOTOMODE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) );
+
+ pExtendedHeader->Capability = ( KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE );
+ pExtendedHeader->Flags = ( m_FilterInPhotoSequence ) ? KSCAMERA_EXTENDEDPROP_PHOTOMODE_SEQUENCE : KSCAMERA_EXTENDEDPROP_PHOTOMODE_NORMAL;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE );
+ pExtendedHeader->Version = 1;
+
+ pExtendedValue->MaxHistoryFrames = 10;
+ pExtendedValue->RequestedHistoryFrames = 0 ;
+ pExtendedValue->SubMode = 0 ;
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_PHOTOMODE );
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO( E_INVALIDARG, done );
+ }
+ }
+
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+
+ return hr;
+}
+
+/*++
+The Extended Max Frame rate is self explanatory
+--*/
+STDMETHODIMP CMultipinMft::ExtendedPhotoMaxFrameRate(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (ulOutputBufferLength < sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE))
+ {
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (pData && ulOutputBufferLength >= sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE))
+ {
+ //
+ //This is for setting the Max frame rate..
+ //
+ //PBYTE pPayload = (PBYTE)pData;
+ //PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = (PKSCAMERA_EXTENDEDPROP_HEADER)(pPayload);
+ //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ DMFTCHECKHR_GOTO(m_eventHandler.SetOneShot(KSPROPERTY_CAMERACONTROL_EXTENDED_PHOTOMAXFRAMERATE), done);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+ }
+ else if ( Property->Flags & KSPROPERTY_TYPE_GET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ hr = HRESULT_FROM_WIN32( ERROR_MORE_DATA );
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ PBYTE pPayload = ( PBYTE )pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_VALUE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) );
+ pExtendedHeader->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL;
+ pExtendedHeader->Flags = 0;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE);
+ pExtendedHeader->Version = 1;
+ pExtendedValue->Value.ratio.HighPart = 30;
+ pExtendedValue->Value.ratio.LowPart = 1;
+ *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_EXTENDEDPROP_VALUE);
+ }
+ else
+ {
+ DMFTCHECKHR_GOTO(E_INVALIDARG, done);
+ }
+ }
+
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::MaxVidFPS_PhotoResHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+ sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES );
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+ sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES ) )
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if (pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES ))
+ {
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ //
+ //Use the extended value to make changes to the property.. refer documentation
+ //PKSCAMERA_MAXVIDEOFPS_FORPHOTORES pExtendedValue = (PKSCAMERA_MAXVIDEOFPS_FORPHOTORES)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ pExtendedHeader->Capability = 0;
+ pExtendedHeader->Flags = 0;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ pExtendedHeader->Version = 1;
+
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_MAXVIDEOFPS_FORPHOTORES );
+ }
+
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+ else if (Property->Flags & KSPROPERTY_TYPE_GET)
+ {
+ if (ulOutputBufferLength == 0)
+ {
+ *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES);
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (ulOutputBufferLength < sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES))
+ {
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (pData && ulOutputBufferLength >= sizeof(KSCAMERA_EXTENDEDPROP_HEADER)+sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES))
+ {
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )(pPayload );
+ PKSCAMERA_MAXVIDEOFPS_FORPHOTORES pExtendedValue = (PKSCAMERA_MAXVIDEOFPS_FORPHOTORES)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ pExtendedHeader->Capability = 0;
+ pExtendedHeader->Flags = 0;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(PKSCAMERA_MAXVIDEOFPS_FORPHOTORES);
+ pExtendedHeader->Version = 1;
+
+ pExtendedValue->PreviewFPSNum = 30;
+ pExtendedValue->PreviewFPSDenom = 1;
+ pExtendedValue->CaptureFPSNum = 30;
+ pExtendedValue->CaptureFPSDenom = 1;
+ pExtendedValue->PhotoResHeight = 240;
+ pExtendedValue->PhotoResWidth = 320;
+
+ *pulBytesReturned = sizeof(KSCAMERA_EXTENDEDPROP_HEADER) + sizeof(KSCAMERA_MAXVIDEOFPS_FORPHOTORES);
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::QPCTimeHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+{
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) )
+ {
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) )
+ {
+ //PBYTE pPayload = (PBYTE)pData;
+ //
+ //If the payload is to be used.. use the below structures
+ //
+ //PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = (PKSCAMERA_EXTENDEDPROP_HEADER)(pPayload);
+ //Use the extended value to make changes to the property.. refer documentation
+ //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload +sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ *pulBytesReturned = sizeof( PKSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+ else if ( Property->Flags & KSPROPERTY_TYPE_GET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) + sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) )
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) + sizeof( KSCAMERA_EXTENDEDPROP_VALUE ) )
+ {
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_VALUE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) );
+ pExtendedHeader->Capability = 0;
+ pExtendedHeader->Flags = KSPROPERTY_CAMERA_PHOTOTRIGGERTIME_SET;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) + sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ pExtendedHeader->Version = 1;
+ pExtendedValue->Value.ull = 0;
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+ sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ }
+ else
+ {
+ hr = E_INVALIDARG;
+ }
+ }
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+STDMETHODIMP CMultipinMft::PhotoFrameRateHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+{
+ HRESULT hr = S_OK;
+
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ //
+ //This is a read only property!!!
+ //
+ hr = E_INVALIDARG;
+ }
+ else if ( Property->Flags & KSPROPERTY_TYPE_GET )
+ {
+ if ( ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ PBYTE pPayload = (PBYTE)pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = ( PKSCAMERA_EXTENDEDPROP_VALUE )( pPayload + sizeof( KSCAMERA_EXTENDEDPROP_HEADER ) );
+ pExtendedHeader->Capability = 0;
+ pExtendedHeader->Flags = 0;
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ pExtendedHeader->Version = 1;
+ pExtendedValue->Value.ratio.HighPart = 30;
+ pExtendedValue->Value.ratio.LowPart = 1;
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+
+ }
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+
+STDMETHODIMP CMultipinMft::WarmStartHandler(
+ _In_ PKSPROPERTY Property,
+ _In_ ULONG ulPropertyLength,
+ _In_ LPVOID pData,
+ _In_ ULONG ulOutputBufferLength,
+ _Inout_ PULONG pulBytesReturned
+ )
+{
+
+ HRESULT hr = S_OK;
+ UNREFERENCED_PARAMETER( ulPropertyLength );
+ *pulBytesReturned = 0;
+
+ if ( Property->Flags & KSPROPERTY_TYPE_SET )
+ {
+ if ( ulOutputBufferLength == 0 )
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done);
+ }
+ else if (ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done);
+ }
+ else if ( pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ PBYTE pPayload = ( PBYTE )pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )pPayload;
+ //
+ //Use the extended value to make changes to the property.. refer documentation
+ //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload + sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ if ( pExtendedHeader->Flags & KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED )
+ {
+ m_filterInWarmStart = true;
+ }
+ else
+ {
+ m_filterInWarmStart = false;
+ }
+
+ *pulBytesReturned = sizeof( PKSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ m_eventHandler.SetOneShot(KSPROPERTY_CAMERACONTROL_EXTENDED_WARMSTART);
+ }
+ else
+ {
+ hr = S_OK;
+ }
+ }
+ else if (Property->Flags & KSPROPERTY_TYPE_GET)
+ {
+ if (ulOutputBufferLength == 0)
+ {
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ DMFTCHECKHR_GOTO(HRESULT_FROM_WIN32(ERROR_MORE_DATA), done);
+ }
+ else if (ulOutputBufferLength < sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ DMFTCHECKHR_GOTO( HRESULT_FROM_WIN32( ERROR_MORE_DATA ), done );
+ }
+ else if (pData && ulOutputBufferLength >= sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE ))
+ {
+ PBYTE pPayload = ( PBYTE )pData;
+ PKSCAMERA_EXTENDEDPROP_HEADER pExtendedHeader = ( PKSCAMERA_EXTENDEDPROP_HEADER )( pPayload );
+ //
+ //Use the extended value to make changes to the property.. refer documentation
+ //PKSCAMERA_EXTENDEDPROP_VALUE pExtendedValue = (PKSCAMERA_EXTENDEDPROP_VALUE)(pPayload +sizeof(KSCAMERA_EXTENDEDPROP_HEADER));
+ //
+ pExtendedHeader->Capability = KSCAMERA_EXTENDEDPROP_CAPS_ASYNCCONTROL | KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED;
+ pExtendedHeader->Flags = 0;
+
+ if (m_filterInWarmStart)
+ {
+ pExtendedHeader->Flags |= KSCAMERA_EXTENDEDPROP_WARMSTART_MODE_ENABLED;
+ }
+
+ pExtendedHeader->Result = 0;
+ pExtendedHeader->Size = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ pExtendedHeader->Version = 1;
+ *pulBytesReturned = sizeof( KSCAMERA_EXTENDEDPROP_HEADER )+sizeof( KSCAMERA_EXTENDEDPROP_VALUE );
+ hr = S_OK;
+ }
+ else
+ {
+ hr = S_OK;
+ }
+ }
+done:
+ DMFTRACE( DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr );
+ return hr;
+}
+
+
+//
+// IMFShutdown interface functions
+//
+
+/*++
+Description:
+Implements the Shutdown from IMFShutdown
+--*/
+STDMETHODIMP CMultipinMft::Shutdown(
+ void
+ )
+{
+ CAutoLock Lock(m_critSec);
+ (VOID) m_eventHandler.Clear();
+ return ShutdownEventGenerator();
+}
+
+//
+// Static method to create an instance of the MFT.
+//
+HRESULT CMultipinMft::CreateInstance(REFIID iid, void **ppMFT)
+{
+ HRESULT hr = S_OK;
+ CMultipinMft *pMFT = NULL;
+ DMFTCHECKNULL_GOTO(ppMFT, done, E_POINTER);
+ pMFT = new (std::nothrow) CMultipinMft();
+ DMFTCHECKNULL_GOTO(pMFT, done, E_OUTOFMEMORY);
+
+ DMFTCHECKHR_GOTO(pMFT->QueryInterface(iid, ppMFT), done);
+
+done:
+ if (FAILED(hr))
+ {
+ SAFERELEASE(pMFT);
+ }
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+
+
+
+
+#if defined (MF_DEVICEMFT_PHTOTOCONFIRMATION)
+/*
+Desciption:
+This function will be called by the preview pin to execute the photo confirmation stored with the
+MFT.
+*/
+
+STDMETHODIMP CMultipinMft::ProcessCapturePhotoConfirmationCallBack(
+ _In_ IMFMediaType* pMediaType,
+ _In_ IMFSample* pSample
+ )
+{
+ //
+ //PhotoConfirmation Implementation
+ //Note this function doesn't scan the metadata as the pipeline does to find out which buffer is the photoconfirmation buffer
+ //The pipeline treats the preview buffer as the photo confirmation buffer and the driver marks the metadata on the buffer as being so.
+ //This example treats every buffer coming on the pin as the confirmation buffer.
+ //
+
+ HRESULT hr = S_OK;
+ ComPtr<IMFMediaType> spMediaType = nullptr;
+ LONGLONG timeStamp = 0;
+
+ DMFTCHECKHR_GOTO(MFCreateMediaType(&spMediaType), done);
+ DMFTCHECKHR_GOTO(pMediaType->CopyAllItems(spMediaType.Get()), done);
+
+ DMFTCHECKHR_GOTO(pSample->SetUnknown(MFSourceReader_SampleAttribute_MediaType_priv, spMediaType.Get()), done);
+
+ DMFTCHECKHR_GOTO(pSample->GetSampleTime(&timeStamp), done);
+ DMFTCHECKHR_GOTO(pSample->SetUINT64(MFSampleExtension_DeviceReferenceSystemTime, timeStamp), done);
+
+ if (m_spPhotoConfirmationCallback)
+ {
+
+ //
+ //We are directly sending the photo sample over to the consumers of the photoconfirmation interface.
+ //
+ ComPtr<IMFAsyncResult> spResult;
+ DMFTCHECKHR_GOTO(MFCreateAsyncResult(pSample, m_spPhotoConfirmationCallback.Get(), NULL, &spResult), done);
+ DMFTCHECKHR_GOTO(MFInvokeCallback(spResult.Get()), done);
+ }
+done:
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}
+
+#endif
+
+//
+// Only worry about this if you have customs pins defined in the driver
+//
+
+STDMETHODIMP CMultipinMft::SetStreamingStateCustomPins(
+ DeviceStreamState State
+ )
+{
+ HRESULT hr = S_OK;
+
+ if ( m_CustomPinCount > 0 )
+ {
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! Custom Pin State changing to %d", State);
+
+ for (ULONG ulIndex = 0; ulIndex < m_InPins.size(); ulIndex++)
+ {
+ BOOL isCustom = false;
+ CInPin* pInPin = static_cast<CInPin*>(m_InPins[ulIndex]);
+
+ if ( SUCCEEDED( CheckCustomPin(pInPin, &isCustom) )
+ && ( isCustom ) )
+ {
+ pInPin->SetState(State);
+ }
+ }
+ }
+ DMFTRACE(DMFT_GENERAL, TRACE_LEVEL_INFORMATION, "%!FUNC! exiting %x = %!HRESULT!", hr, hr);
+ return hr;
+}